Search in sources :

Example 1 with ModulePath

use of com.google.javascript.jscomp.deps.ModuleLoader.ModulePath in project closure-compiler by google.

the class RewriteDynamicImports method visit.

@Override
public void visit(NodeTraversal t, Node n, Node parent) {
    if (n.getToken() != Token.DYNAMIC_IMPORT) {
        return;
    }
    // If the module specifier is a string, attempt to resolve the module
    final ModuleMap moduleMap = compiler.getModuleMap();
    final Node importSpecifier = n.getFirstChild();
    if (importSpecifier.isStringLit() && moduleMap != null) {
        final ModulePath targetPath = t.getInput().getPath().resolveJsModule(importSpecifier.getString(), n.getSourceFileName(), n.getLineno(), n.getCharno());
        final Module module = (targetPath == null) ? null : compiler.getModuleMap().getModule(targetPath);
        final String targetModuleVarName = (module == null) ? null : GlobalizedModuleName.create(module.metadata(), null, null).aliasName().join();
        final Var targetModuleNS = (targetModuleVarName == null) ? null : t.getScope().getVar(targetModuleVarName);
        if (targetModuleNS != null) {
            final JSChunk targetModule = targetModuleNS.getInput().getChunk();
            // No further rewriting occurs for this case.
            if (t.getChunk() == targetModule) {
                replaceDynamicImportWithPromise(t, n, targetModuleNS);
                return;
            } else {
                // The target output chunk is recognized and different from the current chunk.
                // Retarget the import specifier path to the output chunk path and rewrite
                // the import to reference the rewritten global module namespace variable.
                retargetImportSpecifier(t, n, targetModule);
                if (NodeUtil.isExpressionResultUsed(n)) {
                    addChainedThen(n, targetModuleNS);
                }
            }
        }
    }
    if (aliasIsValid()) {
        aliasDynamicImport(t, n);
    } else if (this.alias != null) {
        t.report(n, DYNAMIC_IMPORT_INVALID_ALIAS);
    } else if (requiresAliasing) {
        t.report(n, DYNAMIC_IMPORT_ALIASING_REQUIRED);
    }
}
Also used : ModulePath(com.google.javascript.jscomp.deps.ModuleLoader.ModulePath) Node(com.google.javascript.rhino.Node) Module(com.google.javascript.jscomp.modules.Module) ModuleMap(com.google.javascript.jscomp.modules.ModuleMap)

Example 2 with ModulePath

use of com.google.javascript.jscomp.deps.ModuleLoader.ModulePath in project closure-compiler by google.

the class RewriteGoogJsImports method process.

@Override
public void process(Node externs, Node root) {
    googModule = null;
    Node googJsScriptNode = findGoogJsScriptNode(root);
    if (googJsScriptNode == null) {
        // Potentially in externs if library level type checking.
        googJsScriptNode = findGoogJsScriptNode(externs);
    }
    if (mode == Mode.LINT_AND_REWRITE) {
        if (googJsScriptNode != null) {
            ModulePath googJsPath = compiler.getInput(googJsScriptNode.getInputId()).getPath();
            googModule = moduleMap.getModule(googJsPath);
            checkNotNull(googModule);
            Predicate<Binding> isFromGoog = (Binding b) -> b.originatingExport().modulePath() == googJsPath;
            checkState(googModule.boundNames().values().stream().allMatch(isFromGoog), "goog.js should never import anything");
            checkState(!googModule.namespace().containsKey("default"), "goog.js should never have a default export.");
            checkState(googModule.namespace().values().stream().allMatch(isFromGoog), "goog.js should never export from anything.");
        }
    } else {
        checkState(mode == Mode.LINT_ONLY);
    }
    for (Node script = root.getFirstChild(); script != null; script = script.getNext()) {
        rewriteImports(script);
    }
    changeModules();
}
Also used : Binding(com.google.javascript.jscomp.modules.Binding) ModulePath(com.google.javascript.jscomp.deps.ModuleLoader.ModulePath) Node(com.google.javascript.rhino.Node)

Example 3 with ModulePath

use of com.google.javascript.jscomp.deps.ModuleLoader.ModulePath in project closure-compiler by google.

the class ProcessCommonJSModules method removeWebpackModuleShim.

/**
 * For AMD wrappers, webpack adds a shim for the "module" variable. We need that to be a free var
 * so we remove the shim.
 */
