Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit acfc33c

Browse filesBrowse files
shadowspawndanielleadams
authored andcommitted
util: add tokens to parseArgs
Offer additional meta-data for building custom and additional behaviour on top of parseArgs. PR-URL: #43459 Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 8a8de94 commit acfc33c
Copy full SHA for acfc33c

File tree

Expand file treeCollapse file tree

3 files changed

+515
-104
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+515
-104
lines changed
Open diff view settings
Collapse file

‎doc/api/util.md‎

Copy file name to clipboardExpand all lines: doc/api/util.md
+121-2Lines changed: 121 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,11 @@ equality.
10241024

10251025
<!-- YAML
10261026
added: v18.3.0
1027+
changes:
1028+
- version: REPLACEME
1029+
pr-url: https://github.com/nodejs/node/pull/43459
1030+
description: add support for returning detailed parse information
1031+
using `tokens` in input `config` and returned properties.
10271032
-->
10281033

10291034
> Stability: 1 - Experimental
@@ -1040,18 +1045,24 @@ added: v18.3.0
10401045
times. If `true`, all values will be collected in an array. If
10411046
`false`, values for the option are last-wins. **Default:** `false`.
10421047
* `short` {string} A single character alias for the option.
1043-
* `strict`: {boolean} Should an error be thrown when unknown arguments
1048+
* `strict` {boolean} Should an error be thrown when unknown arguments
10441049
are encountered, or when arguments are passed that do not match the
10451050
`type` configured in `options`.
10461051
**Default:** `true`.
1047-
* `allowPositionals`: {boolean} Whether this command accepts positional
1052+
* `allowPositionals` {boolean} Whether this command accepts positional
10481053
arguments.
10491054
**Default:** `false` if `strict` is `true`, otherwise `true`.
1055+
* `tokens` {boolean} Return the parsed tokens. This is useful for extending
1056+
the built-in behavior, from adding additional checks through to reprocessing
1057+
the tokens in different ways.
1058+
**Default:** `false`.
10501059

10511060
* Returns: {Object} The parsed command line arguments:
10521061
* `values` {Object} A mapping of parsed option names with their {string}
10531062
or {boolean} values.
10541063
* `positionals` {string\[]} Positional arguments.
1064+
* `tokens` {Object\[] | undefined} See [parseArgs tokens](#parseargs-tokens)
1065+
section. Only returned if `config` includes `tokens: true`.
10551066

10561067
Provides a higher level API for command-line argument parsing than interacting
10571068
with `process.argv` directly. Takes a specification for the expected arguments
@@ -1100,6 +1111,114 @@ console.log(values, positionals);
11001111
`util.parseArgs` is experimental and behavior may change. Join the
11011112
conversation in [pkgjs/parseargs][] to contribute to the design.
11021113

1114+
### `parseArgs` `tokens`
1115+
1116+
Detailed parse information is available for adding custom behaviours by
1117+
specifying `tokens: true` in the configuration.
1118+
The returned tokens have properties describing:
1119+
1120+
* all tokens
1121+
* `kind` {string} One of 'option', 'positional', or 'option-terminator'.
1122+
* `index` {number} Index of element in `args` containing token. So the
1123+
source argument for a token is `args[token.index]`.
1124+
* option tokens
1125+
* `name` {string} Long name of option.
1126+
* `rawName` {string} How option used in args, like `-f` of `--foo`.
1127+
* `value` {string | undefined} Option value specified in args.
1128+
Undefined for boolean options.
1129+
* `inlineValue` {boolean | undefined} Whether option value specified inline,
1130+
like `--foo=bar`.
1131+
* positional tokens
1132+
* `value` {string} The value of the positional argument in args (i.e. `args[index]`).
1133+
* option-terminator token
1134+
1135+
The returned tokens are in the order encountered in the input args. Options
1136+
that appear more than once in args produce a token for each use. Short option
1137+
groups like `-xy` expand to a token for each option. So `-xxx` produces
1138+
three tokens.
1139+
1140+
For example to use the returned tokens to add support for a negated option
1141+
like `--no-color`, the tokens can be reprocessed to change the value stored
1142+
for the negated option.
1143+
1144+
```mjs
1145+
import { parseArgs } from 'node:util';
1146+
1147+
const options = {
1148+
'color': { type: 'boolean' },
1149+
'no-color': { type: 'boolean' },
1150+
'logfile': { type: 'string' },
1151+
'no-logfile': { type: 'boolean' },
1152+
};
1153+
const { values, tokens } = parseArgs({ options, tokens: true });
1154+
1155+
// Reprocess the option tokens and overwrite the returned values.
1156+
tokens
1157+
.filter((token) => token.kind === 'option')
1158+
.forEach((token) => {
1159+
if (token.name.startsWith('no-')) {
1160+
// Store foo:false for --no-foo
1161+
const positiveName = token.name.slice(3);
1162+
values[positiveName] = false;
1163+
delete values[token.name];
1164+
} else {
1165+
// Resave value so last one wins if both --foo and --no-foo.
1166+
values[token.name] = token.value ?? true;
1167+
}
1168+
});
1169+
1170+
const color = values.color;
1171+
const logfile = values.logfile ?? 'default.log';
1172+
1173+
console.log({ logfile, color });
1174+
```
1175+
1176+
```cjs
1177+
const { parseArgs } = require('node:util');
1178+
1179+
const options = {
1180+
'color': { type: 'boolean' },
1181+
'no-color': { type: 'boolean' },
1182+
'logfile': { type: 'string' },
1183+
'no-logfile': { type: 'boolean' },
1184+
};
1185+
const { values, tokens } = parseArgs({ options, tokens: true });
1186+
1187+
// Reprocess the option tokens and overwrite the returned values.
1188+
tokens
1189+
.filter((token) => token.kind === 'option')
1190+
.forEach((token) => {
1191+
if (token.name.startsWith('no-')) {
1192+
// Store foo:false for --no-foo
1193+
const positiveName = token.name.slice(3);
1194+
values[positiveName] = false;
1195+
delete values[token.name];
1196+
} else {
1197+
// Resave value so last one wins if both --foo and --no-foo.
1198+
values[token.name] = token.value ?? true;
1199+
}
1200+
});
1201+
1202+
const color = values.color;
1203+
const logfile = values.logfile ?? 'default.log';
1204+
1205+
console.log({ logfile, color });
1206+
```
1207+
1208+
Example usage showing negated options, and when an option is used
1209+
multiple ways then last one wins.
1210+
1211+
```console
1212+
$ node negate.js
1213+
{ logfile: 'default.log', color: undefined }
1214+
$ node negate.js --no-logfile --no-color
1215+
{ logfile: false, color: false }
1216+
$ node negate.js --logfile=test.log --color
1217+
{ logfile: 'test.log', color: true }
1218+
$ node negate.js --no-logfile --logfile=test.log --color --no-color
1219+
{ logfile: 'test.log', color: false }
1220+
```
1221+
11031222
## `util.promisify(original)`
11041223
11051224
<!-- YAML

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.