From b94fef74d91aafa6f3e09db75f8c9f0a1758673b Mon Sep 17 00:00:00 2001 From: Landon Yarrington Date: Sun, 19 Dec 2021 14:00:28 -0700 Subject: [PATCH 1/2] fix!: provided values should not be combined with config values --- lib/command.ts | 21 +++++++++++++++++++-- test/command.cjs | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/command.ts b/lib/command.ts index 19d8053c6..19231dd60 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -593,17 +593,34 @@ export class CommandInstance { positionalKeys.push(...parsed.aliases[key]); }); - const defaults = yargs.getOptions().default; + const {configObjects, default: defaults} = yargs.getOptions(); + Object.keys(parsed.argv).forEach(key => { if (positionalKeys.includes(key)) { // any new aliases need to be placed in positionalMap, which // is used for validation. if (!positionalMap[key]) positionalMap[key] = parsed.argv[key]; // Addresses: https://github.com/yargs/yargs/issues/1637 - // If both positionals/options provided, no default was set, + // If both positionals/options provided, + // and no default or config values were set for that key, // and if at least one is an array: don't overwrite, combine. if ( + // Check configObject values + !configObjects.some(config => + Object.prototype.hasOwnProperty.call(config, key) + ) && + !configObjects.some(config => + Object.prototype.hasOwnProperty.call( + config, + this.shim.Parser.camelCase(key) + ) + ) && + // Check default values !Object.prototype.hasOwnProperty.call(defaults, key) && + !Object.prototype.hasOwnProperty.call( + defaults, + this.shim.Parser.camelCase(key) + ) && Object.prototype.hasOwnProperty.call(argv, key) && Object.prototype.hasOwnProperty.call(parsed.argv, key) && (Array.isArray(argv[key]) || Array.isArray(parsed.argv[key])) diff --git a/test/command.cjs b/test/command.cjs index 189a16596..275994615 100644 --- a/test/command.cjs +++ b/test/command.cjs @@ -264,6 +264,31 @@ describe('Command', () => { .parse('cmd apples cherries grapes'); }); + it('does not combine config values and provided values', () => { + yargs('foo bar baz qux') + .command({ + command: '$0 [arg-2] [arg-3..]', + desc: 'default description', + builder: yargs => + yargs + .option('arg-1', {type: 'string'}) + .option('arg-2', {type: 'string'}) + .option('arg-3', {type: 'string'}) + .config({ + arg2: 'bar', + arg3: ['baz', 'qux'], + }), + handler: argv => { + argv.arg1.should.equal('foo'); + argv.arg2.should.equal('bar'); + argv.arg3.should.deep.equal(['baz', 'qux']); + argv['arg-3'].should.deep.equal(['baz', 'qux']); + }, + }) + .strict() + .parse(); + }); + it('does not overwrite options in argv if variadic and preserves falsy values', () => { yargs .command({ From fe1ba88ed3a6ec49f88e8530f61e144288c923c9 Mon Sep 17 00:00:00 2001 From: Landon Yarrington Date: Sun, 2 Jan 2022 15:46:20 -0700 Subject: [PATCH 2/2] fixes --- lib/command.ts | 20 ++------------------ lib/yargs-factory.ts | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/command.ts b/lib/command.ts index 19231dd60..df277b851 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -593,8 +593,6 @@ export class CommandInstance { positionalKeys.push(...parsed.aliases[key]); }); - const {configObjects, default: defaults} = yargs.getOptions(); - Object.keys(parsed.argv).forEach(key => { if (positionalKeys.includes(key)) { // any new aliases need to be placed in positionalMap, which @@ -605,22 +603,8 @@ export class CommandInstance { // and no default or config values were set for that key, // and if at least one is an array: don't overwrite, combine. if ( - // Check configObject values - !configObjects.some(config => - Object.prototype.hasOwnProperty.call(config, key) - ) && - !configObjects.some(config => - Object.prototype.hasOwnProperty.call( - config, - this.shim.Parser.camelCase(key) - ) - ) && - // Check default values - !Object.prototype.hasOwnProperty.call(defaults, key) && - !Object.prototype.hasOwnProperty.call( - defaults, - this.shim.Parser.camelCase(key) - ) && + !yargs.isInConfigs(key) && + !yargs.isDefaulted(key) && Object.prototype.hasOwnProperty.call(argv, key) && Object.prototype.hasOwnProperty.call(parsed.argv, key) && (Array.isArray(argv[key]) || Array.isArray(parsed.argv[key])) diff --git a/lib/yargs-factory.ts b/lib/yargs-factory.ts index 2dff7e395..016af04c1 100644 --- a/lib/yargs-factory.ts +++ b/lib/yargs-factory.ts @@ -855,6 +855,30 @@ export class YargsInstance { this.#validation.implies(key, value); return this; } + // Check defaults for key (and camel case version of key) + isDefaulted(key: string): boolean { + const {default: defaults} = this.getOptions(); + return ( + Object.prototype.hasOwnProperty.call(defaults, key) || + Object.prototype.hasOwnProperty.call( + defaults, + this.#shim.Parser.camelCase(key) + ) + ); + } + // Check each config for key (and camel case version of key) + isInConfigs(key: string): boolean { + const {configObjects} = this.getOptions(); + return ( + configObjects.some(c => Object.prototype.hasOwnProperty.call(c, key)) || + configObjects.some(c => + Object.prototype.hasOwnProperty.call( + c, + this.#shim.Parser.camelCase(key) + ) + ) + ); + } locale(locale?: string): YargsInstance | string { argsert('[string]', [locale], arguments.length); if (!locale) {