From 114ac2e2d2ca4c584b8186056ad7492fdb519deb Mon Sep 17 00:00:00 2001 From: Joshua Lipstone Date: Fri, 5 Aug 2022 20:30:17 -0500 Subject: [PATCH] Implemented option to delay treating non-flags as haltable --- lib/yargs-parser-types.ts | 2 ++ lib/yargs-parser.ts | 10 ++++++++-- test/yargs-parser.cjs | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/yargs-parser-types.ts b/lib/yargs-parser-types.ts index 9e03ff2c..91cd75c5 100644 --- a/lib/yargs-parser-types.ts +++ b/lib/yargs-parser-types.ts @@ -88,6 +88,8 @@ export interface Configuration { 'strip-dashed': boolean; /** Should unknown options be treated like regular arguments? An unknown option is one that is not configured in opts. Default is `false` */ 'unknown-options-as-args': boolean; + /** Should we delay treating non-flag tokens as invalid until we've seen a flag. Default is 'false' **/ + 'wait-for-first-flag-before-filtering-options': boolean; } export type ArrayOption = string | { key: string; boolean?: boolean, string?: boolean, number?: boolean, integer?: boolean }; diff --git a/lib/yargs-parser.ts b/lib/yargs-parser.ts index 764ca64e..3312b063 100644 --- a/lib/yargs-parser.ts +++ b/lib/yargs-parser.ts @@ -83,7 +83,8 @@ export class YargsParser { 'short-option-groups': true, 'strip-aliased': false, 'strip-dashed': false, - 'unknown-options-as-args': false + 'unknown-options-as-args': false, + 'wait-for-first-flag-before-filtering-options': false }, opts.configuration) const defaults: OptionsDefault = Object.assign(Object.create(null), opts.default) const configObjects = opts.configObjects || [] @@ -210,6 +211,7 @@ export class YargsParser { // remove all prototypes from objects returned by this API, we might want // to gradually move towards doing so. const argvReturn: { [argName: string]: any } = {} + let requireDash = !configuration['wait-for-first-flag-before-filtering-options']; for (let i = 0; i < args.length; i++) { const arg = args[i] @@ -221,8 +223,12 @@ export class YargsParser { let next: string let value: string + if (!requireDash && arg.length > 0 && arg.charAt(0) === '-') { + requireDash = true; + } + // any unknown option (except for end-of-options, "--") - if (arg !== '--' && /^-/.test(arg) && isUnknownOptionAsArg(arg)) { + if (arg !== '--' && (!requireDash || /^-/.test(arg)) && isUnknownOptionAsArg(arg)) { pushPositional(arg) // ---, ---=, ----, etc, } else if (truncatedArg.match(/^---+(=|$)/)) { diff --git a/test/yargs-parser.cjs b/test/yargs-parser.cjs index 492e3b90..076bd2f3 100644 --- a/test/yargs-parser.cjs +++ b/test/yargs-parser.cjs @@ -3011,11 +3011,41 @@ describe('yargs-parser', function () { it('is not influenced by unknown options when "unknown-options-as-args" is true', function () { const parse = parser( - ['-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'], + ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'], { configuration: { 'halt-at-non-option': true, 'unknown-options-as-args': true }, boolean: ['foo'] } ) parse.should.deep.equal({ - _: ['-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'] + _: ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'] + }) + }) + it('is initially influenced by unknown options when "unknown-options-as-args" and "wait-for-first-flag-before-filtering-options" are true', function () { + const parse = parser( + ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'], + { configuration: { 'halt-at-non-option': true, 'unknown-options-as-args': true, 'wait-for-first-flag-before-filtering-options': true }, boolean: ['foo'] } + ) + parse.should.deep.equal({ + _: ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'] + }) + }) + + it('puts all unknown options in "--" when "populate--" and "unknown-options-as-args" are true', function () { + const parse = parser( + ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'], + { configuration: { 'populate--': true, 'halt-at-non-option': true, 'unknown-options-as-args': true }, boolean: ['foo'] } + ) + parse.should.deep.equal({ + _: [], + "--": ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'] + }) + }) + it('puts later unknown options in "--" when "populate--", "unknown-options-as-args", and "wait-for-first-flag-before-filtering-options" are true', function () { + const parse = parser( + ['abc', 'def', '-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'], + { configuration: { 'populate--': true, 'halt-at-non-option': true, 'unknown-options-as-args': true, 'wait-for-first-flag-before-filtering-options': true }, boolean: ['foo'] } + ) + parse.should.deep.equal({ + _: ['abc', 'def', '-v', '--long'], + "--": ['arg', './file.js', '--foo', '--', 'barbar'] }) }) })