@@ -94,14 +94,24 @@ To specify an option argument starting with a dash use ${example}.`;
94
94
* @param {object } token - from tokens as available from parseArgs
95
95
*/
96
96
function checkOptionUsage ( config , token ) {
97
- if ( ! ObjectHasOwn ( config . options , token . name ) ) {
98
- throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
99
- token . rawName , config . allowPositionals ) ;
97
+ let tokenName = token . name ;
98
+ if ( ! ObjectHasOwn ( config . options , tokenName ) ) {
99
+ // Check for negated boolean option.
100
+ if ( config . allowNegative && StringPrototypeStartsWith ( tokenName , 'no-' ) ) {
101
+ tokenName = StringPrototypeSlice ( tokenName , 3 ) ;
102
+ if ( ! ObjectHasOwn ( config . options , tokenName ) || optionsGetOwn ( config . options , tokenName , 'type' ) !== 'boolean' ) {
103
+ throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
104
+ token . rawName , config . allowPositionals ) ;
105
+ }
106
+ } else {
107
+ throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
108
+ token . rawName , config . allowPositionals ) ;
109
+ }
100
110
}
101
111
102
- const short = optionsGetOwn ( config . options , token . name , 'short' ) ;
103
- const shortAndLong = `${ short ? `-${ short } , ` : '' } --${ token . name } ` ;
104
- const type = optionsGetOwn ( config . options , token . name , 'type' ) ;
112
+ const short = optionsGetOwn ( config . options , tokenName , 'short' ) ;
113
+ const shortAndLong = `${ short ? `-${ short } , ` : '' } --${ tokenName } ` ;
114
+ const type = optionsGetOwn ( config . options , tokenName , 'type' ) ;
105
115
if ( type === 'string' && typeof token . value !== 'string' ) {
106
116
throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE ( `Option '${ shortAndLong } <value>' argument missing` ) ;
107
117
}
@@ -114,16 +124,25 @@ function checkOptionUsage(config, token) {
114
124
115
125
/**
116
126
* Store the option value in `values`.
117
- * @param {string } longOption - long option name e.g. 'foo'
118
- * @param {string|undefined } optionValue - value from user args
127
+ * @param {object } token - from tokens as available from parseArgs
119
128
* @param {object } options - option configs, from parseArgs({ options })
120
129
* @param {object } values - option values returned in `values` by parseArgs
130
+ * @param {boolean } allowNegative - allow negative optinons if true
121
131
*/
122
- function storeOption ( longOption , optionValue , options , values ) {
132
+ function storeOption ( token , options , values , allowNegative ) {
133
+ let longOption = token . name ;
134
+ let optionValue = token . value ;
123
135
if ( longOption === '__proto__' ) {
124
136
return ; // No. Just no.
125
137
}
126
138
139
+ if ( allowNegative && StringPrototypeStartsWith ( longOption , 'no-' ) && optionValue === undefined ) {
140
+ // Boolean option negation: --no-foo
141
+ longOption = StringPrototypeSlice ( longOption , 3 ) ;
142
+ token . name = longOption ;
143
+ optionValue = false ;
144
+ }
145
+
127
146
// We store based on the option value rather than option type,
128
147
// preserving the users intent for author to deal with.
129
148
const newValue = optionValue ?? true ;
@@ -290,15 +309,17 @@ const parseArgs = (config = kEmptyObject) => {
290
309
const strict = objectGetOwn ( config , 'strict' ) ?? true ;
291
310
const allowPositionals = objectGetOwn ( config , 'allowPositionals' ) ?? ! strict ;
292
311
const returnTokens = objectGetOwn ( config , 'tokens' ) ?? false ;
312
+ const allowNegative = objectGetOwn ( config , 'allowNegative' ) ?? false ;
293
313
const options = objectGetOwn ( config , 'options' ) ?? { __proto__ : null } ;
294
314
// Bundle these up for passing to strict-mode checks.
295
- const parseConfig = { args, strict, options, allowPositionals } ;
315
+ const parseConfig = { args, strict, options, allowPositionals, allowNegative } ;
296
316
297
317
// Validate input configuration.
298
318
validateArray ( args , 'args' ) ;
299
319
validateBoolean ( strict , 'strict' ) ;
300
320
validateBoolean ( allowPositionals , 'allowPositionals' ) ;
301
321
validateBoolean ( returnTokens , 'tokens' ) ;
322
+ validateBoolean ( allowNegative , 'allowNegative' ) ;
302
323
validateObject ( options , 'options' ) ;
303
324
ArrayPrototypeForEach (
304
325
ObjectEntries ( options ) ,
@@ -360,7 +381,7 @@ const parseArgs = (config = kEmptyObject) => {
360
381
checkOptionUsage ( parseConfig , token ) ;
361
382
checkOptionLikeValue ( token ) ;
362
383
}
363
- storeOption ( token . name , token . value , options , result . values ) ;
384
+ storeOption ( token , options , result . values , parseConfig . allowNegative ) ;
364
385
} else if ( token . kind === 'positional' ) {
365
386
if ( ! allowPositionals ) {
366
387
throw new ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL ( token . value ) ;
0 commit comments