Package com.google.template.soy.soytree

Source Code of com.google.template.soy.soytree.TemplateDelegateNode$CommandTextInfo

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

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.template.soy.base.BaseUtils;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.data.SanitizedContent.ContentKind;
import com.google.template.soy.data.internalutils.NodeContentKinds;
import com.google.template.soy.exprparse.ExprParseUtils;
import com.google.template.soy.exprtree.ExprRootNode;
import com.google.template.soy.exprtree.StringNode;
import com.google.template.soy.soytree.CommandTextAttributesParser.Attribute;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;


/**
* Node representing a delegate template.
*
* <p> Important: Do not use outside of Soy code (treat as superpackage-private).
*
* @author Kai Huang
*/
public class TemplateDelegateNode extends TemplateNode {


  /**
   * Value class for a delegate template key (name and variant).
   *
   * <p> Important: Do not use outside of Soy code (treat as superpackage-private).
   */
  public static final class DelTemplateKey {

    public final String name;
    public final String variant;

    public DelTemplateKey(String name, String variant) {
      this.name = name;
      this.variant = variant;
    }

    @Override public boolean equals(Object other) {
      if (! (other instanceof DelTemplateKey)) {
        return false;
      }
      DelTemplateKey otherKey = (DelTemplateKey) other;
      return this.name.equals(otherKey.name) && this.variant.equals(otherKey.variant);
    }

    @Override public int hashCode() {
      return Objects.hashCode(name, variant);
    }

    @Override public String toString() {
      return name + ((variant.length() == 0) ? "" : ":" + variant);
    }
  }


  /**
   * Private helper class used by constructors. Encapsulates all the info derived from the command
   * text.
   */
  @Immutable
  private static class CommandTextInfo extends TemplateNode.CommandTextInfo {

    public final String delTemplateName;
    public final String delTemplateVariant;
    public final int delPriority;

    public CommandTextInfo(
        String commandText, String delTemplateName, String delTemplateVariant, int delPriority,
        String templateName, @Nullable String partialTemplateName, AutoescapeMode autoescapeMode,
        ContentKind contentKind) {
      super(
          commandText, templateName, partialTemplateName, false /*deltemplate is never private*/,
          autoescapeMode, contentKind, SyntaxVersion.V2);
      this.delTemplateName = delTemplateName;
      this.delTemplateVariant = delTemplateVariant;
      this.delPriority = delPriority;
    }
  }


  /** Pattern for the command text. */
  // 2 capturing groups: del template name, attributes.
  private static final Pattern COMMAND_TEXT_PATTERN =
      Pattern.compile("([.\\w]+) ( \\s .* | $ )", Pattern.COMMENTS | Pattern.DOTALL);

  /** Parser for the attributes in command text. */
  private static final CommandTextAttributesParser ATTRIBUTES_PARSER =
      new CommandTextAttributesParser("deltemplate",
          new Attribute("variant", Attribute.ALLOW_ALL_VALUES, null),
          new Attribute("autoescape", AutoescapeMode.getAttributeValues(), null),
          new Attribute("kind", NodeContentKinds.getAttributeValues(), null));


  /** The delegate template name. */
  private final String delTemplateName;

  /** The delegate template variant. */
  private final String delTemplateVariant;

  /** The delegate template key (name and variant). */
  private final DelTemplateKey delTemplateKey;

  /** The delegate priority. */
  private final int delPriority;


  /**
   * Creates a TemplateDelegateNode given the source command text.
   * @param id The id for this node.
   * @param soyFileHeaderInfo Info from the containing Soy file's header declarations.
   * @param commandText The command text.
   * @param soyDoc The full SoyDoc, including the start/end tokens, or null if the template is not
   *     preceded by SoyDoc.
   * @throws SoySyntaxException If a syntax error is found.
   */
  public TemplateDelegateNode(
      int id, SoyFileHeaderInfo soyFileHeaderInfo, String commandText, @Nullable String soyDoc)
      throws SoySyntaxException {
    this(id, soyFileHeaderInfo, parseCommandTextHelper(id, soyFileHeaderInfo, commandText), soyDoc);
  }


