Repository: yargs/yargs-parser
Pull request #243 (2020-02-09 21:43:45)

fix: array should take precedence over nargs, but enforce nargs
by switching the order of parsing `nargs` and `array`, but enforcing the `nargs` count in `array`, we can address the issue discussed in https://github.com/yargs/yargs/issues/1098.

Refs: https://github.com/yargs/yargs/issues/1098


Patch:
diff --git a/index.js b/index.js
index 658b679..c7f728a 100644
--- a/index.js
+++ b/index.js
@@ -163,14 +163,14 @@ function parse (args, opts) {
       // http://stackoverflow.com/a/1068308/13216
       m = arg.match(/^--?([^=]+)=([\s\S]*)$/)
 
-      // nargs format = '--f=monkey washing cat'
-      if (checkAllAliases(m[1], flags.nargs)) {
-        args.splice(i + 1, 0, m[2])
-        i = eatNargs(i, m[1], args)
       // arrays format = '--f=a b c'
-      } else if (checkAllAliases(m[1], flags.arrays)) {
+      if (checkAllAliases(m[1], flags.arrays)) {
         args.splice(i + 1, 0, m[2])
         i = eatArray(i, m[1], args)
+      } else if (checkAllAliases(m[1], flags.nargs)) {
+        // nargs format = '--f=monkey washing cat'
+        args.splice(i + 1, 0, m[2])
+        i = eatNargs(i, m[1], args)
       } else {
         setArg(m[1], m[2])
       }
@@ -184,13 +184,13 @@ function parse (args, opts) {
     )) {
       key = arg.match(/^--?(.+)/)[1]
 
-      // nargs format = '--foo a b c'
-      // should be truthy even if: flags.nargs[key] === 0
-      if (checkAllAliases(key, flags.nargs) !== false) {
-        i = eatNargs(i, key, args)
-      // array format = '--foo a b c'
-      } else if (checkAllAliases(key, flags.arrays)) {
+      if (checkAllAliases(key, flags.arrays)) {
+        // array format = '--foo a b c'
         i = eatArray(i, key, args)
+      } else if (checkAllAliases(key, flags.nargs) !== false) {
+        // nargs format = '--foo a b c'
+        // should be truthy even if: flags.nargs[key] === 0
+        i = eatNargs(i, key, args)
       } else {
         next = args[i + 1]
 
@@ -237,14 +237,14 @@ function parse (args, opts) {
           value = arg.slice(j + 3)
           key = letters[j]
 
-          // nargs format = '-f=monkey washing cat'
-          if (checkAllAliases(key, flags.nargs)) {
-            args.splice(i + 1, 0, value)
-            i = eatNargs(i, key, args)
-          // array format = '-f=a b c'
-          } else if (checkAllAliases(key, flags.arrays)) {
+          if (checkAllAliases(key, flags.arrays)) {
+            // array format = '-f=a b c'
             args.splice(i + 1, 0, value)
             i = eatArray(i, key, args)
+          } else if (checkAllAliases(key, flags.nargs)) {
+            // nargs format = '-f=monkey washing cat'
+            args.splice(i + 1, 0, value)
+            i = eatNargs(i, key, args)
           } else {
             setArg(key, value)
           }
@@ -278,13 +278,13 @@ function parse (args, opts) {
       key = arg.slice(-1)[0]
 
       if (!broken && key !== '-') {
-        // nargs format = '-f a b c'
-        // should be truthy even if: flags.nargs[key] === 0
-        if (checkAllAliases(key, flags.nargs) !== false) {
-          i = eatNargs(i, key, args)
-        // array format = '-f a b c'
-        } else if (checkAllAliases(key, flags.arrays)) {
+        if (checkAllAliases(key, flags.arrays)) {
+          // array format = '-f a b c'
           i = eatArray(i, key, args)
+        } else if (checkAllAliases(key, flags.nargs) !== false) {
+          // nargs format = '-f a b c'
+          // should be truthy even if: flags.nargs[key] === 0
+          i = eatNargs(i, key, args)
         } else {
           next = args[i + 1]
 
@@ -409,6 +409,13 @@ function parse (args, opts) {
       }
     }
 
+    // If both array and nargs are configured, create an error if less than
+    // nargs positionals were found:
+    const toEat = checkAllAliases(key, flags.nargs)
+    if (toEat && argsToSet.length < toEat) {
+      error = Error(__('Not enough arguments following: %s', key))
+    }
+
     setArg(key, argsToSet)
     return i
   }


Test patch:
diff --git a/test/yargs-parser.js b/test/yargs-parser.js
index 30a0c6f..dd69197 100644
--- a/test/yargs-parser.js
+++ b/test/yargs-parser.js
@@ -3539,4 +3539,28 @@ describe('yargs-parser', function () {
     })
     parse.infinite.should.equal(false)
   })
+
+  // See: https://github.com/yargs/yargs/issues/1098
+  describe('array with nargs', () => {
+    it('allows array and nargs to be configured in conjunction, enforcing the nargs value', () => {
+      var parse = parser(['-a', 'apple', 'banana'], {
+        array: 'a',
+        narg: {
+          a: 1
+        }
+      })
+      parse.a.should.eql(['apple', 'banana'])
+    })
+
+    it('returns an error if not enough positionals were provided for nargs', () => {
+      var parse = parser.detailed(['-a'], {
+        array: 'a',
+        narg: {
+          a: 1
+        }
+      })
+      parse.argv.a.should.eql([])
+      parse.error.message.should.equal('Not enough arguments following: a')
+    })
+  })
 })