Skip to content

Commit

Permalink
Add combineFlagAndOptionalValue (#1326)
Browse files Browse the repository at this point in the history
* Add combineFlagAndOptionalValue

* Add combineFlagAndOptionalValue to migration tips

* Add missing minus

* Reorder example
  • Loading branch information
shadowspawn committed Aug 11, 2020
1 parent 6b2e42c commit 84fe0da
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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)
Expand Down
21 changes: 20 additions & 1 deletion index.js
Expand Up @@ -127,6 +127,7 @@ class Command extends EventEmitter {
this._defaultCommandName = null;
this._exitCallback = null;
this._aliases = [];
this._combineFlagAndOptionalValue = true;

this._hidden = false;
this._hasHelpOption = true;
Expand Down Expand Up @@ -196,6 +197,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);
Expand Down Expand Up @@ -638,6 +640,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.
*
Expand Down Expand Up @@ -1111,7 +1130,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 {
Expand Down
21 changes: 21 additions & 0 deletions tests/command.parseOptions.test.js
Expand Up @@ -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 });
});
});
4 changes: 4 additions & 0 deletions typings/commander-tests.ts
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions typings/index.d.ts
Expand Up @@ -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(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
*/
combineFlagAndOptionalValue(arg?: boolean): this;

/**
* Allow unknown options on the command line.
*
Expand Down

0 comments on commit 84fe0da

Please sign in to comment.