@@ -94,14 +94,24 @@ To specify an option argument starting with a dash use ${example}.`;
9494 * @param {object } token - from tokens as available from parseArgs
9595 */
9696function 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+ }
100110 }
101111
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' ) ;
105115 if ( type === 'string' && typeof token . value !== 'string' ) {
106116 throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE ( `Option '${ shortAndLong } <value>' argument missing` ) ;
107117 }
@@ -118,12 +128,22 @@ function checkOptionUsage(config, token) {
118128 * @param {string|undefined } optionValue - value from user args
119129 * @param {object } options - option configs, from parseArgs({ options })
120130 * @param {object } values - option values returned in `values` by parseArgs
131+ * @param {boolean } allowNegative - allow negative optinons if true
121132 */
122- function storeOption ( longOption , optionValue , options , values ) {
133+ function storeOption ( longOption , optionValue , options , values , allowNegative ) {
123134 if ( longOption === '__proto__' ) {
124135 return ; // No. Just no.
125136 }
126137
138+ if ( allowNegative && StringPrototypeStartsWith ( longOption , 'no-' ) ) {
139+ // Boolean option negation: --no-foo
140+ const longOptionWithoutPrefixNo = StringPrototypeSlice ( longOption , 3 ) ;
141+ if ( optionsGetOwn ( options , longOptionWithoutPrefixNo , 'type' ) !== 'string' ) {
142+ longOption = StringPrototypeSlice ( longOption , 3 ) ;
143+ optionValue = false ;
144+ }
145+ }
146+
127147 // We store based on the option value rather than option type,
128148 // preserving the users intent for author to deal with.
129149 const newValue = optionValue ?? true ;
@@ -290,15 +310,17 @@ const parseArgs = (config = kEmptyObject) => {
290310 const strict = objectGetOwn ( config , 'strict' ) ?? true ;
291311 const allowPositionals = objectGetOwn ( config , 'allowPositionals' ) ?? ! strict ;
292312 const returnTokens = objectGetOwn ( config , 'tokens' ) ?? false ;
313+ const allowNegative = objectGetOwn ( config , 'allowNegative' ) ?? false ;
293314 const options = objectGetOwn ( config , 'options' ) ?? { __proto__ : null } ;
294315 // Bundle these up for passing to strict-mode checks.
295- const parseConfig = { args, strict, options, allowPositionals } ;
316+ const parseConfig = { args, strict, options, allowPositionals, allowNegative } ;
296317
297318 // Validate input configuration.
298319 validateArray ( args , 'args' ) ;
299320 validateBoolean ( strict , 'strict' ) ;
300321 validateBoolean ( allowPositionals , 'allowPositionals' ) ;
301322 validateBoolean ( returnTokens , 'tokens' ) ;
323+ validateBoolean ( allowNegative , 'allowNegative' ) ;
302324 validateObject ( options , 'options' ) ;
303325 ArrayPrototypeForEach (
304326 ObjectEntries ( options ) ,
@@ -360,7 +382,7 @@ const parseArgs = (config = kEmptyObject) => {
360382 checkOptionUsage ( parseConfig , token ) ;
361383 checkOptionLikeValue ( token ) ;
362384 }
363- storeOption ( token . name , token . value , options , result . values ) ;
385+ storeOption ( token . name , token . value , options , result . values , parseConfig . allowNegative ) ;
364386 } else if ( token . kind === 'positional' ) {
365387 if ( ! allowPositionals ) {
366388 throw new ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL ( token . value ) ;
0 commit comments