com.google.common.css.compiler.passes.CheckDependencyNodes.java Source code

Java tutorial

Introduction

Here is the source code for com.google.common.css.compiler.passes.CheckDependencyNodes.java

Source

/*
 * 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.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.css.compiler.ast.CssAtRuleNode;
import com.google.common.css.compiler.ast.CssCompilerPass;
import com.google.common.css.compiler.ast.CssLiteralNode;
import com.google.common.css.compiler.ast.CssNode;
import com.google.common.css.compiler.ast.CssProvideNode;
import com.google.common.css.compiler.ast.CssRequireNode;
import com.google.common.css.compiler.ast.CssStringNode;
import com.google.common.css.compiler.ast.CssUnknownAtRuleNode;
import com.google.common.css.compiler.ast.CssValueNode;
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.MutatingVisitController;

import java.util.List;
import java.util.Set;

/**
 * {@link CheckDependencyNodes} ensures that {@code @provide} nodes appear
 * before {@code @require} nodes.
 *
 * @author bolinfest@google.com (Michael Bolin)
 */
public class CheckDependencyNodes extends DefaultTreeVisitor implements CssCompilerPass {

    private static final String provideName = CssAtRuleNode.Type.PROVIDE.getCanonicalName();
    private static final String requireName = CssAtRuleNode.Type.REQUIRE.getCanonicalName();
    private final MutatingVisitController visitController;
    private final ErrorManager errorManager;
    private final boolean suppressDependencyCheck;

    /**
     * A linked collection is used so the dependencies can be iterated in the
     * order in which they were provided.
     */
    private Set<String> provides = Sets.newLinkedHashSet();

    public CheckDependencyNodes(MutatingVisitController visitController, ErrorManager errorManager) {
        this(visitController, errorManager, true /* suppressDependencyCheck */);
    }

    public CheckDependencyNodes(MutatingVisitController visitController, ErrorManager errorManager,
            boolean suppressDependencyCheck) {
        this.visitController = visitController;
        this.errorManager = errorManager;
        this.suppressDependencyCheck = suppressDependencyCheck;
    }

    @Override
    public boolean enterUnknownAtRule(CssUnknownAtRuleNode node) {
        String atRuleName = node.getName().getValue();
        CssNode dependencyNode;
        if (provideName.equals(atRuleName)) {
            CssLiteralNode arg = extractArgument(node);
            if (arg != null) {
                dependencyNode = createProvideNode(node, arg);
            } else {
                return false;
            }
        } else if (requireName.equals(atRuleName)) {
            CssLiteralNode arg = extractArgument(node);
            if (arg != null) {
                dependencyNode = createRequireNode(node, arg);
            } else {
                return false;
            }
        } else {
            return true;
        }

        visitController.replaceCurrentBlockChildWith(Lists.newArrayList(dependencyNode),
                false /* visitTheReplacementNodes */);
        return true;
    }

    private CssLiteralNode extractArgument(CssUnknownAtRuleNode node) {
        String atRuleName = node.getName().getValue();
        if (node.getType().hasBlock()) {
            reportError("@" + atRuleName + " with block", node);
            return null;
        }
        List<CssValueNode> params = node.getParameters();
        if (params.isEmpty()) {
            reportError("@" + atRuleName + " without name", node);
            return null;
        }
        CssNode nameNode = params.get(0);
        if (!(nameNode instanceof CssStringNode)) {
            reportError("@" + atRuleName + " without a quoted string as name", node);
            return null;
        }
        CssStringNode nameStringNode = (CssStringNode) nameNode;
        return new CssLiteralNode(nameStringNode.getValue());
    }

    private CssProvideNode createProvideNode(CssUnknownAtRuleNode node, CssLiteralNode provideArgument) {
        //TODO(user): Make CssProvideNode & CssRequireNode consistent with other at-rule nodes.
        // Pass the @name as CssLiteralNode and the namespace as CssValueNode.
        CssProvideNode provideNode = new CssProvideNode(provideArgument, node.getComments(),
                node.getSourceCodeLocation());
        String provide = provideNode.getProvide();
        if (provides.contains(provide)) {
            reportError("Duplicate provide for: " + provide, node);
        }
        provides.add(provide);
        return provideNode;
    }

    private CssRequireNode createRequireNode(CssUnknownAtRuleNode node, CssLiteralNode requireArgument) {
        CssRequireNode requireNode = new CssRequireNode(requireArgument, node.getComments(),
                node.getSourceCodeLocation());
        String require = requireNode.getRequire();
        if (!provides.contains(require)) {
            reportError("Missing provide for: " + require, node);
        }
        return requireNode;
    }

    private void reportError(String message, CssNode node) {
        if (!suppressDependencyCheck) {
            errorManager.report(new GssError(message, node.getSourceCodeLocation()));
            visitController.removeCurrentNode();
        }
    }

    @Override
    public void runPass() {
        visitController.startVisit(this);
    }

    @VisibleForTesting
    List<String> getProvidesInOrder() {
        return ImmutableList.copyOf(provides);
    }
}