blob: 2e18839041be4c295bb8fd645d828eb3e99c7730 [file] [log] [blame]
/*
*
* 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();
}
}