diff --git a/README.md b/README.md index a0e3a26c..0125c797 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ java -jar closure-stylesheets.jar --help ``` [download]: https://github.com/google/closure-stylesheets/releases -[build it from source]: https://github.com/google/closure-stylesheets/wiki/Building From Source.md +[build it from source]: https://github.com/google/closure-stylesheets/wiki/Building-From-Source.md ## CSS Extensions diff --git a/pom.xml b/pom.xml index 2a6dc81b..176b3a47 100644 --- a/pom.xml +++ b/pom.xml @@ -119,13 +119,27 @@ ${java.version} true - org.javacc.parser ${project.basedir}/src ${project.build.directory}/generated-sources + + org.apache.maven.plugins + maven-assembly-plugin + 2.6 + + + + com.google.common.css.compiler.commandline.ClosureCommandLineCompiler + + + + jar-with-dependencies + + + @@ -133,9 +147,7 @@ args4j args4j - - 2.0.16 + 2.0.26 @@ -171,14 +183,14 @@ com.google.javascript - closure-compiler - v20160619 + closure-compiler-unshaded + v20160713 junit junit - 4.8.2 + 4.11 test diff --git a/src/com/google/common/css/compiler/ast/CssComponentNode.java b/src/com/google/common/css/compiler/ast/CssComponentNode.java index 7addb19b..b3881426 100644 --- a/src/com/google/common/css/compiler/ast/CssComponentNode.java +++ b/src/com/google/common/css/compiler/ast/CssComponentNode.java @@ -77,7 +77,7 @@ public boolean isAbstract() { return getType() == CssAtRuleNode.Type.ABSTRACT_COMPONENT; } - @SuppressWarnings("StringEquality") + @SuppressWarnings("ReferenceEquality") public boolean isImplicitlyNamed() { // Test against the exact string instance. return getName().getValue() == IMPLICIT_NODE_NAME; diff --git a/src/com/google/common/css/compiler/ast/CssRulesetNode.java b/src/com/google/common/css/compiler/ast/CssRulesetNode.java index 8376b086..d52957ea 100644 --- a/src/com/google/common/css/compiler/ast/CssRulesetNode.java +++ b/src/com/google/common/css/compiler/ast/CssRulesetNode.java @@ -81,6 +81,7 @@ public CssRulesetNode(List comments) { */ public CssRulesetNode(CssRulesetNode node) { this(node.getDeclarations().deepCopy()); + this.setSourceCodeLocation(node.getSourceCodeLocation()); this.setComments(node.getComments()); this.selectors = node.getSelectors().deepCopy(); } diff --git a/src/com/google/common/css/compiler/ast/CssTreeBuilder.java b/src/com/google/common/css/compiler/ast/CssTreeBuilder.java index 9176f120..1309ab96 100644 --- a/src/com/google/common/css/compiler/ast/CssTreeBuilder.java +++ b/src/com/google/common/css/compiler/ast/CssTreeBuilder.java @@ -367,6 +367,7 @@ public void onRulesetStart(CssSelectorListNode selectorList) { Preconditions.checkState(ruleset == null); ruleset = new CssRulesetNode(comments); + ruleset.setSourceCodeLocation(selectorList.getSourceCodeLocation()); ruleset.setSelectors(selectorList); comments.clear(); diff --git a/src/com/google/common/css/compiler/passes/BrowserPrefixGenerator.java b/src/com/google/common/css/compiler/passes/BrowserPrefixGenerator.java index df0c5030..43936dee 100644 --- a/src/com/google/common/css/compiler/passes/BrowserPrefixGenerator.java +++ b/src/com/google/common/css/compiler/passes/BrowserPrefixGenerator.java @@ -289,6 +289,14 @@ private static ImmutableList buildExpansionRules() { .addExpandPropertyValue("repeating-linear-gradient") .build()); + builder.add(new BrowserPrefixRule.Builder() + .matchPropertyName("cursor") + .matchPropertyValue("grab") + .isFunction(false) + .addExpandPropertyValue("-moz-grab") + .addExpandPropertyValue("-webkit-grab") + .build()); + // Needed for Firefox 15, Chrome 25, Safari 6, iOS Safari 6.1 or less builder.add(new BrowserPrefixRule.Builder() .matchPropertyValue("calc") diff --git a/src/com/google/common/css/compiler/passes/CheckMissingRequire.java b/src/com/google/common/css/compiler/passes/CheckMissingRequire.java index 991ec941..440dc37c 100644 --- a/src/com/google/common/css/compiler/passes/CheckMissingRequire.java +++ b/src/com/google/common/css/compiler/passes/CheckMissingRequire.java @@ -54,10 +54,10 @@ public final class CheckMissingRequire extends DefaultTreeVisitor implements Css private static final Logger logger = Logger.getLogger(CheckMissingRequire.class.getName()); private static final Pattern OVERRIDE_SELECTOR_REGEX = Pattern.compile( - "/\\*\\s+@overrideSelector\\s+\\{(.*)\\}\\s+\\*/"); + "/\\*\\*?\\s+@overrideSelector\\s+\\{(.*)\\}\\s+\\*/"); private static final Pattern OVERRIDE_DEF_REGEX = Pattern.compile( - "/\\*\\s+@overrideDef\\s+\\{(.*)\\}\\s+\\*/"); + "/\\*\\*?\\s+@overrideDef\\s+\\{(.*)\\}\\s+\\*/"); private final VisitController visitController; private final ErrorManager errorManager; diff --git a/src/com/google/common/css/compiler/passes/CollectProvideNamespaces.java b/src/com/google/common/css/compiler/passes/CollectProvideNamespaces.java index 167a5376..b4ca2cad 100644 --- a/src/com/google/common/css/compiler/passes/CollectProvideNamespaces.java +++ b/src/com/google/common/css/compiler/passes/CollectProvideNamespaces.java @@ -17,8 +17,6 @@ package com.google.common.css.compiler.passes; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; @@ -28,12 +26,9 @@ import com.google.common.css.compiler.ast.CssProvideNode; import com.google.common.css.compiler.ast.CssRequireNode; import com.google.common.css.compiler.ast.DefaultTreeVisitor; -import com.google.common.css.compiler.ast.ErrorManager; import com.google.common.css.compiler.ast.VisitController; import java.util.Map; -import java.util.logging.Logger; -import java.util.regex.Pattern; /** * A compiler pass to help find missing {@code @require} lines for def constant references @@ -41,15 +36,11 @@ * This pass simply collects namespaces that correpond to constant definitions and mixins. * Also see the CheckMissingRequire pass that is used in conjunction with this one. * + * NOTE: The maps in this class can only be used within the same set of pass runs. + * */ public final class CollectProvideNamespaces extends DefaultTreeVisitor implements CssCompilerPass { - private static final Logger logger = Logger.getLogger(CollectProvideNamespaces.class.getName()); - - private static final Pattern OVERRIDE_REGEX = Pattern.compile( - "/\\*\\s+@overrideSelector\\s+\\{(.*)\\}\\s+\\*/"); - private final VisitController visitController; - private final ErrorManager errorManager; // Key: filename; Value: provide namespace private final Map filenameProvideMap = Maps.newHashMap(); @@ -63,25 +54,23 @@ public final class CollectProvideNamespaces extends DefaultTreeVisitor implement private final ListMultimap defmixinProvideMap = LinkedListMultimap.create(); public Map getFilenameProvideMap() { - return ImmutableMap.copyOf(filenameProvideMap); + return filenameProvideMap; } public ListMultimap getFilenameRequireMap() { - return ImmutableListMultimap.copyOf(filenameRequireMap); + return filenameRequireMap; } public ListMultimap getDefProvideMap() { - return ImmutableListMultimap.copyOf(defProvideMap); + return defProvideMap; } public ListMultimap getDefmixinProvideMap() { - return ImmutableListMultimap.copyOf(defmixinProvideMap); + return defmixinProvideMap; } - public CollectProvideNamespaces(VisitController visitController, - ErrorManager errorManager) { + public CollectProvideNamespaces(VisitController visitController) { this.visitController = visitController; - this.errorManager = errorManager; } @Override @@ -135,6 +124,10 @@ public boolean enterMixinDefinition(CssMixinDefinitionNode node) { @Override public void runPass() { + filenameProvideMap.clear(); + filenameRequireMap.clear(); + defProvideMap.clear(); + defmixinProvideMap.clear(); visitController.startVisit(this); } } diff --git a/src/com/google/common/css/compiler/passes/DefaultGssSourceMapGenerator.java b/src/com/google/common/css/compiler/passes/DefaultGssSourceMapGenerator.java index 4412e1bb..18271dca 100644 --- a/src/com/google/common/css/compiler/passes/DefaultGssSourceMapGenerator.java +++ b/src/com/google/common/css/compiler/passes/DefaultGssSourceMapGenerator.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; import java.util.List; import java.util.Map; @@ -176,54 +177,80 @@ public void setSourceRoot(String path){ ((SourceMapGeneratorV3) generator).setSourceRoot(path); } - private void addMapping(Mapping mapping) { - CssNode node = mapping.node; - FilePosition outputStartPosition = mapping.start; - FilePosition outputEndPosition = mapping.end; - String sourceFile = getSourceFileName(node); - - // If the node does not have an associated source file or source location - // is unknown, then the node does not have sufficient info for source map. - if (sourceFile == null || node.getSourceCodeLocation().isUnknown()) { - return; - } - - // TODO: could pass in an optional symbol name - generator.addMapping( - sourceFile, null, - new FilePosition(getStartLineno(node), getStartCharIndex(node)), - outputStartPosition, outputEndPosition); - } - /** - * Gets the source file file for current node. + * Generates the source map by passing all mappings to {@link #generator}. */ - private String getSourceFileName(CssNode node) { - return node.getSourceCodeLocation().getSourceCode().getFileName(); + private void generateSourceMap() { + List completeMappings = new ArrayList<>(allMappings.size()); + for (Mapping mapping : allMappings) { + // If the node does not have an associated source file or source location + // is unknown, then the node does not have sufficient info for source map. + if (mapping.node.getSourceCodeLocation().isUnknown()) { + continue; + } + CompleteMapping completeMapping = new CompleteMapping(mapping); + if (completeMapping.sourceFile == null) { + continue; + } + completeMappings.add(completeMapping); + } + Collections.sort(completeMappings); + for (CompleteMapping completeMapping : completeMappings) { + // TODO: could pass in an optional symbol name + generator.addMapping( + completeMapping.sourceFile, null, + completeMapping.inputStart, + completeMapping.outputStart, completeMapping.outputEnd); + } } - /** - * Gets the start line index in the source code of {@code node} adjusted to 0-based indices. - * - *

Notes: Gss compiler uses a 1-based line number and source map V3 uses a 0-based line number. - */ - private int getStartLineno(CssNode node) { - return node.getSourceCodeLocation().getLineNumber() - 1; - } - /** - * Gets the start character index in the output buffer for current {@code node}. - */ - private int getStartCharIndex(CssNode node) { - return node.getSourceCodeLocation().getCharacterIndex(); - } + private static final class CompleteMapping implements Comparable { + final String sourceFile; + final FilePosition inputStart; + final FilePosition outputStart; + final FilePosition outputEnd; - /** - * Generates the source map by passing all mappings to {@link #generator}. - */ - private void generateSourceMap(){ - for (Mapping mapping : allMappings) { - addMapping(mapping); + CompleteMapping(Mapping mapping) { + CssNode node = mapping.node; + this.sourceFile = getSourceFileName(node); + this.inputStart = new FilePosition( + getStartLineno(node), getStartCharIndex(node)); + this.outputStart = mapping.start; + this.outputEnd = mapping.end; + } + + @Override + public int compareTo(CompleteMapping m) { + int delta = outputStart.getLine() - m.outputStart.getLine(); + if (delta == 0) { + delta = outputStart.getColumn() - m.outputStart.getColumn(); + } + return delta; + } + + /** + * Gets the source file file for current node. + */ + private static String getSourceFileName(CssNode node) { + return node.getSourceCodeLocation().getSourceCode().getFileName(); + } + + /** + * Gets the start line index in the source code of {@code node} adjusted to 0-based indices. + * + *

+ * Note: Gss compiler uses a 1-based line number and source map V3 uses a 0-based line number. + */ + private static int getStartLineno(CssNode node) { + return node.getSourceCodeLocation().getLineNumber() - 1; + } + + /** + * Gets the start character index in the output buffer for current {@code node}. + */ + private static int getStartCharIndex(CssNode node) { + return node.getSourceCodeLocation().getCharacterIndex(); } } } diff --git a/src/com/google/common/css/compiler/passes/ProcessComponents.java b/src/com/google/common/css/compiler/passes/ProcessComponents.java index d620dffb..2d5a04d0 100644 --- a/src/com/google/common/css/compiler/passes/ProcessComponents.java +++ b/src/com/google/common/css/compiler/passes/ProcessComponents.java @@ -219,6 +219,7 @@ private List transformNodes( Set constants, CssComponentNode target, CssComponentNode source) { CssBlockNode sourceBlock = source.getBlock(); CssBlockNode copyBlock = new CssBlockNode(false, sourceBlock.deepCopy().getChildren()); + copyBlock.setSourceCodeLocation(source.getBlock().getSourceCodeLocation()); CssTree tree = new CssTree( target.getSourceCodeLocation().getSourceCode(), new CssRootNode(copyBlock)); new TransformNodes(constants, target, target != source, diff --git a/src/com/google/common/css/compiler/passes/SplitRulesetNodes.java b/src/com/google/common/css/compiler/passes/SplitRulesetNodes.java index 685d15c8..87c5d3f4 100644 --- a/src/com/google/common/css/compiler/passes/SplitRulesetNodes.java +++ b/src/com/google/common/css/compiler/passes/SplitRulesetNodes.java @@ -61,6 +61,7 @@ public boolean enterRuleset(CssRulesetNode node) { for (CssSelectorNode sel : selectors.childIterable()) { for (CssNode child : declarations.childIterable()) { CssRulesetNode ruleset = new CssRulesetNode(); + ruleset.setSourceCodeLocation(node.getSourceCodeLocation()); ruleset.addDeclaration(child.deepCopy()); ruleset.addSelector(sel.deepCopy()); diff --git a/tests/com/google/common/css/compiler/ast/testing/NewFunctionalTestBase.java b/tests/com/google/common/css/compiler/ast/testing/NewFunctionalTestBase.java index dccf0e0b..0e1ffa41 100644 --- a/tests/com/google/common/css/compiler/ast/testing/NewFunctionalTestBase.java +++ b/tests/com/google/common/css/compiler/ast/testing/NewFunctionalTestBase.java @@ -243,7 +243,9 @@ public void print(String message) { if (exactMatch) { assertEquals(expectedMessages[currentIndex], message); } else { - assertTrue(message.contains(expectedMessages[currentIndex])); + assertTrue("Expected error '" + message + "' to contain '" + + expectedMessages[currentIndex] + "'.", + message.contains(expectedMessages[currentIndex])); } currentIndex++; } diff --git a/tests/com/google/common/css/compiler/passes/CheckMissingRequireTest.java b/tests/com/google/common/css/compiler/passes/CheckMissingRequireTest.java index ea2d867e..1389741b 100644 --- a/tests/com/google/common/css/compiler/passes/CheckMissingRequireTest.java +++ b/tests/com/google/common/css/compiler/passes/CheckMissingRequireTest.java @@ -42,7 +42,7 @@ protected void runPasses(TestErrorManager errorMgr) { pass.runPass(); } CollectProvideNamespaces collectProvides = new CollectProvideNamespaces( - tree.getVisitController(), errorMgr); + tree.getVisitController()); collectProvides.runPass(); new CheckMissingRequire( tree.getVisitController(),