Package com.google.template.soy.soytree

Source Code of com.google.template.soy.soytree.SoyFileNode

/*
* Copyright 2008 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.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.template.soy.base.BaseUtils;
import com.google.template.soy.base.SourceLocation;
import com.google.template.soy.base.SoyFileKind;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.soytree.CommandTextAttributesParser.Attribute;
import com.google.template.soy.soytree.SoyNode.SplitLevelTopNode;

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

import javax.annotation.Nullable;


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


  /** Decomposes namespace command text into a namespace (group 1) and attributes (group 2). */
  private static final Pattern CMD_TEXT_PATTERN = Pattern.compile(
      "\\s* (" + BaseUtils.DOTTED_IDENT_RE + ") (\\s .*)?", Pattern.COMMENTS);

  /** The default autoescape mode if none is specified in the command text. */
  private static final AutoescapeMode DEFAULT_FILE_WIDE_DEFAULT_AUTOESCAPE_MODE =
      AutoescapeMode.TRUE;

  /** Parser for the command text besides the namespace. */
  private static final CommandTextAttributesParser ATTRIBUTES_PARSER =
      new CommandTextAttributesParser("namespace",
          new Attribute("autoescape", AutoescapeMode.getAttributeValues(),
              DEFAULT_FILE_WIDE_DEFAULT_AUTOESCAPE_MODE.getAttributeValue()));


  /** The kind of this Soy file */
  private final SoyFileKind soyFileKind;

  /** The name of the containing delegate package, or null if none. */
  @Nullable private final String delPackageName;

  /** This Soy file's namespace, or null if syntax version V1. */
  @Nullable private final String namespace;

  /** The autoescape mode for templates in this file that do not declare an autoescape mode. */
  private final AutoescapeMode defaultAutoescapeMode;

  /** Map from aliases to namespaces for this file. */
  private final ImmutableMap<String, String> aliasToNamespaceMap;

  /** This Soy file's name (null if not supplied). */
  @Nullable private String fileName;


  /**
   * @param id The id for this node.
   * @param soyFileKind The kind of this Soy file.
   * @param delpackageCmdText This Soy file's delegate package, or null if none.
   * @param namespaceCmdText This Soy file's namespace and attributes. Nullable for backwards
   *     compatibility only.
   * @param aliasCmdTexts The command texts of the 'alias' declarations. Allowed to be null.
   * @throws SoySyntaxException If a syntax error is found.
   */
  public SoyFileNode(
      int id, SoyFileKind soyFileKind, @Nullable String delpackageCmdText,
      @Nullable String namespaceCmdText, @Nullable List<String> aliasCmdTexts)
      throws SoySyntaxException {
    super(id);

    this.soyFileKind = soyFileKind;

    if (delpackageCmdText != null) {
      this.delPackageName = delpackageCmdText.trim();
      if (! BaseUtils.isDottedIdentifier(delPackageName)) {
        throw SoySyntaxException.createWithoutMetaInfo(
            "Invalid delegate package name \"" + delPackageName + "\".");
      }
    } else {
      this.delPackageName = null;
    }

    String namespace = null;
    AutoescapeMode defaultAutoescapeMode = DEFAULT_FILE_WIDE_DEFAULT_AUTOESCAPE_MODE;

    if (namespaceCmdText != null) {
      Matcher matcher = CMD_TEXT_PATTERN.matcher(namespaceCmdText);
      if (matcher.matches()) {
        namespace = matcher.group(1);
        String attributeText = matcher.group(2);
        if (attributeText != null) {
          attributeText = attributeText.trim();
          Map<String, String> attributes = ATTRIBUTES_PARSER.parse(attributeText);
          if (attributes.containsKey("autoescape")) {
            defaultAutoescapeMode = AutoescapeMode.forAttributeValue(attributes.get("autoescape"));
          }
        }
      } else {
        throw SoySyntaxException.createWithoutMetaInfo(
            "Invalid namespace command text \"" + namespaceCmdText + "\".");
      }
    }

    this.namespace = namespace;
    this.defaultAutoescapeMode = defaultAutoescapeMode;
    if (namespace == null) {
      maybeSetSyntaxVersion(SyntaxVersion.V1);
    } else if (!BaseUtils.isDottedIdentifier(namespace)) {
      throw SoySyntaxException.createWithoutMetaInfo(
          "Invalid namespace name \"" + namespace + "\".");
    }

    if (aliasCmdTexts != null) {
      Preconditions.checkNotNull(this.namespace);
      String aliasForFileNamespace = BaseUtils.extractPartAfterLastDot(this.namespace);
      Map<String, String> tempAliasToNamespaceMap = Maps.newLinkedHashMap();
      for (String aliasCmdText : aliasCmdTexts) {
        // Note: The form of the 'alias' tag with "as ..." is currently disabled in the parser.
        String aliasNamespace = aliasCmdText.trim();
        Preconditions.checkArgument(BaseUtils.isDottedIdentifier(aliasNamespace));
        String alias = BaseUtils.extractPartAfterLastDot(aliasNamespace);
        if (alias.equals(aliasForFileNamespace) && ! aliasNamespace.equals(this.namespace)) {
          throw SoySyntaxException.createWithoutMetaInfo(String.format(
              "Not allowed to alias the last part of the file's namespace to some other namespace" +
                  " (file's namespace is \"%s\", while aliased namespace is \"%s\").",
              this.namespace, aliasNamespace));
        }
        if (tempAliasToNamespaceMap.containsKey(alias)) {
          throw SoySyntaxException.createWithoutMetaInfo(String.format(
              "Found 2 namespaces with the same alias (\"%s\" and \"%s\").",
              tempAliasToNamespaceMap.get(alias), aliasNamespace));
        }
        tempAliasToNamespaceMap.put(alias, aliasNamespace);
      }
      aliasToNamespaceMap = ImmutableMap.copyOf(tempAliasToNamespaceMap);
    } else {
      aliasToNamespaceMap = ImmutableMap.of();
    }
  }


  /**
   * Copy constructor.
   * @param orig The node to copy.
   */
  protected SoyFileNode(SoyFileNode orig) {
    super(orig);
    this.soyFileKind = orig.soyFileKind;
    this.delPackageName = orig.delPackageName;
    this.namespace = orig.namespace;
    this.defaultAutoescapeMode = orig.defaultAutoescapeMode;
    this.aliasToNamespaceMap = orig.aliasToNamespaceMap;  // immutable
    this.fileName = orig.fileName;
  }


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


  /** Returns the kind of this Soy file. */
  public SoyFileKind getSoyFileKind() {
    return soyFileKind;
  }


  /** Returns the name of the containing delegate package, or null if none. */
  @Nullable public String getDelPackageName() {
    return delPackageName;
  }


  /** Returns this Soy file's namespace, or null if syntax version V1. */
  @Nullable public String getNamespace() {
    return namespace;
  }


  /** Returns the default autoescaping mode for contained templates. */
  public AutoescapeMode getDefaultAutoescapeMode() {
    return defaultAutoescapeMode;
  }


  /** Returns the map from aliases to namespaces for this file. */
  public ImmutableMap<String, String> getAliasToNamespaceMap() {
    return aliasToNamespaceMap;
  }


  @Override public void setSourceLocation(SourceLocation srcLoc) {
    super.setSourceLocation(srcLoc);

    String filePath = srcLoc.getFilePath();
    int lastSlashIndex = CharMatcher.anyOf("/\\").lastIndexIn(filePath);
    if (lastSlashIndex != -1 && lastSlashIndex != filePath.length() - 1) {
      fileName = filePath.substring(lastSlashIndex + 1);
    } else {
      fileName = filePath;
    }
  }


  /** @param filePath The path to the source Soy file. */
  public void setFilePath(String filePath) {
    setSourceLocation(new SourceLocation(filePath, 0));
  }


  /** Returns the path to the source Soy file ("unknown" if not supplied). */
  public String getFilePath() {
    return getSourceLocation().getFilePath();
  }


  /** Returns this Soy file's name (null if not supplied). */
  @Nullable public String getFileName() {
    return fileName;
  }


  @Override public String toSourceString() {

    StringBuilder sb = new StringBuilder();

    if (delPackageName != null) {
      sb.append("{delpackage ").append(delPackageName).append("}\n");
    }
    if (namespace != null) {
      sb.append("{namespace ").append(namespace).append("}\n");
    }

    if (aliasToNamespaceMap.size() > 0) {
      sb.append("\n");
      for (String aliasNamespace : aliasToNamespaceMap.values()) {
        sb.append("{alias ").append(aliasNamespace).append("}\n");
      }
    }

    for (SoyNode child : getChildren()) {
      sb.append("\n");
      sb.append(child.toSourceString());
    }

    return sb.toString();
  }


  @Override public SoyFileSetNode getParent() {
    return (SoyFileSetNode) super.getParent();
  }


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

}
TOP

Related Classes of com.google.template.soy.soytree.SoyFileNode

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.