src: mark config file as stable

Signed-off-by: Marco Ippolito <marcoippolito54@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66431
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
This commit is contained in:
Marco Ippolito authored and Node.js GitHub Bot committed 2026-10-05 16:47:38 +00:00
1 parent c413d1acb4
commit 3c577146aa
24 files changed
+435 -425

No files matched your search

+157 -171
View File
@@ -799,6 +799,163 @@ For example, to run a module with "development" resolutions:
node -C development app.js
```
### `--config-file=path`, `--config-file`
<!-- YAML
added:
- v23.10.0
- v22.16.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/66431
description: This flag was renamed from `--experimental-config-file` to
`--config-file` and is now stable. `--experimental-config-file`
and `--experimental-default-config-file` are kept as aliases.
- version: v26.7.0
pr-url: https://github.com/nodejs/node/pull/64516
description: Marked as release candidate.
-->
If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a `node.config.json` file
in the current working directory.
To specify a custom path, use the `--config-file=path` form.
The space-separated `--config-file path` form is not supported.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. `vX.Y.Z`
in the `$schema` must be replaced with the version of Node.js you are using or
`latest-vX.x` for the latest version of that major release line.
```json
{
"$schema": "https://nodejs.org/dist/vX.Y.Z/docs/node-config-schema.json",
"nodeOptions": {
"import": [
"amaro/strip"
],
"watch-path": "src",
"watch-preserve-output": true
},
"test": {
"test-isolation": "process"
},
"watch": {
"watch-preserve-output": true
}
}
```
The configuration file supports namespace-specific options:
* The `nodeOptions` field contains CLI flags that are allowed in [`NODE_OPTIONS`][].
* Namespace fields like `test`, `watch`, and `permission` contain configuration specific to that subsystem.
The configuration file can target a specific Node.js major version with
`nodeVersion`:
```json
{
"nodeVersion": 25,
"nodeOptions": {
"watch-path": "src"
}
}
```
To keep multiple version-specific configurations in the same file, use the
`configs` array. Node.js will use the first entry whose `nodeVersion` matches
the current Node.js major version:
```json
{
"$schema": "https://nodejs.org/dist/latest-v26.x/docs/node-config-schema.json",
"configs": [
{
"nodeVersion": 25,
"config": {
"$schema": "https://nodejs.org/dist/latest-v25.x/docs/node-config-schema.json",
"nodeOptions": {
"watch-path": "src"
}
}
}
]
}
```
When `configs` is used, the top level may only contain `$schema` and
`configs`. Each `configs` item must define an integer `nodeVersion` and an
object `config`. A single top-level config does not require `nodeVersion`, but
if present it must match the current Node.js major version.
When a namespace is present in the
configuration file, Node.js automatically enables the corresponding flag
(e.g., `--test`, `--watch`, `--permission`). This allows you to configure
subsystem-specific options without explicitly passing the flag on the command line.
For example:
```json
{
"test": {
"test-isolation": "process"
}
}
```
is equivalent to:
```bash
node --test --test-isolation=process
```
To disable the automatic flag while still using namespace options, you can
explicitly set the flag to `false` within the namespace:
```json
{
"test": {
"test": false,
"test-isolation": "process"
}
}
```
No-op flags are not supported.
Not all V8 flags are currently supported.
It is possible to use the [official JSON schema](../node-config-schema.json)
to validate the configuration file, which may vary depending on the Node.js version.
Each key in the configuration file corresponds to a flag that can be passed
as a command-line argument. The value of the key is the value that would be
passed to the flag.
For example, the configuration file above is equivalent to
the following command-line arguments:
```bash
node --import amaro/strip --watch-path=src --watch-preserve-output --test-isolation=process
```
The priority in configuration is as follows:
1. NODE\_OPTIONS and command-line options
2. Dotenv NODE\_OPTIONS
3. Configuration file
Values in the configuration file will not override the values in the environment
variables, command-line options, or the `NODE_OPTIONS` env file parsed by the
`--env-file` flag.
Keys cannot be duplicated within the same or different namespaces.
The configuration parser will throw an error if the configuration file contains
unknown keys or keys that cannot be used in a namespace.
Node.js will not sanitize or perform validation on the user-provided configuration,
so **NEVER** use untrusted configuration files.
### `--cpu-prof`
<!-- YAML
@@ -1280,177 +1437,6 @@ added: v26.9.0
Enable the experimental `node:bench` module and command-line benchmark runner.
### `--experimental-config-file=path`, `--experimental-config-file`
<!-- YAML
added:
- v23.10.0
- v22.16.0
changes:
- version: v26.7.0
pr-url: https://github.com/nodejs/node/pull/64516
description: Marked as release candidate.
-->
> Stability: 1.2 - Release candidate
If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a `node.config.json` file
in the current working directory.
To specify a custom path, use the `--experimental-config-file=path` form.
The space-separated `--experimental-config-file path` form is not supported.
The alias `--experimental-default-config-file` is equivalent to
`--experimental-config-file` without an argument.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. `vX.Y.Z`
in the `$schema` must be replaced with the version of Node.js you are using or
`latest-vX.x` for the latest version of that major release line.
```json
{
"$schema": "https://nodejs.org/dist/vX.Y.Z/docs/node-config-schema.json",
"nodeOptions": {
"import": [
"amaro/strip"
],
"watch-path": "src",
"watch-preserve-output": true
},
"test": {
"test-isolation": "process"
},
"watch": {
"watch-preserve-output": true
}
}
```
The configuration file supports namespace-specific options:
* The `nodeOptions` field contains CLI flags that are allowed in [`NODE_OPTIONS`][].
* Namespace fields like `test`, `watch`, and `permission` contain configuration specific to that subsystem.
The configuration file can target a specific Node.js major version with
`nodeVersion`:
```json
{
"nodeVersion": 25,
"nodeOptions": {
"watch-path": "src"
}
}
```
To keep multiple version-specific configurations in the same file, use the
`configs` array. Node.js will use the first entry whose `nodeVersion` matches
the current Node.js major version:
```json
{
"$schema": "https://nodejs.org/dist/latest-v26.x/docs/node-config-schema.json",
"configs": [
{
"nodeVersion": 25,
"config": {
"$schema": "https://nodejs.org/dist/latest-v25.x/docs/node-config-schema.json",
"nodeOptions": {
"watch-path": "src"
}
}
}
]
}
```
When `configs` is used, the top level may only contain `$schema` and
`configs`. Each `configs` item must define an integer `nodeVersion` and an
object `config`. A single top-level config does not require `nodeVersion`, but
if present it must match the current Node.js major version.
When a namespace is present in the
configuration file, Node.js automatically enables the corresponding flag
(e.g., `--test`, `--watch`, `--permission`). This allows you to configure
subsystem-specific options without explicitly passing the flag on the command line.
For example:
```json
{
"test": {
"test-isolation": "process"
}
}
```
is equivalent to:
```bash
node --test --test-isolation=process
```
To disable the automatic flag while still using namespace options, you can
explicitly set the flag to `false` within the namespace:
```json
{
"test": {
"test": false,
"test-isolation": "process"
}
}
```
No-op flags are not supported.
Not all V8 flags are currently supported.
It is possible to use the [official JSON schema](../node-config-schema.json)
to validate the configuration file, which may vary depending on the Node.js version.
Each key in the configuration file corresponds to a flag that can be passed
as a command-line argument. The value of the key is the value that would be
passed to the flag.
For example, the configuration file above is equivalent to
the following command-line arguments:
```bash
node --import amaro/strip --watch-path=src --watch-preserve-output --test-isolation=process
```
The priority in configuration is as follows:
1. NODE\_OPTIONS and command-line options
2. Dotenv NODE\_OPTIONS
3. Configuration file
Values in the configuration file will not override the values in the environment
variables, command-line options, or the `NODE_OPTIONS` env file parsed by the
`--env-file` flag.
Keys cannot be duplicated within the same or different namespaces.
The configuration parser will throw an error if the configuration file contains
unknown keys or keys that cannot be used in a namespace.
Node.js will not sanitize or perform validation on the user-provided configuration,
so **NEVER** use untrusted configuration files.
### `--experimental-default-config-file`
<!-- YAML
added:
- v23.10.0
- v22.16.0
-->
> Stability: 1.0 - Early development
This flag is an alias for `--experimental-config-file` without an argument.
If present, Node.js will look for a
`node.config.json` file in the current working directory and load it as a
configuration file.
### `--experimental-dtls`
<!-- YAML
+6 -5
View File
@@ -375,9 +375,9 @@ programs.
#### Configuration file support
In addition to passing permission flags on the command line, they can also be
declared in a Node.js configuration file when using the experimental
\[`--experimental-config-file`]\[] flag. Permission options must be placed inside
the `permission` top-level object.
declared in a Node.js configuration file when using the [`--config-file`][]
flag. Permission options must be placed inside the `permission` top-level
object.
Example `node.config.json`:
@@ -400,7 +400,7 @@ When the `permission` namespace is present in the configuration file, Node.js
automatically enables the `--permission` flag. Run with:
```console
$ node --experimental-default-config-file app.js
$ node --config-file app.js
```
A configuration file, like the `NODE_OPTIONS` defined in an [`--env-file`][]
@@ -410,7 +410,7 @@ enable the Permission Model, the `allow-env` values these files define can only
narrow the access that [`--allow-env`][] grants, and never widen it:
```console
$ node --permission --allow-env=APP_* --experimental-config-file=node.config.json app.js
$ node --permission --allow-env=APP_* --config-file=node.config.json app.js
```
With `"allow-env": ["*"]` in `node.config.json`, only the variables starting with
@@ -539,6 +539,7 @@ Developers relying on --permission to sandbox untrusted code should be aware tha
[`--allow-openssl-store`]: cli.md#--allow-openssl-store
[`--allow-wasi`]: cli.md#--allow-wasi
[`--allow-worker`]: cli.md#--allow-worker
[`--config-file`]: cli.md#--config-filepath---config-file
[`--env-file-if-exists`]: cli.md#--env-file-if-existsfile
[`--env-file`]: cli.md#--env-filefile
[`--permission-audit`]: cli.md#--permission-audit
+2 -3
View File
@@ -885,10 +885,9 @@ test runner functionality:
* `--experimental-test-tag-filter` - Filter expressions are validated by the parent
process and re-emitted to child processes
* `--watch` - Watch mode is handled at the parent level
* `--experimental-default-config-file` - Config file loading is handled by the parent
* `--test-reporter` - Reporting is managed by the parent process
* `--test-reporter-destination` - Output destinations are controlled by the parent
* `--experimental-config-file` - Config file paths are managed by the parent
* `--config-file` - Config file paths are managed by the parent
* `--test-randomize` - Randomization is managed by the parent process and
propagated to child processes
* `--test-random-seed` - Randomization seed is managed by the parent process and
@@ -5051,7 +5050,7 @@ test.describe('my suite', (suite) => {
[`suite()`]: #suitename-options-fn
[`test()`]: #testname-options-fn
[code coverage]: #collecting-code-coverage
[configuration files]: cli.md#--experimental-config-filepath---experimental-config-file
[configuration files]: cli.md#--config-filepath---config-file
[describe options]: #describename-options-fn
[it options]: #testname-options-fn
[module customization hooks]: module.md#customization-hooks
+124 -132
View File
@@ -480,6 +480,130 @@ For example, to run a module with "development" resolutions:
node -C development app.js
.Ed
.
.It Fl -config-file Ns = Ns Ar path , Fl -config-file
If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a \fBnode.config.json\fR file
in the current working directory.
To specify a custom path, use the \fB--config-file=path\fR form.
The space-separated \fB--config-file path\fR form is not supported.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. \fBvX.Y.Z\fR
in the \fB$schema\fR must be replaced with the version of Node.js you are using or
\fBlatest-vX.x\fR for the latest version of that major release line.
.Bd -literal
{
"$schema": "https://nodejs.org/dist/vX.Y.Z/docs/node-config-schema.json",
"nodeOptions": {
"import": [
"amaro/strip"
],
"watch-path": "src",
"watch-preserve-output": true
},
"test": {
"test-isolation": "process"
},
"watch": {
"watch-preserve-output": true
}
}
.Ed
The configuration file supports namespace-specific options:
.Bl -bullet
.It
The \fBnodeOptions\fR field contains CLI flags that are allowed in \fBNODE_OPTIONS\fR.
.It
Namespace fields like \fBtest\fR, \fBwatch\fR, and \fBpermission\fR contain configuration specific to that subsystem.
.El
The configuration file can target a specific Node.js major version with
\fBnodeVersion\fR:
.Bd -literal
{
"nodeVersion": 25,
"nodeOptions": {
"watch-path": "src"
}
}
.Ed
To keep multiple version-specific configurations in the same file, use the
\fBconfigs\fR array. Node.js will use the first entry whose \fBnodeVersion\fR matches
the current Node.js major version:
.Bd -literal
{
"$schema": "https://nodejs.org/dist/latest-v26.x/docs/node-config-schema.json",
"configs": [
{
"nodeVersion": 25,
"config": {
"$schema": "https://nodejs.org/dist/latest-v25.x/docs/node-config-schema.json",
"nodeOptions": {
"watch-path": "src"
}
}
}
]
}
.Ed
When \fBconfigs\fR is used, the top level may only contain \fB$schema\fR and
\fBconfigs\fR. Each \fBconfigs\fR item must define an integer \fBnodeVersion\fR and an
object \fBconfig\fR. A single top-level config does not require \fBnodeVersion\fR, but
if present it must match the current Node.js major version.
When a namespace is present in the
configuration file, Node.js automatically enables the corresponding flag
(e.g., \fB--test\fR, \fB--watch\fR, \fB--permission\fR). This allows you to configure
subsystem-specific options without explicitly passing the flag on the command line.
For example:
.Bd -literal
{
"test": {
"test-isolation": "process"
}
}
.Ed
is equivalent to:
.Bd -literal
node --test --test-isolation=process
.Ed
To disable the automatic flag while still using namespace options, you can
explicitly set the flag to \fBfalse\fR within the namespace:
.Bd -literal
{
"test": {
"test": false,
"test-isolation": "process"
}
}
.Ed
No-op flags are not supported.
Not all V8 flags are currently supported.
It is possible to use the official JSON schema
to validate the configuration file, which may vary depending on the Node.js version.
Each key in the configuration file corresponds to a flag that can be passed
as a command-line argument. The value of the key is the value that would be
passed to the flag.
For example, the configuration file above is equivalent to
the following command-line arguments:
.Bd -literal
node --import amaro/strip --watch-path=src --watch-preserve-output --test-isolation=process
.Ed
The priority in configuration is as follows:
.Bl -bullet
.It
NODE_OPTIONS and command-line options
.It
Dotenv NODE_OPTIONS
.It
Configuration file
.El
Values in the configuration file will not override the values in the environment
variables, command-line options, or the \fBNODE_OPTIONS\fR env file parsed by the
\fB--env-file\fR flag.
Keys cannot be duplicated within the same or different namespaces.
The configuration parser will throw an error if the configuration file contains
unknown keys or keys that cannot be used in a namespace.
Node.js will not sanitize or perform validation on the user-provided configuration,
so \fBNEVER\fR use untrusted configuration files.
.
.It Fl -cpu-prof
Starts the V8 CPU profiler on start up, and writes the CPU profile to disk
before exit.
@@ -722,138 +846,6 @@ Enable experimental import support for \fB.node\fR addons.
.It Fl -experimental-bench
Enable the experimental \fBnode:bench\fR module and command-line benchmark runner.
.
.It Fl -experimental-config-file Ns = Ns Ar path , Fl -experimental-config-file
If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a \fBnode.config.json\fR file
in the current working directory.
To specify a custom path, use the \fB--experimental-config-file=path\fR form.
The space-separated \fB--experimental-config-file path\fR form is not supported.
The alias \fB--experimental-default-config-file\fR is equivalent to
\fB--experimental-config-file\fR without an argument.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. \fBvX.Y.Z\fR
in the \fB$schema\fR must be replaced with the version of Node.js you are using or
\fBlatest-vX.x\fR for the latest version of that major release line.
.Bd -literal
{
"$schema": "https://nodejs.org/dist/vX.Y.Z/docs/node-config-schema.json",
"nodeOptions": {
"import": [
"amaro/strip"
],
"watch-path": "src",
"watch-preserve-output": true
},
"test": {
"test-isolation": "process"
},
"watch": {
"watch-preserve-output": true
}
}
.Ed
The configuration file supports namespace-specific options:
.Bl -bullet
.It
The \fBnodeOptions\fR field contains CLI flags that are allowed in \fBNODE_OPTIONS\fR.
.It
Namespace fields like \fBtest\fR, \fBwatch\fR, and \fBpermission\fR contain configuration specific to that subsystem.
.El
The configuration file can target a specific Node.js major version with
\fBnodeVersion\fR:
.Bd -literal
{
"nodeVersion": 25,
"nodeOptions": {
"watch-path": "src"
}
}
.Ed
To keep multiple version-specific configurations in the same file, use the
\fBconfigs\fR array. Node.js will use the first entry whose \fBnodeVersion\fR matches
the current Node.js major version:
.Bd -literal
{
"$schema": "https://nodejs.org/dist/latest-v26.x/docs/node-config-schema.json",
"configs": [
{
"nodeVersion": 25,
"config": {
"$schema": "https://nodejs.org/dist/latest-v25.x/docs/node-config-schema.json",
"nodeOptions": {
"watch-path": "src"
}
}
}
]
}
.Ed
When \fBconfigs\fR is used, the top level may only contain \fB$schema\fR and
\fBconfigs\fR. Each \fBconfigs\fR item must define an integer \fBnodeVersion\fR and an
object \fBconfig\fR. A single top-level config does not require \fBnodeVersion\fR, but
if present it must match the current Node.js major version.
When a namespace is present in the
configuration file, Node.js automatically enables the corresponding flag
(e.g., \fB--test\fR, \fB--watch\fR, \fB--permission\fR). This allows you to configure
subsystem-specific options without explicitly passing the flag on the command line.
For example:
.Bd -literal
{
"test": {
"test-isolation": "process"
}
}
.Ed
is equivalent to:
.Bd -literal
node --test --test-isolation=process
.Ed
To disable the automatic flag while still using namespace options, you can
explicitly set the flag to \fBfalse\fR within the namespace:
.Bd -literal
{
"test": {
"test": false,
"test-isolation": "process"
}
}
.Ed
No-op flags are not supported.
Not all V8 flags are currently supported.
It is possible to use the official JSON schema
to validate the configuration file, which may vary depending on the Node.js version.
Each key in the configuration file corresponds to a flag that can be passed
as a command-line argument. The value of the key is the value that would be
passed to the flag.
For example, the configuration file above is equivalent to
the following command-line arguments:
.Bd -literal
node --import amaro/strip --watch-path=src --watch-preserve-output --test-isolation=process
.Ed
The priority in configuration is as follows:
.Bl -bullet
.It
NODE_OPTIONS and command-line options
.It
Dotenv NODE_OPTIONS
.It
Configuration file
.El
Values in the configuration file will not override the values in the environment
variables, command-line options, or the \fBNODE_OPTIONS\fR env file parsed by the
\fB--env-file\fR flag.
Keys cannot be duplicated within the same or different namespaces.
The configuration parser will throw an error if the configuration file contains
unknown keys or keys that cannot be used in a namespace.
Node.js will not sanitize or perform validation on the user-provided configuration,
so \fBNEVER\fR use untrusted configuration files.
.
.It Fl -experimental-default-config-file
This flag is an alias for \fB--experimental-config-file\fR without an argument.
If present, Node.js will look for a
\fBnode.config.json\fR file in the current working directory and load it as a
configuration file.
.
.It Fl -experimental-dtls
Enable experimental support for the DTLS protocol. See the
dtls documentation for details.
+3 -1
View File
@@ -118,6 +118,7 @@ const kFilterArgValues = [
'--bench-reporter-destination',
'--bench-samples',
'--bench-warmup',
'--config-file',
'--experimental-config-file',
];
const kIncompatibleExecArgv = new SafeSet([
@@ -652,7 +653,8 @@ function filterExecArgv(arg, index, args) {
return !ArrayPrototypeIncludes(kFilterArgs, name) &&
!ArrayPrototypeSome(kFilterArgValues, (option) => {
return name === option ||
(option !== '--experimental-config-file' &&
(option !== '--config-file' &&
option !== '--experimental-config-file' &&
index > 0 &&
StringPrototypeIndexOf(args[index - 1], '=') === -1 &&
getOptionName(args[index - 1]) === option);
+2 -1
View File
@@ -113,7 +113,8 @@ function validateChildArgs(childArgs) {
const arg = shiftArg();
if (arg === '--') { break; }
if (!isSynthetic &&
(arg === '--experimental-config-file' ||
(arg === '--config-file' ||
arg === '--experimental-config-file' ||
arg === '--experimental-default-config-file')) {
// ConfigReader rewrites these to an inline default path before parsing.
continue;
+3 -1
View File
@@ -68,7 +68,9 @@ for (let i = 0; i < process.execArgv.length; i++) {
}
continue;
}
if (arg === '--experimental-config-file' ||
if (arg === '--config-file' ||
StringPrototypeStartsWith(arg, '--config-file=') ||
arg === '--experimental-config-file' ||
StringPrototypeStartsWith(arg, '--experimental-config-file=')) {
continue;
}
-8
View File
@@ -135,8 +135,6 @@ function prepareExecution(options) {
initializeSourceMapsHandlers();
initializeDeprecations();
initializeConfigFileSupport();
// internal/dns/utils (and internal/net behind it) is only needed up front
// to validate an explicit --dns-result-order or to register the resolver's
// snapshot serialization; otherwise it is loaded with node:dns.
@@ -490,12 +488,6 @@ function setupOptionGatedBuiltins() {
BuiltinModule.allowOptionGatedBuiltins(getOptionValue);
}
function initializeConfigFileSupport() {
if (getOptionValue('--experimental-config-file')) {
emitExperimentalWarning('--experimental-config-file');
}
}
function setupWebStorage() {
if (getEmbedderOptions().noBrowserGlobals ||
!getOptionValue('--experimental-webstorage')) {
+3 -1
View File
@@ -118,6 +118,7 @@ const kFilterArgValues = [
'--test-reporter',
'--test-reporter-destination',
'--test-random-seed',
'--config-file',
'--experimental-config-file',
];
const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', 'skipped', 'todo', 'duration_ms'];
@@ -194,7 +195,8 @@ function filterExecArgv(arg, i, arr) {
!ArrayPrototypeSome(kFilterArgValues, (p) => {
return arg === p ||
StringPrototypeStartsWith(arg, `${p}=`) ||
(p !== '--experimental-config-file' && i > 0 && arr[i - 1] === p);
(p !== '--config-file' && p !== '--experimental-config-file' &&
i > 0 && arr[i - 1] === p);
});
}
+14 -14
View File
@@ -7,7 +7,10 @@
namespace node {
constexpr std::string_view kConfigFileFlag = "--experimental-config-file";
constexpr std::string_view kConfigFileFlag = "--config-file";
// TODO(marco-ippolito): Remove these aliases in a semver-major.
constexpr std::string_view kExperimentalConfigFileFlag =
"--experimental-config-file";
constexpr std::string_view kDefaultConfigFileFlag =
"--experimental-default-config-file";
constexpr std::string_view kDefaultConfigFileName = "node.config.json";
@@ -26,23 +29,20 @@ std::optional<std::string_view> ConfigReader::GetDataFromArgs(
for (size_t i = 0; i < args->size(); ++i) {
std::string& arg = (*args)[i];
if (arg == kConfigFileFlag) {
// --experimental-config-file
arg = std::string(kConfigFileFlag) + "=" +
std::string(kDefaultConfigFileName);
result = kDefaultConfigFileName;
} else if (HasEqualsPrefix(arg, kConfigFileFlag)) {
// --experimental-config-file=path
std::string_view path =
std::string_view(arg).substr(kConfigFileFlag.size() + 1);
if (!path.empty()) {
result = path;
}
} else if (arg == kDefaultConfigFileFlag) {
if (arg == kConfigFileFlag || arg == kExperimentalConfigFileFlag ||
arg == kDefaultConfigFileFlag) {
// --config-file, --experimental-config-file or
// --experimental-default-config-file
arg = std::string(kConfigFileFlag) + "=" +
std::string(kDefaultConfigFileName);
result = kDefaultConfigFileName;
} else if (HasEqualsPrefix(arg, kConfigFileFlag) ||
HasEqualsPrefix(arg, kExperimentalConfigFileFlag)) {
// --config-file=path or --experimental-config-file=path
std::string_view path = std::string_view(arg).substr(arg.find('=') + 1);
if (!path.empty()) {
result = path;
}
} else if (HasEqualsPrefix(arg, kDefaultConfigFileFlag)) {
invalid_default_config_file_argument_ = true;
}
+1 -1
View File
@@ -23,7 +23,7 @@ namespace node {
enum ParseResult { Valid, FileError, InvalidContent };
// ConfigReader is the class that parses the configuration JSON file.
// It reads the file provided by --experimental-config-file and
// It reads the file provided by --config-file and
// extracts the flags.
class ConfigReader {
public:
+4 -3
View File
@@ -1117,11 +1117,12 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"set environment variables from supplied file",
&EnvironmentOptions::optional_env_file);
Implies("--env-file-if-exists", "[has_env_file_string]");
AddOption("--experimental-config-file",
AddOption("--config-file",
"set config file path",
&EnvironmentOptions::experimental_config_file_path,
&EnvironmentOptions::config_file_path,
kDisallowedInEnvvar);
AddAlias("--experimental-default-config-file", "--experimental-config-file");
AddAlias("--experimental-config-file", "--config-file");
AddAlias("--experimental-default-config-file", "--config-file");
AddOption("--experimental-package-map",
"use the specified file for package map resolution",
&EnvironmentOptions::experimental_package_map_path,
+1 -1
View File
@@ -150,7 +150,7 @@ class EnvironmentOptions : public Options {
std::string watch_mode_kill_signal = "SIGTERM";
std::string eval_string;
std::string tls_keylog;
std::string experimental_config_file_path;
std::string config_file_path;
std::string experimental_package_map_path;
std::string vfs_load_source;
#if HAVE_INSPECTOR
@@ -2,7 +2,7 @@ import { test } from 'node:test';
import { strictEqual } from 'node:assert';
import internal from 'internal/options';
test('it should not receive --experimental-config-file option', () => {
const optionValue = internal.getOptionValue("--experimental-config-file");
test('it should not receive --config-file option', () => {
const optionValue = internal.getOptionValue("--config-file");
strictEqual(optionValue, '');
})
+1 -1
View File
@@ -428,7 +428,7 @@ if (common.hasInspector) {
const result = spawnNode([
'--no-warnings',
'--experimental-bench',
`--experimental-config-file=${fixtures.path('bench-runner/node.config.json')}`,
`--config-file=${fixtures.path('bench-runner/node.config.json')}`,
fixtures.path('bench-runner/a.cjs'),
]);
assert.strictEqual(result.status, 0);
@@ -122,6 +122,5 @@ for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) {
// add alias handling
manPagesOptions.delete('-trace-events-enabled');
manPagesOptions.delete('-experimental-default-config-file');
assert.strictEqual(manPagesOptions.size, 0, `Man page options not documented: ${[...manPagesOptions]}`);
+2 -2
View File
@@ -56,7 +56,7 @@ describe('getOptionsAsFlagsFromBinding', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${configFile}`,
`--config-file=${configFile}`,
fixtureFile,
]);
@@ -75,7 +75,7 @@ describe('getOptionsAsFlagsFromBinding', () => {
'--no-warnings',
'--expose-internals',
'--stack-trace-limit=512',
`--experimental-config-file=${configFile}`,
`--config-file=${configFile}`,
fixtureFile,
]);
+78 -57
View File
@@ -24,7 +24,7 @@ const onlyWithInspectorAndNodeOptions = {
test('should handle non existing json', async () => {
const result = await spawnPromisified(process.execPath, [
'--experimental-config-file=i-do-not-exist.json',
'--config-file=i-do-not-exist.json',
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Cannot read configuration from i-do-not-exist\.json: no such file or directory/);
@@ -35,7 +35,7 @@ test('should handle non existing json', async () => {
test('should handle empty json', async () => {
const result = await spawnPromisified(process.execPath, [
`--experimental-config-file=${fixtures.path('rc/empty.json')}`,
`--config-file=${fixtures.path('rc/empty.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Can't parse/);
@@ -47,7 +47,7 @@ test('should handle empty json', async () => {
test('should handle empty object json', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/empty-object.json')}`,
`--config-file=${fixtures.path('rc/empty-object.json')}`,
'-p', '"Hello, World!"',
]);
assert.strictEqual(result.stderr, '');
@@ -65,7 +65,7 @@ describe('runtime version checks', () => {
return spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${configPath}`,
`--config-file=${configPath}`,
'-p', 'http.maxHeaderSize',
]);
}
@@ -284,17 +284,17 @@ describe('runtime version checks', () => {
test('should parse boolean flag', onlyWithAmaroAndNodeOptions, async () => {
const result = await spawnPromisified(process.execPath, [
`--experimental-config-file=${fixtures.path('rc/strip-types.json')}`,
`--config-file=${fixtures.path('rc/strip-types.json')}`,
fixtures.path('typescript/ts/test-typescript.ts'),
]);
assert.match(result.stderr, /--experimental-config-file is an experimental feature and might change at any time/);
assert.strictEqual(result.stderr, '');
assert.match(result.stdout, /Hello, TypeScript!/);
assert.strictEqual(result.code, 0);
});
test('should parse boolean flag defaulted to true', onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
`--experimental-config-file=${fixtures.path('rc/warnings-false.json')}`,
`--config-file=${fixtures.path('rc/warnings-false.json')}`,
'-p', 'process.emitWarning("A warning")',
]);
assert.strictEqual(result.stderr, '');
@@ -305,7 +305,7 @@ test('should parse boolean flag defaulted to true', onlyIfNodeOptionsSupport, as
test('should throw an error when a flag is declared twice', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/override-property.json')}`,
`--config-file=${fixtures.path('rc/override-property.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Option --strip-types is already defined/);
@@ -316,7 +316,7 @@ test('should throw an error when a flag is declared twice', async () => {
test('should not override env-file', onlyWithAmaroAndNodeOptions, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/strip-types.json')}`,
`--config-file=${fixtures.path('rc/strip-types.json')}`,
'--env-file', fixtures.path('dotenv/node-options-no-tranform.env'),
fixtures.path('typescript/ts/test-typescript.ts'),
]);
@@ -328,7 +328,7 @@ test('should not override env-file', onlyWithAmaroAndNodeOptions, async () => {
test('should not override NODE_OPTIONS', onlyWithAmaro, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/strip-types.json')}`,
`--config-file=${fixtures.path('rc/strip-types.json')}`,
fixtures.path('typescript/ts/test-typescript.ts'),
], {
env: {
@@ -345,7 +345,7 @@ test('should not override CLI flags', onlyWithAmaro, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--no-strip-types',
`--experimental-config-file=${fixtures.path('rc/strip-types.json')}`,
`--config-file=${fixtures.path('rc/strip-types.json')}`,
fixtures.path('typescript/ts/test-typescript.ts'),
]);
assert.match(result.stderr, /SyntaxError/);
@@ -356,7 +356,7 @@ test('should not override CLI flags', onlyWithAmaro, async () => {
test('should parse array flag correctly', onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/import.json')}`,
`--config-file=${fixtures.path('rc/import.json')}`,
'--eval', 'setTimeout(() => console.log("D"),99)',
]);
assert.strictEqual(result.stderr, '');
@@ -367,7 +367,7 @@ test('should parse array flag correctly', onlyIfNodeOptionsSupport, async () =>
test('should validate invalid array flag', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/invalid-import.json')}`,
`--config-file=${fixtures.path('rc/invalid-import.json')}`,
'--eval', 'setTimeout(() => console.log("D"),99)',
]);
assert.match(result.stderr, /invalid-import\.json: invalid content/);
@@ -378,7 +378,7 @@ test('should validate invalid array flag', async () => {
test('should validate array flag as string', onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/import-as-string.json')}`,
`--config-file=${fixtures.path('rc/import-as-string.json')}`,
'--eval', 'setTimeout(() => console.log("B"),99)',
]);
assert.strictEqual(result.stderr, '');
@@ -389,7 +389,7 @@ test('should validate array flag as string', onlyIfNodeOptionsSupport, async ()
test('should throw at unknown flag', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/unknown-flag.json')}`,
`--config-file=${fixtures.path('rc/unknown-flag.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Unknown or not allowed option some-unknown-flag for namespace nodeOptions/);
@@ -400,7 +400,7 @@ test('should throw at unknown flag', async () => {
test('should throw at flag not available in NODE_OPTIONS', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/not-node-options-flag.json')}`,
`--config-file=${fixtures.path('rc/not-node-options-flag.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Unknown or not allowed option test for namespace nodeOptions/);
@@ -411,7 +411,7 @@ test('should throw at flag not available in NODE_OPTIONS', async () => {
test('unsigned flag should be parsed correctly', onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/numeric.json')}`,
`--config-file=${fixtures.path('rc/numeric.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.strictEqual(result.stderr, '');
@@ -422,7 +422,7 @@ test('unsigned flag should be parsed correctly', onlyIfNodeOptionsSupport, async
test('numeric flag should not allow negative values', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/negative-numeric.json')}`,
`--config-file=${fixtures.path('rc/negative-numeric.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.match(result.stderr, /Invalid value for --max-http-header-size/);
@@ -434,7 +434,7 @@ test('numeric flag should not allow negative values', async () => {
test('v8 flag should not be allowed in config file', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/v8-flag.json')}`,
`--config-file=${fixtures.path('rc/v8-flag.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /V8 flag --abort-on-uncaught-exception is currently not supported/);
@@ -446,7 +446,7 @@ test('string flag should be parsed correctly', onlyIfNodeOptionsSupport, async (
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--test',
`--experimental-config-file=${fixtures.path('rc/string.json')}`,
`--config-file=${fixtures.path('rc/string.json')}`,
fixtures.path('rc/test.js'),
]);
assert.strictEqual(result.stderr, '');
@@ -458,7 +458,7 @@ test('host port flag should be parsed correctly', onlyWithInspectorAndNodeOption
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/host-port.json')}`,
`--config-file=${fixtures.path('rc/host-port.json')}`,
'-p', 'require("internal/options").getOptionValue("--inspect-port").port',
]);
assert.strictEqual(result.stderr, '');
@@ -469,7 +469,7 @@ test('host port flag should be parsed correctly', onlyWithInspectorAndNodeOption
test('--inspect=true should be parsed correctly', onlyWithInspectorAndNodeOptions, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/inspect-true.json')}`,
`--config-file=${fixtures.path('rc/inspect-true.json')}`,
'--inspect-port', '0',
'-p', 'require("node:inspector").url()',
]);
@@ -481,7 +481,7 @@ test('--inspect=true should be parsed correctly', onlyWithInspectorAndNodeOption
test('--inspect=false should be parsed correctly', { skip: !process.features.inspector }, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/inspect-false.json')}`,
`--config-file=${fixtures.path('rc/inspect-false.json')}`,
'-p', 'require("node:inspector").url()',
]);
assert.strictEqual(result.stderr, '');
@@ -492,7 +492,7 @@ test('--inspect=false should be parsed correctly', { skip: !process.features.ins
test('no op flag should throw', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/no-op.json')}`,
`--config-file=${fixtures.path('rc/no-op.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /No-op flag --http-parser is currently not supported/);
@@ -504,7 +504,7 @@ test('no op flag should throw', async () => {
test('should not allow users to sneak in a flag', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/sneaky-flag.json')}`,
`--config-file=${fixtures.path('rc/sneaky-flag.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /The number of NODE_OPTIONS doesn't match the number of flags in the config file/);
@@ -515,7 +515,7 @@ test('should not allow users to sneak in a flag', async () => {
test('non object root', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/non-object-root.json')}`,
`--config-file=${fixtures.path('rc/non-object-root.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Root value unexpected not an object for/);
@@ -526,7 +526,7 @@ test('non object root', async () => {
test('non object node options', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/non-object-node-options.json')}`,
`--config-file=${fixtures.path('rc/non-object-node-options.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /"nodeOptions" value unexpected for/);
@@ -537,7 +537,7 @@ test('non object node options', async () => {
test('should throw correct error when a json is broken', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/broken.json')}`,
`--config-file=${fixtures.path('rc/broken.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Can't parse/);
@@ -549,7 +549,7 @@ test('should throw correct error when a json is broken', async () => {
test('broken value in node_options', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/broken-node-options.json')}`,
`--config-file=${fixtures.path('rc/broken-node-options.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Can't parse/);
@@ -571,11 +571,11 @@ test('should use node.config.json as default', onlyIfNodeOptionsSupport, async (
assert.strictEqual(result.code, 0);
});
test('should use node.config.json when --experimental-config-file has no argument',
test('should use node.config.json when --config-file has no argument',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-config-file',
'--config-file',
'-p', 'http.maxHeaderSize',
], {
cwd: fixtures.path('rc/default'),
@@ -589,7 +589,7 @@ test('should not treat the script path as a config file argument',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-config-file',
'--config-file',
fixtures.path('printA.js'),
], {
cwd: fixtures.path('rc/default'),
@@ -603,7 +603,7 @@ test('should treat a space-separated config file path as the script',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-config-file',
'--config-file',
fixtures.path('rc/empty.json'),
fixtures.path('printA.js'),
], {
@@ -617,16 +617,16 @@ test('should treat a space-separated config file path as the script',
assert.strictEqual(result.code, 1);
});
test('should error when --experimental-config-file= has empty argument',
test('should error when --config-file= has empty argument',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-config-file=',
'--config-file=',
'-p', 'http.maxHeaderSize',
], {
cwd: fixtures.path('rc/default'),
});
assert.match(result.stderr, /--experimental-config-file= requires an argument/);
assert.match(result.stderr, /--config-file= requires an argument/);
assert.strictEqual(result.code, 9);
});
@@ -647,7 +647,7 @@ test('should override node.config.json when specified', onlyIfNodeOptionsSupport
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-default-config-file',
`--experimental-config-file=${fixtures.path('rc/default/override.json')}`,
`--config-file=${fixtures.path('rc/default/override.json')}`,
'-p', 'http.maxHeaderSize',
], {
cwd: fixtures.path('rc/default'),
@@ -657,11 +657,11 @@ test('should override node.config.json when specified', onlyIfNodeOptionsSupport
assert.strictEqual(result.code, 0);
});
test('should work with --experimental-config-file=path',
test('should work with --config-file=path',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/default/node.config.json')}`,
`--config-file=${fixtures.path('rc/default/node.config.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.strictEqual(result.stderr, '');
@@ -669,12 +669,33 @@ test('should work with --experimental-config-file=path',
assert.strictEqual(result.code, 0);
});
test('should support the --experimental-config-file alias',
onlyIfNodeOptionsSupport, async () => {
const withPath = await spawnPromisified(process.execPath, [
`--experimental-config-file=${fixtures.path('rc/default/node.config.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.strictEqual(withPath.stderr, '');
assert.strictEqual(withPath.stdout, '10\n');
assert.strictEqual(withPath.code, 0);
const withoutPath = await spawnPromisified(process.execPath, [
'--experimental-config-file',
'-p', 'http.maxHeaderSize',
], {
cwd: fixtures.path('rc/default'),
});
assert.strictEqual(withoutPath.stderr, '');
assert.strictEqual(withoutPath.stdout, '10\n');
assert.strictEqual(withoutPath.code, 0);
});
test('should use last config file when multiple are specified',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/default/node.config.json')}`,
`--experimental-config-file=${fixtures.path('rc/default/override.json')}`,
`--config-file=${fixtures.path('rc/default/node.config.json')}`,
`--config-file=${fixtures.path('rc/default/override.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.strictEqual(result.stderr, '');
@@ -686,7 +707,7 @@ test('should use default when next argument starts with dash',
onlyIfNodeOptionsSupport, async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--experimental-config-file',
'--config-file',
'-p', 'http.maxHeaderSize',
], {
cwd: fixtures.path('rc/default'),
@@ -724,7 +745,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
`--config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
'--no-test',
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
]);
@@ -736,7 +757,7 @@ describe('namespace-scoped options', () => {
it('should throw an error when a namespace-scoped option is not recognised', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/unknown-flag-namespace.json')}`,
`--config-file=${fixtures.path('rc/unknown-flag-namespace.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Unknown or not allowed option unknown-flag for namespace test/);
@@ -747,7 +768,7 @@ describe('namespace-scoped options', () => {
it('should throw an error when a namespace is not recognised', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/unknown-namespace.json')}`,
`--config-file=${fixtures.path('rc/unknown-namespace.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /Unknown namespace an-invalid-namespace/);
@@ -759,7 +780,7 @@ describe('namespace-scoped options', () => {
it('should allow the $schema field', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/schema.json')}`,
`--config-file=${fixtures.path('rc/schema.json')}`,
'-p', 'http.maxHeaderSize',
]);
assert.strictEqual(result.stderr, '');
@@ -770,7 +791,7 @@ describe('namespace-scoped options', () => {
it('should handle an empty namespace valid namespace', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/empty-valid-namespace.json')}`,
`--config-file=${fixtures.path('rc/empty-valid-namespace.json')}`,
'-p', '"Hello, World!"',
]);
assert.strictEqual(result.stderr, '');
@@ -782,7 +803,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/override-node-option-with-namespace.json')}`,
`--config-file=${fixtures.path('rc/override-node-option-with-namespace.json')}`,
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
]);
assert.match(result.stderr, /Option --test-isolation is already defined/);
@@ -794,7 +815,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/override-namespace.json')}`,
`--config-file=${fixtures.path('rc/override-namespace.json')}`,
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
]);
assert.match(result.stderr, /Option --test-isolation is already defined/);
@@ -807,7 +828,7 @@ describe('namespace-scoped options', () => {
'--no-warnings',
'--expose-internals',
'--test-isolation', 'process',
`--experimental-config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
`--config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
'--no-test',
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
]);
@@ -822,7 +843,7 @@ describe('namespace-scoped options', () => {
'--expose-internals',
'--test-coverage-exclude', 'cli-pattern1',
'--test-coverage-exclude', 'cli-pattern2',
`--experimental-config-file=${fixtures.path('rc/namespace-with-array.json')}`,
`--config-file=${fixtures.path('rc/namespace-with-array.json')}`,
'--no-test',
'-p', 'JSON.stringify(require("internal/options").getOptionValue("--test-coverage-exclude"))',
]);
@@ -844,7 +865,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/namespace-with-disallowed-envvar.json')}`,
`--config-file=${fixtures.path('rc/namespace-with-disallowed-envvar.json')}`,
'--no-test',
'-p', 'require("internal/options").getOptionValue("--test-concurrency")',
]);
@@ -860,7 +881,7 @@ describe('namespace-scoped options', () => {
'--no-warnings',
'--expose-internals',
'--test-concurrency', '2',
`--experimental-config-file=${fixtures.path('rc/namespace-with-disallowed-envvar.json')}`,
`--config-file=${fixtures.path('rc/namespace-with-disallowed-envvar.json')}`,
'--no-test',
'-p', 'require("internal/options").getOptionValue("--test-concurrency")',
]);
@@ -872,7 +893,7 @@ describe('namespace-scoped options', () => {
it('should throw an error for removed "testRunner" namespace', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/deprecated-testrunner-namespace.json')}`,
`--config-file=${fixtures.path('rc/deprecated-testrunner-namespace.json')}`,
'-p', '"Hello, World!"',
]);
assert.match(result.stderr, /the "testRunner" namespace has been removed\. Use "test" instead\./);
@@ -883,7 +904,7 @@ describe('namespace-scoped options', () => {
it('should automatically enable --test flag when test namespace is present', async () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
`--experimental-config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
`--config-file=${fixtures.path('rc/namespaced/node.config.json')}`,
fixtures.path('rc/test.js'),
]);
assert.strictEqual(result.code, 0);
@@ -894,7 +915,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/permission-namespace.json')}`,
`--config-file=${fixtures.path('rc/permission-namespace.json')}`,
'-p', 'require("internal/options").getOptionValue("--permission")',
]);
assert.strictEqual(result.stderr, '');
@@ -906,7 +927,7 @@ describe('namespace-scoped options', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${fixtures.path('rc/test-namespace-explicit-false.json')}`,
`--config-file=${fixtures.path('rc/test-namespace-explicit-false.json')}`,
'-p', 'require("internal/options").getOptionValue("--test")',
]);
assert.strictEqual(result.stderr, '');
@@ -120,6 +120,14 @@ assertSuccessfulProbe([
// ConfigReader rewrites these bare options to use the default path without
// consuming the following argument.
Promise.all([
assert.rejects(
launchChildProcess([
'--config-file',
'--no-inspect-brk',
'probe.js',
], '127.0.0.1', 0, () => {}),
incompatibleInspectBrk,
),
assert.rejects(
launchChildProcess([
'--experimental-config-file',
@@ -13,7 +13,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${readOnlyConfigPath}`,
`--config-file=${readOnlyConfigPath}`,
readTestPath,
]);
assert.strictEqual(result.code, 0);
@@ -22,7 +22,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${readWriteConfigPath}`,
`--config-file=${readWriteConfigPath}`,
writeTestPath,
]);
assert.strictEqual(result.code, 0);
@@ -31,7 +31,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${readOnlyConfigPath}`,
`--config-file=${readOnlyConfigPath}`,
writeTestPath,
]);
assert.strictEqual(result.code, 1);
@@ -47,7 +47,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${configPath}`,
`--config-file=${configPath}`,
childTestPath,
]);
assert.strictEqual(result.code, 0);
@@ -56,7 +56,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${readOnlyConfigPath}`,
`--config-file=${readOnlyConfigPath}`,
childTestPath,
]);
assert.strictEqual(result.code, 1, result.stderr);
@@ -71,7 +71,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${configPath}`,
`--config-file=${configPath}`,
'-p',
'process.permission.has("net") && process.permission.has("inspector")',
]);
@@ -82,7 +82,7 @@ describe('Permission model config file support', () => {
{
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${readOnlyConfigPath}`,
`--config-file=${readOnlyConfigPath}`,
'-p',
'process.permission.has("net") + process.permission.has("inspector")',
]);
@@ -96,7 +96,7 @@ describe('Permission model config file support', () => {
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${configPath}`,
`--config-file=${configPath}`,
'--allow-fs-read=*',
'-p',
'process.permission.has("addon") && process.permission.has("wasi")',
@@ -110,7 +110,7 @@ describe('Permission model config file support', () => {
const result = await spawnPromisified(process.execPath, [
'--permission',
`--experimental-config-file=${configPath}`,
`--config-file=${configPath}`,
'--allow-child-process',
'--allow-fs-write=*',
'-p',
@@ -58,19 +58,19 @@ assert.deepStrictEqual(
visible([
'--permission',
'--allow-env=PERMISSION_ENV_A',
`--experimental-config-file=${bothConfig}`,
`--config-file=${bothConfig}`,
]),
['PERMISSION_ENV_A']);
assert.deepStrictEqual(
visible(['--permission', `--experimental-config-file=${allConfig}`]),
visible(['--permission', `--config-file=${allConfig}`]),
[]);
assert.deepStrictEqual(
visible([
'--permission',
'--allow-env=PERMISSION_ENV_PREFIX_*',
`--experimental-config-file=${prefixConfig}`,
`--config-file=${prefixConfig}`,
]),
['PERMISSION_ENV_PREFIX_DB_URL']);
@@ -86,7 +86,7 @@ assert.deepStrictEqual(
// When only the configuration file enables the permission model, its
// --allow-env values apply.
assert.deepStrictEqual(
visible([`--experimental-config-file=${bothConfig}`]),
visible([`--config-file=${bothConfig}`]),
['PERMISSION_ENV_A', 'PERMISSION_ENV_B']);
// The NODE_OPTIONS environment variable is not a file, and can grant access.
+3 -1
View File
@@ -454,6 +454,8 @@ for (const isolation of ['none', 'process']) {
// Should not propagate config file options to sub tests in isolation process.
const fixturePath = join(testFixtures, 'options-propagation');
const configFlagVariants = [
['--config-file=node.config.json'],
['--config-file'],
['--experimental-config-file=node.config.json'],
['--experimental-config-file'],
['--experimental-default-config-file'],
@@ -492,7 +494,7 @@ for (const isolation of ['none', 'process']) {
const args = [
'--test-reporter=tap',
'--no-warnings',
`--experimental-config-file=node.config.json`,
`--config-file=node.config.json`,
'--expose-internals',
'--test',
];
@@ -15,9 +15,11 @@ const runner = path.join(fixtureDir, 'runner.mjs');
describe('test runner flag propagation', () => {
describe('via command line', () => {
const flagPropagationTests = [
['--experimental-config-file=node.config.json', '', '', '--experimental-config-file',
['--config-file=node.config.json', '', '', '--config-file',
'should not propagate --config-file to child tests'],
['--experimental-config-file=node.config.json', '', '', '--config-file',
'should not propagate --experimental-config-file to child tests'],
['--experimental-default-config-file', '', '', '--experimental-config-file',
['--experimental-default-config-file', '', '', '--config-file',
'should not propagate --experimental-default-config-file to child tests'],
['--env-file', '.env', '.env'],
['--env-file-if-exists', '.env', '.env'],
@@ -108,7 +110,7 @@ describe('test runner flag propagation', () => {
'--test-reporter=tap',
'--no-warnings',
'--expose-internals',
`--experimental-config-file=${configFile}`,
`--config-file=${configFile}`,
runner,
`--flag=${flagName}`,
`--expected=${expectedValue}`,
+3 -3
View File
@@ -874,7 +874,7 @@ process.on('message', (message) => {
const file = createTmpFile();
const configFile = createTmpFile(JSON.stringify({ watch: { 'watch': true } }), '.json');
const { stderr, stdout } = await runWriteSucceed({
file, watchedFile: file, args: [`--experimental-config-file=${configFile}`, file], options: {
file, watchedFile: file, args: [`--config-file=${configFile}`, file], options: {
timeout: 10000,
},
});
@@ -899,7 +899,7 @@ process.on('message', (message) => {
const watchedFile = createTmpFile('', '.js', dir);
const configFile = createTmpFile(JSON.stringify({ watch: { 'watch-path': [dir] } }), '.json', dir);
const args = [`--experimental-config-file=${configFile}`, file];
const args = [`--config-file=${configFile}`, file];
const { stderr, stdout } = await runWriteSucceed({ file, watchedFile, args });
assert.strictEqual(stderr, '');
@@ -924,7 +924,7 @@ process.on('message', (message) => {
const { stderr, stdout } = await runWriteSucceed({
file,
watchedFile: file,
args: ['--experimental-default-config-file', file],
args: ['--config-file', file],
options: {
timeout: 10000,
cwd: dir,