1
1
'use strict' ;
2
2
3
+ /* eslint max-len: ["error", {"code": 120}], */
4
+
3
5
const {
4
6
ArrayPrototypeForEach,
5
7
ArrayPrototypeIncludes,
@@ -95,14 +97,24 @@ To specify an option argument starting with a dash use ${example}.`;
95
97
* @param {object } token - from tokens as available from parseArgs
96
98
*/
97
99
function checkOptionUsage ( config , token ) {
98
- if ( ! ObjectHasOwn ( config . options , token . name ) ) {
99
- throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
100
- token . rawName , config . allowPositionals ) ;
100
+ let tokenName = token . name ;
101
+ if ( ! ObjectHasOwn ( config . options , tokenName ) ) {
102
+ // Check for negated boolean option.
103
+ if ( config . allowNegative && StringPrototypeStartsWith ( tokenName , 'no-' ) ) {
104
+ tokenName = StringPrototypeSlice ( tokenName , 3 ) ;
105
+ if ( ! ObjectHasOwn ( config . options , tokenName ) || optionsGetOwn ( config . options , tokenName , 'type' ) !== 'boolean' ) {
106
+ throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
107
+ token . rawName , config . allowPositionals ) ;
108
+ }
109
+ } else {
110
+ throw new ERR_PARSE_ARGS_UNKNOWN_OPTION (
111
+ token . rawName , config . allowPositionals ) ;
112
+ }
101
113
}
102
114
103
- const short = optionsGetOwn ( config . options , token . name , 'short' ) ;
104
- const shortAndLong = `${ short ? `-${ short } , ` : '' } --${ token . name } ` ;
105
- const type = optionsGetOwn ( config . options , token . name , 'type' ) ;
115
+ const short = optionsGetOwn ( config . options , tokenName , 'short' ) ;
116
+ const shortAndLong = `${ short ? `-${ short } , ` : '' } --${ tokenName } ` ;
117
+ const type = optionsGetOwn ( config . options , tokenName , 'type' ) ;
106
118
if ( type === 'string' && typeof token . value !== 'string' ) {
107
119
throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE ( `Option '${ shortAndLong } <value>' argument missing` ) ;
108
120
}
@@ -115,17 +127,25 @@ function checkOptionUsage(config, token) {
115
127
116
128
/**
117
129
* Store the option value in `values`.
118
- *
119
- * @param {string } longOption - long option name e.g. 'foo'
120
- * @param {string|undefined } optionValue - value from user args
130
+ * @param {object } token - from tokens as available from parseArgs
121
131
* @param {object } options - option configs, from parseArgs({ options })
122
132
* @param {object } values - option values returned in `values` by parseArgs
133
+ * @param {boolean } allowNegative - allow negative optinons if true
123
134
*/
124
- function storeOption ( longOption , optionValue , options , values ) {
135
+ function storeOption ( token , options , values , allowNegative ) {
136
+ let longOption = token . name ;
137
+ let optionValue = token . value ;
125
138
if ( longOption === '__proto__' ) {
126
139
return ; // No. Just no.
127
140
}
128
141
142
+ if ( allowNegative && StringPrototypeStartsWith ( longOption , 'no-' ) && optionValue === undefined ) {
143
+ // Boolean option negation: --no-foo
144
+ longOption = StringPrototypeSlice ( longOption , 3 ) ;
145
+ token . name = longOption ;
146
+ optionValue = false ;
147
+ }
148
+
129
149
// We store based on the option value rather than option type,
130
150
// preserving the users intent for author to deal with.
131
151
const newValue = optionValue ?? true ;
@@ -295,15 +315,17 @@ const parseArgs = (config = kEmptyObject) => {
295
315
const strict = objectGetOwn ( config , 'strict' ) ?? true ;
296
316
const allowPositionals = objectGetOwn ( config , 'allowPositionals' ) ?? ! strict ;
297
317
const returnTokens = objectGetOwn ( config , 'tokens' ) ?? false ;
318
+ const allowNegative = objectGetOwn ( config , 'allowNegative' ) ?? false ;
298
319
const options = objectGetOwn ( config , 'options' ) ?? { __proto__ : null } ;
299
320
// Bundle these up for passing to strict-mode checks.
300
- const parseConfig = { args, strict, options, allowPositionals } ;
321
+ const parseConfig = { args, strict, options, allowPositionals, allowNegative } ;
301
322
302
323
// Validate input configuration.
303
324
validateArray ( args , 'args' ) ;
304
325
validateBoolean ( strict , 'strict' ) ;
305
326
validateBoolean ( allowPositionals , 'allowPositionals' ) ;
306
327
validateBoolean ( returnTokens , 'tokens' ) ;
328
+ validateBoolean ( allowNegative , 'allowNegative' ) ;
307
329
validateObject ( options , 'options' ) ;
308
330
ArrayPrototypeForEach (
309
331
ObjectEntries ( options ) ,
@@ -365,7 +387,7 @@ const parseArgs = (config = kEmptyObject) => {
365
387
checkOptionUsage ( parseConfig , token ) ;
366
388
checkOptionLikeValue ( token ) ;
367
389
}
368
- storeOption ( token . name , token . value , options , result . values ) ;
390
+ storeOption ( token , options , result . values , parseConfig . allowNegative ) ;
369
391
} else if ( token . kind === 'positional' ) {
370
392
if ( ! allowPositionals ) {
371
393
throw new ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL ( token . value ) ;
0 commit comments