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

CI fixes for latest commits and reland #45 #49

Merged
merged 15 commits into from
Mar 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ module.exports = {
{
files: [
'doc/api/esm.md',
'test/es-module/test-esm-type-flag.js',
'test/es-module/test-esm-type-flag-alias.js',
'*.mjs',
],
parserOptions: { sourceType: 'module' },
Expand Down
12 changes: 12 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,18 @@ added: v2.4.0

Track heap object allocations for heap snapshots.

### `-m`, `--type=type`

When using `--experimental-modules`, this informs the module resolution type
to interpret the top-level entry into Node.js.

Works with stdin, `--eval`, `--print` as well as standard execution.

Valid values are `"commonjs"` and `"module"`, where the default is to infer
from the file extension and package type boundary.

`-m` is an alias for `--type=module`.

### `--use-bundled-ca`, `--use-openssl-ca`
<!-- YAML
added: v6.11.0
Expand Down
32 changes: 31 additions & 1 deletion doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,11 @@ An invalid or unexpected value was passed in an options object.

An invalid or unknown file encoding was passed.

<a id="ERR_INVALID_PACKAGE_CONFIG"></a>
### ERR_INVALID_PACKAGE_CONFIG

An invalid `package.json` file was found which failed parsing.

<a id="ERR_INVALID_PERFORMANCE_MARK"></a>
### ERR_INVALID_PERFORMANCE_MARK

Expand Down Expand Up @@ -2206,6 +2211,32 @@ A non-specific HTTP/2 error has occurred.
Used in the `repl` in case the old history file is used and an error occurred
while trying to read and parse it.

<a id="ERR_INVALID_REPL_TYPE"></a>
### ERR_INVALID_REPL_TYPE

> Stability: 1 - Experimental

The `--type=...` flag is not compatible with the Node.js REPL.

<a id="ERR_TYPE_MISMATCH"></a>
### ERR_TYPE_MISMATCH

> Stability: 1 - Experimental

The `--type=commonjs` flag was used to attempt to execute an `.mjs` file or
a `.js` file where the nearest parent `package.json` contains
`"type": "module"`; or
the `--type=module` flag was used to attempt to execute a `.cjs` file or
a `.js` file where the nearest parent `package.json` either lacks a `"type"`
field or contains `"type": "commonjs"`.

<a id="ERR_INVALID_TYPE_FLAG"></a>
### ERR_INVALID_TYPE_FLAG

> Stability: 1 - Experimental

An invalid `--type=...` flag value was provided.

<a id="ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK"></a>
#### ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK

Expand Down Expand Up @@ -2236,7 +2267,6 @@ size.
This `Error` is thrown when a read is attempted on a TTY `WriteStream`,
such as `process.stdout.on('data')`.


[`'uncaughtException'`]: process.html#process_event_uncaughtexception
[`--force-fips`]: cli.html#cli_force_fips
[`Class: assert.AssertionError`]: assert.html#assert_class_assert_assertionerror
Expand Down
38 changes: 26 additions & 12 deletions doc/api/esm.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ The algorithm to load an ES module specifier is given through the
module specifier relative to a parentURL, in addition to the unique module
format for that resolved URL given by the **ESM_FORMAT** routine.

The _"esm"_ format is returned for an ECMAScript Module, while the
_"legacy"_ format is used to indicate loading through the legacy
The _"module"_ format is returned for an ECMAScript Module, while the
_"commonjs"_ format is used to indicate loading through the legacy
CommonJS loader. Additional formats such as _"wasm"_ or _"addon"_ can be
extended in future updates.

Expand All @@ -168,6 +168,12 @@ of these top-level routines.

_isMain_ is **true** when resolving the Node.js application entry point.

If the top-level `--type` is _"commonjs"_, then the ESM resolver is skipped
entirely for the CommonJS loader.

If the top-level `--type` is _"module"_, then the ESM resolver is used
as described here, with the conditional `--type` check in **ESM_FORMAT**.

**ESM_RESOLVE(_specifier_, _parentURL_, _isMain_)**
> 1. Let _resolvedURL_ be **undefined**.
> 1. If _specifier_ is a valid URL, then
Expand All @@ -184,7 +190,8 @@ _isMain_ is **true** when resolving the Node.js application entry point.
> **PACKAGE_RESOLVE**(_specifier_, _parentURL_).
> 1. If the file at _resolvedURL_ does not exist, then
> 1. Throw a _Module Not Found_ error.
> 1. Let _format_ be the result of **ESM_FORMAT**(_url_, _isMain_).
> 1. Set _resolvedURL_ to the real path of _resolvedURL_.
> 1. Let _format_ be the result of **ESM_FORMAT**(_resolvedURL_, _isMain_).
> 1. Load _resolvedURL_ as module format, _format_.

PACKAGE_RESOLVE(_packageSpecifier_, _parentURL_)
Expand Down Expand Up @@ -234,7 +241,7 @@ PACKAGE_MAIN_RESOLVE(_packageURL_, _pjson_)
> _pjson.main_.
> 1. If the file at _resolvedMain_ exists, then
> 1. Return _resolvedMain_.
> 1. If _pjson.type_ is equal to _"esm"_, then
> 1. If _pjson.type_ is equal to _"module"_, then
> 1. Throw a _Module Not Found_ error.
> 1. Let _legacyMainURL_ be the result applying the legacy
> **LOAD_AS_DIRECTORY** CommonJS resolver to _packageURL_, throwing a
Expand All @@ -245,18 +252,25 @@ PACKAGE_MAIN_RESOLVE(_packageURL_, _pjson_)

**ESM_FORMAT(_url_, _isMain_)**
> 1. Assert: _url_ corresponds to an existing file.
> 1. If _isMain_ is **true** and the `--type` flag is _"module"_, then
> 1. If _url_ ends with _".cjs"_, then
> 1. Throw a _Type Mismatch_ error.
> 1. Return _"module"_.
> 1. Let _pjson_ be the result of **READ_PACKAGE_BOUNDARY**(_url_).
> 1. If _pjson_ is **null** and _isMain_ is **true**, then
> 1. Return _"legacy"_.
> 1. If _pjson.type_ exists and is _"esm"_, then
> 1. If _url_ does not end in _".js"_ or _".mjs"_, then
> 1. Throw an _Unsupported File Extension_ error.
> 1. Return _"esm"_.
> 1. If _url_ ends in _".mjs"_, then
> 1. Return _"module"_.
> 1. Return _"commonjs"_.
> 1. If _pjson.type_ exists and is _"module"_, then
> 1. If _url_ ends in _".cjs"_, then
> 1. Return _"commonjs"_.
> 1. Return _"module"_.
> 1. Otherwise,
> 1. If _url_ ends in _".mjs"_, then
> 1. Return _"esm"_.
> 1. Otherwise,
> 1. Return _"legacy"_.
> 1. Return _"module"_.
> 1. If _url_ does not end in _".js"_, then
> 1. Throw an _Unsupported File Extension_ error.
> 1. Return _"commonjs"_.

READ_PACKAGE_BOUNDARY(_url_)
> 1. Let _boundaryURL_ be _url_.
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ Print stack traces for process warnings (including deprecations).
.It Fl -track-heap-objects
Track heap object allocations for heap snapshots.
.
.It Fl -type Ns = Ns Ar type
Set the top-level module resolution type.
.
.It Fl -use-bundled-ca , Fl -use-openssl-ca
Use bundled Mozilla CA store as supplied by current Node.js version or use OpenSSL's default CA store.
The default store is selectable at build-time.
Expand Down
25 changes: 22 additions & 3 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -774,13 +774,17 @@ E('ERR_INVALID_OPT_VALUE', (name, value) =>
RangeError);
E('ERR_INVALID_OPT_VALUE_ENCODING',
'The value "%s" is invalid for option "encoding"', TypeError);
E('ERR_INVALID_PACKAGE_CONFIG',
'Invalid package config in \'%s\' imported from %s', Error);
E('ERR_INVALID_PERFORMANCE_MARK',
'The "%s" performance mark has not been set', Error);
E('ERR_INVALID_PROTOCOL',
'Protocol "%s" not supported. Expected "%s"',
TypeError);
E('ERR_INVALID_REPL_EVAL_CONFIG',
'Cannot specify both "breakEvalOnSigint" and "eval" for REPL', TypeError);
E('ERR_INVALID_REPL_TYPE',
'Cannot specify --type for REPL', TypeError);
E('ERR_INVALID_RETURN_PROPERTY', (input, name, prop, value) => {
return `Expected a valid ${input} to be returned for the "${prop}" from the` +
` "${name}" function but got ${value}.`;
Expand Down Expand Up @@ -811,6 +815,9 @@ E('ERR_INVALID_SYNC_FORK_INPUT',
TypeError);
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError);
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError);
E('ERR_INVALID_TYPE_FLAG',
'Type flag must be one of "module", "commonjs". Received --type=%s',
TypeError);
E('ERR_INVALID_URI', 'URI malformed', URIError);
E('ERR_INVALID_URL', 'Invalid URL: %s', TypeError);
E('ERR_INVALID_URL_SCHEME',
Expand Down Expand Up @@ -949,6 +956,20 @@ E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
E('ERR_TRANSFORM_WITH_LENGTH_0',
'Calling transform done when writableState.length != 0', Error);
E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError);
E('ERR_TYPE_MISMATCH', (filename, ext, typeFlag, conflict) => {
const typeString =
typeFlag === 'module' ? '--type=module or -m' : '--type=commonjs';
// --type mismatches file extension
if (conflict === 'extension')
return `Extension ${ext} is not supported for ` +
`${typeString} loading ${filename}`;
// --type mismatches package.json "type"
else if (conflict === 'scope')
return `Cannot use ${typeString} because nearest parent package.json ` +
((typeFlag === 'module') ?
'includes "type": "commonjs"' : 'includes "type": "module",') +
` which controls the type to use for ${filename}`;
}, TypeError);
E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
'`process.setupUncaughtExceptionCapture()` was called while a capture ' +
'callback was already active',
Expand All @@ -965,12 +986,10 @@ E('ERR_UNHANDLED_ERROR',
// This should probably be a `TypeError`.
E('ERR_UNKNOWN_CREDENTIAL', '%s identifier does not exist: %s', Error);
E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);

E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: %s', TypeError);
// This should probably be a `TypeError`.
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError);
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
E('ERR_UNSUPPORTED_FILE_EXTENSION', 'Unsupported file extension: \'%s\' ' +
'imported from %s', Error);

E('ERR_V8BREAKITERATOR',
'Full ICU data not installed. See https://github.com/nodejs/node/wiki/Intl',
Expand Down
27 changes: 24 additions & 3 deletions lib/internal/main/check_syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const {
readStdin
} = require('internal/process/execution');

const { pathToFileURL } = require('url');

const CJSModule = require('internal/modules/cjs/loader');
const vm = require('vm');
const {
Expand All @@ -34,20 +36,39 @@ if (process.argv[1] && process.argv[1] !== '-') {

markBootstrapComplete();

checkScriptSyntax(source, filename);
checkSyntax(source, filename);
} else {
// TODO(joyeecheung): not every one of these are necessary
prepareMainThreadExecution();
markBootstrapComplete();

readStdin((code) => {
checkScriptSyntax(code, '[stdin]');
checkSyntax(code, '[stdin]');
});
}

function checkScriptSyntax(source, filename) {
function checkSyntax(source, filename) {
// Remove Shebang.
source = stripShebang(source);

const experimentalModules =
require('internal/options').getOptionValue('--experimental-modules');
if (experimentalModules) {
let isModule = false;
if (filename === '[stdin]' || filename === '[eval]') {
isModule = require('internal/process/esm_loader').typeFlag === 'module';
} else {
const resolve = require('internal/modules/esm/default_resolve');
const { format } = resolve(pathToFileURL(filename).toString());
isModule = format === 'module';
}
if (isModule) {
const { ModuleWrap } = internalBinding('module_wrap');
new ModuleWrap(source, filename);
return;
}
}

// Remove BOM.
source = stripBOM(source);
// Wrap it.
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/main/eval_stdin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
} = require('internal/bootstrap/pre_execution');

const {
evalModule,
evalScript,
readStdin
} = require('internal/process/execution');
Expand All @@ -16,5 +17,8 @@ markBootstrapComplete();

readStdin((code) => {
process._eval = code;
evalScript('[stdin]', process._eval, process._breakFirstLine);
if (require('internal/process/esm_loader').typeFlag === 'module')
evalModule(process._eval);
else
evalScript('[stdin]', process._eval, process._breakFirstLine);
});
7 changes: 5 additions & 2 deletions lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
const {
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');
const { evalScript } = require('internal/process/execution');
const { evalModule, evalScript } = require('internal/process/execution');
const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers');

const source = require('internal/options').getOptionValue('--eval');
prepareMainThreadExecution();
addBuiltinLibsToObject(global);
markBootstrapComplete();
evalScript('[eval]', source, process._breakFirstLine);
if (require('internal/process/esm_loader').typeFlag === 'module')
evalModule(source);
else
evalScript('[eval]', source, process._breakFirstLine);
7 changes: 7 additions & 0 deletions lib/internal/main/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ const {
evalScript
} = require('internal/process/execution');

const { ERR_INVALID_REPL_TYPE } = require('internal/errors').codes;

prepareMainThreadExecution();

// --type flag not supported in REPL
if (require('internal/process/esm_loader').typeFlag) {
throw ERR_INVALID_REPL_TYPE();
}

const cliRepl = require('internal/repl');
cliRepl.createInternalRepl(process.env, (err, repl) => {
if (err) {
Expand Down
26 changes: 13 additions & 13 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -858,21 +858,21 @@ if (experimentalModules) {
// bootstrap main module.
Module.runMain = function() {
// Load the main module--the command line argument.
const base = path.basename(process.argv[1]);
const ext = path.extname(base);
const isESM = ext === '.mjs';

if (experimentalModules && isESM) {
if (experimentalModules) {
if (asyncESM === undefined) lazyLoadESM();
asyncESM.loaderPromise.then((loader) => {
return loader.import(pathToFileURL(process.argv[1]).pathname);
})
.catch((e) => {
internalBinding('util').triggerFatalException(e);
});
} else {
Module._load(process.argv[1], null, true);
if (asyncESM.typeFlag !== 'commonjs') {
asyncESM.loaderPromise.then((loader) => {
return loader.import(pathToFileURL(process.argv[1]).pathname);
})
.catch((e) => {
internalBinding('util').triggerFatalException(e);
});
// Handle any nextTicks added in the first tick of the program
process._tickCallback();
return;
}
}
Module._load(process.argv[1], null, true);
// Handle any nextTicks added in the first tick of the program
process._tickCallback();
};
Expand Down
Loading