/*
* Copyright 2011 Google Inc.
*
* Licensed 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 com.google.common.css.compiler.passes;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.css.compiler.ast.CssBlockNode;
import com.google.common.css.compiler.ast.CssCommentNode;
import com.google.common.css.compiler.ast.CssDeclarationBlockNode;
import com.google.common.css.compiler.ast.CssNode;
import com.google.common.css.compiler.ast.CssRootNode;
import com.google.common.css.compiler.ast.CssRulesetNode;
import com.google.common.css.compiler.ast.CssSelectorListNode;
import com.google.common.css.compiler.ast.CssSelectorNode;
import com.google.common.css.compiler.ast.CssTree;
import java.util.List;
/**
* Utility methods that can be useful for compiler passes.
*
* @author fbenz@google.com (Florian Benz)
*/
public class PassUtil {
/**
* Annotation to explicitly state that several consecutive declarations are
* alternatives and it should be left up to the user agent to interpret
* whichever is appropriate. The annotation excludes the declarations from
* being treated as redundant.
*/
@VisibleForTesting
public static final String ALTERNATE = "/* @alternate */";
/**
* Prints a selector including the combinators and refiners but without
* a block behind with the compact printer.
*/
public static String printSelector(CssSelectorNode selector) {
CssTree t = createTreeWithSelector(selector);
// Print the whole tree.
String selectorString = compactPrintTree(t);
// As the whole tree is printed, the output is the selector with an empty
// declaration block (e.g. 'foo{}'). The two curly brackets are removed so
// that only the selector remains.
return selectorString.substring(0, selectorString.length() - 2);
}
/**
* Prints a list of selector including the combinators and refiners but
* without a block behind with the compact printer.
*/
public static String printSelectorList(CssSelectorListNode selectorList) {
CssTree t = createTreeWithSelectorList(selectorList);
// Print the whole tree.
String selectorListString = compactPrintTree(t);
// As the whole tree is printed, the output is the selector with an empty
// declaration block (e.g. 'foo{}'). The two curly brackets are removed so
// that only the selector remains.
return selectorListString.substring(0, selectorListString.length() - 2);
}
/**
* Prints a selector including the combinators and refiners but without
* a block behind with the pretty printer.
*/
public static String prettyPrintSelector(CssSelectorNode selector) {
CssTree t = createTreeWithSelector(selector);
// Print the whole tree.
PrettyPrinter prettyPrinter = new PrettyPrinter(t.getVisitController());
prettyPrinter.runPass();
String selectorString = prettyPrinter.getPrettyPrintedString();
// As the whole tree is printed, the output is the selector with an empty
// declaration block (e.g. 'foo {\n}\n'). The two curly brackets are removed so
// that only the selector remains.
int index = selectorString.indexOf('{');
return selectorString.substring(0, index - 1);
}
private static CssTree createTreeWithSelector(CssSelectorNode selector) {
// Create tree with only this selector.
CssDeclarationBlockNode declarations = new CssDeclarationBlockNode();
CssRulesetNode rulesetNode = new CssRulesetNode(declarations);
rulesetNode.addSelector(selector);
return createTreeWithRuleset(rulesetNode);
}
private static CssTree createTreeWithSelectorList(
CssSelectorListNode selectorList) {
CssDeclarationBlockNode declarations = new CssDeclarationBlockNode();
CssRulesetNode rulesetNode = new CssRulesetNode(declarations);
rulesetNode.setSelectors(selectorList);
return createTreeWithRuleset(rulesetNode);
}
private static CssTree createTreeWithRuleset(CssRulesetNode rulesetNode) {
List<CssNode> blockChildren = ImmutableList.of((CssNode) rulesetNode);
CssBlockNode block = new CssBlockNode(false, blockChildren);
CssRootNode root = new CssRootNode(block);
return new CssTree(null, root);
}
private static String compactPrintTree(CssTree tree) {
CompactPrinter compactPrinter = new CompactPrinter(tree);
compactPrinter.runPass();
return compactPrinter.getCompactPrintedString();
}
/**
* Returns whether the ALTERNATE comment has been found among the comments of
* the node.
*/
public static boolean hasAlternateAnnotation(CssNode node) {
for (CssCommentNode comment : node.getComments()) {
if (comment.getValue().equals(ALTERNATE)) {
return true;
}
}
return false;
}
}