From e0823dd7e6ced7eaf1d7d1e67f77374f4ef5cbce Mon Sep 17 00:00:00 2001 From: Gyubong Date: Sun, 15 May 2022 07:00:55 +0900 Subject: [PATCH 1/5] fix: handle multiple node_modules folders determining mainFilename for ESM (#2123) Co-authored-by: Landon Yarrington <33426811+jly36963@users.noreply.github.com> Co-authored-by: Benjamin E. Coe --- lib/platform-shims/esm.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/platform-shims/esm.mjs b/lib/platform-shims/esm.mjs index 92f2f0993..c25baa5a3 100644 --- a/lib/platform-shims/esm.mjs +++ b/lib/platform-shims/esm.mjs @@ -21,7 +21,7 @@ try { } catch (e) { __dirname = process.cwd(); } -const mainFilename = __dirname.split('node_modules')[0] +const mainFilename = __dirname.substring(0, __dirname.lastIndexOf('node_modules')); export default { assert: { From 4dac5b8c2f03488c31d40f075075d2ac43134412 Mon Sep 17 00:00:00 2001 From: Landon Yarrington <33426811+jly36963@users.noreply.github.com> Date: Sat, 14 May 2022 16:07:06 -0600 Subject: [PATCH 2/5] fix: passed arguments should take precedence over values in config (#2100) --- lib/command.ts | 11 ++++++----- lib/yargs-factory.ts | 24 ++++++++++++++++++++++++ test/command.cjs | 25 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/command.ts b/lib/command.ts index ff9da5b1b..2d4f462d7 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -593,19 +593,20 @@ export class CommandInstance { positionalKeys.push(...parsed.aliases[key]); }); - const defaults = yargs.getOptions().default; 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 ( - !Object.hasOwnProperty.call(defaults, key) && - Object.hasOwnProperty.call(argv, key) && - Object.hasOwnProperty.call(parsed.argv, 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])) ) { argv[key] = ([] as string[]).concat(argv[key], parsed.argv[key]); diff --git a/lib/yargs-factory.ts b/lib/yargs-factory.ts index 279d8bcce..b806688e1 100644 --- a/lib/yargs-factory.ts +++ b/lib/yargs-factory.ts @@ -869,6 +869,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) { diff --git a/test/command.cjs b/test/command.cjs index 867f8f9b5..d5f94b8cb 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 b672e709e4fc45f50d77f54e42025a5fa7c66a42 Mon Sep 17 00:00:00 2001 From: Landon Yarrington <33426811+jly36963@users.noreply.github.com> Date: Sun, 15 May 2022 07:20:45 -0600 Subject: [PATCH 3/5] fix: prevent infinite loop with empty locale (#2179) Co-authored-by: Benjamin E. Coe --- lib/yargs-factory.ts | 2 +- test/yargs.cjs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/yargs-factory.ts b/lib/yargs-factory.ts index b806688e1..077a44e3a 100644 --- a/lib/yargs-factory.ts +++ b/lib/yargs-factory.ts @@ -895,7 +895,7 @@ export class YargsInstance { } locale(locale?: string): YargsInstance | string { argsert('[string]', [locale], arguments.length); - if (!locale) { + if (locale === undefined) { this[kGuessLocale](); return this.#shim.y18n.getLocale(); } diff --git a/test/yargs.cjs b/test/yargs.cjs index e743a70da..42b4b83b8 100644 --- a/test/yargs.cjs +++ b/test/yargs.cjs @@ -757,6 +757,38 @@ describe('yargs dsl tests', () => { r.logs.join(' ').should.match(/Parlay this here code of conduct/); }); + // Addresses: https://github.com/yargs/yargs/issues/2178 + it('does not enter infinite loop when locale is invalid', () => { + // Save env vars + const lcAll = process.env.LC_ALL; + const lcMessages = process.env.LC_MESSAGES; + const lang = process.env.LANG; + const language = process.env.LANGUAGE; + // Change + delete process.env.LC_ALL; + delete process.env.LC_MESSAGES; + process.env.LANG = '.UTF-8'; + delete process.env.LANGUAGE; + try { + yargs + .command({ + command: 'cmd1', + desc: 'cmd1 desc', + builder: () => {}, + handler: _argv => {}, + }) + .parse(); + } catch { + expect.fail(); + } finally { + // Restore + process.env.LC_ALL = lcAll; + process.env.LC_MESSAGES = lcMessages; + process.env.LANG = lang; + process.env.LANGUAGE = language; + } + }); + describe('updateLocale', () => { it('allows you to override the default locale strings', () => { const r = checkOutput(() => { From 2109bd687d4084f41a47a8eea61aacd7ce44f4f0 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sun, 15 May 2022 20:53:46 -0400 Subject: [PATCH 4/5] refactor: make isDefaulted private (#2188) Co-authored-by: Landon Yarrington <33426811+jly36963@users.noreply.github.com> --- lib/command.ts | 25 +++++++++++++++++++++++-- lib/yargs-factory.ts | 24 ------------------------ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/lib/command.ts b/lib/command.ts index 2d4f462d7..42c0e570b 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -603,8 +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 ( - !yargs.isInConfigs(key) && - !yargs.isDefaulted(key) && + !this.isInConfigs(yargs, key) && + !this.isDefaulted(yargs, key) && Object.prototype.hasOwnProperty.call(argv, key) && Object.prototype.hasOwnProperty.call(parsed.argv, key) && (Array.isArray(argv[key]) || Array.isArray(parsed.argv[key])) @@ -617,6 +617,27 @@ export class CommandInstance { }); } } + // Check defaults for key (and camel case version of key) + isDefaulted(yargs: YargsInstance, key: string): boolean { + const {default: defaults} = yargs.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(yargs: YargsInstance, key: string): boolean { + const {configObjects} = yargs.getOptions(); + return ( + configObjects.some(c => Object.prototype.hasOwnProperty.call(c, key)) || + configObjects.some(c => + Object.prototype.hasOwnProperty.call(c, this.shim.Parser.camelCase(key)) + ) + ); + } runDefaultBuilderOn(yargs: YargsInstance): unknown | Promise { if (!this.defaultCommand) return; if (this.shouldUpdateUsage(yargs)) { diff --git a/lib/yargs-factory.ts b/lib/yargs-factory.ts index 077a44e3a..c3f88348f 100644 --- a/lib/yargs-factory.ts +++ b/lib/yargs-factory.ts @@ -869,30 +869,6 @@ 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 === undefined) { From 1c331f22c71496e3d50cf103a1b21f4a05d97aac Mon Sep 17 00:00:00 2001 From: edukisto <52005215+edukisto@users.noreply.github.com> Date: Mon, 16 May 2022 03:54:59 +0300 Subject: [PATCH 5/5] fix(lang): add missing terms to Russian translation (#2181) --- locales/ru.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/locales/ru.json b/locales/ru.json index 5f7f76810..d5c9e323b 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -42,5 +42,10 @@ "Path to JSON config file": "Путь к файлу конфигурации JSON", "Show help": "Показать помощь", "Show version number": "Показать номер версии", - "Did you mean %s?": "Вы имели в виду %s?" + "Did you mean %s?": "Вы имели в виду %s?", + "Arguments %s and %s are mutually exclusive": "Аргументы %s и %s являются взаимоисключающими", + "Positionals:": "Позиционные аргументы:", + "command": "команда", + "deprecated": "устар.", + "deprecated: %s": "устар.: %s" }