  /**
   * Creates a TemplateDelegateNode given values for fields.
   * @param id The id for this node.
   * @param soyFileHeaderInfo Info from the containing Soy file's header declarations.
   * @param delTemplateName The delegate name for this template.
   * @param delTemplateVariant The delegate variant for this template.
   * @param delPriority The delegate priority.
   * @param autoescapeMode The kind of autoescaping, if any, done for this template.
   * @param soyDoc The full SoyDoc, including the start/end tokens, or null if the template is not
   *     preceded by SoyDoc.
   */
  public TemplateDelegateNode(
      int id, SoyFileHeaderInfo soyFileHeaderInfo, String delTemplateName,
      String delTemplateVariant, int delPriority, AutoescapeMode autoescapeMode,
      ContentKind contentKind, @Nullable String soyDoc) {
    this(id, soyFileHeaderInfo,
        buildCommandTextInfoHelper(
            id, soyFileHeaderInfo, null, delTemplateName, delTemplateVariant, delPriority,
            autoescapeMode, contentKind),
        soyDoc);
    Preconditions.checkState(
        (this.getContentKind() != null) == (this.getAutoescapeMode() == AutoescapeMode.STRICT));
  }


  /**
   * Private helper for constructor
   * {@link #TemplateDelegateNode(int, SoyFileHeaderInfo, String, String)}.
   */
  private static final CommandTextInfo parseCommandTextHelper(
      int id, SoyFileHeaderInfo soyFileHeaderInfo, String commandText) {

    Matcher matcher = COMMAND_TEXT_PATTERN.matcher(commandText);
    if (! matcher.matches()) {
      throw SoySyntaxException.createWithoutMetaInfo(
          "Invalid 'deltemplate' command text \"" + commandText + "\".");
    }

    String delTemplateName = matcher.group(1);
    if (! BaseUtils.isDottedIdentifier(delTemplateName)) {
      throw SoySyntaxException.createWithoutMetaInfo(
          "Invalid delegate template name \"" + delTemplateName + "\".");
    }

    Map<String, String> attributes = ATTRIBUTES_PARSER.parse(matcher.group(2).trim());

    int delPriority = soyFileHeaderInfo.defaultDelPriority;
    if (delPriority < 0 || delPriority > TemplateNode.MAX_PRIORITY) {
      throw SoySyntaxException.createWithoutMetaInfo(String.format(
          "Invalid delegate template priority %s (valid range is 0 to %s).",
          delPriority, TemplateNode.MAX_PRIORITY));
    }

    String variantExprText = attributes.get("variant");
    String delTemplateVariant;
    if (variantExprText == null) {
      delTemplateVariant = "";
    } else {
      ExprRootNode<?> variantExpr = ExprParseUtils.parseExprElseThrowSoySyntaxException(
          variantExprText,
          String.format("Invalid variant expression \"%s\" in 'deltemplate'.", variantExprText));
      // For now, the variant expression must be a fixed string. In the future, we have the ability
      // to allow expressions containing compile-time globals, if necessary.
      if (! (variantExpr.getChild(0) instanceof StringNode)) {
        throw SoySyntaxException.createWithoutMetaInfo(
            "Invalid variant expression \"" + variantExprText + "\" in 'deltemplate'" +
                " (must be a string literal that contains an identifier).");
      }
      delTemplateVariant = ((StringNode) variantExpr.getChild(0)).getValue();
      if (delTemplateVariant.length() > 0 && ! BaseUtils.isIdentifier(delTemplateVariant)) {
        throw SoySyntaxException.createWithoutMetaInfo(
            "Invalid variant \"" + delTemplateVariant + "\" in 'deltemplate'" +
                " (must be an identifier).");
      }
    }

    AutoescapeMode autoescapeMode;
    String autoescapeModeStr = attributes.get("autoescape");
    if (autoescapeModeStr != null) {
      autoescapeMode = AutoescapeMode.forAttributeValue(autoescapeModeStr);
    } else {
      autoescapeMode = soyFileHeaderInfo.defaultAutoescapeMode;  // Inherit from containing file.
    }

    ContentKind contentKind = (attributes.get("kind") != null) ?
        NodeContentKinds.forAttributeValue(attributes.get("kind")) : null;

    return buildCommandTextInfoHelper(
        id, soyFileHeaderInfo, commandText, delTemplateName, delTemplateVariant, delPriority,
        autoescapeMode, contentKind);
  }


