All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.modules.EsModuleProcessor Maven / Gradle / Ivy

/*
 * Copyright 2018 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.javascript.jscomp.modules;

import static com.google.common.base.Preconditions.checkState;
import static com.google.javascript.jscomp.modules.ModuleMapCreator.DOES_NOT_HAVE_EXPORT;

import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import com.google.javascript.jscomp.AbstractCompiler;
import com.google.javascript.jscomp.DiagnosticType;
import com.google.javascript.jscomp.Es6ToEs3Util;
import com.google.javascript.jscomp.JSError;
import com.google.javascript.jscomp.NodeTraversal;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.jscomp.NodeTraversal.Callback;
import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.jscomp.Scope;
import com.google.javascript.jscomp.Var;
import com.google.javascript.jscomp.deps.ModuleLoader;
import com.google.javascript.jscomp.deps.ModuleLoader.ModulePath;
import com.google.javascript.jscomp.modules.ModuleMapCreator.ModuleProcessor;
import com.google.javascript.jscomp.modules.ModuleMetadataMap.ModuleMetadata;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.Nullable;

/**
 * Collects information related to and resolves ES imports and exports. Also performs several ES
 * module related checks.
 *
 * 

This information is stored outside of any {@link Scope} because it should never be * recalculated. Recalculation is prevented for the following reasons: * *

    *
  • Calculation is expensive. *
  • When ES modules are hotswapped, we want the original information, not the "current" * information, because it would show no other ES modules. *
* * * Suggested reading */ public final class EsModuleProcessor implements Callback, ModuleProcessor { /** * Error occurs when there is an ambiguous export, which can happen if there are multiple {@code * export * from} statements. If two modules that were {@code export * from}'d have the same key * as an export that export is now ambiguous. It can be resolved by exporting that key explicitly * locally. * *

So if modules "first" and "second" both export "x" then this is ambiguous: * *

   * export * from 'first';
   * export * from 'second';
   * 
* *

However we can resolve it by explicitly exporting an "x" locally: * *

   * // Note: any one of these is a solution. Using 2 or more together causes a duplicate key error.
   *
   * // specifically export x from first
   * export {x} from 'first';
   * // specifically export x from second
   * export {x} from 'second';
   * // export our own x instead
   * export let x;
   * 
* * Note: This is purposefully a warning. The spec does not treat this as an error. It is only an * error if an import attempts to use an ambiguous name. But just having ambiguous names is not * itself an error. */ public static final DiagnosticType AMBIGUOUS_EXPORT_DEFINITION = DiagnosticType.warning("JSC_AMBIGUOUS_EXPORT_DEFINITION", "The export \"{0}\" is ambiguous."); public static final DiagnosticType CYCLIC_EXPORT_DEFINITION = DiagnosticType.error( "JSC_CYCLIC_EXPORT_DEFINITION", "Cyclic export detected while resolving name \"{0}\"."); // Note: We only check for duplicate exports, not imports. Imports cannot be shadowed (by any // other binding, including other imports) and so we check that in VariableReferenceCheck. public static final DiagnosticType DUPLICATE_EXPORT = DiagnosticType.error("JSC_DUPLICATE_EXPORT", "Duplicate export of \"{0}\"."); public static final DiagnosticType IMPORTED_AMBIGUOUS_EXPORT = DiagnosticType.error( "JSC_IMPORTED_AMBIGUOUS_EXPORT", "The requested name \"{0}\" is ambiguous."); public static final DiagnosticType NAMESPACE_IMPORT_CANNOT_USE_STAR = DiagnosticType.error( "JSC_NAMESPACE_IMPORT_CANNOT_USE_STAR", "Namespace imports ('goog:some.Namespace') cannot use import * as. " + "Did you mean to import {0} from ''{1}'';?"); public static final DiagnosticType CANNOT_PATH_IMPORT_CLOSURE_FILE = DiagnosticType.error( "JSC_CANNOT_PATH_IMPORT_CLOSURE_FILE", "Cannot import Closure files by path. Use either import 'goog:namespace' or" + " goog.require('namespace')"); /** * Marks all exports that are mutated in an inner scope as mutable. * *

Exports mutated at the module scope are not marked as mutable as they are effectively * constant after module evaluation. */ private static final class FindMutableExports extends AbstractPostOrderCallback { final List exports; final ListMultimap exportsByLocalName; FindMutableExports(List exports) { // There may be multiple exports with the same local name because you can export a local // variable with an alias many different times. Example: // // let x; // export {x as y, x as z}; this.exports = exports; exportsByLocalName = ArrayListMultimap.create(); for (Export e : exports) { exportsByLocalName.put(e.localName(), e); } } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (!n.isName()) { return; } Scope scope = t.getScope(); if (!NodeUtil.isLValue(n) || scope.getClosestHoistScope().isModuleScope()) { return; } List exports = exportsByLocalName.get(n.getString()); if (exports.isEmpty()) { return; } Var var = scope.getVar(n.getString()); // A var declared in the module scope with the same name as an export must be the // export. And we know we're setting it in a function scope, so this cannot be the // declaration itself. We must be mutating. if (var == null || !var.getScope().isModuleScope()) { return; } for (Export e : new ArrayList<>(exports)) { int i = this.exports.indexOf(e); Export mutated = e.mutatedCopy(); this.exports.set(i, mutated); exportsByLocalName.remove(e.localName(), e); exportsByLocalName.put(e.localName(), mutated); } } } /** * Collects all imports and exports of a module. Builds a {@link UnresolvedEsModule} by slotting * the exports into one of three categories: * *

    *
  • Local exports - exports whose original definition is in this file. *
  • Indirect exports - exports that come from another file. Either via {@code export {name} * from} or {@code import {name}; export {name};} *
  • Star exports - {@code export * from} exports *
*/ private final class UnresolvedModuleBuilder { private final ModuleLoader.ModulePath path; private final Node root; private final Map importsByLocalName; private final List exports; private final Set exportedNames; UnresolvedModuleBuilder(ModuleLoader.ModulePath path, Node root) { this.path = path; this.root = root; importsByLocalName = new HashMap<>(); exports = new ArrayList<>(); exportedNames = new HashSet<>(); } void add(Import i) { importsByLocalName.put(i.localName(), i); } /** True if the export was successfully added or false if the exported name already exists. */ boolean add(Export e) { if (e.exportName() == null) { exports.add(e); return true; } else { if (exportedNames.contains(e.exportName())) { return false; } exports.add(e); exportedNames.add(e.exportName()); return true; } } UnresolvedModule build() { List localExports = new ArrayList<>(); ImmutableList.Builder indirectExportsBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder starExportsBuilder = new ImmutableList.Builder<>(); for (Export ee : exports) { if (ee.moduleRequest() == null) { if (importsByLocalName.containsKey(ee.localName())) { // import A from ''; // export { A }; // import * as ns from ''; // export { ns }; indirectExportsBuilder.add(ee); } else { // var y; // export { y }; // export var x; localExports.add(ee); } } else if ("*".equals(ee.importName())) { // export * from ''; starExportsBuilder.add(ee); } else { // export { A } from ''; indirectExportsBuilder.add(ee); } } NodeTraversal.traverse(compiler, root, new FindMutableExports(localExports)); return new UnresolvedEsModule( metadata, path, ImmutableMap.copyOf(importsByLocalName), ImmutableList.copyOf(localExports), indirectExportsBuilder.build(), starExportsBuilder.build()); } } /** * A module that has had its exports and imports parsed and categorized but has yet to * transitively resolve them. */ private final class UnresolvedEsModule extends UnresolvedModule { private final ModuleMetadata metadata; private final ModuleLoader.ModulePath path; private final ImmutableMap importsByLocalName; private final ImmutableList localExports; private final ImmutableList indirectExports; private final ImmutableList starExports; private ImmutableSet exportedNames; private final Map resolvedImports; private final Map resolvedExports; private Module resolved; private UnresolvedEsModule( ModuleMetadata metadata, ModuleLoader.ModulePath path, ImmutableMap importsByLocalName, ImmutableList localExports, ImmutableList indirectExports, ImmutableList starExports) { this.metadata = metadata; this.path = path; this.importsByLocalName = importsByLocalName; this.localExports = localExports; this.indirectExports = indirectExports; this.starExports = starExports; exportedNames = null; resolvedImports = new HashMap<>(); resolvedExports = new HashMap<>(); resolved = null; } @Override void reset() { resolved = null; exportedNames = null; resolvedImports.clear(); resolvedExports.clear(); } @Override public Module resolve( ModuleRequestResolver moduleRequestResolver, @Nullable String moduleSpecifier) { if (resolved == null) { // Every import creates a locally bound name. Map boundNames = new LinkedHashMap<>(getAllResolvedImports(moduleRequestResolver)); Map localNameToLocalExport = new HashMap<>(); // Only local exports that are not an anonymous default export create local bindings. for (Export e : localExports) { localNameToLocalExport.put(e.localName(), e); if (!Export.DEFAULT_EXPORT_NAME.equals(e.localName())) { ResolveExportResult b = resolveExport(moduleRequestResolver, e.exportName()); checkState(b.resolved(), "Cannot have invalid missing own export!"); if (!b.isAmbiguous()) { boundNames.put(e.localName(), b.getBinding()); } } } // getAllResolvedExports is required to make a module but also performs cycle checking. resolved = Module.builder() .boundNames(ImmutableMap.copyOf(boundNames)) .namespace(ImmutableMap.copyOf(getAllResolvedExports(moduleRequestResolver))) .metadata(metadata) .path(path) .localNameToLocalExport(ImmutableMap.copyOf(localNameToLocalExport)) .unresolvedModule(this) .build(); } return resolved; } @Override ModuleMetadata metadata() { return metadata; } /** A map from import bound name to binding. */ Map getAllResolvedImports(ModuleRequestResolver moduleRequestResolver) { Map imports = new HashMap<>(); for (String name : importsByLocalName.keySet()) { ResolveExportResult b = resolveImport(moduleRequestResolver, name); if (b.resolved()) { imports.put(name, b.getBinding()); } } return imports; } public ResolveExportResult resolveImport( ModuleRequestResolver moduleRequestResolver, String name, Set resolveSet, Set exportStarSet) { if (resolvedImports.containsKey(name)) { return resolvedImports.get(name); } ResolveExportResult b = resolveImportImpl(moduleRequestResolver, name, resolveSet, exportStarSet); resolvedImports.put(name, b); return b; } public ResolveExportResult resolveImport( ModuleRequestResolver moduleRequestResolver, String name) { return resolveImport(moduleRequestResolver, name, new HashSet<>(), new HashSet<>()); } private ResolveExportResult resolveImportImpl( ModuleRequestResolver moduleRequestResolver, String name, Set resolveSet, Set exportStarSet) { Import i = importsByLocalName.get(name); UnresolvedModule requested = moduleRequestResolver.resolve(i); if (requested == null) { return ResolveExportResult.ERROR; } else { boolean importStar = i.importName().equals("*"); if (importStar || (i.importName().equals(Export.DEFAULT) && (requested.metadata().isGoogProvide() || requested.metadata().isGoogModule()))) { if (!GoogEsImports.isGoogImportSpecifier(i.moduleRequest()) && (requested.metadata().isGoogModule() || requested.metadata().isGoogProvide())) { compiler.report( JSError.make( path.toString(), i.importNode().getLineno(), i.importNode().getCharno(), CANNOT_PATH_IMPORT_CLOSURE_FILE, i.localName(), i.moduleRequest())); return ResolveExportResult.ERROR; } if (importStar && GoogEsImports.isGoogImportSpecifier(i.moduleRequest())) { compiler.report( JSError.make( path.toString(), i.importNode().getLineno(), i.importNode().getCharno(), NAMESPACE_IMPORT_CANNOT_USE_STAR, i.localName(), i.moduleRequest())); return ResolveExportResult.ERROR; } String closureNamespace = GoogEsImports.isGoogImportSpecifier(i.moduleRequest()) ? GoogEsImports.getClosureIdFromGoogImportSpecifier(i.moduleRequest()) : null; return ResolveExportResult.of( Binding.from(requested.metadata(), closureNamespace, i.nameNode())); } else { ResolveExportResult result = requested.resolveExport( moduleRequestResolver, i.moduleRequest(), i.importName(), resolveSet, exportStarSet); if (!result.found() && !result.hadError()) { compiler.report( JSError.make( path.toString(), i.importNode().getLineno(), i.importNode().getCharno(), DOES_NOT_HAVE_EXPORT, i.importName())); return ResolveExportResult.ERROR; } else if (result.isAmbiguous()) { compiler.report( JSError.make( path.toString(), i.importNode().getLineno(), i.importNode().getCharno(), IMPORTED_AMBIGUOUS_EXPORT, i.importName())); return ResolveExportResult.ERROR; } Node forSourceInfo = i.nameNode() == null ? i.importNode() : i.nameNode(); return result.copy(forSourceInfo, Binding.CreatedBy.IMPORT); } } } @Override public ImmutableSet getExportedNames(ModuleRequestResolver moduleRequestResolver) { if (exportedNames == null) { exportedNames = getExportedNames(moduleRequestResolver, new HashSet<>()); } return exportedNames; } @Override public ImmutableSet getExportedNames( ModuleRequestResolver moduleRequestResolver, Set visited) { if (visited.contains(this)) { // import * cycle return ImmutableSet.of(); } visited.add(this); // exports are in Array.prototype.sort() order. Set exportedNames = new TreeSet<>(); for (Export e : localExports) { exportedNames.add(e.exportName()); } for (Export e : indirectExports) { exportedNames.add(e.exportName()); } for (Export e : starExports) { UnresolvedModule requested = moduleRequestResolver.resolve(e); if (requested != null) { if (requested.metadata().isEs6Module()) { for (String n : requested.getExportedNames(moduleRequestResolver, visited)) { // Default exports are not exported with export *. if (!Export.DEFAULT.equals(n) && !exportedNames.contains(n)) { exportedNames.add(n); } } } else { compiler.report( JSError.make( e.exportNode(), Es6ToEs3Util.CANNOT_CONVERT_YET, "Wildcard export for non-ES module")); } } } return ImmutableSet.copyOf(exportedNames); } /** Map of exported name to binding. */ Map getAllResolvedExports(ModuleRequestResolver moduleRequestResolver) { Map exports = new LinkedHashMap<>(); for (String name : getExportedNames(moduleRequestResolver)) { ResolveExportResult b = resolveExport(moduleRequestResolver, name); checkState(b.found(), "Cannot have invalid own export."); if (b.resolved()) { exports.put(name, b.getBinding()); } else if (b.isAmbiguous()) { compiler.report(JSError.make(path.toString(), -1, -1, AMBIGUOUS_EXPORT_DEFINITION, name)); } } return exports; } private ResolveExportResult resolveExport( ModuleRequestResolver moduleRequestResolver, String exportName, Set resolveSet, Set exportStarSet) { if (!getExportedNames(moduleRequestResolver).contains(exportName)) { return ResolveExportResult.NOT_FOUND; } if (!resolveSet.add(ExportTrace.create(this, exportName))) { // Cycle! compiler.report(JSError.make(path.toString(), 0, 0, CYCLIC_EXPORT_DEFINITION, exportName)); return ResolveExportResult.ERROR; } for (Export e : localExports) { if (exportName.equals(e.exportName())) { Node forSourceInfo = e.nameNode() != null ? e.nameNode() : e.exportNode(); return ResolveExportResult.of(Binding.from(e, forSourceInfo)); } } for (Export e : indirectExports) { if (exportName.equals(e.exportName())) { if (importsByLocalName.containsKey(e.localName())) { // import whatever from 'mod'; // export { whatever }; return resolveImport(moduleRequestResolver, e.localName(), resolveSet, exportStarSet) .copy(e.nameNode(), Binding.CreatedBy.EXPORT); } else { UnresolvedModule requested = moduleRequestResolver.resolve(e); if (requested == null) { return ResolveExportResult.ERROR; } else { // export { whatever } from 'mod'; ResolveExportResult result = requested.resolveExport( moduleRequestResolver, e.moduleRequest(), e.importName(), resolveSet, exportStarSet); if (!result.found() && !result.hadError()) { compiler.report( JSError.make( path.toString(), e.exportNode().getLineno(), e.exportNode().getCharno(), DOES_NOT_HAVE_EXPORT, e.importName())); return ResolveExportResult.ERROR; } else if (result.isAmbiguous()) { compiler.report( JSError.make( path.toString(), e.exportNode().getLineno(), e.exportNode().getCharno(), IMPORTED_AMBIGUOUS_EXPORT, e.importName())); } return result.copy(e.nameNode(), Binding.CreatedBy.EXPORT); } } } } checkState(!Export.DEFAULT.equals(exportName), "Default export cannot come from export *."); if (exportStarSet.contains(this)) { // Cycle! compiler.report( JSError.make(path.toString(), -1, -1, CYCLIC_EXPORT_DEFINITION, exportName)); return ResolveExportResult.ERROR; } exportStarSet.add(this); ResolveExportResult starResolution = null; for (Export e : starExports) { UnresolvedModule requested = moduleRequestResolver.resolve(e); if (requested == null) { return ResolveExportResult.ERROR; } else if (requested.getExportedNames(moduleRequestResolver).contains(exportName)) { ResolveExportResult resolution = requested.resolveExport( moduleRequestResolver, e.moduleRequest(), exportName, resolveSet, exportStarSet); if (resolution.hadError()) { // Recursive case; error was reported on base case. return resolution; } else if (resolution.isAmbiguous()) { return resolution; } else { if (starResolution == null) { // First time finding something, not ambiguous. starResolution = resolution.copy(e.exportNode(), Binding.CreatedBy.EXPORT); } else { // Second time finding something, might be ambiguous! // Not ambiguous if it is the same export (same module and export name). if (starResolution != resolution) { return ResolveExportResult.AMBIGUOUS; } } } } } if (starResolution == null) { return ResolveExportResult.ERROR; } return starResolution; } @Override public ResolveExportResult resolveExport( ModuleRequestResolver moduleRequestResolver, @Nullable String moduleSpecifier, String exportName, Set resolveSet, Set exportStarSet) { // Explicit containsKey check here since values can be null! if (resolvedExports.containsKey(exportName)) { return resolvedExports.get(exportName); } ResolveExportResult b = resolveExport(moduleRequestResolver, exportName, resolveSet, exportStarSet); resolvedExports.put(exportName, b); return b; } } EsModuleProcessor(AbstractCompiler compiler) { this.compiler = compiler; } private final AbstractCompiler compiler; private UnresolvedModuleBuilder currentModuleBuilder; private ModuleMetadata metadata; @Override public UnresolvedModule process( ModuleMetadata metadata, ModulePath path, Node script) { this.metadata = metadata; currentModuleBuilder = new UnresolvedModuleBuilder(path, script); NodeTraversal.traverse(compiler, script, this); UnresolvedModule m = currentModuleBuilder.build(); this.metadata = null; currentModuleBuilder = null; return m; } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { switch (n.getToken()) { case ROOT: case SCRIPT: case MODULE_BODY: case EXPORT: case IMPORT: return true; default: return false; } } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getToken()) { case EXPORT: visitExport(t, n); break; case IMPORT: visitImport(t, n); break; default: break; } } private void visitExportAllFrom(NodeTraversal t, Node export) { // export * from ''; currentModuleBuilder.add( Export.builder() .exportName(null) .moduleRequest(export.getSecondChild().getString()) .importName("*") .localName(null) .modulePath(t.getInput().getPath()) .exportNode(export) .moduleMetadata(metadata) .build()); } private void visitExportDefault(NodeTraversal t, Node export) { // export default ; Node child = export.getFirstChild(); String name = Export.DEFAULT_EXPORT_NAME; if (child.isFunction() || child.isClass()) { String maybeName = NodeUtil.getName(child); if (!Strings.isNullOrEmpty(maybeName)) { name = maybeName; } } if (!currentModuleBuilder.add( Export.builder() .exportName(Export.DEFAULT) .moduleRequest(null) .importName(null) .localName(name) .modulePath(t.getInput().getPath()) .exportNode(export) .moduleMetadata(metadata) .build())) { t.report(export, DUPLICATE_EXPORT, Export.DEFAULT); } } private void visitExportFrom(NodeTraversal t, Node export) { // export { Foo, Bar as Rab } from ''; for (Node child = export.getFirstFirstChild(); child != null; child = child.getNext()) { String importName = child.getFirstChild().getString(); String exportedName = child.getLastChild().getString(); if (!currentModuleBuilder.add( Export.builder() .exportName(exportedName) .moduleRequest(export.getSecondChild().getString()) .importName(importName) .localName(null) .modulePath(t.getInput().getPath()) .exportNode(export) .nameNode(child.getFirstChild()) .moduleMetadata(metadata) .build())) { t.report(export, DUPLICATE_EXPORT, exportedName); } } } private void visitExportSpecs(NodeTraversal t, Node export) { // export { Foo, Bar as Rab }; for (Node child = export.getFirstFirstChild(); child != null; child = child.getNext()) { String localName = child.getFirstChild().getString(); String exportedName = child.getLastChild().getString(); if (!currentModuleBuilder.add( Export.builder() .exportName(exportedName) .moduleRequest(null) .importName(null) .localName(localName) .modulePath(t.getInput().getPath()) .exportNode(export) .nameNode(child.getFirstChild()) .moduleMetadata(metadata) .build())) { t.report(export, DUPLICATE_EXPORT, exportedName); } } } private void visitExportNameDeclaration(NodeTraversal t, Node export, Node declaration) { // export var Foo; // export let {a, b:[c,d]} = {}; List lhsNodes = NodeUtil.findLhsNodesInNode(declaration); for (Node lhs : lhsNodes) { checkState(lhs.isName()); String name = lhs.getString(); if (!currentModuleBuilder.add( Export.builder() .exportName(name) .moduleRequest(null) .importName(null) .localName(name) .modulePath(t.getInput().getPath()) .exportNode(export) .nameNode(lhs) .moduleMetadata(metadata) .build())) { t.report(export, DUPLICATE_EXPORT, name); } } } private void visitExportFunctionOrClass(NodeTraversal t, Node export, Node declaration) { // export function foo() {} // export class Foo {} checkState(declaration.isFunction() || declaration.isClass()); Node nameNode = declaration.getFirstChild(); String name = nameNode.getString(); if (!currentModuleBuilder.add( Export.builder() .exportName(name) .moduleRequest(null) .importName(null) .localName(name) .modulePath(t.getInput().getPath()) .exportNode(export) .nameNode(nameNode) .moduleMetadata(metadata) .build())) { t.report(export, DUPLICATE_EXPORT, name); } } private void visitExport(NodeTraversal t, Node export) { if (export.getBooleanProp(Node.EXPORT_ALL_FROM)) { visitExportAllFrom(t, export); } else if (export.getBooleanProp(Node.EXPORT_DEFAULT)) { visitExportDefault(t, export); } else if (export.hasTwoChildren()) { visitExportFrom(t, export); } else if (export.getFirstChild().getToken() == Token.EXPORT_SPECS) { visitExportSpecs(t, export); } else { Node declaration = export.getFirstChild(); if (NodeUtil.isNameDeclaration(declaration)) { visitExportNameDeclaration(t, export, declaration); } else { visitExportFunctionOrClass(t, export, declaration); } } } private void visitImportDefault(NodeTraversal t, Node importNode, String moduleRequest) { // import Default from ''; currentModuleBuilder.add( Import.builder() .moduleRequest(moduleRequest) .importName(Export.DEFAULT) .localName(importNode.getFirstChild().getString()) .modulePath(t.getInput().getPath()) .importNode(importNode) .nameNode(importNode.getFirstChild()) .build()); } private void visitImportSpecs(NodeTraversal t, Node importNode, String moduleRequest) { // import { A, b as B } from ''; for (Node child = importNode.getSecondChild().getFirstChild(); child != null; child = child.getNext()) { String importName = child.getFirstChild().getString(); String localName = child.getLastChild().getString(); currentModuleBuilder.add( Import.builder() .moduleRequest(moduleRequest) .importName(importName) .localName(localName) .modulePath(t.getInput().getPath()) .importNode(importNode) .nameNode(child.getSecondChild()) .build()); } } private void visitImportStar(NodeTraversal t, Node importNode, String moduleRequest) { // import * as ns from ''; currentModuleBuilder.add( Import.builder() .moduleRequest(moduleRequest) .importName("*") .localName(importNode.getSecondChild().getString()) .importNode(importNode) .modulePath(t.getInput().getPath()) .nameNode(importNode.getSecondChild()) .build()); } private void visitImport(NodeTraversal t, Node importNode) { String moduleRequest = importNode.getLastChild().getString(); if (importNode.getFirstChild().isName()) { visitImportDefault(t, importNode, moduleRequest); } if (importNode.getSecondChild().isImportSpecs()) { visitImportSpecs(t, importNode, moduleRequest); } else if (importNode.getSecondChild().isImportStar()) { visitImportStar(t, importNode, moduleRequest); } // no entry for import ''; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy