Skip to content

Commit 1d0fe63

Browse files
committed
Refactor _hasHelpOption, add explicit lazy getter
1 parent d97b828 commit 1d0fe63

File tree

4 files changed

+46
-37
lines changed

4 files changed

+46
-37
lines changed

lib/command.js

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class Command extends EventEmitter {
6666
};
6767

6868
this._hidden = false;
69+
/** @type {Option | undefined | null} */
6970
this._helpOption = undefined; // Lazy created on demand.
70-
this._hasHelpOption = true;
7171
this._addImplicitHelpCommand = undefined; // Deliberately undefined, not decided whether true or false
7272
this._helpCommandName = 'help';
7373
this._helpCommandnameAndArgs = 'help [command]';
@@ -85,8 +85,7 @@ class Command extends EventEmitter {
8585
*/
8686
copyInheritedSettings(sourceCommand) {
8787
this._outputConfiguration = sourceCommand._outputConfiguration;
88-
this._helpOption = sourceCommand.helpOption();
89-
this._hasHelpOption = sourceCommand._hasHelpOption;
88+
this._helpOption = sourceCommand._helpOption;
9089
this._helpCommandName = sourceCommand._helpCommandName;
9190
this._helpCommandnameAndArgs = sourceCommand._helpCommandnameAndArgs;
9291
this._helpCommandDescription = sourceCommand._helpCommandDescription;
@@ -1097,7 +1096,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
10971096

10981097
// Fallback to parsing the help flag to invoke the help.
10991098
return this._dispatchSubcommand(subcommandName, [], [
1100-
this.helpOption().long ?? this.helpOption().short ?? '--help'
1099+
this._getHelpOption().long ?? this._getHelpOption().short ?? '--help'
11011100
]);
11021101
}
11031102

@@ -1902,7 +1901,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
19021901
return humanReadableArgName(arg);
19031902
});
19041903
return [].concat(
1905-
(this.options.length || this._hasHelpOption ? '[options]' : []),
1904+
(this.options.length || (this._helpOption !== null) ? '[options]' : []),
19061905
(this.commands.length ? '[command]' : []),
19071906
(this.registeredArguments.length ? args : [])
19081907
).join(' ');
@@ -2023,8 +2022,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
20232022
}
20242023
context.write(helpInformation);
20252024

