com.google.common.css.compiler.passes.StrictCss2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of closure-stylesheets Show documentation
Show all versions of closure-stylesheets Show documentation
Closure Stylesheets is an extension to CSS that adds variables, functions,
conditionals, and mixins to standard CSS. The tool also supports
minification, linting, RTL flipping, and CSS class renaming.
/*
* 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.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.css.compiler.ast.*;
import com.google.common.css.compiler.ast.CssAttributeSelectorNode.MatchType;
import com.google.common.css.compiler.ast.CssCombinatorNode.Combinator;
import java.util.Set;
/**
* This compiler pass enforces that only correct CSS 2.1 is used.
* See "http://www.w3.org/TR/CSS21/" for the specification.
*
* @author [email protected] (Florian Benz)
*/
public class StrictCss2 extends StrictCssBase {
private static final ImmutableSet PSEUDO_CLASSES_OR_ELEMENT =
ImmutableSet.of("first-child", "link", "visited", "active", "hover",
"focus", "first-line", "first-letter", "before", "after");
private static final ImmutableSet
ALLOWED_COMBINATORS = ImmutableSet.of(Combinator.DESCENDANT,
Combinator.CHILD, Combinator.ADJACENT_SIBLING);
private static final ImmutableSet
ALLOWED_ATTRIBUTE_SELECTORS = ImmutableSet.of(MatchType.ANY,
MatchType.EXACT, MatchType.EXACT_OR_DASH, MatchType.ONE_WORD);
/**
* Units.
* See Section 4.3.2 of
* http://www.w3.org/TR/CSS2/syndata.html#value-def-length
*/
private static final Set UNITS = Sets.newHashSet(
"",
// Relative measures
"em",
"ex",
"%",
// Absolute measures
"in",
"cm",
"mm",
"pt",
"pc",
"px");
@VisibleForTesting
static final String UNSUPPORTED_COMBINATOR_ERROR_MESSAGE =
"An unsupported combinator is used.";
@VisibleForTesting
static final String UNSUPPORTED_PESUDO_CLASS_OR_ELEMENT_ERROR_MESSAGE =
"An unsupported pseudo-class or pseudo-element is used.";
@VisibleForTesting
static final String NEW_PESUDO_ELEMENTS_NOT_ALLOWED_ERROR_MESSAGE =
"Pseudo-elements starting with '::' are not allowed in CSS 2.1.";
@VisibleForTesting
static final String FORBIDDEN_ATTRIBUTE_COMPARER_ERROR_MESSAGE =
"An operator for matching attributes not allowed in CSS 2.1 is used.";
public StrictCss2(VisitController visitController,
ErrorManager errorManager) {
super(visitController, errorManager);
}
/**
* Idenitifies valid units of 'width', 'height', etc.
*/
@Override
Set getValidCssUnits() {
return UNITS;
}
/**
* Ensures that the combinator '~' (introduced in CSS 3) is not used.
*/
@Override
public boolean enterCombinator(CssCombinatorNode combinator) {
if (!ALLOWED_COMBINATORS.contains(combinator.getCombinatorType())) {
errorManager.report(new GssError(UNSUPPORTED_COMBINATOR_ERROR_MESSAGE,
combinator.getSourceCodeLocation()));
return false;
}
return true;
}
/**
* Ensures that only pseudo-classes valid in CSS 2.1 are used. Especially, the
* new pseudo-classes introduced in CSS 3 are not valid.
*/
@Override
public boolean enterPseudoClass(CssPseudoClassNode node) {
switch (node.getFunctionType()) {
case NONE:
return checkNonFunctionPseudoClass(node);
case NTH:
case NOT:
reportUnsupported(node,
UNSUPPORTED_PESUDO_CLASS_OR_ELEMENT_ERROR_MESSAGE,
PSEUDO_CLASSES_OR_ELEMENT);
return false;
}
return true;
}
/**
* Ensures that only pseudo-classes and pseudo-elements listed in the
* specification are used.
*/
private boolean checkNonFunctionPseudoClass(CssRefinerNode refiner) {
if (!PSEUDO_CLASSES_OR_ELEMENT.contains(refiner.getRefinerName())) {
reportUnsupported(refiner,
UNSUPPORTED_PESUDO_CLASS_OR_ELEMENT_ERROR_MESSAGE,
PSEUDO_CLASSES_OR_ELEMENT);
return false;
}
return true;
}
/**
* Ensures that the new pseudo-element notation (::) is not used, because
* the notation has been introduced in CSS 3.
*/
@Override
public boolean enterPseudoElement(CssPseudoElementNode node) {
errorManager.report(new GssError(
NEW_PESUDO_ELEMENTS_NOT_ALLOWED_ERROR_MESSAGE,
node.getSourceCodeLocation()));
return false;
}
/**
* Ensures that attribute selectors are valid. If the equal sign is preceded
* by a special character, only '~' and '|' are allowed.
* Valid CSS 2.1 examples: {@code [att]}, {@code [att=val]},
* {@code [att~=val]}, {@code [att|=val]}
*/
@Override
public boolean enterAttributeSelector(CssAttributeSelectorNode node) {
if (!ALLOWED_ATTRIBUTE_SELECTORS.contains(node.getMatchType())) {
errorManager.report(new GssError(
FORBIDDEN_ATTRIBUTE_COMPARER_ERROR_MESSAGE,
node.getSourceCodeLocation()));
return false;
}
return true;
}
}