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

Java tutorial

Introduction

Here is the source code for com.google.common.css.compiler.passes.PassRunner.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.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.css.JobDescription;
import com.google.common.css.PrefixingSubstitutionMap;
import com.google.common.css.RecordingSubstitutionMap;
import com.google.common.css.SubstitutionMap;
import com.google.common.css.compiler.ast.CssCompilerPass;
import com.google.common.css.compiler.ast.CssTree;
import com.google.common.css.compiler.ast.ErrorManager;
import com.google.common.css.compiler.ast.GssFunction;

import java.util.Map;

import javax.annotation.Nullable;

/**
 * {@link PassRunner} runs applies a sequence of {@link CssCompilerPass}es to a
 * {@link CssTree}.
 *
 * @author bolinfest@google.com (Michael Bolin)
 */
public class PassRunner {

    private static final ImmutableMap<String, GssFunction> EMPTY_GSS_FUNCTION_MAP = ImmutableMap.of();

    private final JobDescription job;
    private final ErrorManager errorManager;
    private final RecordingSubstitutionMap recordingSubstitutionMap;

    public PassRunner(JobDescription job, ErrorManager errorManager) {
        this(job, errorManager, createSubstitutionMap(job));
    }

    public PassRunner(JobDescription job, ErrorManager errorManager,
            RecordingSubstitutionMap recordingSubstitutionMap) {
        this.job = job;
        this.errorManager = errorManager;
        this.recordingSubstitutionMap = recordingSubstitutionMap;
    }

    /**
     * Runs the passes on the specified {@link CssTree}. This method may be
     * invoked multiple times, as one compilation job may have one {@link CssTree}
     * per input file.
     */
    public void runPasses(CssTree cssTree) {
        new CheckDependencyNodes(cssTree.getMutatingVisitController(), errorManager, false).runPass();
        new CreateStandardAtRuleNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new CreateMixins(cssTree.getMutatingVisitController(), errorManager).runPass();
        new CreateDefinitionNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new CreateConstantReferences(cssTree.getMutatingVisitController()).runPass();
        new CreateConditionalNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new CreateForLoopNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new CreateComponentNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new ValidatePropertyValues(cssTree.getVisitController(), errorManager).runPass();

        new HandleUnknownAtRuleNodes(cssTree.getMutatingVisitController(), errorManager, job.allowedAtRules,
                true /* report */, false /* remove */).runPass();
        new ProcessKeyframes(cssTree.getMutatingVisitController(), errorManager,
                job.allowKeyframes || job.allowWebkitKeyframes, job.simplifyCss).runPass();
        new CreateVendorPrefixedKeyframes(cssTree.getMutatingVisitController(), errorManager).runPass();
        new EvaluateCompileConstants(cssTree.getMutatingVisitController(), job.compileConstants).runPass();
        new UnrollLoops(cssTree.getMutatingVisitController(), errorManager).runPass();
        new ProcessRefiners(cssTree.getMutatingVisitController(), errorManager, job.simplifyCss).runPass();

        // Collect mixin definitions and replace mixins
        CollectMixinDefinitions collectMixinDefinitions = new CollectMixinDefinitions(
                cssTree.getMutatingVisitController(), errorManager);
        collectMixinDefinitions.runPass();
        new ReplaceMixins(cssTree.getMutatingVisitController(), errorManager,
                collectMixinDefinitions.getDefinitions()).runPass();

        new ProcessComponents<Object>(cssTree.getMutatingVisitController(), errorManager).runPass();
        // Eliminate conditional nodes.
        new EliminateConditionalNodes(cssTree.getMutatingVisitController(),
                ImmutableSet.copyOf(job.trueConditionNames)).runPass();
        // Collect constant definitions.
        CollectConstantDefinitions collectConstantDefinitionsPass = new CollectConstantDefinitions(cssTree);
        collectConstantDefinitionsPass.runPass();
        // Replace constant references.
        ReplaceConstantReferences replaceConstantReferences = new ReplaceConstantReferences(cssTree,
                collectConstantDefinitionsPass.getConstantDefinitions(), true /* removeDefs */, errorManager,
                false);
        replaceConstantReferences.runPass();

        Map<String, GssFunction> gssFunctionMap = getGssFunctionMap();
        new ResolveCustomFunctionNodes(cssTree.getMutatingVisitController(), errorManager, gssFunctionMap,
                job.allowUnrecognizedFunctions, job.allowedNonStandardFunctions).runPass();

        if (job.simplifyCss) {
            // Eliminate empty rules.
            new EliminateEmptyRulesetNodes(cssTree.getMutatingVisitController()).runPass();
            // Eliminating units for zero values.
            new EliminateUnitsFromZeroNumericValues(cssTree.getMutatingVisitController()).runPass();
            // Optimize color values.
            new ColorValueOptimizer(cssTree.getMutatingVisitController()).runPass();
            // Compress redundant top-right-bottom-left value lists.
            new AbbreviatePositionalValues(cssTree.getMutatingVisitController()).runPass();
        }
        if (job.eliminateDeadStyles) {
            // Report errors for duplicate declarations
            new DisallowDuplicateDeclarations(cssTree.getVisitController(), errorManager).runPass();
            // Split rules by selector and declaration.
            new SplitRulesetNodes(cssTree.getMutatingVisitController()).runPass();
            // Dead code elimination.
            new MarkRemovableRulesetNodes(cssTree).runPass();
            new EliminateUselessRulesetNodes(cssTree).runPass();
            // Merge of rules with same selector.
            new MergeAdjacentRulesetNodesWithSameSelector(cssTree).runPass();
            new EliminateUselessRulesetNodes(cssTree).runPass();
            // Merge of rules with same styles.
            new MergeAdjacentRulesetNodesWithSameDeclarations(cssTree).runPass();
            new EliminateUselessRulesetNodes(cssTree).runPass();
        }
        // Perform BiDi flipping if required.
        if (job.needsBiDiFlipping()) {
            new MarkNonFlippableNodes(cssTree.getVisitController(), errorManager).runPass();
            new BiDiFlipper(cssTree.getMutatingVisitController(), job.swapLtrRtlInUrl, job.swapLeftRightInUrl)
                    .runPass();
        }
        // If specified, remove all vendor-specific properties except for the
        // whitelisted vendor.
        if (job.vendor != null) {
            new RemoveVendorSpecificProperties(job.vendor, cssTree.getMutatingVisitController()).runPass();
        }
        // Unless all unrecognized properties are allowed, check for unrecognized
        // properties.
        if (!job.allowUnrecognizedProperties) {
            new VerifyRecognizedProperties(job.allowedUnrecognizedProperties, cssTree.getVisitController(),
                    errorManager).runPass();
        }
        // Rename class names
        if (recordingSubstitutionMap != null) {
            new CssClassRenaming(cssTree.getMutatingVisitController(), recordingSubstitutionMap, null).runPass();
        }
    }

