use of com.google.template.soy.soytree.CallBasicNode in project closure-templates by google.
the class GenCallCodeUtils method gen.
/**
* Generates the JS expression for a given call.
*
* <p> Important: If there are CallParamContentNode children whose contents are not computable as
* JS expressions, then this function assumes that, elsewhere, code has been generated to define
* their respective 'param<n>' temporary variables.
*
* <p> Here are five example calls:
* <pre>
* {call some.func data="all" /}
* {call some.func data="$boo.foo" /}
* {call some.func}
* {param goo = $moo /}
* {/call}
* {call some.func data="$boo"}
* {param goo}Blah{/param}
* {/call}
* {call some.func}
* {param goo}
* {for $i in range(3)}{$i}{/for}
* {/param}
* {/call}
* </pre>
* Their respective generated calls might be the following:
* <pre>
* some.func(opt_data)
* some.func(opt_data.boo.foo)
* some.func({goo: opt_data.moo})
* some.func(soy.$$assignDefaults({goo: 'Blah'}, opt_data.boo))
* some.func({goo: param65})
* </pre>
* Note that in the last case, the param content is not computable as JS expressions, so we assume
* that code has been generated to define the temporary variable 'param<n>'.
*
* @param callNode The call to generate code for.
* @param templateAliases A mapping of fully qualified calls to a variable in scope.
* @return The JS expression for the call.
*/
public CodeChunk.WithValue gen(CallNode callNode, TemplateAliases templateAliases, TranslationContext translationContext, ErrorReporter errorReporter) {
// Build the JS CodeChunk for the callee's name.
CodeChunk.WithValue callee;
if (callNode instanceof CallBasicNode) {
// Case 1: Basic call.
// TODO(lukes): add the logic for the goog.require here. The simplest strategy requires a
// TemplateRegistry to detect external templates.
callee = CodeChunk.dottedIdNoRequire(templateAliases.get(((CallBasicNode) callNode).getCalleeName()));
} else {
// Case 2: Delegate call.
CallDelegateNode callDelegateNode = (CallDelegateNode) callNode;
CodeChunk.WithValue calleeId = JsRuntime.SOY_GET_DELTEMPLATE_ID.call(stringLiteral(delTemplateNamer.getDelegateName(callDelegateNode)));
ExprRootNode variantSoyExpr = callDelegateNode.getDelCalleeVariantExpr();
CodeChunk.WithValue variant;
if (variantSoyExpr == null) {
// Case 2a: Delegate call with empty variant.
variant = LITERAL_EMPTY_STRING;
} else {
// Case 2b: Delegate call with variant expression.
variant = new TranslateExprNodeVisitor(translationContext, errorReporter).exec(variantSoyExpr);
}
callee = SOY_GET_DELEGATE_FN.call(calleeId, variant, callDelegateNode.allowEmptyDefault() ? LITERAL_TRUE : LITERAL_FALSE);
}
// Generate the data object to pass to callee
CodeChunk.WithValue objToPass = genObjToPass(callNode, templateAliases, translationContext, errorReporter);
// Generate the main call expression.
CodeChunk.WithValue call = callee.call(objToPass, JsRuntime.OPT_IJ_DATA);
if (callNode.getEscapingDirectives().isEmpty()) {
return call;
}
// Apply escaping directives as necessary.
//
// The print directive system continues to use JsExpr, as it is a publicly available API and
// migrating it to CodeChunk would be a major change. Therefore, we convert our CodeChunks
// to JsExpr and back here.
JsExpr callResult = call.singleExprOrName();
RequiresCollector.IntoImmutableSet collector = new RequiresCollector.IntoImmutableSet();
call.collectRequires(collector);
for (SoyPrintDirective directive : callNode.getEscapingDirectives()) {
Preconditions.checkState(directive instanceof SoyJsSrcPrintDirective, "Contextual autoescaping produced a bogus directive: %s", directive.getName());
callResult = ((SoyJsSrcPrintDirective) directive).applyForJsSrc(callResult, ImmutableList.<JsExpr>of());
if (directive instanceof SoyLibraryAssistedJsSrcPrintDirective) {
for (String name : ((SoyLibraryAssistedJsSrcPrintDirective) directive).getRequiredJsLibNames()) {
collector.add(GoogRequire.create(name));
}
}
}
return fromExpr(callResult, collector.get()).withInitialStatements(call.initialStatements());
}
use of com.google.template.soy.soytree.CallBasicNode in project closure-templates by google.
the class GenJsCodeVisitor method addCodeToRequireSoyNamespaces.
/**
* Helper for visitSoyFileNode(SoyFileNode) to add code to require Soy namespaces.
*
* @param soyFile The node we're visiting.
*/
private void addCodeToRequireSoyNamespaces(SoyFileNode soyFile) {
String prevCalleeNamespace = null;
Set<String> calleeNamespaces = new TreeSet<>();
for (CallBasicNode node : new FindCalleesNotInFileVisitor().exec(soyFile)) {
String calleeNotInFile = node.getCalleeName();
int lastDotIndex = calleeNotInFile.lastIndexOf('.');
calleeNamespaces.add(calleeNotInFile.substring(0, lastDotIndex));
}
for (String calleeNamespace : calleeNamespaces) {
if (calleeNamespace.length() > 0 && !calleeNamespace.equals(prevCalleeNamespace)) {
jsCodeBuilder.addGoogRequire(GoogRequire.create(calleeNamespace));
prevCalleeNamespace = calleeNamespace;
}
}
}
use of com.google.template.soy.soytree.CallBasicNode 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.CallBasicNode in project closure-templates by google.
the class GenJsCodeVisitor method addCodeToRequireGoogModules.
/**
* Generates the module imports and aliasing. This generates code like the following:
*
* <pre>
* var $import1 = goog.require('some.namespace');
* var $templateAlias1 = $import1.tmplOne;
* var $templateAlias2 = $import1.tmplTwo;
* var $import2 = goog.require('other.namespace');
* ...
* </pre>
*
* @param soyFile The node we're visiting.
*/
private void addCodeToRequireGoogModules(SoyFileNode soyFile) {
int counter = 1;
// Get all the unique calls in the file.
Set<String> calls = new HashSet<>();
for (CallBasicNode callNode : SoyTreeUtils.getAllNodesOfType(soyFile, CallBasicNode.class)) {
calls.add(callNode.getCalleeName());
}
// Map all the unique namespaces to the templates in those namespaces.
SetMultimap<String, String> namespaceToTemplates = TreeMultimap.create();
for (String call : calls) {
namespaceToTemplates.put(call.substring(0, call.lastIndexOf('.')), call);
}
for (String namespace : namespaceToTemplates.keySet()) {
// Skip the file's own namespace as there is nothing to import/alias.
if (namespace.equals(soyFile.getNamespace())) {
continue;
}
// Add a require of the module
String namespaceAlias = "$import" + counter++;
String importNamespace = getGoogModuleNamespace(namespace);
jsCodeBuilder.append(VariableDeclaration.builder(namespaceAlias).setRhs(GOOG_REQUIRE.call(stringLiteral(importNamespace))).build());
// Alias all the templates used from the module
for (String fullyQualifiedName : namespaceToTemplates.get(namespace)) {
String alias = templateAliases.get(fullyQualifiedName);
String shortName = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.'));
jsCodeBuilder.append(VariableDeclaration.builder(alias).setRhs(dottedIdNoRequire(namespaceAlias + shortName)).build());
}
}
}
use of com.google.template.soy.soytree.CallBasicNode in project closure-templates by google.
the class AliasUtils method createTemplateAliases.
/**
* Creates a mapping for assigning and looking up the variable alias for templates both within a
* file and referenced from external files. For local files, the alias is just the local
* template's name. For external templates, the alias is an identifier that is unique for that
* template.
*
* <p>For V1 templates, no alias is generated and the template should be called by the fully
* qualified name.
*
* @param fileNode The {@link SoyFileNode} to create an alias mapping for.
* @return A {@link TemplateAliases} to look up aliases with.
*/
static TemplateAliases createTemplateAliases(SoyFileNode fileNode) {
Map<String, String> aliasMap = new HashMap<>();
Set<String> localTemplates = new HashSet<>();
int counter = 0;
// Go through templates first and just alias them to their local name.
for (TemplateBasicNode templateBasicNode : SoyTreeUtils.getAllNodesOfType(fileNode, TemplateBasicNode.class)) {
String partialName = templateBasicNode.getPartialTemplateName();
String fullyQualifiedName = templateBasicNode.getTemplateName();
localTemplates.add(fullyQualifiedName);
Preconditions.checkState(partialName != null, "Aliasing not supported for V1 templates");
// Need to start the alias with something that cannot be a part of a reserved
// JavaScript identifier like 'function' or 'catch'.
String alias = "$" + partialName.substring(1);
aliasMap.put(fullyQualifiedName, alias);
}
// Go through all call sites looking for foreign template calls and create an alias for them.
for (CallBasicNode callBasicNode : SoyTreeUtils.getAllNodesOfType(fileNode, CallBasicNode.class)) {
String fullyQualifiedName = callBasicNode.getCalleeName();
// to a local template.
if (localTemplates.contains(fullyQualifiedName) || aliasMap.containsKey(fullyQualifiedName)) {
continue;
}
String alias = TEMPLATE_ALIAS_PREFIX + (++counter);
aliasMap.put(fullyQualifiedName, alias);
}
return new Aliases(aliasMap);
}
Aggregations