| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.royale.formatter.config; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.royale.compiler.common.IPathResolver; |
| import org.apache.royale.compiler.exceptions.ConfigurationException; |
| import org.apache.royale.compiler.exceptions.ConfigurationException.CannotOpen; |
| import org.apache.royale.compiler.internal.config.annotations.Arguments; |
| import org.apache.royale.compiler.internal.config.annotations.Config; |
| import org.apache.royale.compiler.internal.config.annotations.InfiniteArguments; |
| import org.apache.royale.compiler.internal.config.annotations.Mapping; |
| import org.apache.royale.compiler.problems.DeprecatedConfigurationOptionProblem; |
| import org.apache.royale.compiler.problems.ICompilerProblem; |
| import org.apache.royale.compiler.problems.RemovedConfigurationOptionProblem; |
| import org.apache.royale.utils.FilenameNormalization; |
| |
| import com.google.common.collect.ImmutableList; |
| |
| public class Configuration { |
| |
| private static Map<String, String> aliases = null; |
| |
| public static Map<String, String> getAliases() |
| { |
| if (aliases == null) |
| { |
| aliases = new HashMap<String, String>(); |
| |
| aliases.put("w", "write-files"); |
| aliases.put("l", "list-files"); |
| } |
| return aliases; |
| } |
| |
| // |
| // PathResolver |
| // |
| private IPathResolver pathResolver; |
| |
| /** |
| * Set a path resolver to resolver files relative to a configuration. Files inside of configuration files are |
| * resolved relative to those configuration files and files on the command line are resolved relative to the root |
| * directory of the compile. |
| * |
| * @param pathResolver a path resolver for this configuration. May not be null. |
| */ |
| public void setPathResolver(IPathResolver pathResolver) |
| { |
| this.pathResolver = pathResolver; |
| } |
| |
| /** |
| * Collection of fatal and non-fatal configuration problems. |
| */ |
| private Collection<ICompilerProblem> configurationProblems = new ArrayList<ICompilerProblem>(); |
| |
| /** |
| * Get the configuration problems. This should be called after the configuration has been processed. |
| * |
| * @return a collection of fatal and non-fatal configuration problems. |
| */ |
| public Collection<ICompilerProblem> getConfigurationProblems() |
| { |
| return configurationProblems; |
| } |
| |
| /** |
| * Validate configuration options values. |
| * |
| * @param configurationBuffer Configuration buffer. |
| * @throws ConfigurationException Error. |
| */ |
| public void validate(ConfigurationBuffer configurationBuffer) throws ConfigurationException |
| { |
| // process the merged configuration buffer. right, can't just process the args. |
| processDeprecatedAndRemovedOptions(configurationBuffer); |
| } |
| |
| private void processDeprecatedAndRemovedOptions(ConfigurationBuffer configurationBuffer) |
| { |
| for (final String var : configurationBuffer.getVars()) |
| { |
| ConfigurationInfo info = configurationBuffer.getInfo(var); |
| List<ConfigurationValue> values = configurationBuffer.getVar(var); |
| if (values != null) |
| { |
| for (final ConfigurationValue cv : values) |
| { |
| if (info.isRemoved()) |
| { |
| addRemovedConfigurationOptionProblem(cv); |
| } |
| else if (info.isDeprecated() && configurationBuffer.getVar(var) != null) |
| { |
| String replacement = info.getDeprecatedReplacement(); |
| String since = info.getDeprecatedSince(); |
| DeprecatedConfigurationOptionProblem problem = new DeprecatedConfigurationOptionProblem(var, |
| replacement, since, cv.getSource(), cv.getLine()); |
| configurationProblems.add(problem); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Add a RemovedConfigurationOptionProblem to the list of configuration problems. |
| * |
| * @param cv |
| */ |
| private void addRemovedConfigurationOptionProblem(ConfigurationValue cv) |
| { |
| RemovedConfigurationOptionProblem problem = new RemovedConfigurationOptionProblem(cv.getVar(), cv.getSource(), |
| cv.getLine()); |
| configurationProblems.add(problem); |
| } |
| |
| // |
| // 'help' option from CommandLineConfiguration |
| // |
| |
| /** |
| * dummy, just a trigger for help text |
| */ |
| @Config(displayed = false, greedy = true) |
| @Arguments("keyword") |
| @InfiniteArguments |
| public void setHelp(ConfigurationValue cv, String[] keywords) |
| { |
| |
| } |
| |
| // |
| // 'version' option from CommandLineConfiguration |
| // |
| |
| /** |
| * Dummy option. Just a trigger for version info. |
| */ |
| @Config |
| public void setVersion(ConfigurationValue cv, boolean value) |
| { |
| } |
| |
| // |
| // 'load-config' option from CommandLineConfiguration |
| // |
| |
| private String configFile = null; |
| |
| /** |
| * @return Normalized path to a Flex configuration file. |
| */ |
| public String getLoadConfig() |
| { |
| return configFile; |
| } |
| |
| /** |
| * Since {@link ConfigurationBuffer} loads the "load-config" files, the value of this configuration option isn't |
| * intersting to the rest part of the compiler. |
| */ |
| @Config(allowMultiple = true) |
| @Arguments("filename") |
| public void setLoadConfig(ConfigurationValue cv, String filename) throws ConfigurationException |
| { |
| configFile = resolvePathStrict(filename, cv); |
| } |
| |
| // |
| // 'files' option |
| // |
| |
| private List<String> files = new ArrayList<String>(); |
| |
| /** |
| * @return A list of filespecs. It's the default variable for command line. |
| */ |
| public List<String> getFiles() |
| { |
| return files; |
| } |
| |
| @Config(allowMultiple = true, hidden = true) |
| @Mapping("files") |
| @Arguments(Arguments.PATH_ELEMENT) |
| @InfiniteArguments |
| public void setFiles(ConfigurationValue cv, List<String> args) throws ConfigurationException |
| { |
| this.files.addAll(args); |
| } |
| |
| // |
| // 'skip-local-config-file' option |
| // |
| |
| private boolean skipLocalConfigFile = false; |
| |
| public boolean getSkipLocalConfigFile() { |
| return skipLocalConfigFile; |
| } |
| |
| @Config |
| @Mapping("skip-local-config-file") |
| public void setSkipLocalConfigFile(ConfigurationValue cv, boolean b) { |
| this.skipLocalConfigFile = b; |
| } |
| |
| // |
| // 'write-files' option |
| // |
| |
| private boolean writeFiles = false; |
| |
| public boolean getWriteFiles() |
| { |
| return writeFiles; |
| } |
| |
| @Config |
| @Mapping("write-files") |
| public void setWriteFiles(ConfigurationValue cv, boolean b) |
| { |
| this.writeFiles = b; |
| } |
| |
| // |
| // 'list-files' option |
| // |
| |
| private boolean listFiles = false; |
| |
| public boolean getListFiles() |
| { |
| return listFiles; |
| } |
| |
| @Config |
| @Mapping("list-files") |
| public void setListFiles(ConfigurationValue cv, boolean b) |
| { |
| this.listFiles = b; |
| } |
| |
| // |
| // 'insert-spaces' option |
| // |
| |
| private boolean insertSpaces = false; |
| |
| public boolean getInsertSpaces() |
| { |
| return insertSpaces; |
| } |
| |
| @Config |
| @Mapping("insert-spaces") |
| public void setInsertSpaces(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaces = b; |
| } |
| |
| // |
| // 'insert-final-new-line' option |
| // |
| |
| private boolean insertFinalNewLine = false; |
| |
| public boolean getInsertFinalNewLine() |
| { |
| return insertFinalNewLine; |
| } |
| |
| @Config |
| @Mapping("insert-final-new-line") |
| public void setInsertFinalNewLine(ConfigurationValue cv, boolean b) |
| { |
| this.insertFinalNewLine = b; |
| } |
| |
| // |
| // 'open-brace-new-line' option |
| // |
| |
| private boolean placeOpenBraceOnNewLine = true; |
| |
| public boolean getPlaceOpenBraceOnNewLine() |
| { |
| return placeOpenBraceOnNewLine; |
| } |
| |
| @Config |
| @Mapping("open-brace-new-line") |
| public void setPlaceOpenBraceOnNewLine(ConfigurationValue cv, boolean b) |
| { |
| this.placeOpenBraceOnNewLine = b; |
| } |
| |
| // |
| // 'insert-space-for-loop-semicolon' option |
| // |
| |
| private boolean insertSpaceAfterSemicolonInForStatements = true; |
| |
| public boolean getInsertSpaceAfterSemicolonInForStatements() |
| { |
| return insertSpaceAfterSemicolonInForStatements; |
| } |
| |
| @Config |
| @Mapping("insert-space-for-loop-semicolon") |
| public void setInsertSpaceAfterSemicolonInForStatements(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceAfterSemicolonInForStatements = b; |
| } |
| |
| // |
| // 'insert-space-control-flow-keywords' option |
| // |
| |
| private boolean insertSpaceAfterKeywordsInControlFlowStatements = true; |
| |
| public boolean getInsertSpaceAfterKeywordsInControlFlowStatements() |
| { |
| return insertSpaceAfterKeywordsInControlFlowStatements; |
| } |
| |
| @Config |
| @Mapping("insert-space-control-flow-keywords") |
| public void setInsertSpaceAfterKeywordsInControlFlowStatements(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceAfterKeywordsInControlFlowStatements = b; |
| } |
| |
| // |
| // 'insert-space-anonymous-function-keyword' option |
| // |
| |
| private boolean insertSpaceAfterFunctionKeywordForAnonymousFunctions = false; |
| |
| public boolean getInsertSpaceAfterFunctionKeywordForAnonymousFunctions() |
| { |
| return insertSpaceAfterFunctionKeywordForAnonymousFunctions; |
| } |
| |
| @Config |
| @Mapping("insert-space-anonymous-function-keyword") |
| public void setInsertSpaceAfterFunctionKeywordForAnonymousFunctions(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceAfterFunctionKeywordForAnonymousFunctions = b; |
| } |
| |
| // |
| // 'insert-space-binary-operators' option |
| // |
| |
| private boolean insertSpaceBeforeAndAfterBinaryOperators = true; |
| |
| public boolean getInsertSpaceBeforeAndAfterBinaryOperators() |
| { |
| return insertSpaceBeforeAndAfterBinaryOperators; |
| } |
| |
| @Config |
| @Mapping("insert-space-binary-operators") |
| public void setInsertSpaceBeforeAndAfterBinaryOperators(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceBeforeAndAfterBinaryOperators = b; |
| } |
| |
| // |
| // 'insert-space-comma-delimiter' option |
| // |
| |
| private boolean insertSpaceAfterCommaDelimiter = true; |
| |
| public boolean getInsertSpaceAfterCommaDelimiter() |
| { |
| return insertSpaceAfterCommaDelimiter; |
| } |
| |
| @Config |
| @Mapping("insert-space-comma-delimiter") |
| public void setInsertSpaceAfterCommaDelimiter(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceAfterCommaDelimiter = b; |
| } |
| |
| // |
| // 'insert-space-meta-attributes' option |
| // |
| |
| private boolean insertSpaceBetweenMetadataAttributes = true; |
| |
| public boolean getInsertSpaceBetweenMetadataAttributes() |
| { |
| return insertSpaceBetweenMetadataAttributes; |
| } |
| |
| @Config |
| @Mapping("insert-space-meta-attributes") |
| public void setInsertSpaceBetweenMetadataAttributes(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceBetweenMetadataAttributes = b; |
| } |
| |
| // |
| // 'insert-space-line-comment' option |
| // |
| |
| private boolean insertSpaceAtStartOfLineComment = true; |
| |
| public boolean getInsertSpaceAtStartOfLineComment() |
| { |
| return insertSpaceAtStartOfLineComment; |
| } |
| |
| @Config |
| @Mapping("insert-space-line-comment") |
| public void setInsertSpaceAtStartOfLineComment(ConfigurationValue cv, boolean b) |
| { |
| this.insertSpaceAtStartOfLineComment = b; |
| } |
| |
| // |
| // 'collapse-empty-blocks' option |
| // |
| |
| private boolean collapseEmptyBlocks = false; |
| |
| public boolean getCollapseEmptyBlocks() |
| { |
| return collapseEmptyBlocks; |
| } |
| |
| @Config |
| @Mapping("collapse-empty-blocks") |
| public void setCollapseEmptyBlocks(ConfigurationValue cv, boolean b) |
| { |
| this.collapseEmptyBlocks = b; |
| } |
| |
| // |
| // 'tab-size' option |
| // |
| |
| private int tabSize = 4; |
| |
| public int getTabSize() |
| { |
| return tabSize; |
| } |
| |
| @Config |
| @Mapping("tab-size") |
| public void setTabSize(ConfigurationValue cv, int b) |
| { |
| this.tabSize = b; |
| } |
| |
| // |
| // 'max-preserve-new-lines' option |
| // |
| |
| private int maxPreserveNewLines = 2; |
| |
| public int getMaxPreserveNewLines() |
| { |
| return maxPreserveNewLines; |
| } |
| |
| @Config |
| @Mapping("max-preserve-new-lines") |
| public void setMaxPreserveNewLines(ConfigurationValue cv, int b) |
| { |
| this.maxPreserveNewLines = b; |
| } |
| |
| // |
| // 'semicolons' option |
| // |
| |
| private Semicolons semicolons = Semicolons.INSERT; |
| |
| public String getSemicolons() |
| { |
| return semicolons.value; |
| } |
| |
| @Config |
| @Mapping("semicolons") |
| public void setSemicolons(ConfigurationValue cv, String b) |
| { |
| this.semicolons = Semicolons.valueOf(b.toUpperCase()); |
| } |
| |
| // |
| // 'ignore-parsing-problems' option |
| // |
| |
| private boolean ignoreParsingProblems = false; |
| |
| public boolean getIgnoreParsingProblems() |
| { |
| return ignoreParsingProblems; |
| } |
| |
| @Config(advanced = true) |
| @Mapping("ignore-parsing-problems") |
| public void setIgnoreParsingProblems(ConfigurationValue cv, boolean b) |
| { |
| this.ignoreParsingProblems = b; |
| } |
| |
| // |
| // 'mxml-align-attributes' option |
| // |
| |
| private boolean mxmlAlignAttributes = false; |
| |
| public boolean getMxmlAlignAttributes() |
| { |
| return mxmlAlignAttributes; |
| } |
| |
| @Config(advanced = true) |
| @Mapping("mxml-align-attributes") |
| public void setMxmlAlignAttributes(ConfigurationValue cv, boolean b) |
| { |
| this.mxmlAlignAttributes = b; |
| } |
| |
| // |
| // 'mxml-insert-new-line-attributes' option |
| // |
| |
| private boolean mxmlInsertNewLineBetweenAttributes = false; |
| |
| public boolean getMxmlInsertNewLineBetweenAttributes() |
| { |
| return mxmlInsertNewLineBetweenAttributes; |
| } |
| |
| @Config(advanced = true) |
| @Mapping("mxml-insert-new-line-attributes") |
| public void setMxmlInsertNewLineBetweenAttributes(ConfigurationValue cv, boolean b) |
| { |
| this.mxmlInsertNewLineBetweenAttributes = b; |
| } |
| |
| /** |
| * |
| * @param path A path to resolve. |
| * @param cv Configuration context. |
| * @return A single normalized resolved file. If the path could be expanded into more than one path, then use |
| * {@link resolvePathsStrict} |
| * @throws CannotOpen |
| */ |
| protected String resolvePathStrict(final String path, final ConfigurationValue cv) throws CannotOpen |
| { |
| return resolvePathStrict(path, cv, false); |
| } |
| |
| /** |
| * Resolve a single path. This is a more strict version of {@link #resolvePaths()} in that it throws |
| * {@link CannotOpen} exception when a file path element can't be resolved. |
| * |
| * @param path A path to resolve. |
| * @param cv Configuration context. |
| * @param returnMissingFiles Determines if the CannotOpen exception is thrown if a file does not exist. Pass true to |
| * disable exceptions and return files that do not exist. Pass false to throw exceptions. |
| * @return A single normalized resolved file. If the path could be expanded into more than one path, then use |
| * {@link resolvePathsStrict}. |
| * @throws CannotOpen error |
| * @see #resolvePaths(ImmutableList, ConfigurationValue) |
| */ |
| private String resolvePathStrict(final String path, final ConfigurationValue cv, final boolean returnMissingFiles) |
| throws CannotOpen |
| { |
| ImmutableList<String> singletonPath = ImmutableList.of(path); |
| ImmutableList<String> results = resolvePathsStrict(singletonPath, cv, returnMissingFiles); |
| return results.get(0); |
| } |
| |
| /** |
| * Resolve a list of paths. This is a more strict version of {@link #resolvePaths()} in that it throws |
| * {@link CannotOpen} exception when a file path element can't be resolved. |
| * |
| * @param paths A list of paths to resolve. |
| * @param cv Configuration context. |
| * @return A list of normalized resolved file paths. |
| * @throws CannotOpen error |
| * @see #resolvePaths(ImmutableList, ConfigurationValue) |
| */ |
| private ImmutableList<String> resolvePathsStrict(final ImmutableList<String> paths, final ConfigurationValue cv) |
| throws CannotOpen |
| { |
| return resolvePathsStrict(paths, cv, false); |
| } |
| |
| /** |
| * Resolve a list of paths. This is a more strict version of {@link #resolvePaths()} in that it throws |
| * {@link CannotOpen} exception when a file path element can't be resolved. |
| * |
| * @param paths A list of paths to resolve. |
| * @param cv Configuration context. |
| * @param returnMissingFiles Determines if the CannotOpen exception is thrown if a file does not exist. Pass true to |
| * disable exceptions and return files that do not exist. Pass false to throw exceptions. |
| * @return A list of normalized resolved file paths. |
| * @throws CannotOpen error |
| * @see #resolvePaths(ImmutableList, ConfigurationValue) |
| */ |
| private ImmutableList<String> resolvePathsStrict(final ImmutableList<String> paths, final ConfigurationValue cv, |
| final boolean returnMissingFiles) throws CannotOpen |
| { |
| assert paths != null : "Expected paths"; |
| assert cv != null : "Require ConfigurationValue as context."; |
| |
| final ImmutableList.Builder<String> resolvedPathsBuilder = new ImmutableList.Builder<String>(); |
| for (String processedPath : paths) |
| { |
| if (cv.getContext() != null) |
| { |
| boolean isAbsolute = new File(processedPath).isAbsolute(); |
| if (!isAbsolute) |
| processedPath = new File(cv.getContext(), processedPath).getAbsolutePath(); |
| } |
| if (processedPath.contains("*")) |
| { |
| // if contains wild card, just prove the part before the wild card is valid |
| int c = processedPath.lastIndexOf(File.separator, processedPath.indexOf("*")); |
| if (c != -1) |
| processedPath = processedPath.substring(0, c); |
| } |
| if (!processedPath.contains(".swc:")) |
| { |
| final File fileSpec = pathResolver.resolve(processedPath); |
| if (!returnMissingFiles && !fileSpec.exists()) |
| { |
| throw new CannotOpen(FilenameNormalization.normalize(processedPath), cv.getVar(), cv.getSource(), |
| cv.getLine()); |
| } |
| resolvedPathsBuilder.add(fileSpec.getAbsolutePath()); |
| } |
| else |
| resolvedPathsBuilder.add(processedPath); |
| } |
| return resolvedPathsBuilder.build(); |
| } |
| } |