    @Nullable
    public RecordingSubstitutionMap getRecordingSubstitutionMap() {
        return recordingSubstitutionMap;
    }

    /**
     * Creates the CSS class substitution map from the provider, if any.
     * Wraps it in a substitution map that optionally prefixes all of the renamed
     * classes. Additionaly wraps in a recording substituion map which excludes a
     * blacklist of classnames and allows the map to produced as an output.
     */
    private static RecordingSubstitutionMap createSubstitutionMap(JobDescription job) {
        if (job.cssSubstitutionMapProvider != null) {
            SubstitutionMap baseMap = job.cssSubstitutionMapProvider.get();
            if (baseMap != null) {
                SubstitutionMap map = baseMap;
                if (!job.cssRenamingPrefix.isEmpty()) {
                    map = new PrefixingSubstitutionMap(baseMap, job.cssRenamingPrefix);
                }
                return new RecordingSubstitutionMap(map,
                        Predicates.not(Predicates.in(job.excludedClassesFromRenaming)));
            }
        }
        return null;
    }

    /**
     * Gets the GSS function map from the provider, if any.
     *
     * @return the provided map or an empty map if none is provided
     */
    private Map<String, GssFunction> getGssFunctionMap() {
        if (job.gssFunctionMapProvider == null) {
            return EMPTY_GSS_FUNCTION_MAP;
        }

        Map<String, GssFunction> map = job.gssFunctionMapProvider.get(GssFunction.class);
        if (map == null) {
            return EMPTY_GSS_FUNCTION_MAP;
        }

        return map;
    }
}