Repository: yargs/yargs
Pull request #1054 (2018-01-20 23:37:23)

feat: requiresArg is now simply an alias for nargs(1)
BREAKING CHANGE: requiresArg now has significantly different error output, matching nargs.

based on @evocateur's clever suggestion, `requiresArg` is now just an alias for `nargs(1)`; simplifying the implementation significantly and moving behavior closer to the parser.


Patch:
diff --git a/lib/validation.js b/lib/validation.js
index 17f0d9f..f4655b4 100644
--- a/lib/validation.js
+++ b/lib/validation.js
@@ -54,40 +54,6 @@ module.exports = function validation (yargs, usage, y18n) {
     }
   }
 
-  // make sure that any args that require an
-  // value (--foo=bar), have a value.
-  self.missingArgumentValue = function missingArgumentValue (argv) {
-    const options = yargs.getOptions()
-    if (options.requiresArg.length > 0) {
-      const missingRequiredArgs = []
-      const defaultValues = new Set([true, false, ''])
-
-      options.requiresArg.forEach((key) => {
-        // if the argument is not set in argv no need to check
-        // whether a right-hand-side has been provided.
-        if (!argv.hasOwnProperty(key)) return
-
-        const value = argv[key]
-        // if a value is explicitly requested,
-        // flag argument as missing if it does not
-        // look like foo=bar was entered.
-        if (defaultValues.has(value) ||
-          (Array.isArray(value) && !value.length)) {
-          missingRequiredArgs.push(key)
-        }
-      })
-
-      if (missingRequiredArgs.length > 0) {
-        usage.fail(__n(
-          'Missing argument value: %s',
-          'Missing argument values: %s',
-          missingRequiredArgs.length,
-          missingRequiredArgs.join(', ')
-        ))
-      }
-    }
-  }
-
   // make sure all the required arguments are present.
   self.requiredArguments = function requiredArguments (argv) {
     const demandedOptions = yargs.getDemandedOptions()
diff --git a/package.json b/package.json
index 92f9fd8..bf49348 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
     "string-width": "^2.0.0",
     "which-module": "^2.0.0",
     "y18n": "^3.2.1",
-    "yargs-parser": "^8.1.0"
+    "yargs-parser": "^9.0.2"
   },
   "devDependencies": {
     "chai": "^4.1.2",
diff --git a/yargs.js b/yargs.js
index 0194e94..9b50b8b 100644
--- a/yargs.js
+++ b/yargs.js
@@ -92,7 +92,7 @@ function Yargs (processArgs, cwd, parentRequire) {
     groups = {}
 
     const arrayOptions = [
-      'array', 'boolean', 'string', 'requiresArg', 'skipValidation',
+      'array', 'boolean', 'string', 'skipValidation',
       'count', 'normalize', 'number'
     ]
 
@@ -204,7 +204,7 @@ function Yargs (processArgs, cwd, parentRequire) {
 
   self.requiresArg = function (keys) {
     argsert('<array|string>', [keys], arguments.length)
-    populateParserHintArray('requiresArg', keys)
+    populateParserHintObject(self.nargs, false, 'narg', keys, 1)
     return self
   }
 
@@ -965,17 +965,6 @@ function Yargs (processArgs, cwd, parentRequire) {
     options.__ = y18n.__
     options.configuration = pkgUp()['yargs'] || {}
 
-    // numbers are defaulted to `undefined`, which makes it impossible to verify requiresArg
-    // so _unlike_ other types, we will implicitly add them to narg when requiresArg is true
-    const numberTyped = new Set(options.number)
-    options.requiresArg
-      .filter(key => numberTyped.has(key))
-      .forEach(key => {
-        // if narg _and_ requiresArg are configured for an option,
-        // we should probably throw an error somewhere indicating conflicting configuration
-        options.narg[key] = 1
-      })
-
     const parsed = Parser.detailed(args, options)
     let argv = parsed.argv
     if (parseContext) argv = Object.assign({}, argv, parseContext)
@@ -1118,7 +1107,6 @@ function Yargs (processArgs, cwd, parentRequire) {
   self._runValidation = function runValidation (argv, aliases, positionalMap, parseErrors) {
     if (parseErrors) throw new YError(parseErrors.message)
     validation.nonOptionCount(argv)
-    validation.missingArgumentValue(argv)
     validation.requiredArguments(argv)
     if (strict) validation.unknownArguments(argv, aliases, positionalMap)
     validation.customChecks(argv, aliases)


Test patch:
diff --git a/test/usage.js b/test/usage.js
index 22d37fc..e1ce066 100644
--- a/test/usage.js
+++ b/test/usage.js
@@ -693,7 +693,7 @@ describe('usage tests', () => {
           '  --version  Show version number  [boolean]',
           '  --foo, -f  foo option',
           '  --bar, -b  bar option',
-          'Missing argument value: foo'
+          'Not enough arguments following: f'
         ])
       })
 
@@ -722,7 +722,7 @@ describe('usage tests', () => {
           '  --version  Show version number  [boolean]',
           '  --foo, -f  foo option',
           '  --bar, -b  bar option',
-          'Missing argument values: foo, bar'
+          'Not enough arguments following: bar'
         ])
       })
     })
@@ -754,7 +754,7 @@ describe('usage tests', () => {
           '  --version  Show version number  [boolean]',
           '  --foo, -f  foo option',
           '  --bar, -b  bar option',
-          'Missing argument value: foo'
+          'Not enough arguments following: f'
         ])
       })
     })
@@ -769,7 +769,7 @@ describe('usage tests', () => {
           .argv
         )
 
-      r.errors[1].should.equal('Missing argument values: foo, bar')
+      r.errors[1].should.equal('Not enough arguments following: bar')
     })
   })
 
diff --git a/test/validation.js b/test/validation.js
index c37be6c..22f613e 100644
--- a/test/validation.js
+++ b/test/validation.js
@@ -441,7 +441,7 @@ describe('validation tests', () => {
         .option('w', {type: 'string', requiresArg: true})
         .parse('-w', (err, argv, output) => {
           expect(err).to.exist
-          expect(err).to.have.property('message', 'Missing argument value: w')
+          expect(err).to.have.property('message', 'Not enough arguments following: w')
           return done()
         })
     })
@@ -451,7 +451,7 @@ describe('validation tests', () => {
         .option('w', {type: 'boolean', requiresArg: true})
         .parse('-w', (err, argv, output) => {
           expect(err).to.exist
-          expect(err).to.have.property('message', 'Missing argument value: w')
+          expect(err).to.have.property('message', 'Not enough arguments following: w')
           return done()
         })
     })
@@ -461,7 +461,7 @@ describe('validation tests', () => {
         .option('w', {type: 'array', requiresArg: true})
         .parse('-w', (err, argv, output) => {
           expect(err).to.exist
-          expect(err).to.have.property('message', 'Missing argument value: w')
+          expect(err).to.have.property('message', 'Not enough arguments following: w')
           return done()
         })
     })
diff --git a/test/yargs.js b/test/yargs.js
index c3365e2..1945228 100644
--- a/test/yargs.js
+++ b/test/yargs.js
@@ -226,7 +226,6 @@ describe('yargs dsl tests', () => {
         defaultDescription: {},
         choices: {},
         coerce: {},
-        requiresArg: [],
         skipValidation: [],
         count: [],
         normalize: [],