Skip to content

Commit c29e5ac

Browse files
addaleaxtargos
authored andcommitted
cli: normalize _- when parsing options
This allows for option syntax similar to V8’s one, e.g. `--no_warnings` has the same effect as `--no-warnings`. PR-URL: #23020 Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: Trivikram Kamat <[email protected]>
1 parent 66484b8 commit c29e5ac

8 files changed

+45
-58
lines changed

doc/api/cli.md

+12-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ Execute without arguments to start the [REPL][].
2121
_For more info about `node inspect`, please see the [debugger][] documentation._
2222

2323
## Options
24+
<!-- YAML
25+
changes:
26+
- version: REPLACEME
27+
pr-url: https://github.com/nodejs/node/pull/23020
28+
description: Underscores instead of dashes are now allowed for
29+
Node.js options as well, in addition to V8 options.
30+
-->
31+
32+
All options, including V8 options, allow words to be separated by both
33+
dashes (`-`) or underscores (`_`).
34+
35+
For example, `--pending-deprecation` is equivalent to `--pending_deprecation`.
2436

2537
### `-`
2638
<!-- YAML
@@ -390,11 +402,6 @@ added: v0.1.3
390402

391403
Print V8 command line options.
392404

393-
V8 options allow words to be separated by both dashes (`-`) or
394-
underscores (`_`).
395-
396-
For example, `--stack-trace-limit` is equivalent to `--stack_trace_limit`.
397-
398405
### `--v8-pool-size=num`
399406
<!-- YAML
400407
added: v5.10.0

lib/internal/bootstrap/node.js

+12-31
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@
616616
// This builds process.allowedNodeEnvironmentFlags
617617
// from data in the config binding
618618

619-
const replaceDashesRegex = /-/g;
619+
const replaceUnderscoresRegex = /_/g;
620620
const leadingDashesRegex = /^--?/;
621621
const trailingValuesRegex = /=.*$/;
622622

