use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.
the class GenerateParseInfoVisitor method visitSoyFileNode.
@Override
protected void visitSoyFileNode(SoyFileNode node) {
if (node.getSoyFileKind() != SoyFileKind.SRC) {
// don't generate code for deps
return;
}
String javaClassName = soyFileToJavaClassNameMap.get(node);
// Collect the following:
// + all the public basic templates (non-private, non-delegate) in a map from the
// upper-underscore template name to the template's node,
// + all the param keys from all templates (including private),
// + for each param key, the list of templates that list it directly.
// + for any params whose type is a proto, get the proto name and Java class name.
LinkedHashMap<String, TemplateNode> publicBasicTemplateMap = Maps.newLinkedHashMap();
List<String> deltemplates = new ArrayList<>();
Set<String> allParamKeys = Sets.newHashSet();
SetMultimap<String, TemplateNode> paramKeyToTemplatesMultimap = LinkedHashMultimap.create();
SortedSet<String> protoTypes = Sets.newTreeSet();
for (TemplateNode template : node.getChildren()) {
if (template.getVisibility() == Visibility.PUBLIC && template instanceof TemplateBasicNode) {
publicBasicTemplateMap.put(convertToUpperUnderscore(template.getPartialTemplateName().substring(1)), template);
}
if (template instanceof TemplateDelegateNode) {
deltemplates.add("\"" + template.getTemplateName() + "\"");
}
for (TemplateParam param : template.getAllParams()) {
if (!param.isInjected()) {
allParamKeys.add(param.name());
paramKeyToTemplatesMultimap.put(param.name(), template);
}
if (param instanceof HeaderParam) {
SoyType paramType = ((HeaderParam) param).type();
findProtoTypesRecurse(paramType, protoTypes);
}
}
// Field access nodes need special handling to ensure that extension references are handled.
for (FieldAccessNode fieldAccess : SoyTreeUtils.getAllNodesOfType(template, FieldAccessNode.class)) {
SoyType baseType = fieldAccess.getBaseExprChild().getType();
if (baseType.getKind() == SoyType.Kind.PROTO) {
FieldDescriptor desc = ((SoyProtoType) baseType).getFieldDescriptor(fieldAccess.getFieldName());
if (desc.isExtension()) {
protoTypes.add(ProtoUtils.getTofuExtensionImport(desc));
}
}
}
// Add enums
for (GlobalNode global : SoyTreeUtils.getAllNodesOfType(template, GlobalNode.class)) {
if (global.isResolved() && global.getType().getKind() == SoyType.Kind.PROTO_ENUM) {
protoTypes.add(((SoyProtoEnumType) global.getType()).getDescriptorExpression());
}
}
// Add proto init
for (ProtoInitNode protoInit : SoyTreeUtils.getAllNodesOfType(template, ProtoInitNode.class)) {
if (protoInit.getType().getKind() == SoyType.Kind.PROTO) {
protoTypes.add(((SoyProtoType) protoInit.getType()).getDescriptorExpression());
}
}
}
// allParamKeysMap is a map from upper-underscore key to original key.
SortedMap<String, String> allParamKeysMap = Maps.newTreeMap();
for (String key : allParamKeys) {
String upperUnderscoreKey = convertToUpperUnderscore(key);
// stage of the compiler.
while (allParamKeysMap.containsKey(upperUnderscoreKey)) {
upperUnderscoreKey = upperUnderscoreKey + "_";
}
allParamKeysMap.put(upperUnderscoreKey, key);
// Updates the convertedIdents here, since we might have changed the value by adding
// prepending underscores. Without this, the generated SoyTemplateInfo still use the
// old mapping and will fail.
convertedIdents.put(key, upperUnderscoreKey);
}
ilb = new IndentedLinesBuilder(2);
// ------ Header. ------
ilb.appendLine("// This file was automatically generated from ", node.getFileName(), ".");
ilb.appendLine("// Please don't edit this file by hand.");
ilb.appendLine();
ilb.appendLine("package ", javaPackage, ";");
ilb.appendLine();
ilb.appendLine("import com.google.common.collect.ImmutableList;");
ilb.appendLine("import com.google.common.collect.ImmutableMap;");
ilb.appendLine("import com.google.common.collect.ImmutableSortedSet;");
if (!protoTypes.isEmpty()) {
ilb.appendLine("import com.google.protobuf.Descriptors.GenericDescriptor;");
}
ilb.appendLine("import com.google.template.soy.parseinfo.SoyFileInfo;");
ilb.appendLine("import com.google.template.soy.parseinfo.SoyTemplateInfo;");
// ------ Class start. ------
ilb.appendLine();
ilb.appendLine();
appendJavadoc(ilb, "Soy parse info for " + node.getFileName() + ".", true, false);
ilb.appendLine("public final class ", javaClassName, " extends SoyFileInfo {");
ilb.increaseIndent();
// ------ Constant for namespace. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/** This Soy file's namespace. */");
ilb.appendLine("public static final String __NAMESPACE__ = \"", node.getNamespace(), "\";");
// ------ Proto types map. ------
if (!protoTypes.isEmpty()) {
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/** Protocol buffer types used by these templates. */");
ilb.appendLine("@Override public ImmutableList<GenericDescriptor> getProtoDescriptors() {");
ilb.increaseIndent();
// Note we use fully-qualified names instead of imports to avoid potential collisions.
List<String> defaultInstances = Lists.newArrayList();
defaultInstances.addAll(protoTypes);
appendListOrSetHelper(ilb, "return ImmutableList.<GenericDescriptor>of", defaultInstances);
ilb.appendLineEnd(";");
ilb.decreaseIndent();
ilb.appendLine("}");
}
// ------ Template names. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("public static final class TemplateName {");
ilb.increaseIndent();
ilb.appendLine("private TemplateName() {}");
ilb.appendLine();
for (Entry<String, TemplateNode> templateEntry : publicBasicTemplateMap.entrySet()) {
StringBuilder javadocSb = new StringBuilder();
javadocSb.append("The full template name of the ").append(templateEntry.getValue().getPartialTemplateName()).append(" template.");
appendJavadoc(ilb, javadocSb.toString(), false, true);
ilb.appendLine("public static final String ", templateEntry.getKey(), " = \"", templateEntry.getValue().getTemplateName(), "\";");
}
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Params. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/**");
ilb.appendLine(" * Param names from all templates in this Soy file.");
ilb.appendLine(" */");
ilb.appendLine("public static final class Param {");
ilb.increaseIndent();
ilb.appendLine("private Param() {}");
ilb.appendLine();
for (Map.Entry<String, String> paramEntry : allParamKeysMap.entrySet()) {
String upperUnderscoreKey = paramEntry.getKey();
String key = paramEntry.getValue();
StringBuilder javadocSb = new StringBuilder();
javadocSb.append("Listed by ");
boolean isFirst = true;
for (TemplateNode template : paramKeyToTemplatesMultimap.get(key)) {
if (isFirst) {
isFirst = false;
} else {
javadocSb.append(", ");
}
javadocSb.append(buildTemplateNameForJavadoc(node, template));
}
javadocSb.append('.');
appendJavadoc(ilb, javadocSb.toString(), false, true);
ilb.appendLine("public static final String ", upperUnderscoreKey, " = \"", key, "\";");
}
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Templates. ------
for (TemplateNode template : publicBasicTemplateMap.values()) {
visit(template);
}
// ------ Constructor. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("private ", javaClassName, "() {");
ilb.increaseIndent();
ilb.appendLine("super(");
ilb.increaseIndent(2);
ilb.appendLine("\"", node.getFileName(), "\",");
ilb.appendLine("\"", node.getNamespace(), "\",");
// Templates.
List<String> itemSnippets = Lists.newArrayList();
itemSnippets.addAll(publicBasicTemplateMap.keySet());
appendImmutableList(ilb, "<SoyTemplateInfo>", itemSnippets);
ilb.appendLineEnd(",");
// CSS names.
SortedMap<String, CssTagsPrefixPresence> cssNameMap = new CollectCssNamesVisitor().exec(node);
ImmutableMap.Builder<String, String> cssTagPrefixes = ImmutableMap.builder();
for (Map.Entry<String, CssTagsPrefixPresence> entry : cssNameMap.entrySet()) {
cssTagPrefixes.put("\"" + entry.getKey() + "\"", "CssTagsPrefixPresence." + entry.getValue().name());
}
appendImmutableMap(ilb, "<String, CssTagsPrefixPresence>", cssTagPrefixes.build());
ilb.appendLineEnd(",");
appendImmutableList(ilb, "<String>", deltemplates);
ilb.appendLineEnd(");");
ilb.decreaseIndent(2);
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Singleton instance and its getter. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("private static final ", javaClassName, " __INSTANCE__ =");
ilb.increaseIndent(2);
ilb.appendLine("new ", javaClassName, "();");
ilb.decreaseIndent(2);
ilb.appendLine();
ilb.appendLine("public static ", javaClassName, " getInstance() {");
ilb.increaseIndent();
ilb.appendLine("return __INSTANCE__;");
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Class end. ------
ilb.appendLine();
ilb.decreaseIndent();
ilb.appendLine("}");
generatedFiles.put(javaClassName + ".java", ilb.toString());
ilb = null;
}
use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.
the class GenerateParseInfoVisitor method visitTemplateNode.
@Override
protected void visitTemplateNode(TemplateNode node) {
// Don't generate anything for private or delegate templates.
if (node.getVisibility() != Visibility.PUBLIC || node instanceof TemplateDelegateNode) {
return;
}
// First build list of all transitive params (direct and indirect).
LinkedHashMap<String, TemplateParam> transitiveParamMap = Maps.newLinkedHashMap();
// Direct params.
for (TemplateParam param : node.getParams()) {
transitiveParamMap.put(param.name(), param);
}
// Indirect params.
IndirectParamsInfo indirectParamsInfo = new FindIndirectParamsVisitor(templateRegistry).exec(node);
for (TemplateParam param : indirectParamsInfo.indirectParams.values()) {
TemplateParam existingParam = transitiveParamMap.get(param.name());
if (existingParam == null) {
// Note: We don't list the description for indirect params.
transitiveParamMap.put(param.name(), param.copyEssential());
}
}
// Get info on injected params.
IjParamsInfo ijParamsInfo = new FindIjParamsVisitor(templateRegistry).exec(node);
// for IntelliJ
@SuppressWarnings("ConstantConditions") String upperUnderscoreName = convertToUpperUnderscore(node.getPartialTemplateName().substring(1));
String templateInfoClassName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, upperUnderscoreName) + "SoyTemplateInfo";
// ------ *SoyTemplateInfo class start. ------
ilb.appendLine();
ilb.appendLine();
appendJavadoc(ilb, Optional.fromNullable(node.getSoyDocDesc()).or(""), true, false);
ilb.appendLine("public static final class ", templateInfoClassName, " extends SoyTemplateInfo {");
ilb.increaseIndent();
// ------ Constants for template name. ------
ilb.appendLine();
ilb.appendLine("/** This template's full name. */");
ilb.appendLine("public static final String __NAME__ = \"", node.getTemplateName(), "\";");
ilb.appendLine("/** This template's partial name. */");
ilb.appendLine("public static final String __PARTIAL_NAME__ = \"", node.getPartialTemplateName(), "\";");
// ------ Param constants. ------
boolean hasSeenFirstDirectParam = false;
boolean hasSwitchedToIndirectParams = false;
for (TemplateParam param : transitiveParamMap.values()) {
if (param.desc() != null) {
// Direct param.
if (!hasSeenFirstDirectParam) {
ilb.appendLine();
hasSeenFirstDirectParam = true;
}
appendJavadoc(ilb, param.desc(), false, false);
} else {
// Indirect param.
if (!hasSwitchedToIndirectParams) {
ilb.appendLine();
ilb.appendLine("// Indirect params.");
hasSwitchedToIndirectParams = true;
}
// Get the list of all transitive callee names as they will appear in the generated
// Javadoc (possibly containing both partial and full names) and sort them before
// generating the Javadoc.
SortedSet<String> sortedJavadocCalleeNames = Sets.newTreeSet();
for (TemplateNode transitiveCallee : indirectParamsInfo.paramKeyToCalleesMultimap.get(param.name())) {
String javadocCalleeName = buildTemplateNameForJavadoc(node.getParent(), transitiveCallee);
sortedJavadocCalleeNames.add(javadocCalleeName);
}
// Generate the Javadoc.
StringBuilder javadocSb = new StringBuilder();
javadocSb.append("Listed by ");
boolean isFirst = true;
for (String javadocCalleeName : sortedJavadocCalleeNames) {
if (isFirst) {
isFirst = false;
} else {
javadocSb.append(", ");
}
javadocSb.append(javadocCalleeName);
}
javadocSb.append('.');
appendJavadoc(ilb, javadocSb.toString(), false, true);
}
// The actual param field.
ilb.appendLine("public static final String ", convertToUpperUnderscore(param.name()), " = \"", param.name(), "\";");
}
// ------ Constructor. ------
ilb.appendLine();
ilb.appendLine("private ", templateInfoClassName, "() {");
ilb.increaseIndent();
ilb.appendLine("super(");
ilb.increaseIndent(2);
ilb.appendLine("\"", node.getTemplateName(), "\",");
if (!transitiveParamMap.isEmpty()) {
ImmutableMap.Builder<String, String> entrySnippetPairs = ImmutableMap.builder();
for (TemplateParam param : transitiveParamMap.values()) {
entrySnippetPairs.put("\"" + param.name() + "\"", param.isRequired() ? "ParamRequisiteness.REQUIRED" : "ParamRequisiteness.OPTIONAL");
}
appendImmutableMap(ilb, "<String, ParamRequisiteness>", entrySnippetPairs.build());
ilb.appendLineEnd(",");
} else {
ilb.appendLine("ImmutableMap.<String, ParamRequisiteness>of(),");
}
appendIjParamSet(ilb, ijParamsInfo);
ilb.appendLineEnd(",");
ilb.appendLine("\"", node.getAutoescapeMode().getAttributeValue(), "\");");
ilb.decreaseIndent(2);
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Singleton instance and its getter. ------
ilb.appendLine();
ilb.appendLine("private static final ", templateInfoClassName, " __INSTANCE__ =");
ilb.increaseIndent(2);
ilb.appendLine("new ", templateInfoClassName, "();");
ilb.decreaseIndent(2);
ilb.appendLine();
ilb.appendLine("public static ", templateInfoClassName, " getInstance() {");
ilb.increaseIndent();
ilb.appendLine("return __INSTANCE__;");
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ *SoyTemplateInfo class end. ------
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Static field with instance of *SoyTemplateInfo class. ------
ilb.appendLine();
ilb.appendLine("/** Same as ", templateInfoClassName, ".getInstance(). */");
ilb.appendLine("public static final ", templateInfoClassName, " ", upperUnderscoreName, " =");
ilb.increaseIndent(2);
ilb.appendLine(templateInfoClassName, ".getInstance();");
ilb.decreaseIndent(2);
}
use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.
the class Inferences method cloneTemplates.
/**
* Clones a template, changing the name.
*
* @return A copy of tn, differing semantically only in name and auto-generated IDs. The new
* templates will be available via {@link #lookupTemplates} with the given name.
*/
public List<TemplateNode> cloneTemplates(String baseName, String derivedName, CallNode callNode) {
if (!lookupTemplates(derivedName).isEmpty()) {
throw new AssertionError(derivedName + " already has templates: " + lookupTemplates(derivedName));
}
ImmutableList.Builder<TemplateNode> b = ImmutableList.builder();
for (TemplateNode tn : lookupTemplates(baseName)) {
if (SoyTreeUtils.hasHtmlNodes(tn)) {
throw SoyAutoescapeException.createWithNode("Non-strict template '" + baseName + "' contains HTML nodes but does not specify the kind. " + "This is no longer allowed, please migrate the template to strict and " + "specify a content kind by adding a kind attribute", callNode);
}
SoyFileHeaderInfo soyFileHeaderInfo = tn.getSoyFileHeaderInfo();
// We trivially clone the template with new ids, this ensures that all the varrefs have proper
// vardefns assigned. Then we manually recopy to a new template in order to modify the name.
// TODO(lukes): we should add direct support for swapping template names to TemplateNode
// or just eliminate usecases for this method.
TemplateNode trivialClonedTemplate = SoyTreeUtils.cloneWithNewIds(tn, idGen);
int cloneId = trivialClonedTemplate.getId();
// We need to use the unnamespaced name in the command text since we'll be inserting this
// template into a file node that already has a namespace declaration.
TemplateNode clone;
if (tn instanceof TemplateBasicNode) {
String derivedPartialName = (tn.getPartialTemplateName() != null) ? derivedName.substring(soyFileHeaderInfo.namespace.length()) : null;
clone = new TemplateBasicNodeBuilder(soyFileHeaderInfo, ErrorReporter.exploding()).setId(cloneId).setSourceLocation(tn.getSourceLocation()).setCmdTextInfo(derivedName, derivedPartialName, tn.getVisibility(), tn.getAutoescapeMode(), tn.getContentKind(), tn.getRequiredCssNamespaces()).addParams(trivialClonedTemplate.getAllParams()).build();
if (!(derivedName.equals(clone.getTemplateName()) && Objects.equals(derivedPartialName, clone.getPartialTemplateName()))) {
throw new AssertionError();
}
} else if (tn instanceof TemplateDelegateNode) {
TemplateDelegateNode tdn = (TemplateDelegateNode) tn;
clone = new TemplateDelegateNodeBuilder(soyFileHeaderInfo, ErrorReporter.exploding()).setId(cloneId).setSourceLocation(tn.getSourceLocation()).setCmdTextInfo(derivedName, tdn.getDelTemplateVariant(), tdn.getDelPriority(), tn.getAutoescapeMode(), tn.getContentKind(), tn.getRequiredCssNamespaces()).addParams(trivialClonedTemplate.getAllParams()).build();
if (!(derivedName.equals(((TemplateDelegateNode) clone).getDelTemplateName()))) {
throw new AssertionError();
}
} else {
throw new AssertionError("Unknown template node type: " + tn.getClass());
}
clone.addChildren(trivialClonedTemplate.getChildren());
// Reassign all the local variable data which isn't maintained by the cloning process above.
clone.setMaxLocalVariableTableSize(tn.getMaxLocalVariableTableSize());
Iterator<TemplateParam> tnIterator = tn.getAllParams().iterator();
Iterator<TemplateParam> cloneIterator = clone.getAllParams().iterator();
while (tnIterator.hasNext()) {
cloneIterator.next().setLocalVariableIndex(tnIterator.next().localVariableIndex());
}
b.add(clone);
}
ImmutableList<TemplateNode> clones = b.build();
templatesByName.putAll(derivedName, clones);
return clones;
}
use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.
the class TemplateCompiler method generateTemplateMetadata.
/**
* Writes a {@link TemplateMetadata} to the generated class.
*/
private void generateTemplateMetadata() {
SanitizedContentKind contentKind = template.node().getContentKind();
String kind = contentKind == null ? "" : contentKind.name();
// using linked hash sets below for determinism
Set<String> uniqueIjs = new LinkedHashSet<>();
for (VarRefNode var : getAllNodesOfType(template.node(), VarRefNode.class)) {
if (var.isInjected()) {
uniqueIjs.add(var.getName());
}
}
Set<String> callees = new LinkedHashSet<>();
for (CallBasicNode call : getAllNodesOfType(template.node(), CallBasicNode.class)) {
callees.add(call.getCalleeName());
}
Set<String> delCallees = new LinkedHashSet<>();
for (CallDelegateNode call : getAllNodesOfType(template.node(), CallDelegateNode.class)) {
delCallees.add(call.getDelCalleeName());
}
TemplateMetadata.DelTemplateMetadata deltemplateMetadata;
if (template.node().getKind() == SoyNode.Kind.TEMPLATE_DELEGATE_NODE) {
TemplateDelegateNode delegateNode = (TemplateDelegateNode) template.node();
deltemplateMetadata = createDelTemplateMetadata(delegateNode.getDelPackageName() == null ? "" : delegateNode.getDelPackageName(), delegateNode.getDelTemplateName(), delegateNode.getDelTemplateVariant());
} else {
deltemplateMetadata = createDefaultDelTemplateMetadata();
}
TemplateMetadata metadata = createTemplateMetadata(kind, uniqueIjs, callees, delCallees, deltemplateMetadata);
TEMPLATE_METADATA_REF.write(metadata, writer);
}
use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.
the class FindTransitiveDepTemplatesVisitor method visitCallDelegateNode.
@Override
protected void visitCallDelegateNode(CallDelegateNode node) {
// Don't forget to visit content within CallParamContentNodes.
visitChildren(node);
// Visit all the possible callee templates.
ImmutableList<TemplateDelegateNode> potentialCallees = templateRegistry.getDelTemplateSelector().delTemplateNameToValues().get(node.getDelCalleeName());
for (TemplateDelegateNode delCallee : potentialCallees) {
processCalleeHelper(delCallee);
}
}
Aggregations