Skip to content

Commit

Permalink
Make ModuleMapCreator tolerant to missing module references.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=231002820
  • Loading branch information
johnplaisted authored and tjgq committed Jan 26, 2019
1 parent fce0853 commit d69b208
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/com/google/javascript/jscomp/modules/Binding.java
Expand Up @@ -78,7 +78,10 @@ Binding withSource(Node sourceNode) {
* <p>This is generally a NAME node inside an import or export statement that represents where the
* name was bound. However as {@code export * from} has no NAME nodes the source node in that
* instance should be the entire export node.
*
* <p>Null for missing ES modules and non-ES modules as they are currently not scanned.
*/
@Nullable
public abstract Node sourceNode();

/**
Expand Down
3 changes: 1 addition & 2 deletions src/com/google/javascript/jscomp/modules/Export.java
Expand Up @@ -82,7 +82,6 @@ final Export build() {

/** Export from an ES module. */
private void validateEsModule(Export e) {
checkNotNull(e.exportNode());
checkState(e.closureNamespace() == null);

checkState(
Expand Down Expand Up @@ -157,7 +156,7 @@ final Export mutatedCopy() {
/**
* Node that this export originates from. Used for its source location.
*
* <p>Null only if from non-ES module.
* <p>Null only if from non-ES module or from a missing ES module.
*/
@Nullable
public abstract Node exportNode();
Expand Down
121 changes: 111 additions & 10 deletions src/com/google/javascript/jscomp/modules/ModuleMapCreator.java
Expand Up @@ -21,13 +21,15 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.javascript.jscomp.AbstractCompiler;
import com.google.javascript.jscomp.CompilerPass;
import com.google.javascript.jscomp.DiagnosticType;
import com.google.javascript.jscomp.JSError;
import com.google.javascript.jscomp.deps.ModuleLoader;
import com.google.javascript.jscomp.deps.ModuleLoader.ModulePath;
import com.google.javascript.jscomp.modules.ModuleMetadataMap.ModuleMetadata;
import com.google.javascript.jscomp.modules.ModuleMetadataMap.ModuleType;
import com.google.javascript.rhino.Node;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -232,6 +234,77 @@ public final int hashCode() {
final class ModuleRequestResolver {
private ModuleRequestResolver() {}

private UnresolvedModule getFallbackForMissingNonClosureModule(ModuleLoader.ModulePath path) {
ModuleMetadata metadata =
ModuleMetadata.builder()
.rootNode(null)
.path(path)
.moduleType(ModuleType.ES6_MODULE)
.isTestOnly(false)
.usesClosure(false)
.build();

return new UnresolvedModule() {
@Override
Module resolve(@Nullable String moduleSpecifier) {
return Module.builder()
.boundNames(ImmutableMap.of())
.namespace(ImmutableMap.of())
.localNameToLocalExport(ImmutableMap.of())
.path(path)
.metadata(metadata)
.build();
}

@Override
boolean isEsModule() {
return true;
}

@Override
ImmutableSet<String> getExportedNames() {
return ImmutableSet.of();
}

@Override
protected ImmutableSet<String> getExportedNames(Set<UnresolvedModule> visited) {
return ImmutableSet.of();
}

@Override
ResolveExportResult resolveExport(
@Nullable String moduleSpecifier,
String exportName,
Set<ExportTrace> resolveSet,
Set<UnresolvedModule> exportStarSet) {
return ResolveExportResult.of(
Binding.from(
Export.builder()
.localName(exportName)
.moduleMetadata(metadata)
.modulePath(path)
.closureNamespace(null)
.build(),
/* sourceNode= */ null));
}
};
}

private UnresolvedModule getFallbackForMissingClosureModule(String namespace) {
return nonEsModuleProcessor.process(
this,
ModuleMetadata.builder()
.addGoogNamespace(namespace)
.isTestOnly(false)
.moduleType(ModuleType.GOOG_PROVIDE)
.path(null)
.rootNode(null)
.usesClosure(true)
.build(),
/* path= */ null,
/* script= */ null);
}

@Nullable
UnresolvedModule resolve(Import i) {
return resolve(i.moduleRequest(), i.modulePath(), i.importNode());
Expand All @@ -250,6 +323,8 @@ private UnresolvedModule resolve(
UnresolvedModule module = unresolvedModulesByClosureNamespace.get(namespace);
if (module == null) {
compiler.report(JSError.make(forLineInfo, MISSING_NAMESPACE_IMPORT, namespace));
module = getFallbackForMissingClosureModule(namespace);
unresolvedModulesByClosureNamespace.put(namespace, module);
}
return module;
}
Expand All @@ -262,7 +337,13 @@ private UnresolvedModule resolve(
forLineInfo.getCharno());

if (requestedPath == null) {
return null;
requestedPath = modulePath.resolveModuleAsPath(moduleRequest);

if (!unresolvedModules.containsKey(requestedPath.toModuleName())) {
UnresolvedModule module = getFallbackForMissingNonClosureModule(requestedPath);
unresolvedModules.put(requestedPath.toModuleName(), module);
return module;
}
}

return unresolvedModules.get(requestedPath.toModuleName());
Expand Down Expand Up @@ -340,18 +421,38 @@ private ModuleMap create() {
}
}

for (Map.Entry<String, UnresolvedModule> e : unresolvedModules.entrySet()) {
Module resolved = e.getValue().resolve();
resolvedModules.put(e.getKey(), resolved);
// We need to resolve in a loop as any missing reference will add a fake to the
// unresolvedModules map (see getFallback* methods above). This would cause a concurrent
// modification exception if we just iterated over unresolvedModules. So the first loop through
// should resolve any "known" modules, and the second any "unrecognized" modules.
do {
Set<String> toResolve =
Sets.difference(unresolvedModules.keySet(), resolvedModules.keySet()).immutableCopy();

for (String key : toResolve) {
Module resolved = unresolvedModules.get(key).resolve();
resolvedModules.put(key, resolved);

for (String namespace : resolved.metadata().googNamespaces()) {
resolvedClosureModules.put(namespace, resolved);
for (String namespace : resolved.metadata().googNamespaces()) {
resolvedClosureModules.put(namespace, resolved);
}
}
}

for (Map.Entry<String, UnresolvedModule> e : unresolvedModulesByClosureNamespace.entrySet()) {
resolvedClosureModules.put(e.getKey(), e.getValue().resolve());
}
} while (!resolvedModules.keySet().containsAll(unresolvedModules.keySet()));

do {
Set<String> toResolve =
Sets.difference(
unresolvedModulesByClosureNamespace.keySet(), resolvedClosureModules.keySet())
.immutableCopy();

for (String namespace : toResolve) {
resolvedClosureModules.put(
namespace, unresolvedModulesByClosureNamespace.get(namespace).resolve());
}
} while (!resolvedClosureModules
.keySet()
.containsAll(unresolvedModulesByClosureNamespace.keySet()));

unresolvedModules.clear();
unresolvedModulesByClosureNamespace.clear();
Expand Down
Expand Up @@ -62,7 +62,7 @@ public ResolveExportResult resolveExport(
Set<ExportTrace> resolveSet,
Set<UnresolvedModule> exportStarSet) {
String namespace = null;
if (GoogEsImports.isGoogImportSpecifier(moduleSpecifier)) {
if (moduleSpecifier != null && GoogEsImports.isGoogImportSpecifier(moduleSpecifier)) {
namespace = GoogEsImports.getClosureIdFromGoogImportSpecifier(moduleSpecifier);
}
return ResolveExportResult.of(
Expand Down

0 comments on commit d69b208

Please sign in to comment.