Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getOptionValue and setOptionValue #1521

Merged
merged 7 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ const program = new Command();

Options are defined with the `.option()` method, also serving as documentation for the options. Each option can have a short flag (single character) and a long name, separated by a comma or space or vertical bar ('|').

The parsed options can be accessed by calling `.opts()` on a `Command` object, and are passed to the action handler. Multi-word options such as "--template-engine" are camel-cased, becoming `program.opts().templateEngine` etc.
The parsed options can be accessed by calling `.opts()` on a `Command` object, and are passed to the action handler.
You can also use `.getOptionValue()` and `.setOptionValue()` to work with a single option value.

Multi-word options such as "--template-engine" are camel-cased, becoming `program.opts().templateEngine` etc.

Multiple short flags may optionally be combined in a single argument following the dash: boolean flags, followed by a single option taking a value (possibly followed by the value).
For example `-a -b -p 80` may be written as `-ab -p80` or even `-abp80`.
Expand Down
40 changes: 20 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1094,11 +1094,11 @@ class Command extends EventEmitter {
// when --no-foo we make sure default is true, unless a --foo option is already defined
if (option.negate) {
const positiveLongFlag = option.long.replace(/^--no-/, '--');
defaultValue = this._findOption(positiveLongFlag) ? this._getOptionValue(name) : true;
defaultValue = this._findOption(positiveLongFlag) ? this.getOptionValue(name) : true;
}
// preassign only if we have a default
if (defaultValue !== undefined) {
this._setOptionValue(name, defaultValue);
this.setOptionValue(name, defaultValue);
}
}

Expand All @@ -1108,7 +1108,7 @@ class Command extends EventEmitter {
// when it's passed assign the value
// and conditionally invoke the callback
this.on('option:' + oname, (val) => {
const oldValue = this._getOptionValue(name);
const oldValue = this.getOptionValue(name);

// custom processing
if (val !== null && option.parseArg) {
Expand All @@ -1129,15 +1129,15 @@ class Command extends EventEmitter {
if (typeof oldValue === 'boolean' || typeof oldValue === 'undefined') {
// if no value, negate false, and we have a default, then use it!
if (val == null) {
this._setOptionValue(name, option.negate
this.setOptionValue(name, option.negate
? false
: defaultValue || true);
} else {
this._setOptionValue(name, val);
this.setOptionValue(name, val);
}
} else if (val !== null) {
// reassign
this._setOptionValue(name, option.negate ? false : val);
this.setOptionValue(name, option.negate ? false : val);
}
});

Expand Down Expand Up @@ -1325,34 +1325,34 @@ class Command extends EventEmitter {
};

/**
* Store option value
* Retrieve option value.
*
* @param {string} key
* @param {Object} value
* @api private
* @return {Object} value
*/

_setOptionValue(key, value) {
getOptionValue(key) {
if (this._storeOptionsAsProperties) {
this[key] = value;
} else {
this._optionValues[key] = value;
return this[key];
}
return this._optionValues[key];
};

/**
* Retrieve option value
* Store option value.
*
* @param {string} key
* @return {Object} value
* @api private
* @param {Object} value
* @return {Command} `this` command for chaining
*/

_getOptionValue(key) {
setOptionValue(key, value) {
if (this._storeOptionsAsProperties) {
return this[key];
this[key] = value;
} else {
this._optionValues[key] = value;
}
return this._optionValues[key];
return this;
};

/**
Expand Down Expand Up @@ -1764,7 +1764,7 @@ class Command extends EventEmitter {
// Walk up hierarchy so can call in subcommand after checking for displaying help.
for (let cmd = this; cmd; cmd = cmd.parent) {
cmd.options.forEach((anOption) => {
if (anOption.mandatory && (cmd._getOptionValue(anOption.attributeName()) === undefined)) {
if (anOption.mandatory && (cmd.getOptionValue(anOption.attributeName()) === undefined)) {
cmd.missingMandatoryOptionValue(anOption);
}
});
Expand Down
6 changes: 6 additions & 0 deletions tests/command.chain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,10 @@ describe('Command methods that should return this for chaining', () => {
const result = program.enablePositionalOptions();
expect(result).toBe(program);
});

test('when call .setOptionValue() then returns this', () => {
const program = new Command();
const result = program.setOptionValue();
expect(result).toBe(program);
});
});
24 changes: 24 additions & 0 deletions tests/options.getset.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const commander = require('../');

describe.each([true, false])('storeOptionsAsProperties is %s', (storeOptionsAsProperties) => {
test('when option specified on CLI then value returned by getOptionValue', () => {
const program = new commander.Command();
program
.storeOptionsAsProperties(storeOptionsAsProperties)
.option('--cheese [type]', 'cheese type');
const cheeseType = 'blue';
program.parse(['node', 'test', '--cheese', cheeseType]);
expect(program.getOptionValue('cheese')).toBe(cheeseType);
});

test('when setOptionValue then value returned by opts', () => {
const program = new commander.Command();
const cheeseType = 'blue';
// Note: opts() only returns declared options when options stored as properties
program
.storeOptionsAsProperties(storeOptionsAsProperties)
.option('--cheese [type]', 'cheese type')
.setOptionValue('cheese', cheeseType);
expect(program.opts().cheese).toBe(cheeseType);
});
});
10 changes: 10 additions & 0 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,16 @@ export class Command {
storeOptionsAsProperties(storeAsProperties: true): this & OptionValues;
storeOptionsAsProperties(storeAsProperties?: boolean): this;

/**
* Retrieve option value.
*/
getOptionValue(key: string): any;

/**
* Store option value.
*/
setOptionValue(key: string, value: unknown): this;

/**
* Alter parsing of short flags with optional values.
*
Expand Down
7 changes: 7 additions & 0 deletions typings/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ expectType<commander.Command & commander.OptionValues>(program.storeOptionsAsPro
expectType<commander.Command & commander.OptionValues>(program.storeOptionsAsProperties(true));
expectType<commander.Command>(program.storeOptionsAsProperties(false));

// getOptionValue
void program.getOptionValue('example');

// setOptionValue
expectType<commander.Command>(program.setOptionValue('example', 'value'));
expectType<commander.Command>(program.setOptionValue('example', true));

// combineFlagAndOptionalValue
expectType<commander.Command>(program.combineFlagAndOptionalValue());
expectType<commander.Command>(program.combineFlagAndOptionalValue(false));
Expand Down