Skip to content

Commit 35e1e1b

Browse files
ChadKillingsworthblickly
authored andcommitted
Support the node module resolution algorithm for ES6 modules.
Adds a --module_resolution flag to specify whether to use the legacy, node, or browser module resolution algorithm to locate modules. Closes #2130 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=145837856
1 parent ca2f0f2 commit 35e1e1b

15 files changed

+644
-163
lines changed

src/com/google/javascript/jscomp/CommandLineRunner.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,23 @@ private static class Flags {
710710
usage = "Rewrite ES6 library calls to use polyfills provided by the compiler's runtime.")
711711
private boolean rewritePolyfills = true;
712712

713-
@Option(name = "--print_source_after_each_pass",
714-
hidden = true,
715-
usage = "Whether to iteratively print resulting JS source per pass.")
716-
private boolean printSourceAfterEachPass = false;
713+
@Option(
714+
name = "--print_source_after_each_pass",
715+
hidden = true,
716+
usage = "Whether to iteratively print resulting JS source per pass."
717+
)
718+
private boolean printSourceAfterEachPass = false;
719+
720+
@Option(
721+
name = "--module_resolution",
722+
hidden = false,
723+
usage =
724+
"Specifies how the compiler locates modules. BROWSER requires all module imports "
725+
+ "to begin with a '.' or '/' and have a file extension. NODE uses the node module "
726+
+ "rules. LEGACY prepends a '/' to any import not already beginning with a "
727+
+ "'.' or '/'."
728+
)
729+
private ModuleLoader.ResolutionMode moduleResolutionMode = ModuleLoader.ResolutionMode.LEGACY;
717730

