From 5dea9dc82deb662cd09fbf2af882a36c58dbe0e4 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 8 Aug 2020 21:47:51 +1200 Subject: [PATCH 1/4] Add combineFlagAndOptionalValue --- index.js | 21 ++++++++++++++++++++- tests/command.parseOptions.test.js | 21 +++++++++++++++++++++ typings/commander-tests.ts | 4 ++++ typings/index.d.ts | 12 ++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index f02281101..fd1a0d0f8 100644 --- a/index.js +++ b/index.js @@ -127,6 +127,7 @@ class Command extends EventEmitter { this._defaultCommandName = null; this._exitCallback = null; this._aliases = []; + this._combineFlagAndOptionalValue = true; this._hidden = false; this._helpFlags = '-h, --help'; @@ -194,6 +195,7 @@ class Command extends EventEmitter { cmd._exitCallback = this._exitCallback; cmd._storeOptionsAsProperties = this._storeOptionsAsProperties; cmd._passCommandToAction = this._passCommandToAction; + cmd._combineFlagAndOptionalValue = this._combineFlagAndOptionalValue; cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor this.commands.push(cmd); @@ -636,6 +638,23 @@ Read more on https://git.io/JJc0W`); return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue); }; + /** + * Alter parsing of short flags with optional values. + * + * Examples: + * + * // for `.option('-f,--flag [value]'): + * .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour + * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b` + * + * @param {Boolean} [arg] - if `true` or omitted, an optional value can be specified directly after the flag. + * @api public + */ + combineFlagAndOptionalValue(arg) { + this._combineFlagAndOptionalValue = (arg === undefined) || arg; + return this; + }; + /** * Allow unknown options on the command line. * @@ -1109,7 +1128,7 @@ Read more on https://git.io/JJc0W`); if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') { const option = this._findOption(`-${arg[1]}`); if (option) { - if (option.required || option.optional) { + if (option.required || (option.optional && this._combineFlagAndOptionalValue)) { // option with value following in same argument this.emit(`option:${option.name()}`, arg.slice(2)); } else { diff --git a/tests/command.parseOptions.test.js b/tests/command.parseOptions.test.js index 3615b7fc4..4c8e8480e 100644 --- a/tests/command.parseOptions.test.js +++ b/tests/command.parseOptions.test.js @@ -288,4 +288,25 @@ describe('Utility Conventions', () => { expect(result).toEqual({ operands: [], unknown: ['--rrr=value'] }); expect(program.opts()).toEqual({ }); }); + + test('when program has combo optional and combineFlagAndOptionalValue() then treat as value', () => { + const program = createProgram(); + program.combineFlagAndOptionalValue(); + program.parseOptions(['-db']); + expect(program.opts()).toEqual({ ddd: 'b' }); + }); + + test('when program has combo optional and combineFlagAndOptionalValue(true) then treat as value', () => { + const program = createProgram(); + program.combineFlagAndOptionalValue(true); + program.parseOptions(['-db']); + expect(program.opts()).toEqual({ ddd: 'b' }); + }); + + test('when program has combo optional and combineFlagAndOptionalValue(false) then treat as boolean', () => { + const program = createProgram(); + program.combineFlagAndOptionalValue(false); + program.parseOptions(['-db']); + expect(program.opts()).toEqual({ ddd: true, bbb: true }); + }); }); diff --git a/typings/commander-tests.ts b/typings/commander-tests.ts index 57392c667..94c46b80b 100644 --- a/typings/commander-tests.ts +++ b/typings/commander-tests.ts @@ -134,6 +134,10 @@ const storeOptionsAsPropertiesThis2: commander.Command = program.storeOptionsAsP const passCommandToActionThis1: commander.Command = program.passCommandToAction(); const passCommandToActionThis2: commander.Command = program.passCommandToAction(false); +// combineFlagAndOptionalValue +const combineFlagAndOptionalValueThis1: commander.Command = program.combineFlagAndOptionalValue(); +const combineFlagAndOptionalValueThis2: commander.Command = program.combineFlagAndOptionalValue(false); + // allowUnknownOption const allowUnknownOptionThis1: commander.Command = program.allowUnknownOption(); const allowUnknownOptionThis2: commander.Command = program.allowUnknownOption(false); diff --git a/typings/index.d.ts b/typings/index.d.ts index c8061ffb3..b6016a25b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -201,6 +201,18 @@ declare namespace commander { */ passCommandToAction(value?: boolean): this; + /** + * Alter parsing of short flags with optional values. + * + * @example + * // for `.option('-f,--flag [value]'): + * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b` + * .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour + * + * @returns `this` command for chaining + */ + combineFlagAndOptionalValue(arg?: boolean): this; + /** * Allow unknown options on the command line. * From 6cc19da59b3259bb3939f5f71555e5f5975a614c Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 8 Aug 2020 22:05:31 +1200 Subject: [PATCH 2/4] Add combineFlagAndOptionalValue to migration tips --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75c67da94..3e5a98103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,9 @@ If you use `program.args` or more complicated tests to detect a missing subcomma If you use `.command('*')` to add a default command, you may be be able to switch to `isDefault:true` with a named command. +If you want to continue combining short options with optional values as though they were boolean flags, set `combineFlagAndOptionalValue(false)` +to expand `fb` to `-f -b` rather than `-f b`. + ## [5.0.0-4] (2020-03-03) (Released in 5.0.0) From bbb61aa4845b875658fa2a7102a021e87f7a8551 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 8 Aug 2020 22:09:01 +1200 Subject: [PATCH 3/4] Add missing minus --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e5a98103..406e1fa00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,7 +115,7 @@ If you use `program.args` or more complicated tests to detect a missing subcomma If you use `.command('*')` to add a default command, you may be be able to switch to `isDefault:true` with a named command. If you want to continue combining short options with optional values as though they were boolean flags, set `combineFlagAndOptionalValue(false)` -to expand `fb` to `-f -b` rather than `-f b`. +to expand `-fb` to `-f -b` rather than `-f b`. ## [5.0.0-4] (2020-03-03) From c6f2c0ca81111a3121d35c01754b2aa7f3a48870 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 9 Aug 2020 23:23:45 +1200 Subject: [PATCH 4/4] Reorder example --- typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index b6016a25b..aa7de1219 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -206,8 +206,8 @@ declare namespace commander { * * @example * // for `.option('-f,--flag [value]'): - * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b` * .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour + * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b` * * @returns `this` command for chaining */