Repository: yargs/yargs
Pull request #944 (2017-08-25 05:53:59)

feat: allow parse with no arguments as alias for yargs.argv
I showed the the [proposed promise API](https://github.com/yargs/yargs/pull/940) for yargs to several coworkers today at npm, and they managed to talk me out of it. Their reasoning being:

1. yargs is for the most part a synchronous API, and they didn't see much value in introducing the deferred behavior.
2. my coworker @zkat felt that the method name `.then()` felt weird; _this method name should be used internally by the Promise api, not by APIs exposing a promise._

Rather than introducing a new method `run()` (or the method I recommended `then()` for exposing a Promise), I feel a good compromise is to instead extend the method `parse()` which already exists in the API. Calling:

```js
require('yargs')
  .option('x', {describe: 'x option'})
  .parse()
```

is now possible, and is equivalent to:

```js
require('yargs')
  .option('x', {describe: 'x option'})
  .argv
```

I like this approach: it gets around the linting warning now frequently triggered by `.argv`, and avoids adding a new method to yargs' already large API surface.

We definitely might revisit a Promise-based API in the future, one recommendation made by my coworker @chrisdickinson was to make yargs' command API promise based, e.g.,

* a command would return a promise to execute.
* yargs would return a promise that resolves once the command is completed.

bernardmcmanus: 👍 this feels much cleaner

Patch:
diff --git a/docs/api.md b/docs/api.md
index 8264699..1b21c8c 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -20,6 +20,12 @@ or use `.parse()` to do the same thing:
 require('yargs').parse([ '-x', '1', '-y', '2' ])
 ````
 
+Calling `.parse()` with no arguments is equivalent to calling `yargs.argv`:
+
+```javascript
+require('yargs').parse()
+```
+
 The rest of these methods below come in just before the terminating `.argv`.
 
 <a name="alias"></a>.alias(key, alias)
@@ -1007,7 +1013,7 @@ Valid `opt` keys include:
     - `'number'`: synonymous for `number: true`, see [`number()`](#number)
     - `'string'`: synonymous for `string: true`, see [`string()`](#string)
 
-.parse(args, [context], [parseCallback])
+.parse([args], [context], [parseCallback])
 ------------
 
 Parse `args` instead of `process.argv`. Returns the `argv` object.
diff --git a/yargs.js b/yargs.js
index 1b98641..c7d6db0 100644
--- a/yargs.js
+++ b/yargs.js
@@ -384,7 +384,7 @@ function Yargs (processArgs, cwd, parentRequire) {
   }
 
   self.demandCommand = function demandCommand (min, max, minMsg, maxMsg) {
-    argsert('[number] [number|string] [string|null] [string|null]', [min, max, minMsg, maxMsg], arguments.length)
+    argsert('[number] [number|string] [string|null|undefined] [string|null|undefined]', [min, max, minMsg, maxMsg], arguments.length)
 
     if (typeof min === 'undefined') min = 1
 
@@ -428,7 +428,7 @@ function Yargs (processArgs, cwd, parentRequire) {
   }
 
   self.usage = function (msg, opts) {
-    argsert('<string|null|object> [object]', [msg, opts], arguments.length)
+    argsert('<string|null|undefined|object> [object]', [msg, opts], arguments.length)
 
     if (!opts && typeof msg === 'object') {
       opts = msg
@@ -511,7 +511,8 @@ function Yargs (processArgs, cwd, parentRequire) {
   let parseFn = null
   let parseContext = null
   self.parse = function parse (args, shortCircuit, _parseFn) {
-    argsert('<string|array> [function|boolean|object] [function]', [args, shortCircuit, _parseFn], arguments.length)
+    argsert('[string|array] [function|boolean|object] [function]', [args, shortCircuit, _parseFn], arguments.length)
+    if (typeof args === 'undefined') args = processArgs
 
     // a context object can optionally be provided, this allows
     // additional information to be passed to a command handler.
@@ -685,7 +686,7 @@ function Yargs (processArgs, cwd, parentRequire) {
   }
 
   self.wrap = function (cols) {
-    argsert('<number|null>', [cols], arguments.length)
+    argsert('<number|null|undefined>', [cols], arguments.length)
     usage.wrap(cols)
     return self
   }


Test patch:
diff --git a/test/yargs.js b/test/yargs.js
index 82db481..ef9f860 100644
--- a/test/yargs.js
+++ b/test/yargs.js
@@ -791,6 +791,17 @@ describe('yargs dsl tests', () => {
       })
       a1.x.should.equal(42)
     })
+
+    it('parses process.argv if no arguments are provided', () => {
+      const r = checkOutput(() => {
+        yargs(['--help'])
+          .command('blerg', 'blerg command')
+          .wrap(null)
+          .parse()
+      })
+
+      r.logs[0].should.match(/Commands:[\s\S]*blerg command/)
+    })
   })
 
   // yargs.parse(['foo', '--bar'], function (err, argv, output) {}