2026-
if (this.helpOption().long) {
2027-
this.emit(this.helpOption().long); // deprecated
2025+
if (this._getHelpOption().long) {
2026+
this.emit(this._getHelpOption().long); // deprecated
20282027
}
20292028
this.emit('afterHelp', context);
20302029
this._getCommandAndAncestors().forEach(command => command.emit('afterAllHelp', context));
@@ -2033,50 +2032,53 @@ Expecting one of '${allowedValues.join("', '")}'`);
20332032
/**
20342033
* You can pass in flags and a description to customise the built-in help option
20352034
* Pass in false to disable the built-in help option.
2036-
* Lastly, can call with no arguments to return the built-in help option.
20372035
*
20382036
* @example
20392037
* program.helpOption('-?, --help' 'show help'); // customise
20402038
* program.helpOption(false); // disable
2041-
* const helpOption = program.helpOption(); // getter
20422039
*
2043-
* @param {string | boolean} [flags]
2040+
* @param {string | boolean} flags
20442041
* @param {string} [description]
2045-
* @return {Command | Option} `this` command for chaining (or help option if no arguments)
2042+
* @return {Command} `this` command for chaining
20462043
*/
20472044

20482045
helpOption(flags, description) {
2049-
// Getter, lazy create help option on demand.
2050-
if (flags === undefined && description === undefined) {
2051-
if (this._helpOption === undefined) {
2052-
this._helpOption = this.createOption('-h, --help', 'display help for command');
2053-
}
2054-
return this._helpOption;
2055-
}
2056-
20572046
// Support disabling built-in help option.
20582047
if (typeof flags === 'boolean') {
2059-
this._hasHelpOption = flags;
2048+
this._helpOption = flags ? undefined : null;
20602049
return this;
20612050
}
20622051

20632052
// Customise flags and description.
2064-
flags = flags ?? this.helpOption().flags;
2065-
description = description ?? this.helpOption().description;
2053+
flags = flags ?? this._getHelpOption().flags;
2054+
description = description ?? this._getHelpOption().description;
20662055
this._helpOption = this.createOption(flags, description);
20672056

20682057
return this;
20692058
}
20702059

2060+
/**
2061+
*
2062+
* @returns {Option} the help option
2063+
*/
2064+
_getHelpOption() {
2065+
// Lazy create help option on demand.
2066+
if (this._helpOption === undefined) {
2067+
this._helpOption = this.createOption('-h, --help', 'display help for command');
2068+
}
2069+
return this._helpOption;
2070+
}
2071+
20712072
/**
20722073
* Supply your own option to use for the built-in help option.
20732074
* This is an alternative to using helpOption() to customise the flags and description etc.
20742075
*
2075-
* @param {Option|undefined} option
2076-
* @return {Command|Option} `this` command for chaining
2076+
* @param {Option} option
2077+
* @return {Command} `this` command for chaining
20772078
*/
20782079
addHelpOption(option) {
20792080
this._helpOption = option;
2081+
return this;
20802082
}
20812083

20822084
/**
@@ -2139,8 +2141,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
21392141
*/
21402142

21412143
function outputHelpIfRequested(cmd, args) {
2142-
const helpOption = cmd.helpOption();
2143-
const helpRequested = cmd._hasHelpOption && args.find(arg => helpOption.is(arg));
2144+
const helpOption = cmd._getHelpOption();
2145+
const helpRequested = helpOption && args.find(arg => helpOption.is(arg));
21442146
if (helpRequested) {
21452147
cmd.outputHelp();
21462148
// (Do not have all displayed text available so only passing placeholder.)

lib/help.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class Help {
6969
visibleOptions(cmd) {
7070
const visibleOptions = cmd.options.filter((option) => !option.hidden);
7171
// Built-in help option.
72-
if (cmd._hasHelpOption && !cmd.helpOption().hidden) {
73-
const helpOption = cmd.helpOption();
72+
const helpOption = cmd._getHelpOption();
73+
if (helpOption && !helpOption.hidden) {
7474
// Automatically hide conflicting flags. (Bit magical and messy, but preserve for now!)
7575
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
7676
const removeLong = helpOption.long && cmd._findOption(helpOption.long);

tests/command.chain.test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,16 @@ describe('Command methods that should return this for chaining', () => {
130130
expect(result).toBe(program);
131131
});
132132

133-
test('when call .helpOption() then returns this', () => {
133+
test('when call .helpOption(flags) then returns this', () => {
134134
const program = new Command();
135-
const result = program.helpOption(false);
135+
const flags = '-h, --help';
136+
const result = program.helpOption(flags);
137+
expect(result).toBe(program);
138+
});
139+
140+
test('when call .addHelpOption() then returns this', () => {
141+
const program = new Command();
142+
const result = program.addHelpOption(new Option('-h, --help'));
136143
expect(result).toBe(program);
137144
});
138145

tests/command.copySettings.test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@ describe('copyInheritedSettings property tests', () => {
3131
test('when copyInheritedSettings then copies helpOption(false)', () => {
3232
const source = new commander.Command();
3333
const cmd = new commander.Command();
34-
expect(cmd._hasHelpOption).toBeTruthy();
3534

3635
source.helpOption(false);
3736
cmd.copyInheritedSettings(source);
38-
expect(cmd._hasHelpOption).toBeFalsy();
37+
expect(cmd._getHelpOption()).toBe(null);
3938
});
4039

4140
test('when copyInheritedSettings then copies helpOption(flags, description)', () => {
@@ -44,11 +43,12 @@ describe('copyInheritedSettings property tests', () => {
4443

4544
source.helpOption('-Z, --zz', 'ddd');
4645
cmd.copyInheritedSettings(source);
47-
const helpOption = cmd.helpOption();
48-
expect(helpOption.flags).toBe('-Z, --zz');
49-
expect(helpOption.description).toBe('ddd');
50-
expect(helpOption.short).toBe('-Z');
51-
expect(helpOption.long).toBe('--zz');
46+
expect(cmd._getHelpOption()).toBe(source._getHelpOption());
47+
// const helpOption = cmd._getHelpOption();
48+
// expect(helpOption.flags).toBe('-Z, --zz');
49+
// expect(helpOption.description).toBe('ddd');
50+
// expect(helpOption.short).toBe('-Z');
51+
// expect(helpOption.long).toBe('--zz');
5252
});
5353

5454
test('when copyInheritedSettings then copies addHelpCommand(name, description)', () => {

0 commit comments

Comments
 (0)