Search in sources :

Example 1 with ShouldEnsureDataIsDefinedVisitor

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()));
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) CodeChunk(com.google.template.soy.jssrc.dsl.CodeChunk) ImmutableList(com.google.common.collect.ImmutableList) GoogRequire(com.google.template.soy.jssrc.dsl.GoogRequire) UniqueNameGenerator(com.google.template.soy.base.internal.UniqueNameGenerator) ShouldEnsureDataIsDefinedVisitor(com.google.template.soy.passes.ShouldEnsureDataIsDefinedVisitor)

Aggregations

ImmutableList (com.google.common.collect.ImmutableList)1 UniqueNameGenerator (com.google.template.soy.base.internal.UniqueNameGenerator)1 CodeChunk (com.google.template.soy.jssrc.dsl.CodeChunk)1 GoogRequire (com.google.template.soy.jssrc.dsl.GoogRequire)1 ShouldEnsureDataIsDefinedVisitor (com.google.template.soy.passes.ShouldEnsureDataIsDefinedVisitor)1 TemplateDelegateNode (com.google.template.soy.soytree.TemplateDelegateNode)1