Skip to content

Commit

Permalink
util: add parseArgs module
Browse files Browse the repository at this point in the history
Adds util.parseArgs helper for higher level command-line argument
parsing.

PR-URL: #42675
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ruy Adorno <ruyadorno@github.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Joe Sepi <sepi@joesepi.com>
Reviewed-By: Ian Sutherland <ian@iansutherland.ca>
  • Loading branch information
bcoe authored and bengl committed May 30, 2022
1 parent baa5d00 commit d6cf409
Show file tree
Hide file tree
Showing 9 changed files with 1,189 additions and 0 deletions.
35 changes: 35 additions & 0 deletions doc/api/errors.md
Expand Up @@ -2344,6 +2344,40 @@ The `package.json` [`"exports"`][] field does not export the requested subpath.
Because exports are encapsulated, private internal modules that are not exported
cannot be imported through the package resolution, unless using an absolute URL.

<a id="ERR_PARSE_ARGS_INVALID_OPTION_VALUE"></a>

### `ERR_PARSE_ARGS_INVALID_OPTION_VALUE`

<!-- YAML
added: REPLACEME
-->

When `strict` set to `true`, thrown by [`util.parseArgs()`][] if a {boolean}
value is provided for an option of type {string}, or if a {string}
value is provided for an option of type {boolean}.

<a id="ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL"></a>

### `ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL`

<!-- YAML
added: REPLACEME
-->

Thrown by [`util.parseArgs()`][], when a postional argument is provided and
`allowPositionals` is set to `false`.

<a id="ERR_PARSE_ARGS_UNKNOWN_OPTION"></a>

### `ERR_PARSE_ARGS_UNKNOWN_OPTION`

<!-- YAML
added: REPLACEME
-->

When `strict` set to `true`, thrown by [`util.parseArgs()`][] if an argument
is not configured in `options`.

<a id="ERR_PERFORMANCE_INVALID_TIMESTAMP"></a>

### `ERR_PERFORMANCE_INVALID_TIMESTAMP`
Expand Down Expand Up @@ -3455,6 +3489,7 @@ The native call from `process.cpuUsage` could not be processed.
[`subprocess.send()`]: child_process.md#subprocesssendmessage-sendhandle-options-callback
[`url.parse()`]: url.md#urlparseurlstring-parsequerystring-slashesdenotehost
[`util.getSystemErrorName(error.errno)`]: util.md#utilgetsystemerrornameerr
[`util.parseArgs()`]: util.md#utilparseargsconfig
[`zlib`]: zlib.md
[crypto digest algorithm]: crypto.md#cryptogethashes
[debugger]: debugger.md
Expand Down
81 changes: 81 additions & 0 deletions doc/api/util.md
Expand Up @@ -1020,6 +1020,86 @@ Otherwise, returns `false`.
See [`assert.deepStrictEqual()`][] for more information about deep strict
equality.

## `util.parseArgs([config])`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental
* `config` {Object} Used to provide arguments for parsing and to configure
the parser. `config` supports the following properties:
* `args` {string\[]} array of argument strings. **Default:** `process.argv`
with `execPath` and `filename` removed.
* `options` {Object} Used to describe arguments known to the parser.
Keys of `options` are the long names of options and values are an
{Object} accepting the following properties:
* `type` {string} Type of argument, which must be either `boolean` or `string`.
* `multiple` {boolean} Whether this option can be provided multiple
times. If `true`, all values will be collected in an array. If
`false`, values for the option are last-wins. **Default:** `false`.
* `short` {string} A single character alias for the option.
* `strict`: {boolean} Should an error be thrown when unknown arguments
are encountered, or when arguments are passed that do not match the
`type` configured in `options`.
**Default:** `true`.
* `allowPositionals`: {boolean} Whether this command accepts positional
arguments.
**Default:** `false` if `strict` is `true`, otherwise `true`.

* Returns: {Object} The parsed command line arguments:
* `values` {Object} A mapping of parsed option names with their {string}
or {boolean} values.
* `positionals` {string\[]} Positional arguments.

Provides a higher level API for command-line argument parsing than interacting
with `process.argv` directly. Takes a specification for the expected arguments
and returns a structured object with the parsed options and positionals.

```mjs
import { parseArgs } from 'node:util';
const args = ['-f', '--bar', 'b'];
const options = {
foo: {
type: 'boolean',
short: 'f'
},
bar: {
type: 'string'
}
};
const {
values,
positionals
} = parseArgs({ args, options });
console.log(values, positionals);
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []
```

```cjs
const { parseArgs } = require('node:util');
const args = ['-f', '--bar', 'b'];
const options = {
foo: {
type: 'boolean',
short: 'f'
},
bar: {
type: 'string'
}
};
const {
values,
positionals
} = parseArgs({ args, options });
console.log(values, positionals);
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []ss
```

`util.parseArgs` is experimental and behavior may change. Join the
conversation in [pkgjs/parseargs][] to contribute to the design.

## `util.promisify(original)`

<!-- YAML
Expand Down Expand Up @@ -2693,5 +2773,6 @@ util.log('Timestamped message.');
[default sort]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
[global symbol registry]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
[list of deprecated APIS]: deprecations.md#list-of-deprecated-apis
[pkgjs/parseargs]: https://github.com/pkgjs/parseargs
[semantically incompatible]: https://github.com/nodejs/node/issues/4179
[util.inspect.custom]: #utilinspectcustom
9 changes: 9 additions & 0 deletions lib/internal/errors.js
Expand Up @@ -1474,6 +1474,15 @@ E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath, base = undefined) => {
return `Package subpath '${subpath}' is not defined by "exports" in ${
pkgPath}package.json${base ? ` imported from ${base}` : ''}`;
}, Error);
E('ERR_PARSE_ARGS_INVALID_OPTION_VALUE', '%s', TypeError);
E('ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL', "Unexpected argument '%s'. This " +
'command does not take positional arguments', TypeError);
E('ERR_PARSE_ARGS_UNKNOWN_OPTION', (option, allowPositionals) => {
const suggestDashDash = allowPositionals ? '. To specify a positional ' +
"argument starting with a '-', place it at the end of the command after " +
`'--', as in '-- ${JSONStringify(option)}` : '';
return `Unknown option '${option}'${suggestDashDash}`;
}, TypeError);
E('ERR_PERFORMANCE_INVALID_TIMESTAMP',
'%d is not a valid timestamp', TypeError);
E('ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS', '%s', TypeError);
Expand Down

0 comments on commit d6cf409

Please sign in to comment.