@@ -1028,6 +1028,11 @@ equality.
1028
1028
1029
1029
<!-- YAML
1030
1030
added: v18.3.0
1031
+ changes:
1032
+ - version: REPLACEME
1033
+ pr-url: https://github.com/nodejs/node/pull/43459
1034
+ description: add support for returning detailed parse information
1035
+ using `tokens` in input `config` and returned properties.
1031
1036
-->
1032
1037
1033
1038
> Stability: 1 - Experimental
@@ -1044,18 +1049,24 @@ added: v18.3.0
1044
1049
times. If ` true ` , all values will be collected in an array. If
1045
1050
` false ` , values for the option are last-wins. ** Default:** ` false ` .
1046
1051
* ` short ` {string} A single character alias for the option.
1047
- * ` strict ` : {boolean} Should an error be thrown when unknown arguments
1052
+ * ` strict ` {boolean} Should an error be thrown when unknown arguments
1048
1053
are encountered, or when arguments are passed that do not match the
1049
1054
` type ` configured in ` options ` .
1050
1055
** Default:** ` true ` .
1051
- * ` allowPositionals ` : {boolean} Whether this command accepts positional
1056
+ * ` allowPositionals ` {boolean} Whether this command accepts positional
1052
1057
arguments.
1053
1058
** Default:** ` false ` if ` strict ` is ` true ` , otherwise ` true ` .
1059
+ * ` tokens ` {boolean} Return the parsed tokens. This is useful for extending
1060
+ the built-in behavior, from adding additional checks through to reprocessing
1061
+ the tokens in different ways.
1062
+ ** Default:** ` false ` .
1054
1063
1055
1064
* Returns: {Object} The parsed command line arguments:
1056
1065
* ` values ` {Object} A mapping of parsed option names with their {string}
1057
1066
or {boolean} values.
1058
1067
* ` positionals ` {string\[ ] } Positional arguments.
1068
+ * ` tokens ` {Object\[ ] | undefined} See [ parseArgs tokens] ( #parseargs-tokens )
1069
+ section. Only returned if ` config ` includes ` tokens: true ` .
1059
1070
1060
1071
Provides a higher level API for command-line argument parsing than interacting
1061
1072
with ` process.argv ` directly. Takes a specification for the expected arguments
@@ -1104,6 +1115,114 @@ console.log(values, positionals);
1104
1115
` util.parseArgs ` is experimental and behavior may change. Join the
1105
1116
conversation in [ pkgjs/parseargs] [ ] to contribute to the design.
1106
1117
1118
+ ### ` parseArgs ` ` tokens `
1119
+
1120
+ Detailed parse information is available for adding custom behaviours by
1121
+ specifying ` tokens: true ` in the configuration.
1122
+ The returned tokens have properties describing:
1123
+
1124
+ * all tokens
1125
+ * ` kind ` {string} One of 'option', 'positional', or 'option-terminator'.
1126
+ * ` index ` {number} Index of element in ` args ` containing token. So the
1127
+ source argument for a token is ` args[token.index] ` .
1128
+ * option tokens
1129
+ * ` name ` {string} Long name of option.
1130
+ * ` rawName ` {string} How option used in args, like ` -f ` of ` --foo ` .
1131
+ * ` value ` {string | undefined} Option value specified in args.
1132
+ Undefined for boolean options.
1133
+ * ` inlineValue ` {boolean | undefined} Whether option value specified inline,
1134
+ like ` --foo=bar ` .
1135
+ * positional tokens
1136
+ * ` value ` {string} The value of the positional argument in args (i.e. ` args[index] ` ).
1137
+ * option-terminator token
1138
+
1139
+ The returned tokens are in the order encountered in the input args. Options
1140
+ that appear more than once in args produce a token for each use. Short option
1141
+ groups like ` -xy ` expand to a token for each option. So ` -xxx ` produces
1142
+ three tokens.
1143
+
1144
+ For example to use the returned tokens to add support for a negated option
1145
+ like ` --no-color ` , the tokens can be reprocessed to change the value stored
1146
+ for the negated option.
1147
+
1148
+ ``` mjs
1149
+ import { parseArgs } from ' node:util' ;
1150
+
1151
+ const options = {
1152
+ ' color' : { type: ' boolean' },
1153
+ ' no-color' : { type: ' boolean' },
1154
+ ' logfile' : { type: ' string' },
1155
+ ' no-logfile' : { type: ' boolean' },
1156
+ };
1157
+ const { values , tokens } = parseArgs ({ options, tokens: true });
1158
+
1159
+ // Reprocess the option tokens and overwrite the returned values.
1160
+ tokens
1161
+ .filter ((token ) => token .kind === ' option' )
1162
+ .forEach ((token ) => {
1163
+ if (token .name .startsWith (' no-' )) {
1164
+ // Store foo:false for --no-foo
1165
+ const positiveName = token .name .slice (3 );
1166
+ values[positiveName] = false ;
1167
+ delete values[token .name ];
1168
+ } else {
1169
+ // Resave value so last one wins if both --foo and --no-foo.
1170
+ values[token .name ] = token .value ?? true ;
1171
+ }
1172
+ });
1173
+
1174
+ const color = values .color ;
1175
+ const logfile = values .logfile ?? ' default.log' ;
1176
+
1177
+ console .log ({ logfile, color });
1178
+ ` ` `
1179
+
1180
+ ` ` ` cjs
1181
+ const { parseArgs } = require (' node:util' );
1182
+
1183
+ const options = {
1184
+ ' color' : { type: ' boolean' },
1185
+ ' no-color' : { type: ' boolean' },
1186
+ ' logfile' : { type: ' string' },
1187
+ ' no-logfile' : { type: ' boolean' },
1188
+ };
1189
+ const { values , tokens } = parseArgs ({ options, tokens: true });
1190
+
1191
+ // Reprocess the option tokens and overwrite the returned values.
1192
+ tokens
1193
+ .filter ((token ) => token .kind === ' option' )
1194
+ .forEach ((token ) => {
1195
+ if (token .name .startsWith (' no-' )) {
1196
+ // Store foo:false for --no-foo
1197
+ const positiveName = token .name .slice (3 );
1198
+ values[positiveName] = false ;
1199
+ delete values[token .name ];
1200
+ } else {
1201
+ // Resave value so last one wins if both --foo and --no-foo.
1202
+ values[token .name ] = token .value ?? true ;
1203
+ }
1204
+ });
1205
+
1206
+ const color = values .color ;
1207
+ const logfile = values .logfile ?? ' default.log' ;
1208
+
1209
+ console .log ({ logfile, color });
1210
+ ` ` `
1211
+
1212
+ Example usage showing negated options, and when an option is used
1213
+ multiple ways then last one wins.
1214
+
1215
+ ` ` ` console
1216
+ $ node negate .js
1217
+ { logfile: ' default.log' , color: undefined }
1218
+ $ node negate .js -- no- logfile -- no- color
1219
+ { logfile: false , color: false }
1220
+ $ node negate .js -- logfile= test .log -- color
1221
+ { logfile: ' test.log' , color: true }
1222
+ $ node negate .js -- no- logfile -- logfile= test .log -- color -- no- color
1223
+ { logfile: ' test.log' , color: false }
1224
+ ` ` `
1225
+
1107
1226
## ` util .promisify (original)`
1108
1227
1109
1228
<!-- YAML
0 commit comments