com.google.template.soy.soytree.TemplateElementNodeBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.google.template.soy.soytree.TemplateElementNodeBuilder.java

Source

/*
 * Copyright 2013 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.template.soy.soytree;

import static com.google.common.collect.ImmutableSet.toImmutableSet;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.template.soy.base.internal.Identifier;
import com.google.template.soy.base.internal.SanitizedContentKind;
import com.google.template.soy.error.ErrorReporter;
import com.google.template.soy.error.SoyErrorKind;
import com.google.template.soy.soytree.TemplateNode.SoyFileHeaderInfo;
import com.google.template.soy.soytree.defn.TemplateHeaderVarDefn;
import com.google.template.soy.soytree.defn.TemplateParam;
import com.google.template.soy.soytree.defn.TemplateStateVar;
import java.util.List;
import java.util.Set;

/**
 * Builder for TemplateElementNode.
 *
 * <p>Important: Do not use outside of Soy code (treat as superpackage-private).
 *
 */
public final class TemplateElementNodeBuilder extends TemplateNodeBuilder<TemplateElementNodeBuilder> {

    private static final SoyErrorKind DUPLICATE_DECLARATION = SoyErrorKind
            .of("Param ''{0}'' is a duplicate of state var ''{0}''.");

    protected static final ImmutableSet<String> BANNED_ATTRIBUTE_NAMES = ImmutableSet.of("autoescape", "kind",
            "stricthtml", "visibility");

    private static final SoyErrorKind BANNED_ATTRIBUTE_NAMES_ERROR = SoyErrorKind
            .of("Attribute ''{0}'' is not allowed on Soy elements.");

    private List<CommandTagAttribute> attrs = ImmutableList.of();

    /** The state variables from template header. */
    private ImmutableList<TemplateStateVar> stateVars = ImmutableList.of();

    /** @param soyFileHeaderInfo Info from the containing Soy file's header declarations. */
    public TemplateElementNodeBuilder(SoyFileHeaderInfo soyFileHeaderInfo, ErrorReporter errorReporter) {
        super(soyFileHeaderInfo, errorReporter);
        setAutoescapeInfo(AutoescapeMode.STRICT, SanitizedContentKind.HTML, this.sourceLocation);
    }

    @Override
    public TemplateElementNodeBuilder setCommandValues(Identifier templateName, List<CommandTagAttribute> attrs) {
        this.attrs = attrs;
        this.cmdText = templateName.identifier() + " " + Joiner.on(' ').join(attrs);
        setCommonCommandValues(attrs);

        setTemplateNames(soyFileHeaderInfo.getNamespace() + templateName.identifier(), templateName.identifier());
        return this;
    }

    public TemplateElementNodeBuilder setStateVars(List<TemplateStateVar> newStateVars) {
        this.stateVars = ImmutableList.copyOf(newStateVars);
        checkDuplicateHeaderVars(params, stateVars, errorReporter);
        return this;
    }

    @Override
    public TemplateElementNodeBuilder addParams(Iterable<? extends TemplateParam> allParams) {
        super.addParams(allParams);
        checkDuplicateHeaderVars(params, stateVars, errorReporter);
        return this;
    }

    @Override
    public TemplateElementNode build() {
        Preconditions.checkState(id != null && cmdText != null);
        for (CommandTagAttribute attr : attrs) {
            if (BANNED_ATTRIBUTE_NAMES.contains(attr.getName().identifier())) {
                this.errorReporter.report(this.sourceLocation, BANNED_ATTRIBUTE_NAMES_ERROR,
                        attr.getName().identifier());
            }
        }
        return new TemplateElementNode(this, soyFileHeaderInfo, params, stateVars);
    }

    /**
     * Check for duplicate header variable names and append error text for each duplicate to the
     * `errorReporter`. For example, this is an error:
     *
     * <pre>{@code
     * {@param s: bool}
     * {@state s: bool}
     * }</pre>
     *
     * Note that it is not possible to have duplicate names of the same declaration type. Any
     * duplicate {@code @state} or {@code @param} will have been flagged as error during the resolve-
     * names pass or in {@link #addParams(Iterable)}.
     */
    @VisibleForTesting
    static void checkDuplicateHeaderVars(ImmutableList<? extends TemplateHeaderVarDefn> params,
            ImmutableList<? extends TemplateHeaderVarDefn> stateVars, ErrorReporter errorReporter) {

        final Set<String> stateVarNames = stateVars.stream().map(TemplateHeaderVarDefn::name)
                .collect(toImmutableSet());

        Iterable<? extends TemplateHeaderVarDefn> duplicateVars = Iterables.filter(params,
                param -> stateVarNames.contains(param.name()));
        for (TemplateHeaderVarDefn duplicateVar : duplicateVars) {
            errorReporter.report(duplicateVar.nameLocation(), DUPLICATE_DECLARATION, duplicateVar.name());
        }
    }
}