Skip to content

Commit a1e122b

Browse files
bcoetargos
authored andcommitted
util: add parseArgs module
Adds util.parseArgs helper for higher level command-line argument parsing. PR-URL: #42675 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Ruy Adorno <[email protected]> Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Joe Sepi <[email protected]> Reviewed-By: Ian Sutherland <[email protected]>
1 parent a6d4d31 commit a1e122b

File tree

9 files changed

+1190
-1
lines changed

9 files changed

+1190
-1
lines changed

doc/api/errors.md

+35
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,40 @@ The `package.json` [`"exports"`][] field does not export the requested subpath.
23342334
Because exports are encapsulated, private internal modules that are not exported
23352335
cannot be imported through the package resolution, unless using an absolute URL.
23362336

2337+
<a id="ERR_PARSE_ARGS_INVALID_OPTION_VALUE"></a>
2338+
2339+
### `ERR_PARSE_ARGS_INVALID_OPTION_VALUE`
2340+
2341+
<!-- YAML
2342+
added: REPLACEME
2343+
-->
2344+
2345+
When `strict` set to `true`, thrown by [`util.parseArgs()`][] if a {boolean}
2346+
value is provided for an option of type {string}, or if a {string}
2347+
value is provided for an option of type {boolean}.
2348+
2349+
<a id="ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL"></a>
2350+
2351+
### `ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL`
2352+
2353+
<!-- YAML
2354+
added: REPLACEME
2355+
-->
2356+
2357+
Thrown by [`util.parseArgs()`][], when a postional argument is provided and
2358+
`allowPositionals` is set to `false`.
2359+
2360+
<a id="ERR_PARSE_ARGS_UNKNOWN_OPTION"></a>
2361+
2362+
### `ERR_PARSE_ARGS_UNKNOWN_OPTION`
2363+
2364+
<!-- YAML
2365+
added: REPLACEME
2366+
-->
2367+
2368+
When `strict` set to `true`, thrown by [`util.parseArgs()`][] if an argument
2369+
is not configured in `options`.
2370+
23372371
<a id="ERR_PERFORMANCE_INVALID_TIMESTAMP"></a>
23382372

23392373
### `ERR_PERFORMANCE_INVALID_TIMESTAMP`
@@ -3425,6 +3459,7 @@ The native call from `process.cpuUsage` could not be processed.
34253459
[`subprocess.kill()`]: child_process.md#subprocesskillsignal
34263460
[`subprocess.send()`]: child_process.md#subprocesssendmessage-sendhandle-options-callback
34273461
[`util.getSystemErrorName(error.errno)`]: util.md#utilgetsystemerrornameerr
3462+
[`util.parseArgs()`]: util.md#utilparseargsconfig
34283463
[`zlib`]: zlib.md
34293464
[crypto digest algorithm]: crypto.md#cryptogethashes
34303465
[debugger]: debugger.md

doc/api/util.md

+81
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,86 @@ Otherwise, returns `false`.
10141014
See [`assert.deepStrictEqual()`][] for more information about deep strict
10151015
equality.
10161016