  /**
   * A helper for constructors.
   */
  private static CommandTextInfo buildCommandTextInfoHelper(
      int id, SoyFileHeaderInfo soyFileHeaderInfo, @Nullable String commandText,
      String delTemplateName, String delTemplateVariant, int delPriority,
      AutoescapeMode autoescapeMode, ContentKind contentKind) {
    Preconditions.checkArgument(BaseUtils.isDottedIdentifier(delTemplateName));
    Preconditions.checkArgument(
        delTemplateVariant.length() == 0 || BaseUtils.isIdentifier(delTemplateVariant));
    Preconditions.checkArgument(0 <= delPriority && delPriority <= TemplateNode.MAX_PRIORITY);

    if (commandText == null) {
      commandText = delTemplateName +
          ((delTemplateVariant.length() == 0) ? "" : " variant=\"" + delTemplateVariant + "\"") +
          " autoescape=\"" + autoescapeMode.getAttributeValue() + "\"";
      if (contentKind != null) {
        commandText += " kind=\"" + NodeContentKinds.toAttributeValue(contentKind) + '"';
      }
    }

    // Compute a SHA-1 hash value for the delPackageName plus delTemplateKey, and take the first 32
    // bits worth as a hex string. This will be included in the generated internal-use template name
    // to prevent collisions in the case where not all Soy files are compiled at once (not really
    // the intended usage of the Soy compiler, but some projects use it this way). Note that the
    // node id is also included in the generated name, which is already sufficient for guaranteeing
    // unique names in the case where all Soy files are compiled together at once.
    String delPackageAndDelTemplateStr =
        (soyFileHeaderInfo.delPackageName == null ? "" : soyFileHeaderInfo.delPackageName) +
            "~" + delTemplateName + "~" + delTemplateVariant;
    String collisionPreventionStr =
        BaseUtils.computePartialSha1AsHexString(delPackageAndDelTemplateStr, 32);

    // Generate the actual internal-use template name.
    String generatedPartialTemplateName = ".__deltemplate_s" + id + "_" + collisionPreventionStr;
    String generatedTemplateName = soyFileHeaderInfo.namespace + generatedPartialTemplateName;

    return new CommandTextInfo(
        commandText, delTemplateName, delTemplateVariant, delPriority, generatedTemplateName,
        generatedPartialTemplateName, autoescapeMode, contentKind);
  }


  /**
   * Private helper constructor used by constructor
   * {@link #TemplateDelegateNode(int, SoyFileHeaderInfo, String, String)}.
   */
  private TemplateDelegateNode(
      int id, SoyFileHeaderInfo soyFileHeaderInfo, CommandTextInfo commandTextInfo,
      @Nullable String soyDoc) {
    super(id, soyFileHeaderInfo, "deltemplate", commandTextInfo, soyDoc);
    if (soyDoc == null) {
      throw SoySyntaxException.createWithoutMetaInfo(
          "Encountered delegate template " + commandTextInfo.delTemplateName + " without SoyDoc.");
    }
    this.delTemplateName = commandTextInfo.delTemplateName;
    this.delTemplateVariant = commandTextInfo.delTemplateVariant;
    this.delTemplateKey = new DelTemplateKey(delTemplateName, delTemplateVariant);
    this.delPriority = commandTextInfo.delPriority;
  }


  /**
   * Copy constructor.
   * @param orig The node to copy.
   */
  protected TemplateDelegateNode(TemplateDelegateNode orig) {
    super(orig);
    this.delTemplateName = orig.delTemplateName;
    this.delTemplateVariant = orig.delTemplateVariant;
    this.delTemplateKey = orig.delTemplateKey;
    this.delPriority = orig.delPriority;
  }


  @Override public Kind getKind() {
    return Kind.TEMPLATE_DELEGATE_NODE;
  }


  @Override public String getTemplateNameForUserMsgs() {
    return delTemplateKey.toString();
  }


  /** Returns the delegate template name. */
  public String getDelTemplateName() {
    return delTemplateName;
  }


  /** Returns the delegate template variant. */
  public String getDelTemplateVariant() {
    return delTemplateVariant;
  }


  /** Returns the delegate template key (name and variant). */
  public DelTemplateKey getDelTemplateKey() {
    return delTemplateKey;
  }


  /** Returns the delegate priority. */
  public int getDelPriority() {
    return delPriority;
  }


  @Override public TemplateDelegateNode clone() {
    return new TemplateDelegateNode(this);
  }

}
TOP

Related Classes of com.google.template.soy.soytree.TemplateDelegateNode$CommandTextInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.