diff options
author | Geoffrey Booth <webmaster@geoffreybooth.com> | 2019-04-15 10:29:56 -0700 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2019-04-16 12:41:59 -0400 |
commit | 96e46d37c458ab3d6cf1148a471cfd1aac7aafe6 (patch) | |
tree | a037559ded34f2450af5c9a41c74463bb89cd56c | |
parent | f85ef977e6e9f0f655a8ff6aa4796d80ae94010e (diff) | |
download | android-node-v8-96e46d37c458ab3d6cf1148a471cfd1aac7aafe6.tar.gz android-node-v8-96e46d37c458ab3d6cf1148a471cfd1aac7aafe6.tar.bz2 android-node-v8-96e46d37c458ab3d6cf1148a471cfd1aac7aafe6.zip |
esm: replace --entry-type with --input-type
New flag is for string input only
PR-URL: https://github.com/nodejs/node/pull/27184
Reviewed-By: Jan Krems <jan.krems@gmail.com>
Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
-rw-r--r-- | doc/api/cli.md | 24 | ||||
-rw-r--r-- | doc/api/errors.md | 32 | ||||
-rw-r--r-- | doc/api/esm.md | 80 | ||||
-rw-r--r-- | doc/node.1 | 6 | ||||
-rw-r--r-- | lib/internal/errors.js | 20 | ||||
-rw-r--r-- | lib/internal/main/check_syntax.js | 2 | ||||
-rw-r--r-- | lib/internal/main/eval_stdin.js | 2 | ||||
-rw-r--r-- | lib/internal/main/eval_string.js | 2 | ||||
-rw-r--r-- | lib/internal/main/repl.js | 6 | ||||
-rw-r--r-- | lib/internal/modules/esm/default_resolve.js | 32 | ||||
-rw-r--r-- | src/node_options.cc | 12 | ||||
-rw-r--r-- | test/es-module/test-esm-no-extension.js | 7 | ||||
-rw-r--r-- | test/es-module/test-esm-type-flag-errors.js | 14 | ||||
-rw-r--r-- | test/es-module/test-esm-type-flag.mjs | 2 | ||||
-rw-r--r-- | test/fixtures/es-modules/package-type-module/noext-esm (renamed from test/fixtures/es-modules/noext-esm) | 0 | ||||
-rw-r--r-- | test/parallel/test-cli-syntax-piped-bad.js | 4 | ||||
-rw-r--r-- | test/parallel/test-cli-syntax-piped-good.js | 4 |
17 files changed, 119 insertions, 130 deletions
diff --git a/doc/api/cli.md b/doc/api/cli.md index f56eb981a9..79f2dcd2ba 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -134,19 +134,6 @@ added: v6.0.0 Enable FIPS-compliant crypto at startup. (Requires Node.js to be built with `./configure --openssl-fips`.) -### `--entry-type=type` -<!-- YAML -added: REPLACEME ---> - -Used with `--experimental-modules`, this configures Node.js to interpret the -initial entry point as CommonJS or as an ES module. - -Valid values are `"commonjs"` and `"module"`. The default is to infer from -the file extension and the `"type"` field in the nearest parent `package.json`. - -Works for executing a file as well as `--eval`, `--print`, `STDIN`. - ### `--es-module-specifier-resolution=mode` <!-- YAML added: REPLACEME @@ -261,6 +248,17 @@ added: v0.11.15 Specify ICU data load path. (Overrides `NODE_ICU_DATA`.) +### `--input-type=type` +<!-- YAML +added: REPLACEME +--> + +Used with `--experimental-modules`, this configures Node.js to interpret string +input as CommonJS or as an ES module. String input is input via `--eval`, +`--print`, or `STDIN`. + +Valid values are `"commonjs"` and `"module"`. The default is `"commonjs"`. + ### `--inspect-brk[=[host:]port]` <!-- YAML added: v7.6.0 diff --git a/doc/api/errors.md b/doc/api/errors.md index e984487820..097b0208f7 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -854,18 +854,6 @@ provided. Encoding provided to `TextDecoder()` API was not one of the [WHATWG Supported Encodings][]. -<a id="ERR_ENTRY_TYPE_MISMATCH"></a> -#### ERR_ENTRY_TYPE_MISMATCH - -> Stability: 1 - Experimental - -The `--entry-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 `--entry-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_FALSY_VALUE_REJECTION"></a> ### ERR_FALSY_VALUE_REJECTION @@ -1166,6 +1154,14 @@ is set for the `Http2Stream`. An option pair is incompatible with each other and can not be used at the same time. +<a id="ERR_INPUT_TYPE_NOT_ALLOWED"></a> +### ERR_INPUT_TYPE_NOT_ALLOWED + +> Stability: 1 - Experimental + +The `--input-type` flag was used to attempt to execute a file. This flag can +only be used with input via `--eval`, `--print` or `STDIN`. + <a id="ERR_INSPECTOR_ALREADY_CONNECTED"></a> ### ERR_INSPECTOR_ALREADY_CONNECTED @@ -2223,6 +2219,18 @@ closed. These errors have never been released, but had been present on master between releases. +<a id="ERR_ENTRY_TYPE_MISMATCH"></a> +#### ERR_ENTRY_TYPE_MISMATCH + +> Stability: 1 - Experimental + +The `--entry-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 `--entry-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_FS_WATCHER_ALREADY_STARTED"></a> #### ERR_FS_WATCHER_ALREADY_STARTED diff --git a/doc/api/esm.md b/doc/api/esm.md index ce616e1f42..36dba24e29 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -30,45 +30,37 @@ specifier resolution, and default behavior. The `--experimental-modules` flag can be used to enable support for ECMAScript modules (ES modules). -## Running Node.js with an ECMAScript Module +Once enabled, Node.js will treat the following as ES modules when passed to +`node` as the initial input, or when referenced by `import` statements within +ES module code: -There are a few ways to start Node.js with an ES module as its input. +- Files ending in `.mjs`. -### Initial entry point with an <code>.mjs</code> extension +- Files ending in `.js`, or extensionless files, when the nearest parent + `package.json` file contains a top-level field `"type"` with a value of + `"module"`. -A file ending with `.mjs` passed to Node.js as an initial entry point will be -loaded as an ES module. +- Strings passed in as an argument to `--eval` or `--print`, or piped to + `node` via `STDIN`, with the flag `--input-type=module`. -```sh -node --experimental-modules my-app.mjs -``` - -### <code>--entry-type=module</code> flag - -Files ending with `.js` or `.mjs`, or lacking any extension, -will be loaded as ES modules when the `--entry-type=module` flag is set. - -```sh -node --experimental-modules --entry-type=module my-app.js -``` +Node.js will treat as CommonJS all other forms of input, such as `.js` files +where the nearest parent `package.json` file contains no top-level `"type"` +field, or string input without the flag `--input-type`. This behavior is to +preserve backward compatibility. However, now that Node.js supports both +CommonJS and ES modules, it is best to be explicit whenever possible. Node.js +will treat the following as CommonJS when passed to `node` as the initial input, +or when referenced by `import` statements within ES module code: -For completeness there is also `--entry-type=commonjs`, for explicitly running -a `.js` file as CommonJS. This is the default behavior if `--entry-type` is -unspecified. +- Files ending in `.cjs`. -The `--entry-type=module` flag can also be used to configure Node.js to treat -as an ES module input sent in via `--eval` or `--print` (or `-e` or `-p`) or -piped to Node.js via `STDIN`. +- Files ending in `.js`, or extensionless files, when the nearest parent + `package.json` file contains a top-level field `"type"` with a value of + `"commonjs"`. -```sh -node --experimental-modules --entry-type=module --eval \ - "import { sep } from 'path'; console.log(sep);" - -echo "import { sep } from 'path'; console.log(sep);" | \ - node --experimental-modules --entry-type=module -``` +- Strings passed in as an argument to `--eval` or `--print`, or piped to + `node` via `STDIN`, with the flag `--input-type=commonjs`. -### <code>package.json</code> <code>"type"</code> field +## <code>package.json</code> <code>"type"</code> field Files ending with `.js` or `.mjs`, or lacking any extension, will be loaded as ES modules when the nearest parent `package.json` file @@ -97,6 +89,14 @@ If the volume root is reached and no `package.json` is found, Node.js defers to the default, a `package.json` with no `"type"` field. +`import` statements of `.js` and extensionless files are treated as ES modules +if the nearest parent `package.json` contains `"type": "module"`. + +```js +// my-app.js, part of the same example as above +import './startup.js'; // Loaded as ES module because of package.json +``` + ## Package Scope and File Extensions A folder containing a `package.json` file, and all subfolders below that @@ -156,6 +156,24 @@ package scope: extension (since both `.js` and `.cjs` files are treated as CommonJS within a `"commonjs"` package scope). +## <code>--input-type</code> flag + +Strings passed in as an argument to `--eval` or `--print` (or `-e` or `-p`), or +piped to `node` via `STDIN`, will be treated as ES modules when the +`--input-type=module` flag is set. + +```sh +node --experimental-modules --input-type=module --eval \ + "import { sep } from 'path'; console.log(sep);" + +echo "import { sep } from 'path'; console.log(sep);" | \ + node --experimental-modules --input-type=module +``` + +For completeness there is also `--input-type=commonjs`, for explicitly running +string input as CommonJS. This is the default behavior if `--input-type` is +unspecified. + ## Package Entry Points The `package.json` `"main"` field defines the entry point for a package, diff --git a/doc/node.1 b/doc/node.1 index e2b52b9e87..3de9a5748c 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -119,9 +119,6 @@ Enable FIPS-compliant crypto at startup. Requires Node.js to be built with .Sy ./configure --openssl-fips . . -.It Fl -entry-type Ns = Ns Ar type -Set the top-level module resolution type. -. .It Fl -es-module-specifier-resolution Select extension resolution algorithm for ES Modules; either 'explicit' (default) or 'node' . @@ -170,6 +167,9 @@ Specify ICU data load path. Overrides .Ev NODE_ICU_DATA . . +.It Fl -input-type Ns = Ns Ar type +Set the module resolution type for input via --eval, --print or STDIN. +. .It Fl -inspect-brk Ns = Ns Ar [host:]port Activate inspector on .Ar host:port diff --git a/lib/internal/errors.js b/lib/internal/errors.js index bc3f43653a..ef8ed8b9a1 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -679,24 +679,6 @@ E('ERR_ENCODING_INVALID_ENCODED_DATA', function(encoding, ret) { }, TypeError); E('ERR_ENCODING_NOT_SUPPORTED', 'The "%s" encoding is not supported', RangeError); -E('ERR_ENTRY_TYPE_MISMATCH', (filename, ext, typeFlag, conflict) => { - const typeString = - typeFlag === 'module' ? '--entry-type=module' : '--entry-type=commonjs'; - // --entry-type mismatches file extension - if (conflict === 'extension') { - return `Extension ${ext} is not supported for ` + - `${typeString} loading ${filename}`; - } - assert( - conflict === 'scope', - '"conflict" value unknown. Set this argument to "extension" or "scope"' - ); - // --entry-type mismatches package.json "type" - 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_FALSY_VALUE_REJECTION', function(reason) { this.reason = reason; return 'Promise was rejected with falsy value'; @@ -809,6 +791,8 @@ E('ERR_HTTP_TRAILER_INVALID', 'Trailers are invalid with this transfer encoding', Error); E('ERR_INCOMPATIBLE_OPTION_PAIR', 'Option "%s" can not be used in combination with option "%s"', TypeError); +E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' + + 'input via --eval, --print, or STDIN', Error); E('ERR_INSPECTOR_ALREADY_CONNECTED', '%s is already connected', Error); E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error); E('ERR_INSPECTOR_COMMAND', 'Inspector error %d: %s', Error); diff --git a/lib/internal/main/check_syntax.js b/lib/internal/main/check_syntax.js index 5bfe4ec3cd..6d335565ab 100644 --- a/lib/internal/main/check_syntax.js +++ b/lib/internal/main/check_syntax.js @@ -60,7 +60,7 @@ function checkSyntax(source, filename) { if (experimentalModules) { let isModule = false; if (filename === '[stdin]' || filename === '[eval]') { - isModule = getOptionValue('--entry-type') === 'module'; + isModule = getOptionValue('--input-type') === 'module'; } else { const resolve = require('internal/modules/esm/default_resolve'); const { format } = resolve(pathToFileURL(filename).toString()); diff --git a/lib/internal/main/eval_stdin.js b/lib/internal/main/eval_stdin.js index 4face9e61e..5c8f40b0e3 100644 --- a/lib/internal/main/eval_stdin.js +++ b/lib/internal/main/eval_stdin.js @@ -17,7 +17,7 @@ markBootstrapComplete(); readStdin((code) => { process._eval = code; - if (require('internal/options').getOptionValue('--entry-type') === 'module') + if (require('internal/options').getOptionValue('--input-type') === 'module') evalModule(process._eval); else evalScript('[stdin]', process._eval, process._breakFirstLine); diff --git a/lib/internal/main/eval_string.js b/lib/internal/main/eval_string.js index b032281925..4597d2a0bb 100644 --- a/lib/internal/main/eval_string.js +++ b/lib/internal/main/eval_string.js @@ -14,7 +14,7 @@ const source = getOptionValue('--eval'); prepareMainThreadExecution(); addBuiltinLibsToObject(global); markBootstrapComplete(); -if (getOptionValue('--entry-type') === 'module') +if (getOptionValue('--input-type') === 'module') evalModule(source); else evalScript('[eval]', source, process._breakFirstLine); diff --git a/lib/internal/main/repl.js b/lib/internal/main/repl.js index d93314646e..aef3e8374d 100644 --- a/lib/internal/main/repl.js +++ b/lib/internal/main/repl.js @@ -15,11 +15,11 @@ const console = require('internal/console/global'); prepareMainThreadExecution(); -// --entry-type flag not supported in REPL -if (require('internal/options').getOptionValue('--entry-type')) { +// --input-type flag not supported in REPL +if (require('internal/options').getOptionValue('--input-type')) { // If we can't write to stderr, we'd like to make this a noop, // so use console.error. - console.error('Cannot specify --entry-type for REPL'); + console.error('Cannot specify --input-type for REPL'); process.exit(1); } diff --git a/lib/internal/modules/esm/default_resolve.js b/lib/internal/modules/esm/default_resolve.js index 8b8c5a2b5a..a83cf9c675 100644 --- a/lib/internal/modules/esm/default_resolve.js +++ b/lib/internal/modules/esm/default_resolve.js @@ -9,12 +9,12 @@ const { getOptionValue } = require('internal/options'); const preserveSymlinks = getOptionValue('--preserve-symlinks'); const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); const experimentalJsonModules = getOptionValue('--experimental-json-modules'); -const typeFlag = getOptionValue('--entry-type'); +const typeFlag = getOptionValue('--input-type'); const { resolve: moduleWrapResolve, getPackageType } = internalBinding('module_wrap'); const { pathToFileURL, fileURLToPath } = require('internal/url'); -const { ERR_ENTRY_TYPE_MISMATCH, +const { ERR_INPUT_TYPE_NOT_ALLOWED, ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes; const { @@ -25,7 +25,7 @@ const { const realpathCache = new SafeMap(); // const TYPE_NONE = 0; -const TYPE_COMMONJS = 1; +// const TYPE_COMMONJS = 1; const TYPE_MODULE = 2; const extensionFormatMap = { @@ -86,26 +86,16 @@ function resolve(specifier, parentURL) { let format = extMap[ext]; if (isMain && typeFlag) { - // Conflict between explicit extension (.mjs, .cjs) and --entry-type - if (ext === '.cjs' && typeFlag === 'module' || - ext === '.mjs' && typeFlag === 'commonjs') { - throw new ERR_ENTRY_TYPE_MISMATCH( - fileURLToPath(url), ext, typeFlag, 'extension'); - } - - // Conflict between package scope type and --entry-type - if (ext === '.js') { - if (type === TYPE_MODULE && typeFlag === 'commonjs' || - type === TYPE_COMMONJS && typeFlag === 'module') { - throw new ERR_ENTRY_TYPE_MISMATCH( - fileURLToPath(url), ext, typeFlag, 'scope'); - } - } + // This is the initial entry point to the program, and --input-type has + // been passed as an option; but --input-type can only be used with + // --eval, --print or STDIN string input. It is not allowed with file + // input, to avoid user confusion over how expansive the effect of the + // flag should be (i.e. entry point only, package scope surrounding the + // entry point, etc.). + throw new ERR_INPUT_TYPE_NOT_ALLOWED(); } if (!format) { - if (isMain && typeFlag) - format = typeFlag; - else if (isMain) + if (isMain) format = type === TYPE_MODULE ? 'module' : 'commonjs'; else throw new ERR_UNKNOWN_FILE_EXTENSION(fileURLToPath(url), diff --git a/src/node_options.cc b/src/node_options.cc index cb490dad75..d9c0d472fb 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -109,11 +109,11 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) { if (!module_type.empty()) { if (!experimental_modules) { - errors->push_back("--entry-type requires " + errors->push_back("--input-type requires " "--experimental-modules to be enabled"); } if (module_type != "commonjs" && module_type != "module") { - errors->push_back("--entry-type must be \"module\" or \"commonjs\""); + errors->push_back("--input-type must be \"module\" or \"commonjs\""); } } @@ -289,15 +289,15 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "(default: llhttp).", &EnvironmentOptions::http_parser, kAllowedInEnvironment); + AddOption("--input-type", + "set module type for string input", + &EnvironmentOptions::module_type, + kAllowedInEnvironment); AddOption("--loader", "(with --experimental-modules) use the specified file as a " "custom loader", &EnvironmentOptions::userland_loader, kAllowedInEnvironment); - AddOption("--entry-type", - "set module type name of the entry point", - &EnvironmentOptions::module_type, - kAllowedInEnvironment); AddOption("--es-module-specifier-resolution", "Select extension resolution algorithm for es modules; " "either 'explicit' (default) or 'node'", diff --git a/test/es-module/test-esm-no-extension.js b/test/es-module/test-esm-no-extension.js index 3e9ffb2bbc..e3f30d6e3c 100644 --- a/test/es-module/test-esm-no-extension.js +++ b/test/es-module/test-esm-no-extension.js @@ -5,14 +5,13 @@ const fixtures = require('../common/fixtures'); const { spawn } = require('child_process'); const assert = require('assert'); -const entry = fixtures.path('/es-modules/noext-esm'); +const entry = fixtures.path('/es-modules/package-type-module/noext-esm'); -// Run a module that does not have extension -// This is to ensure the --entry-type works as expected +// Run a module that does not have extension. +// This is to ensure that "type": "module" applies to extensionless files. const child = spawn(process.execPath, [ '--experimental-modules', - '--entry-type=module', entry ]); diff --git a/test/es-module/test-esm-type-flag-errors.js b/test/es-module/test-esm-type-flag-errors.js index 612ada584d..169118e018 100644 --- a/test/es-module/test-esm-type-flag-errors.js +++ b/test/es-module/test-esm-type-flag-errors.js @@ -19,17 +19,9 @@ expect('', packageTypeModuleMain, 'package-type-module'); expect('', packageTypeCommonJsMain, 'package-type-commonjs'); expect('', packageWithoutTypeMain, 'package-without-type'); -// Check that running with --entry-type and no package.json "type" works -expect('--entry-type=commonjs', packageWithoutTypeMain, 'package-without-type'); -expect('--entry-type=module', packageWithoutTypeMain, 'package-without-type'); - -// Check that running with conflicting --entry-type flags throws errors -expect('--entry-type=commonjs', mjsFile, 'ERR_ENTRY_TYPE_MISMATCH', true); -expect('--entry-type=module', cjsFile, 'ERR_ENTRY_TYPE_MISMATCH', true); -expect('--entry-type=commonjs', packageTypeModuleMain, - 'ERR_ENTRY_TYPE_MISMATCH', true); -expect('--entry-type=module', packageTypeCommonJsMain, - 'ERR_ENTRY_TYPE_MISMATCH', true); +// Check that --input-type isn't allowed for files +expect('--input-type=module', packageTypeModuleMain, + 'ERR_INPUT_TYPE_NOT_ALLOWED', true); function expect(opt = '', inputFile, want, wantsError = false) { // TODO: Remove when --experimental-modules is unflagged diff --git a/test/es-module/test-esm-type-flag.mjs b/test/es-module/test-esm-type-flag.mjs index 2f5d0b626a..4c04ef03e1 100644 --- a/test/es-module/test-esm-type-flag.mjs +++ b/test/es-module/test-esm-type-flag.mjs @@ -1,4 +1,4 @@ -// Flags: --experimental-modules --entry-type=module +// Flags: --experimental-modules /* eslint-disable node-core/required-modules */ import cjs from '../fixtures/baz.js'; import '../common/index.mjs'; diff --git a/test/fixtures/es-modules/noext-esm b/test/fixtures/es-modules/package-type-module/noext-esm index 251d6e538a..251d6e538a 100644 --- a/test/fixtures/es-modules/noext-esm +++ b/test/fixtures/es-modules/package-type-module/noext-esm diff --git a/test/parallel/test-cli-syntax-piped-bad.js b/test/parallel/test-cli-syntax-piped-bad.js index 6d6f800a40..5da5f07e57 100644 --- a/test/parallel/test-cli-syntax-piped-bad.js +++ b/test/parallel/test-cli-syntax-piped-bad.js @@ -34,12 +34,12 @@ syntaxArgs.forEach(function(arg) { assert.strictEqual(c.status, 1); }); -// Check --entry-type=module +// Check --input-type=module syntaxArgs.forEach(function(arg) { const stdin = 'export var p = 5; var foo bar;'; const c = spawnSync( node, - ['--experimental-modules', '--entry-type=module', '--no-warnings', arg], + ['--experimental-modules', '--input-type=module', '--no-warnings', arg], { encoding: 'utf8', input: stdin } ); diff --git a/test/parallel/test-cli-syntax-piped-good.js b/test/parallel/test-cli-syntax-piped-good.js index b2b02172cb..5df5eb1c51 100644 --- a/test/parallel/test-cli-syntax-piped-good.js +++ b/test/parallel/test-cli-syntax-piped-good.js @@ -25,12 +25,12 @@ syntaxArgs.forEach(function(arg) { assert.strictEqual(c.status, 0); }); -// Check --entry-type=module +// Check --input-type=module syntaxArgs.forEach(function(arg) { const stdin = 'export var p = 5; throw new Error("should not get run");'; const c = spawnSync( node, - ['--experimental-modules', '--no-warnings', '--entry-type=module', arg], + ['--experimental-modules', '--no-warnings', '--input-type=module', arg], { encoding: 'utf8', input: stdin } ); |