1017+
## `util.parseArgs([config])`
1018+
1019+
<!-- YAML
1020+
added: REPLACEME
1021+
-->
1022+
1023+
> Stability: 1 - Experimental
1024+
1025+
* `config` {Object} Used to provide arguments for parsing and to configure
1026+
the parser. `config` supports the following properties:
1027+
* `args` {string\[]} array of argument strings. **Default:** `process.argv`
1028+
with `execPath` and `filename` removed.
1029+
* `options` {Object} Used to describe arguments known to the parser.
1030+
Keys of `options` are the long names of options and values are an
1031+
{Object} accepting the following properties:
1032+
* `type` {string} Type of argument, which must be either `boolean` or `string`.
1033+
* `multiple` {boolean} Whether this option can be provided multiple
1034+
times. If `true`, all values will be collected in an array. If
1035+
`false`, values for the option are last-wins. **Default:** `false`.
1036+
* `short` {string} A single character alias for the option.
1037+
* `strict`: {boolean} Should an error be thrown when unknown arguments
1038+
are encountered, or when arguments are passed that do not match the
1039+
`type` configured in `options`.
1040+
**Default:** `true`.
1041+
* `allowPositionals`: {boolean} Whether this command accepts positional
1042+
arguments.
1043+
**Default:** `false` if `strict` is `true`, otherwise `true`.
1044+
1045+
* Returns: {Object} The parsed command line arguments:
1046+
* `values` {Object} A mapping of parsed option names with their {string}
1047+
or {boolean} values.
1048+
* `positionals` {string\[]} Positional arguments.
1049+
1050+
Provides a higher level API for command-line argument parsing than interacting
1051+
with `process.argv` directly. Takes a specification for the expected arguments
1052+
and returns a structured object with the parsed options and positionals.
1053+
1054+
```mjs
1055+
import { parseArgs } from 'node:util';
1056+
const args = ['-f', '--bar', 'b'];
1057+
const options = {
1058+
foo: {
1059+
type: 'boolean',
1060+
short: 'f'
1061+
},
1062+
bar: {
1063+
type: 'string'
1064+
}
1065+
};
1066+
const {
1067+
values,
1068+
positionals
1069+
} = parseArgs({ args, options });
1070+
console.log(values, positionals);
1071+
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []
1072+
```
1073+
1074+
```cjs
1075+
const { parseArgs } = require('node:util');
1076+
const args = ['-f', '--bar', 'b'];
1077+
const options = {
1078+
foo: {
1079+
type: 'boolean',
1080+
short: 'f'
1081+
},
1082+
bar: {
1083+
type: 'string'
1084+
}
1085+
};
1086+
const {
1087+
values,
1088+
positionals
1089+
} = parseArgs({ args, options });
1090+
console.log(values, positionals);
1091+
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []ss
1092+
```
1093+
1094+
`util.parseArgs` is experimental and behavior may change. Join the
1095+
conversation in [pkgjs/parseargs][] to contribute to the design.
1096+
10171097
## `util.promisify(original)`
10181098

10191099
<!-- YAML
@@ -2685,5 +2765,6 @@ util.log('Timestamped message.');
26852765
[default sort]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
26862766
[global symbol registry]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
26872767
[list of deprecated APIS]: deprecations.md#list-of-deprecated-apis
2768+
[pkgjs/parseargs]: https://github.com/pkgjs/parseargs
26882769
[semantically incompatible]: https://github.com/nodejs/node/issues/4179
26892770
[util.inspect.custom]: #utilinspectcustom

lib/internal/errors.js

+9
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,15 @@ E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath, base = undefined) => {
14961496
return `Package subpath '${subpath}' is not defined by "exports" in ${
14971497
pkgPath}package.json${base ? ` imported from ${base}` : ''}`;
14981498
}, Error);
1499+
E('ERR_PARSE_ARGS_INVALID_OPTION_VALUE', '%s', TypeError);
1500+
E('ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL', "Unexpected argument '%s'. This " +
1501+
'command does not take positional arguments', TypeError);
1502+
E('ERR_PARSE_ARGS_UNKNOWN_OPTION', (option, allowPositionals) => {
1503+
const suggestDashDash = allowPositionals ? '. To specify a positional ' +
1504+
"argument starting with a '-', place it at the end of the command after " +
1505+
`'--', as in '-- ${JSONStringify(option)}` : '';
1506+
return `Unknown option '${option}'${suggestDashDash}`;
1507+
}, TypeError);
14991508
E('ERR_PERFORMANCE_INVALID_TIMESTAMP',
15001509
'%d is not a valid timestamp', TypeError);
15011510
E('ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS', '%s', TypeError);

0 commit comments

Comments
 (0)