@@ -628,20 +628,14 @@
628628
const get = () => {
629629
const {
630630
getOptions,
631-
types: { kV8Option },
632631
envSettings: { kAllowedInEnvironment }
633632
} = internalBinding('options');
634633
const { options, aliases } = getOptions();
635634

636-
const allowedV8EnvironmentFlags = [];
637635
const allowedNodeEnvironmentFlags = [];
638636
for (const [name, info] of options) {
639637
if (info.envVarSettings === kAllowedInEnvironment) {
640-
if (info.type === kV8Option) {
641-
allowedV8EnvironmentFlags.push(name);
642-
} else {
643-
allowedNodeEnvironmentFlags.push(name);
644-
}
638+
allowedNodeEnvironmentFlags.push(name);
645639
}
646640
}
647641

@@ -675,11 +669,9 @@
675669
// process.allowedNodeEnvironmentFlags.has() which lack leading dashes.
676670
// Avoid interference w/ user code by flattening `Set.prototype` into
677671
// each object.
678-
const [nodeFlags, v8Flags] = [
679-
allowedNodeEnvironmentFlags, allowedV8EnvironmentFlags
680-
].map((flags) => Object.defineProperties(
681-
new Set(flags.map(trimLeadingDashes)),
682-
Object.getOwnPropertyDescriptors(Set.prototype))
672+
const nodeFlags = Object.defineProperties(
673+
new Set(allowedNodeEnvironmentFlags.map(trimLeadingDashes)),
674+
Object.getOwnPropertyDescriptors(Set.prototype)
683675
);
684676

685677
class NodeEnvironmentFlagsSet extends Set {
@@ -703,29 +695,18 @@
703695
has(key) {
704696
// This will return `true` based on various possible
705697
// permutations of a flag, including present/missing leading
706-
// dash(es) and/or underscores-for-dashes in the case of V8-specific
707-
// flags. Strips any values after `=`, inclusive.
698+
// dash(es) and/or underscores-for-dashes.
699+
// Strips any values after `=`, inclusive.
708700
// TODO(addaleax): It might be more flexible to run the option parser
709701
// on a dummy option set and see whether it rejects the argument or
710702
// not.
711703
if (typeof key === 'string') {
712-
key = replace(key, trailingValuesRegex, '');
704+
key = replace(key, replaceUnderscoresRegex, '-');
713705
if (test(leadingDashesRegex, key)) {
714-
return has(this, key) ||
715-
has(v8Flags,
716-
replace(
717-
replace(
718-
key,
719-
leadingDashesRegex,
720-
''
721-
),
722-
replaceDashesRegex,
723-
'_'
724-
)
725-
);
706+
key = replace(key, trailingValuesRegex, '');
707+
return has(this, key);
726708
}
727-
return has(nodeFlags, key) ||
728-
has(v8Flags, replace(key, replaceDashesRegex, '_'));
709+
return has(nodeFlags, key);
729710
}
730711
return false;
731712
}
@@ -736,7 +717,7 @@
736717

737718
return process.allowedNodeEnvironmentFlags = Object.freeze(
738719
new NodeEnvironmentFlagsSet(
739-
allowedNodeEnvironmentFlags.concat(allowedV8EnvironmentFlags)
720+
allowedNodeEnvironmentFlags
740721
));
741722
};
742723

src/node_options-inl.h

+6-13
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,12 @@ void OptionsParser<Options>::Parse(
307307
if (equals_index != std::string::npos)
308308
original_name += '=';
309309

310+
// Normalize by replacing `_` with `-` in options.
311+
for (std::string::size_type i = 2; i < name.size(); ++i) {
312+
if (name[i] == '_')
313+
name[i] = '-';
314+
}
315+
310316
{
311317
auto it = aliases_.end();
312318
// Expand aliases:
@@ -341,19 +347,6 @@ void OptionsParser<Options>::Parse(
341347

342348
auto it = options_.find(name);
343349

344-
if (it == options_.end()) {
345-
// We would assume that this is a V8 option if neither we nor any child
346-
// parser knows about it, so we convert - to _ for
347-
// canonicalization (since V8 accepts both) and look up again in order
348-
// to find a match.
349-
// TODO(addaleax): Make the canonicalization unconditional, i.e. allow
350-
// both - and _ in Node's own options as well.
351-
std::string::size_type index = 2; // Start after initial '--'.
352-
while ((index = name.find('-', index + 1)) != std::string::npos)
353-
name[index] = '_';
354-
it = options_.find(name);
355-
}
356-
357350
if ((it == options_.end() ||
358351
it->second.env_setting == kDisallowedInEnvironment) &&
359352
required_env_settings == kAllowedInEnvironment) {

src/node_options.cc

+5-7
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
102102
&EnvironmentOptions::experimental_worker,
103103
kAllowedInEnvironment);
104104
AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals);
105-
// TODO(addaleax): Remove this when adding -/_ canonicalization to the parser.
106-
AddAlias("--expose_internals", "--expose-internals");
107105
AddOption("--loader",
108106
"(with --experimental-modules) use the specified file as a "
109107
"custom loader",
@@ -206,15 +204,15 @@ PerIsolateOptionsParser::PerIsolateOptionsParser() {
206204
kAllowedInEnvironment);
207205

208206
// Explicitly add some V8 flags to mark them as allowed in NODE_OPTIONS.
209-
AddOption("--abort_on_uncaught_exception",
207+
AddOption("--abort-on-uncaught-exception",
210208
"aborting instead of exiting causes a core file to be generated "
211209
"for analysis",
212210
V8Option{},
213211
kAllowedInEnvironment);
214-
AddOption("--max_old_space_size", "", V8Option{}, kAllowedInEnvironment);
215-
AddOption("--perf_basic_prof", "", V8Option{}, kAllowedInEnvironment);
216-
AddOption("--perf_prof", "", V8Option{}, kAllowedInEnvironment);
217-
AddOption("--stack_trace_limit", "", V8Option{}, kAllowedInEnvironment);
212+
AddOption("--max-old-space-size", "", V8Option{}, kAllowedInEnvironment);
213+
AddOption("--perf-basic-prof", "", V8Option{}, kAllowedInEnvironment);
214+
AddOption("--perf-prof", "", V8Option{}, kAllowedInEnvironment);
215+
AddOption("--stack-trace-limit", "", V8Option{}, kAllowedInEnvironment);
218216

219217
Insert(&EnvironmentOptionsParser::instance,
220218
&PerIsolateOptions::get_per_env_options);

test/parallel/test-cli-node-options-disallowed.js

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ disallow('--interactive');
2929
disallow('-i');
3030
disallow('--v8-options');
3131
disallow('--');
32-
disallow('--no_warnings'); // Node options don't allow '_' instead of '-'.
3332

3433
function disallow(opt) {
3534
const env = Object.assign({}, process.env, { NODE_OPTIONS: opt });

test/parallel/test-cli-node-options.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ expect(`-r ${printA}`, 'A\nB\n');
1919
expect(`-r ${printA} -r ${printA}`, 'A\nB\n');
2020
expect('--no-deprecation', 'B\n');
2121
expect('--no-warnings', 'B\n');
22+
expect('--no_warnings', 'B\n');
2223
expect('--trace-warnings', 'B\n');
2324
expect('--redirect-warnings=_', 'B\n');
2425
expect('--trace-deprecation', 'B\n');

test/parallel/test-pending-deprecation.js

+8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ switch (process.argv[2]) {
3636
assert.strictEqual(code, 0, message('--pending-deprecation'));
3737
}));
3838

39+
// Test the --pending_deprecation command line switch.
40+
fork(__filename, ['switch'], {
41+
execArgv: ['--pending_deprecation'],
42+
silent: true
43+
}).on('exit', common.mustCall((code) => {
44+
assert.strictEqual(code, 0, message('--pending_deprecation'));
45+
}));
46+
3947
// Test the NODE_PENDING_DEPRECATION environment var.
4048
fork(__filename, ['env'], {
4149
env: Object.assign({}, process.env, { NODE_PENDING_DEPRECATION: 1 }),

test/parallel/test-process-env-allowed-flags.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ require('../common');
1919
].concat(process.config.variables.v8_enable_inspector ? [
2020
'--inspect-brk',
2121
'inspect-brk',
22+
'--inspect_brk',
2223
] : []);
2324

2425
const badFlags = [
25-
'--inspect_brk',
2626
'INSPECT-BRK',
2727
'--INSPECT-BRK',
2828
'--r',

0 commit comments

Comments
 (0)