Repository: yargs/yargs (js)

Issue:
defaultDescription should work with positional()
Within a command builder function:

```js
    yargs.positional('spec', {
      description: 'One or more files, directories, or globs to test',
      type: 'array',
      default: ['test/'],
      defaultDescription: 'yabba dabba doo'
    })
```

but help shows:

```plain
  spec  One or more files, directories, or globs to test    [default: ["test/"]]
```

It should show `[default: "yabba dabba doo"]`.


Pull request description:
feat: support defaultDescription for positional arguments
**Summary**
Add `defaultDescription` to `supportedOpts` for positional arguments.

Fixes #1241

Patch:
diff --git a/docs/api.md b/docs/api.md
index 3fbb5f9..386845d 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1234,6 +1234,7 @@ Valid `opt` keys include:
   - `coerce`: function, coerce or transform parsed command line values into another value, see [`coerce()`](#coerce)
   - `conflicts`: string or object, require certain keys not to be set, see [`conflicts()`](#conflicts)
   - `default`: value, set a default value for the option, see [`default()`](#default)
+  - `defaultDescription`: string, use this description for the default value in help content, see [`default()`](#default)
   - `desc`/`describe`/`description`: string, the option description for help content, see [`describe()`](#describe)
   - `implies`: string or object, require certain keys to be set, see [`implies()`](#implies)
   - `normalize`: boolean, apply `path.normalize()` to the option, see [`normalize()`](#normalize)
diff --git a/yargs.js b/yargs.js
index ea1f15f..9a2e633 100644
--- a/yargs.js
+++ b/yargs.js
@@ -694,8 +694,8 @@ function Yargs (processArgs, cwd, parentRequire) {
     }
 
     // .positional() only supports a subset of the configuration
-    // options availble to .option().
-    const supportedOpts = ['default', 'implies', 'normalize',
+    // options available to .option().
+    const supportedOpts = ['default', 'defaultDescription', 'implies', 'normalize',
       'choices', 'conflicts', 'coerce', 'type', 'describe',
       'desc', 'description', 'alias']
     opts = objFilter(opts, (k, v) => {


Test patch:
diff --git a/test/usage.js b/test/usage.js
index fd6197e..4d21153 100644
--- a/test/usage.js
+++ b/test/usage.js
@@ -2095,6 +2095,118 @@ describe('usage tests', () => {
         r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
       })
     })
+
+    describe('using positional() without default()', () => {
+      it('should output given desc with default value', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs.positional('port', {
+              describe: 'The port value for URL',
+              defaultDescription: '80 for HTTP and 443 for HTTPS',
+              default: 80
+            })
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
+      })
+
+      it('should output given desc without default value', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs.positional('port', {
+              describe: 'The port value for URL',
+              defaultDescription: '80 for HTTP and 443 for HTTPS'
+            })
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
+      })
+
+      it('should prefer given desc over function desc', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs.positional('port', {
+              describe: 'The port value for URL',
+              defaultDescription: '80 for HTTP and 443 for HTTPS',
+              default: function determinePort () {
+                return 80
+              }
+            })
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
+      })
+    })
+
+    describe('using positional() with default()', () => {
+      it('should prefer default() desc when given last', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs
+              .positional('port', {
+                describe: 'The port value for URL',
+                defaultDescription: 'depends on protocol'
+              })
+              .default('port', null, '80 for HTTP and 443 for HTTPS')
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
+      })
+
+      it('should prefer positional() desc when given last', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs
+              .default('port', null, '80 for HTTP and 443 for HTTPS')
+              .positional('port', {
+                describe: 'The port value for URL',
+                defaultDescription: 'depends on protocol'
+              })
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: depends on protocol')
+      })
+
+      it('should prefer positional() desc over default() function', () => {
+        const r = checkUsage(() => yargs(['url', '-h'])
+          .help('h')
+          .command('url', 'Print a URL', (yargs) => {
+            yargs
+              .positional('port', {
+                describe: 'The port value for URL',
+                defaultDescription: '80 for HTTP and 443 for HTTPS'
+              })
+              .default('port', function determinePort () {
+                return 80
+              })
+          })
+          .wrap(null)
+          .parse()
+        )
+
+        r.logs[0].should.include('default: 80 for HTTP and 443 for HTTPS')
+      })
+    })
   })
 
   describe('normalizeAliases', () => {
diff --git a/test/yargs.js b/test/yargs.js
index 47911c1..fa232e2 100644
--- a/test/yargs.js
+++ b/test/yargs.js
@@ -2046,6 +2046,20 @@ describe('yargs dsl tests', () => {
       argv.heroes.should.eql(['batman', 'Iron Man'])
     })
 
+    it('allows a defaultDescription to be set', () => {
+      yargs('cmd')
+        .command('cmd [heroes...]', 'a command', (yargs) => {
+          yargs.positional('heroes', {
+            default: ['batman', 'Iron Man'],
+            defaultDescription: 'batman and Iron Man'
+          })
+        }).parse()
+
+      yargs.getOptions().defaultDescription.should.deep.equal({
+        heroes: 'batman and Iron Man'
+      })
+    })
+
     it('allows an implied argument to be specified', (done) => {
       yargs()
         .command('cmd <hero>', 'a command', (yargs) => {