/* * 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.collect.ImmutableSet; import com.google.common.css.compiler.ast.CssCompilerPass; import com.google.common.css.compiler.ast.CssDeclarationNode; import com.google.common.css.compiler.ast.CssNode; import com.google.common.css.compiler.ast.CssPropertyNode; import com.google.common.css.compiler.ast.DefaultTreeVisitor; import com.google.common.css.compiler.ast.ErrorManager; import com.google.common.css.compiler.ast.GssError; import com.google.common.css.compiler.ast.Property; import com.google.common.css.compiler.ast.VisitController; import java.util.Set; /** * CSS Compiler pass that checks that all properties in the stylesheet are * either on the built-in recognized property list, or were whitelisted * explicitly. * * @author bolinfest@google.com (Michael Bolin) */ public class VerifyRecognizedProperties extends DefaultTreeVisitor implements CssCompilerPass { private final Set<String> allowedUnrecognizedProperties; private final VisitController visitController; private final ErrorManager errorManager; public VerifyRecognizedProperties(Set<String> allowedUnrecognizedProperties, VisitController visitController, ErrorManager errorManager) { this.allowedUnrecognizedProperties = ImmutableSet.copyOf( allowedUnrecognizedProperties); this.visitController = visitController; this.errorManager = errorManager; } /** * Checks whether the {@code Property} of {@code declarationNode} is a * recognized property. If not, an error is reported. */ @Override public boolean enterDeclaration(CssDeclarationNode declarationNode) { // TODO(bolinfest): Associate CSS version with a Property so that this check // can also verify the "compliance level." For example, it may want to // enforce that all properties are CSS 2.1 or earlier. CssPropertyNode propertyNode = declarationNode.getPropertyName(); Property property = propertyNode.getProperty(); String propertyName = property.getName(); // TODO(bolinfest): Have separate options to specify whether the star hack // or underscore hack should be allowed. See: // http://en.wikipedia.org/wiki/CSS_filter#Star_hack // http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack // // If the star or underscore hack is employed, consider the name without the // hack character in determining whether it is a "recognized property." if (propertyName.startsWith("*") || propertyName.startsWith("_")) { propertyName = propertyName.substring(1); property = Property.byName(propertyName); } if (!allowedUnrecognizedProperties.contains(property.getName())) { if (!property.isRecognizedProperty()) { reportError(String.format("%s is an unrecognized property", property.getName()), propertyNode); } else if (property.hasWarning()) { errorManager.reportWarning(new GssError( String.format( "WARNING for use of CSS property %s: %s\n", property.getName(), property.getWarning()), propertyNode.getSourceCodeLocation())); } } return true; } private void reportError(String message, CssNode node) { errorManager.report(new GssError(message, node.getSourceCodeLocation())); } @Override public void runPass() { visitController.startVisit(this); } }