use of com.google.template.soy.passes.ShouldEnsureDataIsDefinedVisitor 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()));
}
Aggregations