From 44621ef08f5d33c332039eb7c62410f9f2d04e62 Mon Sep 17 00:00:00 2001 From: Landon Yarrington Date: Tue, 3 Aug 2021 21:39:33 -0600 Subject: [PATCH 1/3] fix: conflicts and strip-dashed --- lib/utils/camel-case.ts | 19 +++++++++++++++++++ lib/validation.ts | 19 +++++++++++++++++++ test/validation.cjs | 21 +++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 lib/utils/camel-case.ts diff --git a/lib/utils/camel-case.ts b/lib/utils/camel-case.ts new file mode 100644 index 000000000..aef8611d2 --- /dev/null +++ b/lib/utils/camel-case.ts @@ -0,0 +1,19 @@ +export function camelCase(s: string) { + if (!s) return ''; + // split camel case, then match ascii words + const words = asciiWords(s.replace(/([a-z0-9])([A-Z])/g, '$1 $2')); + return words.length > 1 + ? words[0].toLowerCase() + words.slice(1).map(capitalizeFirst).join('') + : words[0].toLowerCase(); +} + +function capitalizeFirst(word: string): string { + return word ? word[0].toUpperCase() + word.slice(1).toLowerCase() : ''; +} + +// eslint-disable-next-line no-control-regex +const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + +function asciiWords(s: string) { + return s.match(reAsciiWord) || []; +} diff --git a/lib/validation.ts b/lib/validation.ts index 71dd77db0..33107cd56 100644 --- a/lib/validation.ts +++ b/lib/validation.ts @@ -6,6 +6,7 @@ import { } from './typings/common-types.js'; import {levenshtein as distance} from './utils/levenshtein.js'; import {objFilter} from './utils/obj-filter.js'; +import {camelCase} from './utils/camel-case'; import {UsageInstance} from './usage.js'; import {YargsInstance, Arguments} from './yargs-factory.js'; import {DetailedArguments} from './typings/yargs-parser-types.js'; @@ -411,6 +412,24 @@ export function validation( }); } }); + + // When strip-dashed is true, match conflicts (kebab) with argv (camel) + // Addresses: https://github.com/yargs/yargs/issues/1952 + if (yargs.getInternalMethods().getParserConfiguration()['strip-dashed']) { + Object.keys(conflicting).forEach(key => { + conflicting[key].forEach(value => { + if ( + value && + argv[camelCase(key)] !== undefined && + argv[camelCase(value)] !== undefined + ) { + usage.fail( + __('Arguments %s and %s are mutually exclusive', key, value) + ); + } + }); + }); + } }; self.recommendCommands = function recommendCommands(cmd, potentialCommands) { diff --git a/test/validation.cjs b/test/validation.cjs index 6e15ab4f9..8a116fdab 100644 --- a/test/validation.cjs +++ b/test/validation.cjs @@ -204,6 +204,27 @@ describe('validation tests', () => { .parse(); }); + // Addresses: https://github.com/yargs/yargs/issues/1952 + it('fails if conflicting arguments are provided, and strip-dashed is enabled', () => { + yargs() + .option('foo-foo', { + description: 'a foo-foo', + type: 'string', + }) + .option('bar-bar', { + description: 'a bar-bar', + type: 'string', + }) + .conflicts({'foo-foo': 'bar-bar'}) + .parserConfiguration({'strip-dashed': true}) + .parse('--foo-foo a --bar-bar b', (error, argv, output) => { + expect(error).to.not.equal(null); + error.message.should.match( + /Arguments foo-foo and bar-bar are mutually exclusive/ + ); + }); + }); + it('should not fail if no conflicting arguments are provided', () => { yargs(['-b', '-c']) .conflicts('f', ['b', 'c']) From 091ab32b8977e01f8d1836f75e88079ba79f3625 Mon Sep 17 00:00:00 2001 From: Landon Yarrington Date: Tue, 3 Aug 2021 21:51:44 -0600 Subject: [PATCH 2/3] fixes --- lib/validation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validation.ts b/lib/validation.ts index 33107cd56..b9d88e159 100644 --- a/lib/validation.ts +++ b/lib/validation.ts @@ -6,7 +6,7 @@ import { } from './typings/common-types.js'; import {levenshtein as distance} from './utils/levenshtein.js'; import {objFilter} from './utils/obj-filter.js'; -import {camelCase} from './utils/camel-case'; +import {camelCase} from './utils/camel-case.js'; import {UsageInstance} from './usage.js'; import {YargsInstance, Arguments} from './yargs-factory.js'; import {DetailedArguments} from './typings/yargs-parser-types.js'; From a483741aa53c5d81800057912cea603a0fba6fa2 Mon Sep 17 00:00:00 2001 From: Landon Yarrington Date: Tue, 7 Sep 2021 14:16:24 -0600 Subject: [PATCH 3/3] fixes --- lib/utils/camel-case.ts | 19 ------------------- lib/validation.ts | 5 ++--- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 lib/utils/camel-case.ts diff --git a/lib/utils/camel-case.ts b/lib/utils/camel-case.ts deleted file mode 100644 index aef8611d2..000000000 --- a/lib/utils/camel-case.ts +++ /dev/null @@ -1,19 +0,0 @@ -export function camelCase(s: string) { - if (!s) return ''; - // split camel case, then match ascii words - const words = asciiWords(s.replace(/([a-z0-9])([A-Z])/g, '$1 $2')); - return words.length > 1 - ? words[0].toLowerCase() + words.slice(1).map(capitalizeFirst).join('') - : words[0].toLowerCase(); -} - -function capitalizeFirst(word: string): string { - return word ? word[0].toUpperCase() + word.slice(1).toLowerCase() : ''; -} - -// eslint-disable-next-line no-control-regex -const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; - -function asciiWords(s: string) { - return s.match(reAsciiWord) || []; -} diff --git a/lib/validation.ts b/lib/validation.ts index b9d88e159..0a5b334a3 100644 --- a/lib/validation.ts +++ b/lib/validation.ts @@ -6,7 +6,6 @@ import { } from './typings/common-types.js'; import {levenshtein as distance} from './utils/levenshtein.js'; import {objFilter} from './utils/obj-filter.js'; -import {camelCase} from './utils/camel-case.js'; import {UsageInstance} from './usage.js'; import {YargsInstance, Arguments} from './yargs-factory.js'; import {DetailedArguments} from './typings/yargs-parser-types.js'; @@ -420,8 +419,8 @@ export function validation( conflicting[key].forEach(value => { if ( value && - argv[camelCase(key)] !== undefined && - argv[camelCase(value)] !== undefined + argv[shim.Parser.camelCase(key)] !== undefined && + argv[shim.Parser.camelCase(value)] !== undefined ) { usage.fail( __('Arguments %s and %s are mutually exclusive', key, value)