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);
}
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();
}
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()));
}
Aggregations