Search in sources :

Example 6 with TemplateDelegateNode

use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.

the class RenderVisitor method visitCallDelegateNode.

@Override
protected void visitCallDelegateNode(CallDelegateNode node) {
    ExprRootNode variantExpr = node.getDelCalleeVariantExpr();
    String variant;
    if (variantExpr == null) {
        variant = "";
    } else {
        try {
            SoyValue variantData = eval(variantExpr, node);
            if (variantData instanceof IntegerData) {
                // An integer constant is being used as variant. Use the value string representation as
                // variant.
                variant = String.valueOf(variantData.longValue());
            } else {
                // Variant is either a StringData or a SanitizedContent. Use the value as a string. If
                // the value is not a string, and exception will be thrown.
                variant = variantData.stringValue();
            }
        } catch (SoyDataException e) {
            throw RenderException.createWithSource(String.format("Variant expression \"%s\" doesn't evaluate to a valid type " + "(Only string and integer are supported).", variantExpr.toSourceString()), e, node);
        }
    }
    DelTemplateKey delegateKey = DelTemplateKey.create(node.getDelCalleeName(), variant);
    TemplateDelegateNode callee;
    try {
        callee = templateRegistry.selectDelTemplate(delegateKey, activeDelPackageSelector);
    } catch (IllegalArgumentException e) {
        throw RenderException.createWithSource(e.getMessage(), e, node);
    }
    if (callee != null) {
        visitCallNodeHelper(node, callee);
    } else if (node.allowEmptyDefault()) {
        // no active delegate implementation, so the call output is empty string
        return;
    } else {
        throw RenderException.createWithSource("Found no active impl for delegate call to \"" + node.getDelCalleeName() + (variant.isEmpty() ? "" : ":" + variant) + "\" (and delcall does not set allowemptydefault=\"true\").", node);
    }
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) IntegerData(com.google.template.soy.data.restricted.IntegerData) DelTemplateKey(com.google.template.soy.soytree.TemplateDelegateNode.DelTemplateKey) SoyValue(com.google.template.soy.data.SoyValue) SoyDataException(com.google.template.soy.data.SoyDataException) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode)

Example 7 with TemplateDelegateNode

use of com.google.template.soy.soytree.TemplateDelegateNode 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)

Example 8 with TemplateDelegateNode

use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.

the class CheckDelegatesVisitor method checkTemplates.

/**
 * Performs checks that only involve templates (uses templateRegistry only).
 */
private void checkTemplates() {
    DelTemplateSelector<TemplateDelegateNode> selector = templateRegistry.getDelTemplateSelector();
    // content kind, and strict html mode.
    for (Collection<TemplateDelegateNode> delTemplateGroup : selector.delTemplateNameToValues().asMap().values()) {
        TemplateDelegateNode firstDelTemplate = null;
        Set<Equivalence.Wrapper<TemplateParam>> firstRequiredParamSet = null;
        SanitizedContentKind firstContentKind = null;
        boolean firstStrictHtml = false;
        // loop over all members of the deltemplate group.
        for (TemplateDelegateNode delTemplate : delTemplateGroup) {
            if (firstDelTemplate == null) {
                // First template encountered.
                firstDelTemplate = delTemplate;
                firstRequiredParamSet = getRequiredParamSet(delTemplate);
                firstContentKind = delTemplate.getContentKind();
                firstStrictHtml = delTemplate.isStrictHtml() && firstContentKind == SanitizedContentKind.HTML;
            } else {
                // Not first template encountered.
                Set<Equivalence.Wrapper<TemplateParam>> currRequiredParamSet = getRequiredParamSet(delTemplate);
                if (!currRequiredParamSet.equals(firstRequiredParamSet)) {
                    errorReporter.report(delTemplate.getSourceLocation(), DELTEMPLATES_WITH_DIFFERENT_PARAM_DECLARATIONS, firstDelTemplate.getDelTemplateName(), firstDelTemplate.getSourceLocation().toString());
                }
                if (delTemplate.getContentKind() != firstContentKind) {
                    // TODO: This is only *truly* a requirement if the strict mode deltemplates are
                    // being called by contextual templates. For a strict-to-strict call, everything
                    // is escaped at runtime at the call sites. You could imagine delegating between
                    // either a plain-text or rich-html template. However, most developers will write
                    // their deltemplates in a parallel manner, and will want to know when the
                    // templates differ. Plus, requiring them all to be the same early-on will allow
                    // future optimizations to avoid the run-time checks, so it's better to start out
                    // as strict as possible and only open up if needed.
                    errorReporter.report(delTemplate.getSourceLocation(), STRICT_DELTEMPLATES_WITH_DIFFERENT_CONTENT_KIND, String.valueOf(firstContentKind), String.valueOf(delTemplate.getContentKind()), firstDelTemplate.getSourceLocation().toString());
                }
                // in this pass.
                if (delTemplate.isStrictHtml() != firstStrictHtml) {
                    errorReporter.report(delTemplate.getSourceLocation(), DELTEMPLATES_WITH_DIFFERENT_STRICT_HTML_MODE, firstDelTemplate.getDelTemplateName(), firstDelTemplate.getSourceLocation().toString());
                }
            }
        }
    }
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) SanitizedContentKind(com.google.template.soy.base.internal.SanitizedContentKind)

