mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
src: implicitly enable namespace in config
PR-URL: https://github.com/nodejs/node/pull/60798 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
parent
49e56bfc55
commit
1758b74829
@ -1029,7 +1029,40 @@ The configuration file supports namespace-specific options:
|
||||
|
||||
* The `nodeOptions` field contains CLI flags that are allowed in [`NODE_OPTIONS`][].
|
||||
|
||||
* Namespace fields like `test` contain configuration specific to that subsystem.
|
||||
* Namespace fields like `test`, `watch`, and `permission` contain configuration specific to that subsystem.
|
||||
|
||||
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.
|
||||
|
||||
@ -175,10 +175,11 @@ Example `node.config.json`:
|
||||
}
|
||||
```
|
||||
|
||||
Run with the configuration file:
|
||||
When the `permission` namespace is present in the configuration file, Node.js
|
||||
automatically enables the `--permission` flag. Run with:
|
||||
|
||||
```console
|
||||
$ node --permission --experimental-default-config-file app.js
|
||||
$ node --experimental-default-config-file app.js
|
||||
```
|
||||
|
||||
#### Using the Permission Model with `npx`
|
||||
|
||||
@ -255,6 +255,9 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
|
||||
available_namespaces.end());
|
||||
// Create a set to track unique options
|
||||
std::unordered_set<std::string> unique_options;
|
||||
// Namespaces in OPTION_NAMESPACE_LIST
|
||||
std::unordered_set<std::string> namespaces_with_implicit_flags;
|
||||
|
||||
// Iterate through the main object to find all namespaces
|
||||
for (auto field : main_object) {
|
||||
std::string_view field_name;
|
||||
@ -281,6 +284,15 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// List of implicit namespace flags
|
||||
for (auto ns_enum : options_parser::AllNamespaces()) {
|
||||
std::string ns_str = options_parser::NamespaceEnumToString(ns_enum);
|
||||
if (!ns_str.empty() && namespace_name == ns_str) {
|
||||
namespaces_with_implicit_flags.insert(namespace_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the namespace object
|
||||
simdjson::ondemand::object namespace_object;
|
||||
auto field_error = field.value().get_object().get(namespace_object);
|
||||
@ -302,6 +314,17 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add implicit flags for namespaces (--test, --permission, --watch)
|
||||
// These flags are automatically enabled when their namespace is present
|
||||
for (const auto& ns : namespaces_with_implicit_flags) {
|
||||
std::string flag = "--" + ns;
|
||||
std::string no_flag = "--no-" + ns;
|
||||
// We skip if the user has already set the flag or its negation
|
||||
if (!unique_options.contains(flag) && !unique_options.contains(no_flag)) {
|
||||
namespace_options_.push_back(flag);
|
||||
}
|
||||
}
|
||||
|
||||
return ParseResult::Valid;
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"max-http-header-size": 8192
|
||||
},
|
||||
"test": {
|
||||
"test": false,
|
||||
"test-isolation": "none"
|
||||
}
|
||||
}
|
||||
|
||||
2
test/fixtures/rc/empty-valid-namespace.json
vendored
2
test/fixtures/rc/empty-valid-namespace.json
vendored
@ -1,3 +1,3 @@
|
||||
{
|
||||
"test": {}
|
||||
"permission": {}
|
||||
}
|
||||
|
||||
5
test/fixtures/rc/permission-namespace.json
vendored
Normal file
5
test/fixtures/rc/permission-namespace.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"permission": {
|
||||
"allow-fs-read": "*"
|
||||
}
|
||||
}
|
||||
6
test/fixtures/rc/test-namespace-explicit-false.json
vendored
Normal file
6
test/fixtures/rc/test-namespace-explicit-false.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"test": {
|
||||
"test": false,
|
||||
"test-isolation": "none"
|
||||
}
|
||||
}
|
||||
5
test/fixtures/rc/watch-namespace.json
vendored
Normal file
5
test/fixtures/rc/watch-namespace.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"watch": {
|
||||
"watch-preserve-output": true
|
||||
}
|
||||
}
|
||||
@ -407,6 +407,7 @@ describe('namespace-scoped options', () => {
|
||||
'--expose-internals',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/namespaced/node.config.json'),
|
||||
'--no-test',
|
||||
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
@ -483,6 +484,7 @@ describe('namespace-scoped options', () => {
|
||||
'--test-isolation', 'process',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/namespaced/node.config.json'),
|
||||
'--no-test',
|
||||
'-p', 'require("internal/options").getOptionValue("--test-isolation")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
@ -498,6 +500,7 @@ describe('namespace-scoped options', () => {
|
||||
'--test-coverage-exclude', 'cli-pattern2',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/namespace-with-array.json'),
|
||||
'--no-test',
|
||||
'-p', 'JSON.stringify(require("internal/options").getOptionValue("--test-coverage-exclude"))',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
@ -520,6 +523,7 @@ describe('namespace-scoped options', () => {
|
||||
'--expose-internals',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/namespace-with-disallowed-envvar.json'),
|
||||
'--no-test',
|
||||
'-p', 'require("internal/options").getOptionValue("--test-concurrency")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
@ -536,6 +540,7 @@ describe('namespace-scoped options', () => {
|
||||
'--test-concurrency', '2',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/namespace-with-disallowed-envvar.json'),
|
||||
'--no-test',
|
||||
'-p', 'require("internal/options").getOptionValue("--test-concurrency")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
@ -554,4 +559,41 @@ describe('namespace-scoped options', () => {
|
||||
assert.strictEqual(result.stdout, '');
|
||||
assert.strictEqual(result.code, 9);
|
||||
});
|
||||
|
||||
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'),
|
||||
fixtures.path('rc/test.js'),
|
||||
]);
|
||||
assert.strictEqual(result.code, 0);
|
||||
assert.match(result.stdout, /tests 1/);
|
||||
});
|
||||
|
||||
it('should automatically enable --permission flag when permission namespace is present', async () => {
|
||||
const result = await spawnPromisified(process.execPath, [
|
||||
'--no-warnings',
|
||||
'--expose-internals',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/permission-namespace.json'),
|
||||
'-p', 'require("internal/options").getOptionValue("--permission")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
assert.strictEqual(result.stdout, 'true\n');
|
||||
assert.strictEqual(result.code, 0);
|
||||
});
|
||||
|
||||
it('should respect explicit test: false in test namespace', async () => {
|
||||
const result = await spawnPromisified(process.execPath, [
|
||||
'--no-warnings',
|
||||
'--expose-internals',
|
||||
'--experimental-config-file',
|
||||
fixtures.path('rc/test-namespace-explicit-false.json'),
|
||||
'-p', 'require("internal/options").getOptionValue("--test")',
|
||||
]);
|
||||
assert.strictEqual(result.stderr, '');
|
||||
assert.strictEqual(result.stdout, 'false\n');
|
||||
assert.strictEqual(result.code, 0);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user