use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class Es6RewriteModules method addGetterExport.
private void addGetterExport(Node script, Node forSourceInfo, Node objLit, String exportedName, Node value) {
Node getter = astFactory.createGetterDef(exportedName, value);
getter.putBooleanProp(Node.MODULE_EXPORT, true);
objLit.addChildToBack(getter);
if (!astFactory.isAddingTypes()) {
// TODO(b/143904518): Remove this code when this pass is permanently moved after type checking
// Type checker doesn't infer getters so mark the return as unknown.
// { /** @return {?} */ get foo() { return foo; } }
JSDocInfo.Builder builder = JSDocInfo.builder().parseDocumentation();
builder.recordReturnType(new JSTypeExpression(new Node(Token.QMARK).srcref(forSourceInfo), script.getSourceFileName()));
getter.setJSDocInfo(builder.build());
} else {
// For a property typed as number, synthesize a type `function(): number`.
getter.setJSType(compiler.getTypeRegistry().createFunctionType(value.getJSType()));
}
getter.srcrefTreeIfMissing(forSourceInfo);
compiler.reportChangeToEnclosingScope(getter.getFirstChild().getLastChild());
compiler.reportChangeToEnclosingScope(getter);
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class Es6RewriteModules method createExportsObject.
private Node createExportsObject(String moduleName, NodeTraversal t, Node script, AstFactory.Type moduleObjectType) {
Node moduleObject = astFactory.createObjectLit(moduleObjectType);
// Going to get renamed by RenameGlobalVars, so the name we choose here doesn't matter as long
// as it doesn't collide with an existing variable. (We can't use `moduleName` since then
// RenameGlobalVars will rename all references to `moduleName` incorrectly). We'll fix the name
// in visitScript after the global renaming to ensure it has a name that is deterministic from
// the path.
//
// So after this method we'll have:
// var $jscomp$tmp$exports$module$name = {};
// module$name.exportName = localName;
//
// After RenameGlobalVars:
// var $jscomp$tmp$exports$module$nameglobalized = {};
// module$name.exportName = localName$globalized;
//
// After visitScript:
// var module$name = {};
// module$name.exportName = localName$globalized;
Node moduleVar = astFactory.createSingleVarNameDeclaration("$jscomp$tmp$exports$module$name", moduleObject);
moduleVar.getFirstChild().putBooleanProp(Node.MODULE_EXPORT, true);
// TODO(b/144593112): Stop adding JSDoc when this pass moves to always be after typechecking.
JSDocInfo.Builder infoBuilder = JSDocInfo.builder();
infoBuilder.recordConstancy();
moduleVar.setJSDocInfo(infoBuilder.build());
moduleVar.getFirstChild().setDeclaredConstantVar(true);
script.addChildToBack(moduleVar.srcrefTreeIfMissing(script));
Module thisModule = moduleMap.getModule(t.getInput().getPath());
for (Map.Entry<String, Binding> entry : thisModule.namespace().entrySet()) {
String exportedName = entry.getKey();
Binding binding = entry.getValue();
Node nodeForSourceInfo = binding.sourceNode();
boolean mutated = binding.isMutated();
QualifiedName boundVariableQualifiedName = ModuleRenaming.getGlobalName(binding);
checkState(boundVariableQualifiedName.isSimple(), "unexpected qualified name: %s", boundVariableQualifiedName);
String boundVariableName = boundVariableQualifiedName.getRoot();
Node getProp = astFactory.createGetPropWithoutColor(astFactory.createName(moduleName, moduleObjectType), exportedName);
getProp.putBooleanProp(Node.MODULE_EXPORT, true);
if (typedefs.contains(exportedName)) {
// /** @typedef {foo} */
// moduleName.foo;
JSDocInfo.Builder builder = JSDocInfo.builder().parseDocumentation();
JSTypeExpression typeExpr = new JSTypeExpression(astFactory.createString(exportedName).srcref(nodeForSourceInfo), script.getSourceFileName());
builder.recordTypedef(typeExpr);
JSDocInfo info = builder.build();
getProp.setJSDocInfo(info);
Node exprResult = astFactory.exprResult(getProp).srcrefTreeIfMissing(nodeForSourceInfo);
script.addChildToBack(exprResult);
} else if (mutated) {
final Node globalExportName = astFactory.createName(boundVariableName, type(getProp));
addGetterExport(script, nodeForSourceInfo, moduleObject, exportedName, globalExportName);
NodeUtil.addFeatureToScript(t.getCurrentScript(), Feature.GETTER, compiler);
} else {
// Avoid the extra complexity of using getters when the property isn't mutated.
// exports.foo = foo;
Node assign = astFactory.createAssign(getProp, astFactory.createName(boundVariableName, type(getProp)));
// TODO(b/144593112): Stop adding JSDoc when this pass moves to always be after typechecking
JSDocInfo.Builder builder = JSDocInfo.builder().parseDocumentation();
builder.recordConstancy();
JSDocInfo info = builder.build();
assign.setJSDocInfo(info);
script.addChildToBack(astFactory.exprResult(assign).srcrefTreeIfMissing(nodeForSourceInfo));
}
}
return moduleVar;
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class JSDocInfoPrinter method print.
public String print(JSDocInfo info) {
boolean multiline = false;
List<String> parts = new ArrayList<>();
parts.add("/**");
if (info.isExterns()) {
parts.add("@externs");
}
if (info.isTypeSummary()) {
parts.add("@typeSummary");
}
if (info.isExport()) {
parts.add("@export");
} else if (info.getVisibility() != null && info.getVisibility() != Visibility.INHERITED) {
parts.add("@" + Ascii.toLowerCase(info.getVisibility().toString()));
}
if (info.getAuthors() != null) {
multiline = true;
for (String name : info.getAuthors()) {
parts.add("@author " + name);
}
}
if (info.isAbstract()) {
parts.add("@abstract");
}
if (info.hasLendsName()) {
parts.add(buildAnnotationWithType("lends", info.getLendsName().getRoot()));
}
if (info.hasConstAnnotation() && !info.isDefine()) {
parts.add("@const");
}
if (info.isFinal()) {
parts.add("@final");
}
String description = info.getDescription();
if (description != null) {
multiline = true;
parts.add("@desc " + description);
}
if (info.getReferences() != null) {
multiline = true;
for (String desc : info.getReferences()) {
parts.add("@see " + desc);
}
}
if (info.isWizaction()) {
parts.add("@wizaction");
}
if (info.isPolymerBehavior()) {
parts.add("@polymerBehavior");
}
if (info.isPolymer()) {
parts.add("@polymer");
}
if (info.isCustomElement()) {
parts.add("@customElement");
}
if (info.isMixinClass()) {
parts.add("@mixinClass");
}
if (info.isMixinFunction()) {
parts.add("@mixinFunction");
}
if (info.isNoSideEffects()) {
parts.add("@nosideeffects");
}
if (info.isNoCompile()) {
parts.add("@nocompile");
}
if (info.isNoInline()) {
parts.add("@noinline");
}
if (info.isIdGenerator()) {
parts.add("@idGenerator {unique}");
}
if (info.isConsistentIdGenerator()) {
parts.add("@idGenerator {consistent}");
}
if (info.isStableIdGenerator()) {
parts.add("@idGenerator {stable}");
}
if (info.isXidGenerator()) {
parts.add("@idGenerator {xid}");
}
if (info.isMappedIdGenerator()) {
parts.add("@idGenerator {mapped}");
}
if (info.makesDicts()) {
parts.add("@dict");
}
if (info.makesStructs()) {
parts.add("@struct");
}
if (info.makesUnrestricted()) {
parts.add("@unrestricted ");
}
if (info.isConstructor()) {
parts.add("@constructor");
}
if (info.isInterface() && !info.usesImplicitMatch()) {
parts.add("@interface");
}
if (info.isInterface() && info.usesImplicitMatch()) {
parts.add("@record");
}
if (info.hasBaseType()) {
multiline = true;
Node typeNode = stripBang(info.getBaseType().getRoot());
parts.add(buildAnnotationWithType("extends", typeNode));
}
for (JSTypeExpression type : info.getExtendedInterfaces()) {
multiline = true;
Node typeNode = stripBang(type.getRoot());
parts.add(buildAnnotationWithType("extends", typeNode));
}
for (JSTypeExpression type : info.getImplementedInterfaces()) {
multiline = true;
Node typeNode = stripBang(type.getRoot());
parts.add(buildAnnotationWithType("implements", typeNode));
}
if (info.hasThisType()) {
multiline = true;
Node typeNode = stripBang(info.getThisType().getRoot());
parts.add(buildAnnotationWithType("this", typeNode));
}
if (info.getParameterCount() > 0) {
multiline = true;
for (String name : info.getParameterNames()) {
parts.add("@param " + buildParamType(info, name));
}
}
if (info.hasReturnType()) {
multiline = true;
parts.add(buildAnnotationWithType("return", info.getReturnType(), info.getReturnDescription()));
}
if (!info.getThrowsAnnotations().isEmpty() && !info.getThrowsAnnotations().get(0).isEmpty()) {
multiline = true;
parts.add("@throws " + info.getThrowsAnnotations().get(0));
}
ImmutableMap<String, JSTypeExpression> templates = info.getTemplateTypes();
if (!templates.isEmpty()) {
multiline = true;
templates.forEach((name, boundExpr) -> {
Node boundRoot = boundExpr.getRoot();
if (boundRoot.getToken() == Token.QMARK && !boundRoot.hasChildren()) {
// If the bound of the expression is `?` (as it is after parsing an unbounded
// template) don't specify a bound.
// TODO(b/140187077): This case becomes redundant when fixed. It also only covers
// explicit `?` bounds, typedefs will remain explicit.
parts.add("@template " + name);
} else {
parts.add(buildAnnotationWithType("template", boundExpr, name));
}
});
}
ImmutableMap<String, Node> typeTransformations = info.getTypeTransformations();
if (!typeTransformations.isEmpty()) {
multiline = true;
for (Map.Entry<String, Node> e : typeTransformations.entrySet()) {
String name = e.getKey();
String tranformationDefinition = new CodePrinter.Builder(e.getValue()).build();
parts.add("@template " + name + " := " + tranformationDefinition + " =:");
}
}
if (info.isOverride()) {
parts.add("@override");
}
if (info.hasType() && !info.isDefine()) {
if (info.isInlineType()) {
parts.add(typeNode(info.getType().getRoot()));
} else {
parts.add(buildAnnotationWithType("type", info.getType()));
}
}
if (info.isDefine()) {
parts.add(buildAnnotationWithType("define", info.getType()));
}
if (info.hasTypedefType()) {
parts.add(buildAnnotationWithType("typedef", info.getTypedefType()));
}
if (info.hasEnumParameterType()) {
parts.add(buildAnnotationWithType("enum", info.getEnumParameterType()));
}
if (info.isImplicitCast()) {
parts.add("@implicitCast");
}
if (info.isNoCollapse()) {
parts.add("@nocollapse");
}
ImmutableMap<ImmutableSet<String>, String> suppressions = info.getSuppressionsAndTheirDescription();
if (!suppressions.isEmpty()) {
// With ImmutableMap, the iteration order will be same as insertion order (i.e. parse order).
for (Map.Entry<ImmutableSet<String>, String> suppression : suppressions.entrySet()) {
String[] warnings = suppression.getKey().toArray(new String[0]);
// Even the warnings inside a suppress annotation are printed in natural order for
// consistency
Arrays.sort(warnings, naturalOrder());
String text = suppression.getValue();
StringBuilder sb = new StringBuilder();
sb.append("@suppress {").append(Joiner.on(',').join(warnings)).append("}");
if (!text.isEmpty()) {
sb.append(" ").append(text);
}
parts.add(sb.toString());
}
multiline = true;
}
if (info.isDeprecated()) {
parts.add("@deprecated " + info.getDeprecationReason());
multiline = true;
}
if (info.isPolymer()) {
multiline = true;
parts.add("@polymer");
}
if (info.isPolymerBehavior()) {
multiline = true;
parts.add("@polymerBehavior");
}
if (info.isMixinFunction()) {
multiline = true;
parts.add("@mixinFunction");
}
if (info.isMixinClass()) {
multiline = true;
parts.add("@mixinClass");
}
if (info.isCustomElement()) {
multiline = true;
parts.add("@customElement");
}
if (info.getClosurePrimitiveId() != null) {
parts.add("@closurePrimitive {" + info.getClosurePrimitiveId() + "}");
}
if (info.isNgInject()) {
parts.add("@ngInject");
}
for (String tsType : info.getTsTypes()) {
parts.add("@tsType " + tsType);
}
if (printDesc && info.getBlockDescription() != null) {
String cleaned = info.getBlockDescription().replaceAll("\n\\s*\\*\\s*", "\n");
if (!cleaned.isEmpty()) {
multiline = true;
cleaned = cleaned.trim();
if (parts.size() > 1) {
// If there is more than one part - the opening "/**" - then add blank line between the
// description and everything else.
cleaned += '\n';
}
parts.add(1, cleaned);
}
}
StringBuilder sb = new StringBuilder();
if (multiline) {
Joiner.on("\n").appendTo(sb, parts);
} else {
Joiner.on(" ").appendTo(sb, parts);
sb.append(" */");
}
// Ensure all lines start with " *", and then ensure all non blank lines have a space after
// the *.
String s = sb.toString().replace("\n", "\n *").replaceAll("\n \\*([^ \n])", "\n * $1");
if (multiline) {
s += "\n */\n";
} else {
s += " ";
}
return s;
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class ProcessClosurePrimitives method checkPossibleGoogProvideInit.
private void checkPossibleGoogProvideInit(String namespace, @Nullable JSDocInfo info, Node definition) {
if (info == null || definition.isFromExterns()) {
return;
}
ModuleMetadata metadata = this.closureModules.get(namespace);
if (metadata == null || !metadata.isGoogProvide()) {
return;
}
// Validate that the namespace is not declared as a generic object type.
JSTypeExpression expr = info.getType();
if (expr == null) {
return;
}
Node n = expr.getRoot();
if (n.getToken() == Token.BANG) {
n = n.getFirstChild();
}
if (n.isStringLit() && // templated object types are ok.
!n.hasChildren() && n.getString().equals("Object")) {
compiler.report(JSError.make(definition, WEAK_NAMESPACE_TYPE));
}
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class ChromePass method setJsDocWithType.
private static void setJsDocWithType(Node target, Node type) {
JSDocInfo.Builder builder = JSDocInfo.builder();
builder.recordType(new JSTypeExpression(type.srcrefTree(VIRTUAL_NODE), VIRTUAL_FILE));
target.setJSDocInfo(builder.build());
}
Aggregations