Example 9 with TemplateDelegateNode

use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.

the class PassManager method doContextualEscaping.

/**
 * Runs the autoescaper and returns whether or not new contextual templates have been added.
 */
private boolean doContextualEscaping(SoyFileSetNode soyTree) {
    List<TemplateNode> extraTemplates = autoescaper.rewrite(soyTree, errorReporter);
    // TODO: Run the redundant template remover here and rename after CL 16642341 is in.
    if (!extraTemplates.isEmpty()) {
        // TODO: pull out somewhere else.  Ideally do the merge as part of the redundant template
        // removal.
        Map<String, SoyFileNode> containingFile = new HashMap<>();
        for (SoyFileNode fileNode : soyTree.getChildren()) {
            for (TemplateNode templateNode : fileNode.getChildren()) {
                String name = templateNode instanceof TemplateDelegateNode ? ((TemplateDelegateNode) templateNode).getDelTemplateName() : templateNode.getTemplateName();
                containingFile.put(DerivedTemplateUtils.getBaseName(name), fileNode);
            }
        }
        for (TemplateNode extraTemplate : extraTemplates) {
            String name = extraTemplate instanceof TemplateDelegateNode ? ((TemplateDelegateNode) extraTemplate).getDelTemplateName() : extraTemplate.getTemplateName();
            containingFile.get(DerivedTemplateUtils.getBaseName(name)).addChild(extraTemplate);
        }
        return true;
    }
    return false;
}
Also used : TemplateNode(com.google.template.soy.soytree.TemplateNode) TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) HashMap(java.util.HashMap) SoyFileNode(com.google.template.soy.soytree.SoyFileNode)

Example 10 with TemplateDelegateNode

use of com.google.template.soy.soytree.TemplateDelegateNode in project closure-templates by google.

the class FindIndirectParamsVisitor method visitCallDelegateNode.

@Override
protected void visitCallDelegateNode(CallDelegateNode node) {
    // Don't forget to visit content within CallParamContentNodes.
    visitChildren(node);
    // We only want to recurse on calls that pass all data.
    if (!node.isPassingAllData()) {
        return;
    }
    // The current Soy file bundle may not contain all the delegate implementations that could
    // potentially be used.
    mayHaveIndirectParamsInExternalDelCalls = true;
    // Visit all the possible callee templates.
    ImmutableList<TemplateDelegateNode> potentialCallees = templateRegistry.getDelTemplateSelector().delTemplateNameToValues().get(node.getDelCalleeName());
    for (TemplateDelegateNode delCallee : potentialCallees) {
        visitCalleeHelper(node, delCallee);
    }
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode)

Aggregations

TemplateDelegateNode (com.google.template.soy.soytree.TemplateDelegateNode)11 TemplateNode (com.google.template.soy.soytree.TemplateNode)5 ImmutableMap (com.google.common.collect.ImmutableMap)3 TemplateParam (com.google.template.soy.soytree.defn.TemplateParam)3 ImmutableList (com.google.common.collect.ImmutableList)2 SanitizedContentKind (com.google.template.soy.base.internal.SanitizedContentKind)2 TemplateBasicNode (com.google.template.soy.soytree.TemplateBasicNode)2 FieldDescriptor (com.google.protobuf.Descriptors.FieldDescriptor)1 IncrementingIdGenerator (com.google.template.soy.base.internal.IncrementingIdGenerator)1 IndentedLinesBuilder (com.google.template.soy.base.internal.IndentedLinesBuilder)1 UniqueNameGenerator (com.google.template.soy.base.internal.UniqueNameGenerator)1 SoyDataException (com.google.template.soy.data.SoyDataException)1 SoyValue (com.google.template.soy.data.SoyValue)1 IntegerData (com.google.template.soy.data.restricted.IntegerData)1 ErrorReporter (com.google.template.soy.error.ErrorReporter)1 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)1 FieldAccessNode (com.google.template.soy.exprtree.FieldAccessNode)1 GlobalNode (com.google.template.soy.exprtree.GlobalNode)1 ProtoInitNode (com.google.template.soy.exprtree.ProtoInitNode)1 VarRefNode (com.google.template.soy.exprtree.VarRefNode)1