718731
@Argument
719732
private List<String> arguments = new ArrayList<>();
@@ -787,7 +800,10 @@ private void parse(List<String> args) throws CmdLineException {
787800
.putAll(
788801
"JS Modules",
789802
ImmutableList.of(
790-
"js_module_root", "process_common_js_modules", "transform_amd_modules"))
803+
"js_module_root",
804+
"module_resolution",
805+
"process_common_js_modules",
806+
"transform_amd_modules"))
791807
.putAll(
792808
"Library and Framework Specific",
793809
ImmutableList.of(
@@ -1690,6 +1706,7 @@ protected CompilerOptions createOptions() {
16901706
options.setStrictModeInput(flags.strictModeInput);
16911707
options.setEmitUseStrict(flags.emitUseStrict);
16921708
options.setSourceMapIncludeSourcesContent(flags.sourceMapIncludeSourcesContent);
1709+
options.setModuleResolutionMode(flags.moduleResolutionMode);
16931710

16941711
return options;
16951712
}

src/com/google/javascript/jscomp/Compiler.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,9 +1491,15 @@ Node parseInputs() {
14911491
|| options.transformAMDToCJSModules
14921492
|| options.processCommonJSModules) {
14931493

1494-
this.moduleLoader = new ModuleLoader(this, options.moduleRoots, inputs);
1495-
1496-
if (options.processCommonJSModules) {
1494+
this.moduleLoader =
1495+
new ModuleLoader(
1496+
this,
1497+
options.moduleRoots,
1498+
inputs,
1499+
ModuleLoader.PathResolver.RELATIVE,
1500+
options.moduleResolutionMode);
1501+
1502+
if (options.moduleResolutionMode == ModuleLoader.ResolutionMode.NODE) {
14971503
this.moduleLoader.setPackageJsonMainEntries(processJsonInputs(inputs));
14981504
}
14991505

src/com/google/javascript/jscomp/CompilerOptions.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,10 +1086,13 @@ public void setWrapGoogModulesForWhitespaceOnly(boolean enable) {
10861086
*/
10871087
private boolean isStrictModeInput = true;
10881088

1089+
/** Which algorithm to use for locating ES6 and CommonJS modules */
1090+
ModuleLoader.ResolutionMode moduleResolutionMode;
1091+
10891092
/**
10901093
* Should the compiler print its configuration options to stderr when they are initialized?
10911094
*
1092-
* <p> Default {@code false}.
1095+
* <p>Default {@code false}.
10931096
*/
10941097
public void setPrintConfig(boolean printConfig) {
10951098
this.printConfig = printConfig;
@@ -1109,6 +1112,9 @@ public CompilerOptions() {
11091112
// Which environment to use
11101113
environment = Environment.BROWSER;
11111114

1115+
// Modules
1116+
moduleResolutionMode = ModuleLoader.ResolutionMode.LEGACY;
1117+
11121118
// Checks
11131119
skipNonTranspilationPasses = false;
11141120
devMode = DevMode.OFF;
@@ -2648,6 +2654,14 @@ public CompilerOptions setEmitUseStrict(boolean emitUseStrict) {
26482654
return this;
26492655
}
26502656

2657+
public ModuleLoader.ResolutionMode getModuleResolutionMode() {
2658+
return this.moduleResolutionMode;
2659+
}
2660+
2661+
public void setModuleResolutionMode(ModuleLoader.ResolutionMode mode) {
2662+
this.moduleResolutionMode = mode;
2663+
}
2664+
26512665
@Override
26522666
public String toString() {
26532667
String strValue =

src/com/google/javascript/jscomp/DiagnosticGroups.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ public DiagnosticGroup forName(String name) {
143143
+ "visibility";
144144

145145
public static final DiagnosticGroup COMMON_JS_MODULE_LOAD =
146-
DiagnosticGroups.registerGroup(
147-
"commonJsModuleLoad", ProcessCommonJSModules.COMMON_JS_MODULE_LOAD_ERROR);
146+
DiagnosticGroups.registerGroup("commonJsModuleLoad",
147+
ProcessCommonJSModules.SUSPICIOUS_EXPORTS_ASSIGNMENT,
148+
ProcessCommonJSModules.UNKNOWN_REQUIRE_ENSURE);
148149

149150
public static final DiagnosticGroup GLOBAL_THIS =
150151
DiagnosticGroups.registerGroup("globalThis",

src/com/google/javascript/jscomp/ProcessCommonJSModules.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ public final class ProcessCommonJSModules implements CompilerPass {
4343
private static final String EXPORTS = "exports";
4444
private static final String MODULE = "module";
4545

46-
public static final DiagnosticType COMMON_JS_MODULE_LOAD_ERROR = DiagnosticType.error(
47-
"JSC_COMMONJS_MODULE_LOAD_ERROR",
48-
"Failed to load module \"{0}\"");
49-
5046
public static final DiagnosticType UNKNOWN_REQUIRE_ENSURE =
5147
DiagnosticType.warning(
5248
"JSC_COMMONJS_UNKNOWN_REQUIRE_ENSURE_ERROR", "Unrecognized require.ensure call: {0}");
@@ -356,9 +352,16 @@ public void visit(NodeTraversal t, Node n, Node parent) {
356352
/** Visit require calls. Emit corresponding goog.require call. */
357353
private void visitRequireCall(NodeTraversal t, Node require, Node parent) {
358354
String requireName = require.getSecondChild().getString();
359-
ModulePath modulePath = t.getInput().getPath().resolveCommonJsModule(requireName);
355+
ModulePath modulePath =
356+
t.getInput()
357+
.getPath()
358+
.resolveJsModule(
359+
requireName,
360+
require.getSourceFileName(),
361+
require.getLineno(),
362+
require.getCharno());
360363
if (modulePath == null) {
361-
compiler.report(t.makeError(require, COMMON_JS_MODULE_LOAD_ERROR, requireName));
364+
// The module loader will issue an error
362365
return;
363366
}
364367

@@ -701,9 +704,16 @@ public void visit(NodeTraversal t, Node n, Node parent) {
701704
*/
702705
private void visitRequireCall(NodeTraversal t, Node require, Node parent) {
703706
String requireName = require.getSecondChild().getString();
704-
ModulePath modulePath = t.getInput().getPath().resolveCommonJsModule(requireName);
707+
ModulePath modulePath =
708+
t.getInput()
709+
.getPath()
710+
.resolveJsModule(
711+
requireName,
712+
require.getSourceFileName(),
713+
require.getLineno(),
714+
require.getCharno());
705715
if (modulePath == null) {
706-
compiler.report(t.makeError(require, COMMON_JS_MODULE_LOAD_ERROR, requireName));
716+
// The module loader will issue an error
707717
return;
708718
}
709719

@@ -1190,7 +1200,11 @@ private String getModuleImportName(NodeTraversal t, Node n) {
11901200
&& rValue.getSecondChild().isString()
11911201
&& t.getScope().getVar(rValue.getFirstChild().getQualifiedName()) == null) {
11921202
String requireName = rValue.getSecondChild().getString();
1193-
ModulePath modulePath = t.getInput().getPath().resolveCommonJsModule(requireName);
1203+
ModulePath modulePath =
1204+
t.getInput()
1205+
.getPath()
1206+
.resolveJsModule(
1207+
requireName, n.getSourceFileName(), n.getLineno(), n.getCharno());
11941208
if (modulePath == null) {
11951209
return null;
11961210
}
@@ -1227,9 +1241,16 @@ private void fixTypeNode(NodeTraversal t, Node typeNode) {
12271241
}
12281242

12291243
String moduleName = name.substring(0, endIndex);
1230-
ModulePath modulePath = t.getInput().getPath().resolveCommonJsModule(moduleName);
1244+
ModulePath modulePath =
1245+
t.getInput()
1246+
.getPath()
1247+
.resolveJsModule(
1248+
moduleName,
1249+
typeNode.getSourceFileName(),
1250+
typeNode.getLineno(),
1251+
typeNode.getCharno());
12311252
if (modulePath == null) {
1232-
t.makeError(typeNode, COMMON_JS_MODULE_LOAD_ERROR, moduleName);
1253+
// The module loader will issue an error
12331254
return;
12341255
}
12351256

src/com/google/javascript/jscomp/ProcessEs6Modules.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,21 @@ private void visitImport(NodeTraversal t, Node importDecl, Node parent) {
165165
// These are rewritten to plain namespace object accesses.
166166
moduleName = importName.substring("goog:".length());
167167
} else {
168-
moduleName = t.getInput().getPath().resolveEs6Module(importName).toModuleName();
168+
ModuleLoader.ModulePath modulePath =
169+
t.getInput()
170+
.getPath()
171+
.resolveJsModule(
172+
importName,
173+
importDecl.getSourceFileName(),
174+
importDecl.getLineno(),
175+
importDecl.getCharno());
176+
if (modulePath == null) {
177+
// The module loader issues an error
178+
// Fall back to assuming the module is a file path
179+
modulePath = t.getInput().getPath().resolveModuleAsPath(importName);
180+
}
181+
182+
moduleName = modulePath.toModuleName();
169183
}
170184

171185
for (Node child : importDecl.children()) {
@@ -270,8 +284,18 @@ private void visitExport(NodeTraversal t, Node export, Node parent) {
270284
parent.addChildBefore(importNode, export);
271285
visit(t, importNode, parent);
272286

273-
String moduleName =
274-
t.getInput().getPath().resolveEs6Module(moduleIdentifier.getString()).toModuleName();
287+
ModuleLoader.ModulePath path =
288+
t.getInput()
289+
.getPath()
290+
.resolveJsModule(
291+
moduleIdentifier.getString(),
292+
export.getSourceFileName(),
293+
export.getLineno(),
294+
export.getCharno());
295+
if (path == null) {
296+
path = t.getInput().getPath().resolveModuleAsPath(moduleIdentifier.getString());
297+
}
298+
String moduleName = path.toModuleName();
275299

276300
for (Node exportSpec : export.getFirstChild().children()) {
277301
String nameFromOtherModule = exportSpec.getFirstChild().getString();
@@ -539,8 +563,20 @@ private void fixTypeNode(NodeTraversal t, Node typeNode) {
539563
}
540564

541565
String moduleName = name.substring(0, endIndex);
542-
String globalModuleName =
543-
t.getInput().getPath().resolveEs6Module(moduleName).toModuleName();
566+
ModuleLoader.ModulePath path =
567+
t.getInput()
568+
.getPath()
569+
.resolveJsModule(
570+
moduleName,
571+
typeNode.getSourceFileName(),
572+
typeNode.getLineno(),
573+
typeNode.getCharno());
574+
575+
if (path == null) {
576+
path = t.getInput().getPath().resolveModuleAsPath(moduleName);
577+
}
578+
String globalModuleName = path.toModuleName();
579+
544580
typeNode.setString(
545581
localTypeName == null ? globalModuleName : globalModuleName + localTypeName);
546582
} else {

src/com/google/javascript/jscomp/deps/JsFileParser.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,11 @@ protected boolean parseLine(String line) throws ParseException {
285285
if (arg.startsWith("goog:")) {
286286
requires.add(arg.substring(5)); // cut off the "goog:" prefix
287287
} else {
288-
requires.add(file.resolveEs6Module(arg).toModuleName());
288+
ModuleLoader.ModulePath path = file.resolveJsModule(arg);
289+
if (path == null) {
290+
path = file.resolveModuleAsPath(arg);
291+
}
292+
requires.add(path.toModuleName());
289293
}
290294
}
291295
}

0 commit comments

Comments
 (0)