use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitor method visitTemplateNode.
/**
* Outputs a {@link TemplateNode}, generating the function open and close, along with a a debug
* template name.
*
* <p>If aliasing is not performed (which is always the case for V1 templates), this looks like:
*
* <pre>
* my.namespace.func = function(opt_data, opt_sb) {
* ...
* };
* if (goog.DEBUG) {
* my.namespace.func.soyTemplateName = 'my.namespace.func';
* }
* </pre>
*
* <p>If aliasing is performed, this looks like:
*
* <pre>
* function $func(opt_data, opt_sb) {
* ...
* }
* exports.func = $func;
* if (goog.DEBUG) {
* $func.soyTemplateName = 'my.namespace.func';
* }
* <p>Note that the alias is not exactly the function name as in may conflict with a reserved
* JavaScript identifier.
* </pre>
*/
@Override
protected void visitTemplateNode(TemplateNode node) {
// TODO(lukes): why don't we always do this? even for old style params this would be useful
boolean useStrongTyping = hasStrictParams(node);
String templateName = node.getTemplateName();
String partialName = node.getPartialTemplateName();
String alias;
boolean addToExports = jsSrcOptions.shouldGenerateGoogModules();
// TODO(lukes): does it make sense to add deltempaltes or private templates to exports?
if (addToExports && node instanceof TemplateDelegateNode) {
alias = node.getPartialTemplateName().substring(1);
} else {
alias = templateAliases.get(templateName);
}
// TODO(lukes): reserve all the namespace prefixes that are in scope
// TODO(lukes): use this for all local variable declarations
UniqueNameGenerator nameGenerator = JsSrcNameGenerators.forLocalVariables();
CodeChunk.Generator codeGenerator = CodeChunk.Generator.create(nameGenerator);
templateTranslationContext = TranslationContext.of(SoyToJsVariableMappings.forNewTemplate(), codeGenerator, nameGenerator);
genJsExprsVisitor = genJsExprsVisitorFactory.create(templateTranslationContext, templateAliases, errorReporter);
assistantForMsgs = null;
String paramsRecordType = null;
String jsDoc = null;
// ------ Generate JS Doc. ------
StringBuilder jsDocBuilder = new StringBuilder();
jsDocBuilder.append("/**\n");
jsDocBuilder.append(" * @param {");
if (useStrongTyping) {
paramsRecordType = genParamsRecordType(node);
jsDocBuilder.append(alias).append(".Params");
} else {
jsDocBuilder.append("Object<string, *>=");
}
jsDocBuilder.append("} opt_data\n");
jsDocBuilder.append(" * @param {Object<string, *>=} opt_ijData\n");
jsDocBuilder.append(" * @param {Object<string, *>=} opt_ijData_deprecated\n");
String returnType = getTemplateReturnType(node);
jsDocBuilder.append(" * @return {").append(returnType).append("}\n");
// Sometimes we will throw an error in the middle and the following code is not reachable.
jsDocBuilder.append(" * @suppress {").append("checkTypes|uselessCode").append("}\n");
if (node.getVisibility() == Visibility.PRIVATE) {
jsDocBuilder.append(" * @private\n");
}
jsDocBuilder.append(" */\n");
jsDoc = jsDocBuilder.toString();
ImmutableList.Builder<CodeChunk> bodyStatements = ImmutableList.builder();
bodyStatements.add(CodeChunk.assign("opt_ijData", CodeChunk.id("opt_ijData_deprecated").or(CodeChunk.id("opt_ijData"), codeGenerator)));
// Generate statement to ensure data is defined, if necessary.
if (new ShouldEnsureDataIsDefinedVisitor().exec(node)) {
bodyStatements.add(assign("opt_data", OPT_DATA.or(EMPTY_OBJECT_LITERAL, codeGenerator)));
}
// ------ Generate function body. ------
bodyStatements.add(generateFunctionBody(node));
CodeChunk.WithValue function = CodeChunk.function(// are too brittle.
ImmutableList.of("opt_data", "opt_ijData", "opt_ijData_deprecated"), CodeChunk.statements(bodyStatements.build()));
ImmutableList.Builder<CodeChunk> declarations = ImmutableList.builder();
if (addToExports) {
declarations.add(VariableDeclaration.builder(alias).setRhs(function).build());
declarations.add(assign("exports" + /* partialName starts with a dot */
partialName, id(alias)));
} else {
declarations.add(CodeChunk.assign(alias, function));
}
// ------ Add the @typedef of opt_data. ------
if (paramsRecordType != null) {
// TODO(b/35203585): find a way to represent jsdoc using code chunks
StringBuilder sb = new StringBuilder();
sb.append("/**\n");
sb.append(" * @typedef {").append(paramsRecordType).append("}\n");
sb.append(" */\n");
// TODO(b/35203585): find a way to represent declarations like this in codechunks
sb.append(alias).append(".Params");
declarations.add(CodeChunk.treatRawStringAsStatementLegacyOnly(sb.toString(), ImmutableList.<GoogRequire>of()));
}
// ------ Add the fully qualified template name to the function to use in debug code. ------
declarations.add(ifStatement(GOOG_DEBUG, assign(alias + ".soyTemplateName", stringLiteral(templateName))).build());
// ------ If delegate template, generate a statement to register it. ------
if (node instanceof TemplateDelegateNode) {
TemplateDelegateNode nodeAsDelTemplate = (TemplateDelegateNode) node;
declarations.add(SOY_REGISTER_DELEGATE_FN.call(SOY_GET_DELTEMPLATE_ID.call(stringLiteral(delTemplateNamer.getDelegateName(nodeAsDelTemplate))), stringLiteral(nodeAsDelTemplate.getDelTemplateVariant()), number(nodeAsDelTemplate.getDelPriority().getValue()), dottedIdNoRequire(alias)));
}
// TODO(b/35203585): find a way to represent jsdoc using code chunks
if (jsDoc != null) {
jsCodeBuilder.append(jsDoc);
}
jsCodeBuilder.append(CodeChunk.statements(declarations.build()));
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitor method visitSwitchNode.
/**
* Example:
*
* <pre>
* {switch $boo}
* {case 0}
* ...
* {case 1, 2}
* ...
* {default}
* ...
* {/switch}
* </pre>
*
* might generate
*
* <pre>
* switch (opt_data.boo) {
* case 0:
* ...
* break;
* case 1:
* case 2:
* ...
* break;
* default:
* ...
* }
* </pre>
*/
@Override
protected void visitSwitchNode(SwitchNode node) {
CodeChunk.WithValue switchOn = coerceTypeForSwitchComparison(node.getExpr());
SwitchBuilder switchBuilder = switch_(switchOn);
for (SoyNode child : node.getChildren()) {
if (child instanceof SwitchCaseNode) {
SwitchCaseNode scn = (SwitchCaseNode) child;
ImmutableList.Builder<CodeChunk.WithValue> caseChunks = ImmutableList.builder();
for (ExprNode caseExpr : scn.getExprList()) {
CodeChunk.WithValue caseChunk = translateExpr(caseExpr);
caseChunks.add(caseChunk);
}
CodeChunk body = visitChildrenReturningCodeChunk(scn);
switchBuilder.case_(caseChunks.build(), body);
} else if (child instanceof SwitchDefaultNode) {
CodeChunk body = visitChildrenReturningCodeChunk((SwitchDefaultNode) child);
switchBuilder.default_(body);
} else {
throw new AssertionError();
}
}
jsCodeBuilder.append(switchBuilder.build());
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenIncrementalDomCodeVisitor method getAttributeValues.
private List<CodeChunk.WithValue> getAttributeValues(HtmlAttributeNode node) {
if (!node.hasValue()) {
// the runtime knows to create an attribute.
return ImmutableList.of(LITERAL_EMPTY_STRING);
}
HtmlAttributeValueNode value = (HtmlAttributeValueNode) node.getChild(1);
if (!isComputableAsJsExprsVisitor.execOnChildren(value)) {
String outputVar = "html_attribute_" + node.getId();
getJsCodeBuilder().pushOutputVar(outputVar).setOutputVarInited();
SanitizedContentKind prev = getJsCodeBuilder().getContentKind();
getJsCodeBuilder().setContentKind(SanitizedContentKind.TEXT);
CodeChunk appends = visitChildrenReturningCodeChunk(value);
getJsCodeBuilder().popOutputVar();
getJsCodeBuilder().setContentKind(prev);
return ImmutableList.of(CodeChunk.id(outputVar).withInitialStatements(ImmutableList.<CodeChunk>of(VariableDeclaration.builder(outputVar).setRhs(CodeChunk.LITERAL_EMPTY_STRING).build(), appends)));
}
return genJsExprsVisitor.execOnChildren(value);
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenIncrementalDomCodeVisitor method generateFunctionBody.
@Override
protected CodeChunk generateFunctionBody(TemplateNode node) {
IncrementalDomCodeBuilder jsCodeBuilder = getJsCodeBuilder();
boolean isTextTemplate = isTextContent(node.getContentKind());
CodeChunk typeChecks = genParamTypeChecks(node);
// the transformation.
if (isTextTemplate) {
// We do our own initialization below, so mark it as such.
jsCodeBuilder.pushOutputVar("output").setOutputVarInited();
}
CodeChunk body = visitChildrenReturningCodeChunk(node);
if (isTextTemplate) {
VariableDeclaration declare = VariableDeclaration.builder("output").setRhs(LITERAL_EMPTY_STRING).build();
jsCodeBuilder.popOutputVar();
body = CodeChunk.statements(declare, body, return_(sanitize(declare.ref(), node.getContentKind())));
}
return CodeChunk.statements(typeChecks, body);
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenCallCodeUtilsTest method getCallExprTextHelper.
private static String getCallExprTextHelper(String callSource, ImmutableList<String> escapingDirectives) {
SoyFileSetNode soyTree = SoyFileSetParserBuilder.forTemplateContents(callSource).parse().fileSet();
CallNode callNode = (CallNode) SharedTestUtils.getNode(soyTree, 0);
// Manually setting the escaping directives.
ImmutableMap<String, ? extends SoyPrintDirective> directives = INJECTOR.getInstance(new Key<ImmutableMap<String, ? extends SoyPrintDirective>>() {
});
callNode.setEscapingDirectives(escapingDirectives.stream().map(directives::get).collect(toImmutableList()));
GenCallCodeUtils genCallCodeUtils = JsSrcTestUtils.createGenCallCodeUtils();
UniqueNameGenerator nameGenerator = JsSrcNameGenerators.forLocalVariables();
CodeChunk call = genCallCodeUtils.gen(callNode, AliasUtils.IDENTITY_ALIASES, TranslationContext.of(SoyToJsVariableMappings.forNewTemplate(), CodeChunk.Generator.create(nameGenerator), nameGenerator), ErrorReporter.exploding());
return call.getCode();
}
Aggregations