private void removeWebpackModuleShim(Node root) {
    checkState(root.isScript());
    Node n = root.getFirstChild();
    // Skip any empty statements from those
    while (n != null && n.isEmpty()) {
        n = n.getNext();
    }
    // and it must be an expression statement.
    if (n == null || !n.isExprResult() || n.getNext() != null) {
        return;
    }
    Node call = n.getFirstChild();
    if (call == null || !call.isCall()) {
        return;
    }
    // Find the IIFE call and function nodes
    Node callTarget = call.getFirstChild();
    if (!callTarget.isFunction()) {
        return;
    }
    Node fnc = callTarget;
    Node params = NodeUtil.getFunctionParameters(fnc);
    Node moduleParam = null;
    Node param = params.getFirstChild();
    int paramNumber = 0;
    while (param != null) {
        paramNumber++;
        if (param.isName() && param.getString().equals(MODULE)) {
            moduleParam = param;
            break;
        }
        param = param.getNext();
    }
    if (moduleParam == null) {
        return;
    }
    boolean isFreeCall = call.getBooleanProp(Node.FREE_CALL);
    Node arg = call.getChildAtIndex(isFreeCall ? paramNumber : paramNumber + 1);
    if (arg == null) {
        return;
    }
    Node argCallTarget = arg.getFirstChild();
    if (arg.isCall() && argCallTarget.isCall() && isCommonJsImport(argCallTarget) && argCallTarget.getNext().matchesName(MODULE)) {
        String importPath = getCommonJsImportPath(argCallTarget);
        ModulePath modulePath = compiler.getInput(root.getInputId()).getPath().resolveJsModule(importPath, arg.getSourceFileName(), arg.getLineno(), arg.getCharno());
        if (modulePath == null) {
            // The module loader will issue an error
            return;
        }
        if (modulePath.toString().contains("/buildin/module.js")) {
            arg.detach();
            param.detach();
            compiler.reportChangeToChangeScope(fnc);
            compiler.reportChangeToEnclosingScope(fnc);
        }
    }
}
Also used : ModulePath(com.google.javascript.jscomp.deps.ModuleLoader.ModulePath) Node(com.google.javascript.rhino.Node)

Example 4 with ModulePath

use of com.google.javascript.jscomp.deps.ModuleLoader.ModulePath in project closure-compiler by google.

the class Compiler method parseInputs.

// ------------------------------------------------------------------------
// Parsing
// ------------------------------------------------------------------------
/**
 * Parses the externs and main inputs.
 *
 * @return A synthetic root node whose two children are the externs root and the main root
 */
Node parseInputs() {
    boolean devMode = options.devMode != DevMode.OFF;
    // If old roots exist (we are parsing a second time), detach each of the
    // individual file parse trees.
    externsRoot.detachChildren();
    jsRoot.detachChildren();
    scriptNodeByFilename.clear();
    Tracer tracer = newTracer(PassNames.PARSE_INPUTS);
    beforePass(PassNames.PARSE_INPUTS);
    try {
        // Parse externs sources.
        if (options.numParallelThreads > 1) {
            new PrebuildAst(this, options.numParallelThreads).prebuild(externs);
        }
        for (CompilerInput input : externs) {
            Node n = checkNotNull(input.getAstRoot(this));
            if (hasErrors()) {
                return null;
            }
            externsRoot.addChildToBack(n);
            scriptNodeByFilename.put(input.getSourceFile().getName(), n);
        }
        if (options.transformAMDToCJSModules) {
            processAMDModules(moduleGraph.getAllInputs());
        }
        if (options.getLanguageIn().toFeatureSet().has(Feature.MODULES) || options.getProcessCommonJSModules()) {
            initializeModuleLoader();
        } else {
            // Use an empty module loader if we're not actually dealing with modules.
            this.moduleLoader = ModuleLoader.EMPTY;
        }
        if (options.getDependencyOptions().needsManagement()) {
            findModulesFromEntryPoints(options.getLanguageIn().toFeatureSet().has(Feature.MODULES), options.getProcessCommonJSModules());
        } else if (options.needsTranspilationFrom(FeatureSet.ES2015_MODULES) || options.getProcessCommonJSModules()) {
            if (options.getLanguageIn().toFeatureSet().has(Feature.MODULES)) {
                parsePotentialModules(moduleGraph.getAllInputs());
            }
            // Build a map of module identifiers for any input which provides no namespace.
            // These files could be imported modules which have no exports, but do have side effects.
            Map<String, CompilerInput> inputModuleIdentifiers = new HashMap<>();
            for (CompilerInput input : moduleGraph.getAllInputs()) {
                if (input.getKnownProvides().isEmpty()) {
                    ModulePath modPath = moduleLoader.resolve(input.getSourceFile().getName());
                    inputModuleIdentifiers.put(modPath.toModuleName(), input);
                }
            }
            // Find out if any input attempted to import a module that had no exports.
            // In this case we must force module rewriting to occur on the imported file
            Map<String, CompilerInput> inputsToRewrite = new HashMap<>();
            for (CompilerInput input : moduleGraph.getAllInputs()) {
                for (String require : input.getKnownRequiredSymbols()) {
                    if (inputModuleIdentifiers.containsKey(require) && !inputsToRewrite.containsKey(require)) {
                        inputsToRewrite.put(require, inputModuleIdentifiers.get(require));
                    }
                }
            }
            for (CompilerInput input : inputsToRewrite.values()) {
                input.setJsModuleType(ModuleType.IMPORTED_SCRIPT);
            }
        }
        if (this.moduleLoader != null) {
            this.moduleLoader.setErrorHandler(this);
        }
        orderInputs();
        // If in IDE mode, we ignore the error and keep going.
        if (hasErrors()) {
            return null;
        }
        // Build the AST.
        if (options.numParallelThreads > 1) {
            new PrebuildAst(this, options.numParallelThreads).prebuild(moduleGraph.getAllInputs());
        }
        for (CompilerInput input : moduleGraph.getAllInputs()) {
            Node n = checkNotNull(input.getAstRoot(this));
            if (devMode) {
                runValidityCheck();
                if (hasErrors()) {
                    return null;
                }
            }
            // externExportsPath.
            if (options.sourceMapOutputPath != null || options.isExternExportsEnabled() || options.externExportsPath != null || !options.replaceStringsFunctionDescriptions.isEmpty()) {
                // Annotate the nodes in the tree with information from the
                // input file. This information is used to construct the SourceMap.
                SourceInformationAnnotator sia = DevMode.OFF.equals(options.devMode) ? SourceInformationAnnotator.create() : SourceInformationAnnotator.createWithAnnotationChecks(input.getName());
                NodeTraversal.traverse(this, n, sia);
            }
            if (NodeUtil.isFromTypeSummary(n)) {
                input.setIsExtern();
                externsRoot.addChildToBack(n);
            } else {
                jsRoot.addChildToBack(n);
            }
            scriptNodeByFilename.put(input.getSourceFile().getName(), n);
        }
        if (hasErrors()) {
            return null;
        }
        return externAndJsRoot;
    } finally {
        afterPass(PassNames.PARSE_INPUTS);
        stopTracer(tracer, PassNames.PARSE_INPUTS);
        // TODO(lharker): do we actually need the synthetic externs file in stage 2?
        if (this.typedAstFilesystem != null) {
            this.typedAstFilesystem = ImmutableMap.of(SYNTHETIC_EXTERNS_FILE, this.typedAstFilesystem.get(SYNTHETIC_EXTERNS_FILE));
        }
    }
}
Also used : ModulePath(com.google.javascript.jscomp.deps.ModuleLoader.ModulePath) Node(com.google.javascript.rhino.Node) Map(java.util.Map) ModuleMap(com.google.javascript.jscomp.modules.ModuleMap) LinkedHashMap(java.util.LinkedHashMap) ModuleMetadataMap(com.google.javascript.jscomp.modules.ModuleMetadataMap) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap)

