Skip to content
This repository was archived by the owner on Apr 16, 2020. It is now read-only.

Commit 8cc0cf6

Browse files
guybedfordnodejs-ci
authored andcommitted
1 parent 4629143 commit 8cc0cf6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+962
-176
lines changed

.eslintrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ module.exports = {
3838
{
3939
files: [
4040
'doc/api/esm.md',
41+
'test/es-module/test-esm-type-flag.js',
42+
'test/es-module/test-esm-type-flag-alias.js',
4143
'*.mjs',
4244
],
4345
parserOptions: { sourceType: 'module' },

doc/api/cli.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,18 @@ added: v2.4.0
504504

505505
Track heap object allocations for heap snapshots.
506506

507+
### `-m`, `--type=type`
508+
509+
When using `--experimental-modules`, this informs the module resolution type
510+
to interpret the top-level entry into Node.js.
511+
512+
Works with stdin, `--eval`, `--print` as well as standard execution.
513+
514+
Valid values are `"commonjs"` and `"module"`, where the default is to infer
515+
from the file extension and package type boundary.
516+
517+
`-m` is an alias for `--type=module`.
518+
507519
### `--use-bundled-ca`, `--use-openssl-ca`
508520
<!-- YAML
509521
added: v6.11.0

doc/api/errors.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,11 @@ An invalid or unexpected value was passed in an options object.
12671267

12681268
An invalid or unknown file encoding was passed.
12691269

1270+
<a id="ERR_INVALID_PACKAGE_CONFIG"></a>
1271+
### ERR_INVALID_PACKAGE_CONFIG
1272+
1273+
An invalid `package.json` file was found which failed parsing.
1274+
12701275
<a id="ERR_INVALID_PERFORMANCE_MARK"></a>
12711276
### ERR_INVALID_PERFORMANCE_MARK
12721277

@@ -2213,6 +2218,32 @@ A non-specific HTTP/2 error has occurred.
22132218
Used in the `repl` in case the old history file is used and an error occurred
22142219
while trying to read and parse it.
22152220

2221+
<a id="ERR_INVALID_REPL_TYPE"></a>
2222+
### ERR_INVALID_REPL_TYPE
2223+
2224+
> Stability: 1 - Experimental
2225+
2226+
The `--type=...` flag is not compatible with the Node.js REPL.
2227+
2228+
<a id="ERR_TYPE_MISMATCH"></a>
2229+
### ERR_TYPE_MISMATCH
2230+
2231+
> Stability: 1 - Experimental
2232+
2233+
The `--type=commonjs` flag was used to attempt to execute an `.mjs` file or
2234+
a `.js` file where the nearest parent `package.json` contains
2235+
`"type": "module"`; or
2236+
the `--type=module` flag was used to attempt to execute a `.cjs` file or
2237+
a `.js` file where the nearest parent `package.json` either lacks a `"type"`
2238+
field or contains `"type": "commonjs"`.
2239+
2240+
<a id="ERR_INVALID_TYPE_FLAG"></a>
2241+
### ERR_INVALID_TYPE_FLAG
2242+
2243+
> Stability: 1 - Experimental
2244+
2245+
An invalid `--type=...` flag value was provided.
2246+
22162247
<a id="ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK"></a>
22172248
#### ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK
22182249

@@ -2243,7 +2274,6 @@ size.
22432274
This `Error` is thrown when a read is attempted on a TTY `WriteStream`,
22442275
such as `process.stdout.on('data')`.
22452276

2246-
22472277
[`'uncaughtException'`]: process.html#process_event_uncaughtexception
22482278
[`--force-fips`]: cli.html#cli_force_fips
22492279
[`Class: assert.AssertionError`]: assert.html#assert_class_assert_assertionerror

doc/api/esm.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ The algorithm to load an ES module specifier is given through the
158158
module specifier relative to a parentURL, in addition to the unique module
159159
format for that resolved URL given by the **ESM_FORMAT** routine.
160160
161-
The _"esm"_ format is returned for an ECMAScript Module, while the
162-
_"legacy"_ format is used to indicate loading through the legacy
161+
The _"module"_ format is returned for an ECMAScript Module, while the
162+
_"commonjs"_ format is used to indicate loading through the legacy
163163
CommonJS loader. Additional formats such as _"wasm"_ or _"addon"_ can be
164164
extended in future updates.
165165
@@ -168,6 +168,12 @@ of these top-level routines.
168168
169169
_isMain_ is **true** when resolving the Node.js application entry point.
170170
171+
If the top-level `--type` is _"commonjs"_, then the ESM resolver is skipped
172+
entirely for the CommonJS loader.
173+
174+
If the top-level `--type` is _"module"_, then the ESM resolver is used
175+
as described here, with the conditional `--type` check in **ESM_FORMAT**.
176+
171177
**ESM_RESOLVE(_specifier_, _parentURL_, _isMain_)**
172178
> 1. Let _resolvedURL_ be **undefined**.
173179
> 1. If _specifier_ is a valid URL, then
@@ -184,7 +190,8 @@ _isMain_ is **true** when resolving the Node.js application entry point.
184190
> **PACKAGE_RESOLVE**(_specifier_, _parentURL_).
185191
> 1. If the file at _resolvedURL_ does not exist, then
186192
> 1. Throw a _Module Not Found_ error.
187-
> 1. Let _format_ be the result of **ESM_FORMAT**(_url_, _isMain_).
193+
> 1. Set _resolvedURL_ to the real path of _resolvedURL_.
194+
> 1. Let _format_ be the result of **ESM_FORMAT**(_resolvedURL_, _isMain_).
188195
> 1. Load _resolvedURL_ as module format, _format_.
189196
190197
PACKAGE_RESOLVE(_packageSpecifier_, _parentURL_)
@@ -234,7 +241,7 @@ PACKAGE_MAIN_RESOLVE(_packageURL_, _pjson_)
234241
> _pjson.main_.
235242
> 1. If the file at _resolvedMain_ exists, then
236243
> 1. Return _resolvedMain_.
237-
> 1. If _pjson.type_ is equal to _"esm"_, then
244+
> 1. If _pjson.type_ is equal to _"module"_, then
238245
> 1. Throw a _Module Not Found_ error.
239246
> 1. Let _legacyMainURL_ be the result applying the legacy
240247
> **LOAD_AS_DIRECTORY** CommonJS resolver to _packageURL_, throwing a
@@ -245,18 +252,25 @@ PACKAGE_MAIN_RESOLVE(_packageURL_, _pjson_)
245252
246253
**ESM_FORMAT(_url_, _isMain_)**
247254
> 1. Assert: _url_ corresponds to an existing file.
255+
> 1. If _isMain_ is **true** and the `--type` flag is _"module"_, then
256+
> 1. If _url_ ends with _".cjs"_, then
257+
> 1. Throw a _Type Mismatch_ error.
258+
> 1. Return _"module"_.
248259
> 1. Let _pjson_ be the result of **READ_PACKAGE_BOUNDARY**(_url_).
249260
> 1. If _pjson_ is **null** and _isMain_ is **true**, then
250-
> 1. Return _"legacy"_.
251-
> 1. If _pjson.type_ exists and is _"esm"_, then
252-
> 1. If _url_ does not end in _".js"_ or _".mjs"_, then
253-
> 1. Throw an _Unsupported File Extension_ error.
254-
> 1. Return _"esm"_.
261+
> 1. If _url_ ends in _".mjs"_, then
262+
> 1. Return _"module"_.
263+
> 1. Return _"commonjs"_.
264+
> 1. If _pjson.type_ exists and is _"module"_, then
265+
> 1. If _url_ ends in _".cjs"_, then
266+
> 1. Return _"commonjs"_.
267+
> 1. Return _"module"_.
255268
> 1. Otherwise,
256269
> 1. If _url_ ends in _".mjs"_, then
257-
> 1. Return _"esm"_.
258-
> 1. Otherwise,
259-
> 1. Return _"legacy"_.
270+
> 1. Return _"module"_.
271+
> 1. If _url_ does not end in _".js"_, then
272+
> 1. Throw an _Unsupported File Extension_ error.
273+
> 1. Return _"commonjs"_.
260274
261275
READ_PACKAGE_BOUNDARY(_url_)
262276
> 1. Let _boundaryURL_ be _url_.

doc/node.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ Print stack traces for process warnings (including deprecations).
270270
.It Fl -track-heap-objects
271271
Track heap object allocations for heap snapshots.
272272
.
273+
.It Fl -type Ns = Ns Ar type
274+
Set the top-level module resolution type.
275+
.
273276
.It Fl -use-bundled-ca , Fl -use-openssl-ca
274277
Use bundled Mozilla CA store as supplied by current Node.js version or use OpenSSL's default CA store.
275278
The default store is selectable at build-time.

lib/internal/errors.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -774,13 +774,17 @@ E('ERR_INVALID_OPT_VALUE', (name, value) =>
774774
RangeError);
775775
E('ERR_INVALID_OPT_VALUE_ENCODING',
776776
'The value "%s" is invalid for option "encoding"', TypeError);
777+
E('ERR_INVALID_PACKAGE_CONFIG',
778+
'Invalid package config in \'%s\' imported from %s', Error);
777779
E('ERR_INVALID_PERFORMANCE_MARK',
778780
'The "%s" performance mark has not been set', Error);
779781
E('ERR_INVALID_PROTOCOL',
780782
'Protocol "%s" not supported. Expected "%s"',
781783
TypeError);
782784
E('ERR_INVALID_REPL_EVAL_CONFIG',
783785
'Cannot specify both "breakEvalOnSigint" and "eval" for REPL', TypeError);
786+
E('ERR_INVALID_REPL_TYPE',
787+
'Cannot specify --type for REPL', TypeError);
784788
E('ERR_INVALID_RETURN_PROPERTY', (input, name, prop, value) => {
785789
return `Expected a valid ${input} to be returned for the "${prop}" from the` +
786790
` "${name}" function but got ${value}.`;
@@ -811,6 +815,9 @@ E('ERR_INVALID_SYNC_FORK_INPUT',
811815
TypeError);
812816
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError);
813817
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError);
818+
E('ERR_INVALID_TYPE_FLAG',
819+
'Type flag must be one of "module", "commonjs". Received --type=%s',
820+
TypeError);
814821
E('ERR_INVALID_URI', 'URI malformed', URIError);
815822
E('ERR_INVALID_URL', 'Invalid URL: %s', TypeError);
816823
E('ERR_INVALID_URL_SCHEME',
@@ -865,13 +872,6 @@ E('ERR_MISSING_ARGS',
865872
E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
866873
'The ES Module loader may not return a format of \'dynamic\' when no ' +
867874
'dynamicInstantiate function was provided', Error);
868-
E('ERR_MODULE_NOT_FOUND', (module, base, legacyResolution) => {
869-
let msg = `Cannot find module '${module}' imported from ${base}.`;
870-
if (legacyResolution)
871-
msg += ' Legacy behavior in require() would have found it at ' +
872-
legacyResolution;
873-
return msg;
874-
}, Error);
875875
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error);
876876
E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function', TypeError);
877877
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
@@ -956,6 +956,20 @@ E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
956956
E('ERR_TRANSFORM_WITH_LENGTH_0',
957957
'Calling transform done when writableState.length != 0', Error);
958958
E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError);
959+
E('ERR_TYPE_MISMATCH', (filename, ext, typeFlag, conflict) => {
960+
const typeString =
961+
typeFlag === 'module' ? '--type=module or -m' : '--type=commonjs';
962+
// --type mismatches file extension
963+
if (conflict === 'extension')
964+
return `Extension ${ext} is not supported for ` +
965+
`${typeString} loading ${filename}`;
966+
// --type mismatches package.json "type"
967+
else if (conflict === 'scope')
968+
return `Cannot use ${typeString} because nearest parent package.json ` +
969+
((typeFlag === 'module') ?
970+
'includes "type": "commonjs"' : 'includes "type": "module",') +
971+
` which controls the type to use for ${filename}`;
972+
}, TypeError);
959973
E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
960974
'`process.setupUncaughtExceptionCapture()` was called while a capture ' +
961975
'callback was already active',
@@ -972,10 +986,8 @@ E('ERR_UNHANDLED_ERROR',
972986
// This should probably be a `TypeError`.
973987
E('ERR_UNKNOWN_CREDENTIAL', '%s identifier does not exist: %s', Error);
974988
E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
975-
989+
E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: %s', TypeError);
976990
// This should probably be a `TypeError`.
977-
E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: \'%s\' imported ' +
978-
'from %s', Error);
979991
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError);
980992
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
981993

