Repository: yargs/yargs
Pull request #1559 (2020-02-12 18:44:25)

feat: deprecateOption
Shows a `[deprecated]` notice in front of an option

* Added a method: `.deprecateOption(key, [message])`
* Added a key in option conrtructor: `.option(key, { deprecated: [boolean|message] })`
* Basic Tests
* Updated Readme

Work towards #1518 

mleguen: Thank you @laggingreflex 

I will try to review this ASAP, but I am afraid I won't have time to do it before next week.

Patch:
diff --git a/docs/api.md b/docs/api.md
index 9f55c07..9fecb99 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -578,6 +578,44 @@ _Note: in `minMsg` and `maxMsg`, every occurrence of `$0` will be replaced
 with the observed value, and every instance of `$1` will be replaced with the
 expected value._
 
+<a name="deprecateOption"></a>.deprecateOption(key, [msg | boolean])
+--------------------
+
+Shows a `[deprecated]` notice in front of the option.
+
+```javascript
+require('yargs')
+  .option('old')
+  .deprecateOption('old')
+  .option('new')
+```
+```bash
+Options:
+  --old                                     [deprecated]
+  --new
+```
+
+You can also specify a message
+
+```javascript
+require('yargs')
+  .option('old')
+  .deprecateOption('old', 'use --new')
+  .option('new')
+```
+```bash
+Options:
+  --old                          [deprecated: use --new]
+  --new
+```
+
+You can also use it within the option constructor
+
+```javascript
+require('yargs')
+  .option('old', { deprecated: true })
+```
+
 <a name="describe"></a>.describe(key, desc)
 --------------------
 