Example 5 with ModulePath

use of com.google.javascript.jscomp.deps.ModuleLoader.ModulePath in project closure-compiler by google.

the class TypeInference method traverseDynamicImport.

private FlowScope traverseDynamicImport(Node dynamicImport, FlowScope scope) {
    JSType templateType = registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
    // If the module specifier is a string, attempt to resolve the module
    ModuleMap moduleMap = compiler.getModuleMap();
    Node importSpecifier = dynamicImport.getFirstChild();
    CompilerInput input = compiler.getInput(NodeUtil.getInputId(dynamicImport));
    if (importSpecifier.isStringLit() && moduleMap != null && input != null) {
        ModulePath targetPath = input.getPath().resolveJsModule(importSpecifier.getString(), importSpecifier.getSourceFileName(), importSpecifier.getLineno(), importSpecifier.getCharno());
        Module targetModule = targetPath != null ? moduleMap.getModule(targetPath) : null;
        if (targetModule != null) {
            // TypedScopeCreator ensures that the MODULE_BODY type is the export namespace type
            Node scriptNode = targetModule.metadata().rootNode();
            if (scriptNode.hasOneChild() && scriptNode.getFirstChild().isModuleBody()) {
                JSType exportNamespaceType = scriptNode != null ? scriptNode.getOnlyChild().getJSType() : null;
                if (exportNamespaceType != null) {
                    templateType = exportNamespaceType;
                }
            } else {
                // Module transpilation has occurred before type inference so a MODULE_BODY node
                // no longer exists. Traverse the script to locate the module namespace variable
                // and retrieve the type from it.
                Node moduleName = NodeUtil.findPreorder(scriptNode, (node) -> node.matchesQualifiedName(targetPath.toModuleName()), Predicates.alwaysTrue());
                if (moduleName != null && moduleName.getJSType() != null) {
                    templateType = moduleName.getJSType();
                }
            }
        }
    }
    dynamicImport.setJSType(registry.createTemplatizedType(registry.getNativeObjectType(JSTypeNative.PROMISE_TYPE), templateType));
    return traverseChildren(dynamicImport, scope);
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) ModulePath(com.google.javascript.jscomp.deps.ModuleLoader.ModulePath) Node(com.google.javascript.rhino.Node) Module(com.google.javascript.jscomp.modules.Module) ModuleMap(com.google.javascript.jscomp.modules.ModuleMap)

Aggregations

ModulePath (com.google.javascript.jscomp.deps.ModuleLoader.ModulePath)6 Node (com.google.javascript.rhino.Node)6 ModuleMap (com.google.javascript.jscomp.modules.ModuleMap)3 Module (com.google.javascript.jscomp.modules.Module)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 Binding (com.google.javascript.jscomp.modules.Binding)1 ModuleMetadataMap (com.google.javascript.jscomp.modules.ModuleMetadataMap)1 JSType (com.google.javascript.rhino.jstype.JSType)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1