lib/internal/main/check_syntax.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ const {
1111
readStdin
1212
} = require('internal/process/execution');
1313

14-
const CJSModule = require('internal/modules/cjs/loader');
14+
const { pathToFileURL } = require('url');
15+
1516
const vm = require('vm');
1617
const {
1718
stripShebang, stripBOM
1819
} = require('internal/modules/cjs/helpers');
1920

21+
let CJSModule;
22+
function CJSModuleInit() {
23+
if (!CJSModule)
24+
CJSModule = require('internal/modules/cjs/loader');
25+
}
2026

2127
if (process.argv[1] && process.argv[1] !== '-') {
2228
// Expand process.argv[1] into a full path.
@@ -25,7 +31,7 @@ if (process.argv[1] && process.argv[1] !== '-') {
2531

2632
// TODO(joyeecheung): not every one of these are necessary
2733
prepareMainThreadExecution();
28-
34+
CJSModuleInit();
2935
// Read the source.
3036
const filename = CJSModule._resolveFilename(process.argv[1]);
3137

@@ -34,20 +40,40 @@ if (process.argv[1] && process.argv[1] !== '-') {
3440

3541
markBootstrapComplete();
3642

37-
checkScriptSyntax(source, filename);
43+
checkSyntax(source, filename);
3844
} else {
3945
// TODO(joyeecheung): not every one of these are necessary
4046
prepareMainThreadExecution();
47+
CJSModuleInit();
4148
markBootstrapComplete();
4249

4350
readStdin((code) => {
44-
checkScriptSyntax(code, '[stdin]');
51+
checkSyntax(code, '[stdin]');
4552
});
4653
}
4754

48-
function checkScriptSyntax(source, filename) {
55+
function checkSyntax(source, filename) {
4956
// Remove Shebang.
5057
source = stripShebang(source);
58+
59+
const experimentalModules =
60+
require('internal/options').getOptionValue('--experimental-modules');
61+
if (experimentalModules) {
62+
let isModule = false;
63+
if (filename === '[stdin]' || filename === '[eval]') {
64+
isModule = require('internal/process/esm_loader').typeFlag === 'module';
65+
} else {
66+
const resolve = require('internal/modules/esm/default_resolve');
67+
const { format } = resolve(pathToFileURL(filename).toString());
68+
isModule = format === 'module';
69+
}
70+
if (isModule) {
71+
const { ModuleWrap } = internalBinding('module_wrap');
72+
new ModuleWrap(source, filename);
73+
return;
74+
}
75+
}
76+
5177
// Remove BOM.
5278
source = stripBOM(source);
5379
// Wrap it.

lib/internal/main/eval_stdin.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
} = require('internal/bootstrap/pre_execution');
88

99
const {
10+
evalModule,
1011
evalScript,
1112
readStdin
1213
} = require('internal/process/execution');
@@ -16,5 +17,8 @@ markBootstrapComplete();
1617

1718
readStdin((code) => {
1819
process._eval = code;
19-
evalScript('[stdin]', process._eval, process._breakFirstLine);
20+
if (require('internal/process/esm_loader').typeFlag === 'module')
21+
evalModule(process._eval);
22+
else
23+
evalScript('[stdin]', process._eval, process._breakFirstLine);
2024
});

lib/internal/main/eval_string.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
const {
77
prepareMainThreadExecution
88
} = require('internal/bootstrap/pre_execution');
9-
const { evalScript } = require('internal/process/execution');
9+
const { evalModule, evalScript } = require('internal/process/execution');
1010
const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers');
1111

1212
const source = require('internal/options').getOptionValue('--eval');
1313
prepareMainThreadExecution();
1414
addBuiltinLibsToObject(global);
1515
markBootstrapComplete();
16-
evalScript('[eval]', source, process._breakFirstLine);
16+
if (require('internal/process/esm_loader').typeFlag === 'module')
17+
evalModule(source);
18+
else
19+
evalScript('[eval]', source, process._breakFirstLine);

lib/internal/main/repl.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@ const {
1111
evalScript
1212
} = require('internal/process/execution');
1313

14+
const { ERR_INVALID_REPL_TYPE } = require('internal/errors').codes;
15+
1416
prepareMainThreadExecution();
1517

18+
// --type flag not supported in REPL
19+
if (require('internal/process/esm_loader').typeFlag) {
20+
throw ERR_INVALID_REPL_TYPE();
21+
}
22+
1623
const cliRepl = require('internal/repl');
1724
cliRepl.createInternalRepl(process.env, (err, repl) => {
1825
if (err) {

0 commit comments

Comments
 (0)