diff --git a/lib/usage.js b/lib/usage.js
index 4ad140e..63779e6 100644
--- a/lib/usage.js
+++ b/lib/usage.js
@@ -155,6 +155,7 @@ module.exports = function usage (yargs, y18n) {
     const base$0 = yargs.customScriptName ? yargs.$0 : path.basename(yargs.$0)
     const demandedOptions = yargs.getDemandedOptions()
     const demandedCommands = yargs.getDemandedCommands()
+    const deprecatedOptions = yargs.getDeprecatedOptions()
     const groups = yargs.getGroups()
     const options = yargs.getOptions()
 
@@ -294,6 +295,11 @@ module.exports = function usage (yargs, y18n) {
         if (~options.number.indexOf(key)) type = `[${__('number')}]`
 
         const extra = [
+          (key in deprecatedOptions) ? (
+            typeof deprecatedOptions[key] === 'string'
+              ? `[${__('deprecated: %s', deprecatedOptions[key])}]`
+              : `[${__('deprecated')}]`
+          ) : null,
           type,
           (key in demandedOptions) ? `[${__('required')}]` : null,
           options.choices && options.choices[key] ? `[${__('choices:')} ${
diff --git a/locales/en.json b/locales/en.json
index 32586be..d794947 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -45,5 +45,7 @@
   "Did you mean %s?": "Did you mean %s?",
   "Arguments %s and %s are mutually exclusive" : "Arguments %s and %s are mutually exclusive",
   "Positionals:": "Positionals:",
-  "command": "command"
+  "command": "command",
+  "deprecated": "deprecated",
+  "deprecated: %s": "deprecated: %s"
 }
diff --git a/yargs.js b/yargs.js
index aa61db7..c320660 100644
--- a/yargs.js
+++ b/yargs.js
@@ -123,7 +123,8 @@ function Yargs (processArgs, cwd, parentRequire) {
 
     const objectOptions = [
       'narg', 'key', 'alias', 'default', 'defaultDescription',
-      'config', 'choices', 'demandedOptions', 'demandedCommands', 'coerce'
+      'config', 'choices', 'demandedOptions', 'demandedCommands', 'coerce',
+      'deprecatedOptions'
     ]
 
     arrayOptions.forEach((k) => {
@@ -448,6 +449,17 @@ function Yargs (processArgs, cwd, parentRequire) {
     return options.demandedCommands
   }
 
+  self.deprecateOption = function deprecateOption (option, message) {
+    argsert('<string> [string|boolean]', [option, message], arguments.length)
+    options.deprecatedOptions[option] = message
+    return self
+  }
+
+  self.getDeprecatedOptions = () => {
+    argsert([], 0)
+    return options.deprecatedOptions
+  }
+
   self.implies = function (key, value) {
     argsert('<string|object> [number|string|array]', [key, value], arguments.length)
     validation.implies(key, value)
@@ -621,6 +633,12 @@ function Yargs (processArgs, cwd, parentRequire) {
 
       if (opt.alias) self.alias(key, opt.alias)
 
+      const deprecate = opt.deprecate || opt.deprecated
+
+      if (deprecate) {
+        self.deprecateOption(key, deprecate)
+      }
+
       const demand = opt.demand || opt.required || opt.require
 
       // A required option can be specified via "demand: true".


Test patch:
diff --git a/test/usage.js b/test/usage.js
index b4fd9df..1d0f3f2 100644
--- a/test/usage.js
+++ b/test/usage.js
@@ -313,6 +313,89 @@ describe('usage tests', () => {
     })
   })
 
+  describe('deprecate options', () => {
+    describe('using .option(x, {deprecate: [boolean|string]})', () => {
+      it('{deprecated: true} should show [deprecated]', () => {
+        const r = checkUsage(() => yargs('--help')
+          .option('x', { deprecated: true })
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated]')
+      })
+      it('{deprecated: string} should show [deprecated: string]', () => {
+        const r = checkUsage(() => yargs('--help')
+          .option('x', { deprecated: 'string' })
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated: string]')
+      })
+      it('{deprecated: boolean} in sub-command', () => {
+        const r = checkUsage(() => yargs('command --help')
+          .option('x', { deprecated: true })
+          .command('command', 'command', yargs => yargs.option('y', { deprecated: true }))
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated]')
+        r.logs[0].should.include('  -y  [deprecated]')
+      })
+      it('{deprecated: string} in sub-command', () => {
+        const r = checkUsage(() => yargs('command --help')
+          .option('x', { deprecated: 'string' })
+          .command('command', 'command', yargs => yargs.option('y', { deprecated: 'string' }))
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated: string]')
+        r.logs[0].should.include('  -y  [deprecated: string]')
+      })
+    })
+    describe('using .deprecateOption(x, [string])', () => {
+      it('.deprecateOption(x) should show [deprecated]', () => {
+        const r = checkUsage(() => yargs('--help')
+          .option('x')
+          .deprecateOption('x')
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated]')
+      })
+      it('.deprecateOption(x, string) should show [deprecated: string]', () => {
+        const r = checkUsage(() => yargs('--help')
+          .option('x')
+          .deprecateOption('x', 'string')
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated: string]')
+      })
+      it('.deprecateOption(x) in a sub-command', () => {
+        const r = checkUsage(() => yargs('command --help')
+          .option('x')
+          .deprecateOption('x')
+          .command('command', 'command', yargs => yargs.option('y').deprecateOption('y'))
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated]')
+        r.logs[0].should.include('  -y  [deprecated]')
+      })
+      it('.deprecateOption(x, string) in a sub-command', () => {
+        const r = checkUsage(() => yargs('command --help')
+          .option('x')
+          .deprecateOption('x', 'string')
+          .command('command', 'command', yargs => yargs.option('y').deprecateOption('y', 'string'))
+          .wrap(null)
+          .parse()
+        )
+        r.logs[0].should.include('  -x  [deprecated: string]')
+        r.logs[0].should.include('  -y  [deprecated: string]')
+      })
+    })
+  })
+
   it('should return valid values when check passes', () => {
     const r = checkUsage(() => yargs('-x 10 -y 20')
       .usage('Usage: $0 -x NUM -y NUM')
diff --git a/test/yargs.js b/test/yargs.js
index a16946f..389a507 100644
--- a/test/yargs.js
+++ b/test/yargs.js
@@ -322,6 +322,7 @@ describe('yargs dsl tests', () => {
         hiddenOptions: [],
         demandedCommands: {},
         demandedOptions: {},
+        deprecatedOptions: {},
         local: [
           '_',
           'foo',