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

Java tutorial

Introduction

Here is the source code for com.google.common.css.compiler.passes.CreateMixins.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.Lists;
import com.google.common.css.compiler.ast.CssAtRuleNode;
import com.google.common.css.compiler.ast.CssCompilerPass;
import com.google.common.css.compiler.ast.CssDeclarationBlockNode;
import com.google.common.css.compiler.ast.CssFunctionArgumentsNode;
import com.google.common.css.compiler.ast.CssFunctionNode;
import com.google.common.css.compiler.ast.CssMixinDefinitionNode;
import com.google.common.css.compiler.ast.CssMixinNode;
import com.google.common.css.compiler.ast.CssNode;
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;

/**
 * A compiler pass that transforms matching {@link CssUnknownAtRuleNode} instances
 * into mixins or mixin definitions.
 *
 * @author fbenz@google.com (Florian Benz)
 */
public class CreateMixins extends DefaultTreeVisitor implements CssCompilerPass {

    @VisibleForTesting
    static final String NO_BLOCK_ERROR_MESSAGE = "This @-rule has to have a block";
    @VisibleForTesting
    static final String BLOCK_ERROR_MESSAGE = "This @-rule is not allowed to have a block";
    @VisibleForTesting
    static final String ONLY_DECLARATION_BLOCK_ERROR_MESSAGE = "Only declaration blocks are allowed for this @-rule";
    @VisibleForTesting
    static final String INVALID_PARAMETERS_ERROR_MESSAGE = "This @-rule has invalid parameters";

    private final MutatingVisitController visitController;
    private final ErrorManager errorManager;

    public CreateMixins(MutatingVisitController visitController, ErrorManager errorManager) {
        this.visitController = visitController;
        this.errorManager = errorManager;
    }

    @Override
    public boolean enterUnknownAtRule(CssUnknownAtRuleNode node) {
        String mixinName = CssAtRuleNode.Type.MIXIN.getCanonicalName();
        String mixinDefinitionName = CssAtRuleNode.Type.DEFMIXIN.getCanonicalName();

        if (node.getName().getValue().equals(mixinName)) {
            createMixin(node);
        } else if (node.getName().getValue().equals(mixinDefinitionName)) {
            createMixinDefinition(node);
        }
        return true;
    }

    private void createMixin(CssUnknownAtRuleNode node) {
        if (node.getBlock() != null) {
            reportError(BLOCK_ERROR_MESSAGE, node);
            return;
        }
        List<CssValueNode> params = node.getParameters();
        if (params.size() != 1 || !(params.get(0) instanceof CssFunctionNode)) {
            reportError(INVALID_PARAMETERS_ERROR_MESSAGE, node);
            return;
        }
        CssFunctionNode function = (CssFunctionNode) params.get(0);
        String name = function.getFunctionName();
        CssFunctionArgumentsNode arguments = function.getArguments();
        CssMixinNode mixin = new CssMixinNode(name, arguments, node.getSourceCodeLocation());
        mixin.setComments(node.getComments());
        visitController.replaceCurrentBlockChildWith(Lists.newArrayList(mixin),
                true /* visitTheReplacementNodes */);
    }

    private void createMixinDefinition(CssUnknownAtRuleNode node) {
        if (node.getBlock() == null) {
            reportError(NO_BLOCK_ERROR_MESSAGE, node);
            return;
        }
        if (!(node.getBlock() instanceof CssDeclarationBlockNode)) {
            reportError(ONLY_DECLARATION_BLOCK_ERROR_MESSAGE, node);
            return;
        }
        List<CssValueNode> params = node.getParameters();
        if (params.size() != 1 || !(params.get(0) instanceof CssFunctionNode)) {
            reportError(INVALID_PARAMETERS_ERROR_MESSAGE, node);
            return;
        }
        CssDeclarationBlockNode block = (CssDeclarationBlockNode) node.getBlock();
        CssFunctionNode function = (CssFunctionNode) params.get(0);
        String name = function.getFunctionName();
        CssFunctionArgumentsNode arguments = function.getArguments();
        CssMixinDefinitionNode mixinDefinition = new CssMixinDefinitionNode(name, arguments, block,
                node.getSourceCodeLocation());
        mixinDefinition.setComments(node.getComments());
        visitController.replaceCurrentBlockChildWith(Lists.newArrayList(mixinDefinition),
                true /* visitTheReplacementNodes */);
    }

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

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