Search in sources :

Example 6 with QualifiedName

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;
}
Also used : Binding(com.google.javascript.jscomp.modules.Binding) Node(com.google.javascript.rhino.Node) QualifiedName(com.google.javascript.rhino.QualifiedName) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo) Module(com.google.javascript.jscomp.modules.Module) ModuleMetadataMap(com.google.javascript.jscomp.modules.ModuleMetadataMap) HashMap(java.util.HashMap) Map(java.util.Map) ModuleMap(com.google.javascript.jscomp.modules.ModuleMap)

Example 7 with QualifiedName

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;
    }
}
Also used : Node(com.google.javascript.rhino.Node) QualifiedName(com.google.javascript.rhino.QualifiedName)

Example 8 with QualifiedName

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;
    }
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) QualifiedName(com.google.javascript.rhino.QualifiedName)

Example 9 with QualifiedName

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());
    }
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) JSType(com.google.javascript.rhino.jstype.JSType) QualifiedName(com.google.javascript.rhino.QualifiedName) Node(com.google.javascript.rhino.Node) Module(com.google.javascript.jscomp.modules.Module)

Example 10 with QualifiedName

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);
    }
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) Node(com.google.javascript.rhino.Node) QualifiedName(com.google.javascript.rhino.QualifiedName) StaticScope(com.google.javascript.rhino.StaticScope) StaticSlot(com.google.javascript.rhino.StaticSlot)

Aggregations

QualifiedName (com.google.javascript.rhino.QualifiedName)10 Node (com.google.javascript.rhino.Node)6 Module (com.google.javascript.jscomp.modules.Module)4 JSDocInfo (com.google.javascript.rhino.JSDocInfo)2 JSType (com.google.javascript.rhino.jstype.JSType)2 ObjectType (com.google.javascript.rhino.jstype.ObjectType)2 ImmutableList (com.google.common.collect.ImmutableList)1 Binding (com.google.javascript.jscomp.modules.Binding)1 ModuleMap (com.google.javascript.jscomp.modules.ModuleMap)1 ModuleMetadataMap (com.google.javascript.jscomp.modules.ModuleMetadataMap)1 ModuleMetadata (com.google.javascript.jscomp.modules.ModuleMetadataMap.ModuleMetadata)1 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)1 StaticScope (com.google.javascript.rhino.StaticScope)1 StaticSlot (com.google.javascript.rhino.StaticSlot)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1