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

Commit

Permalink
esm: replace --entry-type with --input-type, which applies only to st…
Browse files Browse the repository at this point in the history
…ring input
  • Loading branch information
GeoffreyBooth committed Apr 3, 2019
1 parent 0a5a762 commit b1da781
Show file tree
Hide file tree
Showing 17 changed files with 119 additions and 129 deletions.
24 changes: 11 additions & 13 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,6 @@ conjunction with native stack and other runtime environment data.
added: v6.0.0
-->

### `--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`.

Enable FIPS-compliant crypto at startup. (Requires Node.js to be built with
`./configure --openssl-fips`.)

Expand Down Expand Up @@ -253,6 +240,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
Expand Down
32 changes: 20 additions & 12 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,18 +864,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

Expand Down Expand Up @@ -1176,6 +1164,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

Expand Down Expand Up @@ -2222,6 +2218,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

Expand Down
80 changes: 49 additions & 31 deletions doc/api/esm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -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'
.
Expand Down Expand Up @@ -167,6 +164,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
Expand Down
20 changes: 2 additions & 18 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -678,24 +678,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';
Expand Down Expand Up @@ -808,6 +790,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);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/check_syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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());
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/eval_stdin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
9 changes: 5 additions & 4 deletions lib/internal/main/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ const {

prepareMainThreadExecution();

// --entry-type flag not supported in REPL
if (require('internal/options').getOptionValue('--entry-type')) {
console.error('Cannot specify --entry-type for REPL');
process.exit(1);
// --input-type flag not supported in REPL
if (require('internal/options').getOptionValue('--input-type')) {
const { ERR_INPUT_TYPE_NOT_ALLOWED } = require('internal/errors').codes;
// Cannot specify --input-type for REPL.
throw new ERR_INPUT_TYPE_NOT_ALLOWED();
}

const cliRepl = require('internal/repl');
Expand Down
32 changes: 11 additions & 21 deletions lib/internal/modules/esm/default_resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 = {
Expand Down Expand Up @@ -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),
Expand Down
8 changes: 4 additions & 4 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 \"module\" or \"commonjs\"");
errors->push_back("--input-type must \"module\" or \"commonjs\"");
}
}

Expand Down Expand Up @@ -338,8 +338,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"show stack traces on process warnings",
&EnvironmentOptions::trace_warnings,
kAllowedInEnvironment);
AddOption("--entry-type",
"set module type name of the entry point",
AddOption("--input-type",
"set module type for string input",
&EnvironmentOptions::module_type,
kAllowedInEnvironment);

Expand Down
7 changes: 3 additions & 4 deletions test/es-module/test-esm-no-extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
]);

Expand Down
Loading

0 comments on commit b1da781

Please sign in to comment.