From 5a201ecb5d1ee3589a1f1ebb9347b0ff52cb2dbd Mon Sep 17 00:00:00 2001 From: John Gee Date: Mon, 19 Dec 2022 19:02:23 +1300 Subject: [PATCH] Add getOptionValueSourceWithGlobals for completeness. (#1832) --- lib/command.js | 19 +++ tests/options.optsWithGlobals.test.js | 164 +++++++++++++++++--------- typings/index.d.ts | 7 +- typings/index.test-d.ts | 3 + 4 files changed, 136 insertions(+), 57 deletions(-) diff --git a/lib/command.js b/lib/command.js index 9284ec39f..7a637cb77 100644 --- a/lib/command.js +++ b/lib/command.js @@ -814,6 +814,25 @@ Expecting one of '${allowedValues.join("', '")}'`); return this._optionValueSources[key]; } + /** + * Get source of option value. See also .optsWithGlobals(). + * Expected values are default | config | env | cli | implied + * + * @param {string} key + * @return {string} + */ + + getOptionValueSourceWithGlobals(key) { + // global overwrites local, like optsWithGlobals + let source; + getCommandAndParents(this).forEach((cmd) => { + if (cmd.getOptionValueSource(key) !== undefined) { + source = cmd.getOptionValueSource(key); + } + }); + return source; + } + /** * Get user arguments from implied or explicit arguments. * Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches. diff --git a/tests/options.optsWithGlobals.test.js b/tests/options.optsWithGlobals.test.js index 4cc52ecd8..95ed2c5dc 100644 --- a/tests/options.optsWithGlobals.test.js +++ b/tests/options.optsWithGlobals.test.js @@ -1,63 +1,115 @@ const commander = require('../'); -test('when variety of options used with program then opts is same as optsWithGlobals', () => { - const program = new commander.Command(); - program - .option('-b, --boolean') - .option('-r, --require-value ', 'description', parseFloat) - .option('-d, --default-value { - const program = new commander.Command(); - let mergedOptions; - program - .option('-g, --global '); - program - .command('sub') - .option('-l, --local { - mergedOptions = cmd.optsWithGlobals(); - }); - - program.parse(['-g', 'GGG', 'sub', '-l', 'LLL'], { from: 'user' }); - expect(mergedOptions).toEqual({ global: 'GGG', local: 'LLL' }); -}); +describe('optsWithGlobals', () => { + test('when variety of options used with program then opts is same as optsWithGlobals', () => { + const program = new commander.Command(); + program + .option('-b, --boolean') + .option('-r, --require-value ', 'description', parseFloat) + .option('-d, --default-value { + const program = new commander.Command(); + let mergedOptions; + program + .option('-g, --global '); + program + .command('sub') + .option('-l, --local { + mergedOptions = cmd.optsWithGlobals(); + }); + + program.parse(['-g', 'GGG', 'sub', '-l', 'LLL'], { from: 'user' }); + expect(mergedOptions).toEqual({ global: 'GGG', local: 'LLL' }); + }); + + test('when options in sub and subsub then optsWithGlobals includes both', () => { + const program = new commander.Command(); + let mergedOptions; + program + .command('sub') + .option('-g, --global { + mergedOptions = cmd.optsWithGlobals(); + }); + + program.parse(['sub', '-g', 'GGG', 'subsub', '-l', 'LLL'], { from: 'user' }); + expect(mergedOptions).toEqual({ global: 'GGG', local: 'LLL' }); + }); + + test('when same named option in sub and program then optsWithGlobals includes global', () => { + const program = new commander.Command(); + let mergedOptions; + program + .option('-c, --common ') + .enablePositionalOptions(); + program + .command('sub') + .option('-c, --common { + mergedOptions = cmd.optsWithGlobals(); + }); -test('when options in sub and subsub then optsWithGlobals includes both', () => { - const program = new commander.Command(); - let mergedOptions; - program - .command('sub') - .option('-g, --global { - mergedOptions = cmd.optsWithGlobals(); - }); - - program.parse(['sub', '-g', 'GGG', 'subsub', '-l', 'LLL'], { from: 'user' }); - expect(mergedOptions).toEqual({ global: 'GGG', local: 'LLL' }); + program.parse(['-c', 'GGG', 'sub', '-c', 'LLL'], { from: 'user' }); + expect(mergedOptions).toEqual({ common: 'GGG' }); + }); }); -test('when same named option in sub and program then optsWithGlobals includes global', () => { - const program = new commander.Command(); - let mergedOptions; - program - .option('-c, --common ') - .enablePositionalOptions(); - program - .command('sub') - .option('-c, --common { - mergedOptions = cmd.optsWithGlobals(); - }); - - program.parse(['-c', 'GGG', 'sub', '-c', 'LLL'], { from: 'user' }); - expect(mergedOptions).toEqual({ common: 'GGG' }); +describe('getOptionValueSourceWithGlobals', () => { + test('when option used with simple command then source is defined', () => { + const program = new commander.Command(); + program + .option('-g, --global'); + + program.parse(['-g'], { from: 'user' }); + expect(program.getOptionValueSourceWithGlobals('global')).toEqual('cli'); + }); + + test('when option used with program then source is defined', () => { + const program = new commander.Command(); + program + .option('-g, --global'); + const sub = program.command('sub') + .option('-l, --local') + .action(() => {}); + + program.parse(['sub', '-g'], { from: 'user' }); + expect(sub.getOptionValueSourceWithGlobals('global')).toEqual('cli'); + }); + + test('when option used with subcommand then source is defined', () => { + const program = new commander.Command(); + program + .option('-g, --global'); + const sub = program.command('sub') + .option('-l, --local') + .action(() => {}); + + program.parse(['sub', '-l'], { from: 'user' }); + expect(sub.getOptionValueSourceWithGlobals('local')).toEqual('cli'); + }); + + test('when same named option in sub and program then source is defined by global', () => { + const program = new commander.Command(); + program + .enablePositionalOptions() + .option('-c, --common ', 'description', 'default value'); + const sub = program.command('sub') + .option('-c, --common ') + .action(() => {}); + + program.parse(['sub', '--common', 'value'], { from: 'user' }); + expect(sub.getOptionValueSourceWithGlobals('common')).toEqual('default'); + }); }); diff --git a/typings/index.d.ts b/typings/index.d.ts index 7c76805d8..e9a5e4b36 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -600,10 +600,15 @@ export class Command { setOptionValueWithSource(key: string, value: unknown, source: OptionValueSource): this; /** - * Retrieve option value source. + * Get source of option value. */ getOptionValueSource(key: string): OptionValueSource | undefined; + /** + * Get source of option value. See also .optsWithGlobals(). + */ + getOptionValueSourceWithGlobals(key: string): OptionValueSource | undefined; + /** * Alter parsing of short flags with optional values. * diff --git a/typings/index.test-d.ts b/typings/index.test-d.ts index 7df4cc9e8..95b171baf 100644 --- a/typings/index.test-d.ts +++ b/typings/index.test-d.ts @@ -174,6 +174,9 @@ expectType(program.setOptionValueWithSource('example', [], 'c // getOptionValueSource expectType(program.getOptionValueSource('example')); +// getOptionValueSourceWithGlobals +expectType(program.getOptionValueSourceWithGlobals('example')); + // combineFlagAndOptionalValue expectType(program.combineFlagAndOptionalValue()); expectType(program.combineFlagAndOptionalValue(false));