Search in sources :

Example 1 with GoogRequire

use of com.google.template.soy.jssrc.dsl.GoogRequire in project closure-templates by google.

the class JsRuntime method symbolWithNamespace.

/**
 * Returns a code chunk that accesses the given symbol.
 *
 * @param requireSymbol The symbol to {@code goog.require}
 * @param fullyQualifiedSymbol The symbol we want to access.
 */
private static CodeChunk.WithValue symbolWithNamespace(String requireSymbol, String fullyQualifiedSymbol) {
    GoogRequire require = GoogRequire.create(requireSymbol);
    if (fullyQualifiedSymbol.equals(require.symbol())) {
        return require.reference();
    }
    String ident = fullyQualifiedSymbol.substring(require.symbol().length() + 1);
    return require.dotAccess(ident);
}
Also used : GoogRequire(com.google.template.soy.jssrc.dsl.GoogRequire)

Example 2 with GoogRequire

use of com.google.template.soy.jssrc.dsl.GoogRequire in project closure-templates by google.

the class GenJsCodeVisitor method genParamsRecordType.

// -----------------------------------------------------------------------------------------------
// Helpers
/**
 * Generate the JSDoc for the opt_data parameter.
 */
private String genParamsRecordType(TemplateNode node) {
    Set<String> paramNames = new HashSet<>();
    // Generate members for explicit params.
    Map<String, String> record = new LinkedHashMap<>();
    for (TemplateParam param : node.getParams()) {
        JsType jsType = getJsType(param.type());
        record.put(genParamAlias(param.name()), jsType.typeExprForRecordMember(/* isOptional= */
        !param.isRequired()));
        for (GoogRequire require : jsType.getGoogRequires()) {
            jsCodeBuilder.addGoogRequire(require);
        }
        paramNames.add(param.name());
    }
    // Do the same for indirect params, if we can find them.
    // If there's a conflict between the explicitly-declared type, and the type
    // inferred from the indirect params, then the explicit type wins.
    // Also note that indirect param types may not be inferrable if the target
    // is not in the current compilation file set.
    IndirectParamsInfo ipi = new FindIndirectParamsVisitor(templateRegistry).exec(node);
    // types in JS allow additional undeclared fields to be present.
    if (!ipi.mayHaveIndirectParamsInExternalCalls && !ipi.mayHaveIndirectParamsInExternalDelCalls) {
        for (String indirectParamName : ipi.indirectParamTypes.keySet()) {
            if (paramNames.contains(indirectParamName)) {
                continue;
            }
            Collection<SoyType> paramTypes = ipi.indirectParamTypes.get(indirectParamName);
            SoyType combinedType = SoyTypes.computeLowestCommonType(typeRegistry, paramTypes);
            // Note that Union folds duplicate types and flattens unions, so if
            // the combinedType is already a union this will do the right thing.
            // TODO: detect cases where nullable is not needed (requires flow
            // analysis to determine if the template is always called.)
            SoyType indirectParamType = typeRegistry.getOrCreateUnionType(combinedType, NullType.getInstance());
            JsType jsType = getJsType(indirectParamType);
            // NOTE: we do not add goog.requires for indirect types.  This is because it might introduce
            // strict deps errors.  This should be fine though since the transitive soy template that
            // actually has the param will add them.
            record.put(genParamAlias(indirectParamName), jsType.typeExprForRecordMember(/* isOptional= */
            true));
        }
    }
    StringBuilder sb = new StringBuilder();
    sb.append("{\n *  ");
    Joiner.on(",\n *  ").withKeyValueSeparator(": ").appendTo(sb, record);
    // trailing comma in record is important in case the last record member is the
    // unknown type
    sb.append(",\n * }");
    return sb.toString();
}
Also used : LinkedHashMap(java.util.LinkedHashMap) IndirectParamsInfo(com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo) GoogRequire(com.google.template.soy.jssrc.dsl.GoogRequire) SoyType(com.google.template.soy.types.SoyType) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) HashSet(java.util.HashSet) FindIndirectParamsVisitor(com.google.template.soy.passes.FindIndirectParamsVisitor)

Example 3 with GoogRequire

use of com.google.template.soy.jssrc.dsl.GoogRequire 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

GoogRequire (com.google.template.soy.jssrc.dsl.GoogRequire)3 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 FindIndirectParamsVisitor (com.google.template.soy.passes.FindIndirectParamsVisitor)1 IndirectParamsInfo (com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo)1 ShouldEnsureDataIsDefinedVisitor (com.google.template.soy.passes.ShouldEnsureDataIsDefinedVisitor)1 TemplateDelegateNode (com.google.template.soy.soytree.TemplateDelegateNode)1 TemplateParam (com.google.template.soy.soytree.defn.TemplateParam)1 SoyType (com.google.template.soy.types.SoyType)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1