use of com.google.javascript.rhino.QualifiedName 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.QualifiedName in project closure-compiler by google.
the class LateEs6ToEs3Converter method visit.
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch(n.getToken()) {
case ASSIGN:
// Find whether this script contains the `$jscomp.createTemplateTagFirstArgWithRaw =
// function(..) {..}` node. If yes, update the templateLitInsertionPoint.
Node lhs = n.getFirstChild();
Node rhs = n.getSecondChild();
if (lhs.isGetProp() && rhs.isFunction() && lhs.getFirstChild().isName()) {
QualifiedName qName = QualifiedName.of("$jscomp.createTemplateTagFirstArgWithRaw");
if (qName.matches(lhs)) {
checkNotNull(n.getParent(), n);
checkState(n.getParent().isExprResult(), n);
templateLitInsertionPoint = n.getParent().getNext();
}
}
break;
case OBJECTLIT:
visitObject(n);
break;
case MEMBER_FUNCTION_DEF:
if (parent.isObjectLit()) {
visitMemberFunctionDefInObjectLit(n);
}
break;
case TAGGED_TEMPLATELIT:
templateLiteralConverter.visitTaggedTemplateLiteral(t, n, templateLitInsertionPoint);
break;
case TEMPLATELIT:
if (!parent.isTaggedTemplateLit()) {
templateLiteralConverter.visitTemplateLiteral(t, n);
}
break;
default:
break;
}
}
use of com.google.javascript.rhino.QualifiedName in project closure-compiler by google.
the class TypeInference method updateModuleScope.
/**
* Updates the given scope after running inference over a goog.module or ES module
*/
private void updateModuleScope(Module module, TypedScope syntacticBlockScope) {
if (module == null) {
return;
}
switch(module.metadata().moduleType()) {
case ES6_MODULE:
// This call only affects exports with an inferred, not declared, type. Declared exports
// were already added to the namespace object type in TypedScopeCreator.
moduleImportResolver.updateEsModuleNamespaceType(syntacticBlockScope.getVar(Export.NAMESPACE).getType().toObjectType(), module, syntacticBlockScope);
return;
case GOOG_MODULE:
case LEGACY_GOOG_MODULE:
TypedVar exportsVar = checkNotNull(syntacticBlockScope.getVar("exports"), "Missing exports var for %s", module.metadata());
JSType exportsType = exportsVar.getType() != null ? exportsVar.getType() : unknownType;
// Store the type of the namespace on the AST for the convenience of later passes that want
// to access it.
Node rootNode = syntacticBlockScope.getRootNode();
if (rootNode.isModuleBody()) {
rootNode.setJSType(exportsType);
} else {
// For goog.loadModule, give the `exports` parameter the correct type.
checkState(rootNode.isBlock(), rootNode);
Node paramList = NodeUtil.getFunctionParameters(rootNode.getParent());
paramList.getOnlyChild().setJSType(exportsType);
}
if (!module.metadata().isLegacyGoogModule() || exportsVar.getType() == null) {
break;
}
// Update the global scope for the implicit assignment "legacy.module.id = exports;" created
// by `goog.module.declareLegacyNamespace();`
String moduleId = module.closureNamespace();
TypedScope globalScope = syntacticBlockScope.getGlobalScope();
TypedVar globalVar = globalScope.getVar(moduleId);
if (globalVar.isTypeInferred()) {
globalVar.setType(exportsType);
}
// Update the property slot on the parent namespace.
QualifiedName moduleQname = QualifiedName.of(moduleId);
if (!moduleQname.isSimple()) {
JSType parentType = globalScope.lookupQualifiedName(moduleQname.getOwner());
ObjectType parentObjectType = parentType != null ? parentType.toMaybeObjectType() : null;
if (parentObjectType != null && !parentObjectType.isPropertyTypeDeclared(moduleQname.getComponent())) {
parentObjectType.defineInferredProperty(moduleQname.getComponent(), exportsType, exportsVar.getNode());
}
}
return;
default:
break;
}
}
use of com.google.javascript.rhino.QualifiedName in project closure-compiler by google.
the class TypeCheck method visitModuleBody.
/**
* Validates the implicit assignment to the global for a legacy goog.module
*/
private void visitModuleBody(NodeTraversal t, Node moduleBody) {
Module associatedModule = ModuleImportResolver.getModuleFromScopeRoot(compiler.getModuleMap(), (b) -> t.getInput(), moduleBody);
if (!associatedModule.metadata().isLegacyGoogModule()) {
return;
}
QualifiedName moduleName = QualifiedName.of(associatedModule.closureNamespace());
Node googModuleCall = moduleBody.getFirstChild();
if (moduleName.isSimple()) {
TypedVar globalVar = topScope.getVar(moduleName.join());
validator.expectCanAssignTo(googModuleCall, moduleBody.getJSType(), globalVar.getType(), "legacy goog.module export");
} else {
JSType parentType = topScope.lookupQualifiedName(moduleName.getOwner());
ObjectType parentObjectType = parentType != null ? parentType.toMaybeObjectType() : null;
if (parentObjectType == null) {
return;
}
validator.expectCanAssignToPropertyOf(googModuleCall, moduleBody.getJSType(), parentObjectType.getPropertyType(moduleName.getComponent()), parentObjectType, () -> moduleName.getOwner().join(), moduleName.getComponent());
}
}
use of com.google.javascript.rhino.QualifiedName in project closure-compiler by google.
the class JSTypeRegistry method createTypeFromCommentNode.
/**
* Creates a JSType from the nodes representing a type.
*
* @param n The node with type info.
* @param sourceName The source file name.
* @param scope A scope for doing type name lookups.
*/
public JSType createTypeFromCommentNode(Node n, String sourceName, StaticTypedScope scope) {
switch(n.getToken()) {
case // Record type.
LC:
return createRecordTypeFromNodes(n.getFirstChild(), sourceName, scope);
case // Not nullable
BANG:
{
JSType child = createTypeFromCommentNode(n.getFirstChild(), sourceName, scope);
if (child instanceof NamedType) {
return ((NamedType) child).getBangType();
}
return child.restrictByNotNullOrUndefined();
}
case // Nullable or unknown
QMARK:
Node firstChild = n.getFirstChild();
if (firstChild == null) {
return getNativeType(UNKNOWN_TYPE);
}
return createNullableType(createTypeFromCommentNode(firstChild, sourceName, scope));
case // Optional
EQUALS:
// TODO(b/117162687): stop automatically converting {string=} to {(string|undefined)]}
return createOptionalType(createTypeFromCommentNode(n.getFirstChild(), sourceName, scope));
case // Var args
ITER_REST:
return createTypeFromCommentNode(n.getFirstChild(), sourceName, scope);
case // The AllType
STAR:
return getNativeType(ALL_TYPE);
case // Union type
PIPE:
ImmutableList.Builder<JSType> builder = ImmutableList.builder();
for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {
builder.add(createTypeFromCommentNode(child, sourceName, scope));
}
return createUnionType(builder.build());
case // When the return value of a function is not specified
EMPTY:
return getNativeType(UNKNOWN_TYPE);
case // Only allowed in the return value of a function.
VOID:
return getNativeType(VOID_TYPE);
case TYPEOF:
{
String name = n.getFirstChild().getString();
// TODO(sdh): require var to be const?
QualifiedName qname = QualifiedName.of(name);
String root = qname.getRoot();
StaticScope declarationScope = scope.getTopmostScopeOfEventualDeclaration(root);
StaticSlot rootSlot = scope.getSlot(root);
JSType type = scope.lookupQualifiedName(qname);
if (type == null || type.isUnknownType() || rootSlot.getScope() != declarationScope) {
// eventually resolve if necessary.
return NamedType.builder(this, "typeof " + name).setScope(scope).setResolutionKind(ResolutionKind.TYPEOF).setErrorReportingLocationFrom(n).build();
}
if (type.isLiteralObject()) {
JSType scopeType = type;
type = NamedType.builder(this, "typeof " + name).setResolutionKind(ResolutionKind.NONE).setReferencedType(scopeType).build();
}
return type;
}
case STRINGLIT:
{
JSType nominalType = getType(scope, n.getString(), sourceName, n.getLineno(), n.getCharno());
ImmutableList<JSType> templateArgs = parseTemplateArgs(nominalType, n, sourceName, scope);
// Handle forward declared types
if (nominalType.isNamedType() && !nominalType.isResolved()) {
if (templateArgs != null) {
nominalType = nominalType.toMaybeNamedType().toBuilder().setTemplateTypes(templateArgs).build();
}
return addNullabilityBasedOnParseContext(n, nominalType, scope);
}
if (!(nominalType instanceof ObjectType) || isNonNullableName(scope, n.getString())) {
return nominalType;
}
if (templateArgs == null || !nominalType.isRawTypeOfTemplatizedType() || nominalType.isUnknownType()) {
// given isRawTypeOfTemplatizedType, but in some contexts is not.
return addNullabilityBasedOnParseContext(n, nominalType, scope);
}
return addNullabilityBasedOnParseContext(n, createTemplatizedType((ObjectType) nominalType, templateArgs), scope);
}
case FUNCTION:
JSType thisType = null;
boolean isConstructor = false;
Node current = n.getFirstChild();
if (current.isThis() || current.isNew()) {
Node contextNode = current.getFirstChild();
JSType candidateThisType = createTypeFromCommentNode(contextNode, sourceName, scope);
// and 'this' access should raise warnings.
if (candidateThisType.isNullType() || candidateThisType.isVoidType()) {
thisType = candidateThisType;
} else if (current.isThis()) {
thisType = candidateThisType.restrictByNotNullOrUndefined();
} else if (current.isNew()) {
thisType = ObjectType.cast(candidateThisType.restrictByNotNullOrUndefined());
if (thisType == null) {
reporter.warning(Msg.JSDOC_FUNCTION_NEWNOTOBJECT.format(), sourceName, contextNode.getLineno(), contextNode.getCharno());
}
}
isConstructor = current.getToken() == Token.NEW;
current = current.getNext();
}
FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this);
if (current.getToken() == Token.PARAM_LIST) {
for (Node arg = current.getFirstChild(); arg != null; arg = arg.getNext()) {
if (arg.getToken() == Token.ITER_REST) {
if (!arg.hasChildren()) {
paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE));
} else {
paramBuilder.addVarArgs(createTypeFromCommentNode(arg.getFirstChild(), sourceName, scope));
}
} else {
JSType type = createTypeFromCommentNode(arg, sourceName, scope);
if (arg.getToken() == Token.EQUALS) {
boolean addSuccess = paramBuilder.addOptionalParams(type);
if (!addSuccess) {
reporter.warning(Msg.JSDOC_FUNCTION_VARARGS.format(), sourceName, arg.getLineno(), arg.getCharno());
}
} else {
paramBuilder.addRequiredParams(type);
}
}
}
current = current.getNext();
}
JSType returnType = createTypeFromCommentNode(current, sourceName, scope);
return FunctionType.builder(this).withParameters(paramBuilder.build()).withReturnType(returnType).withTypeOfThis(thisType).withKind(isConstructor ? FunctionType.Kind.CONSTRUCTOR : FunctionType.Kind.ORDINARY).build();
default:
throw new IllegalStateException("Unexpected node in type expression: " + n);
}
}
Aggregations