diff --git a/docs/api.md b/docs/api.md index 9f55c0788..9fecb99ac 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._ +.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 }) +``` + .describe(key, desc) -------------------- diff --git a/lib/usage.js b/lib/usage.js index 4ad140e1d..63779e61d 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 32586becc..d794947dc 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/test/usage.js b/test/usage.js index b4fd9dfb0..1d0f3f233 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 a16946fe5..389a50711 100644 --- a/test/yargs.js +++ b/test/yargs.js @@ -322,6 +322,7 @@ describe('yargs dsl tests', () => { hiddenOptions: [], demandedCommands: {}, demandedOptions: {}, + deprecatedOptions: {}, local: [ '_', 'foo', diff --git a/yargs.js b/yargs.js index aa61db7a8..c32066020 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|boolean]', [option, message], arguments.length) + options.deprecatedOptions[option] = message + return self + } + + self.getDeprecatedOptions = () => { + argsert([], 0) + return options.deprecatedOptions + } + self.implies = function (key, value) { argsert(' [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".