Skip to content

Commit 63abdac

Browse files
authored
Have help command call help directly for subcommands, when possible (#1864)
1 parent fac9d8c commit 63abdac

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

lib/command.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
10841084
return hookResult;
10851085
}
10861086

1087+
/**
1088+
* Invoke help directly if possible, or dispatch if necessary.
1089+
* e.g. help foo
1090+
*
1091+
* @api private
1092+
*/
1093+
1094+
_dispatchHelpCommand(subcommandName) {
1095+
if (!subcommandName) {
1096+
this.help();
1097+
}
1098+
const subCommand = this._findCommand(subcommandName);
1099+
if (subCommand && !subCommand._executableHandler) {
1100+
subCommand.help();
1101+
}
1102+
1103+
// Fallback to parsing the help flag to invoke the help.
1104+
return this._dispatchSubcommand(subcommandName, [], [this._helpLongFlag]);
1105+
}
1106+
10871107
/**
10881108
* Check this.args against expected this._args.
10891109
*
@@ -1248,10 +1268,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
12481268
return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
12491269
}
12501270
if (this._hasImplicitHelpCommand() && operands[0] === this._helpCommandName) {
1251-
if (operands.length === 1) {
1252-
this.help();
1253-
}
1254-
return this._dispatchSubcommand(operands[1], [], [this._helpLongFlag]);
1271+
return this._dispatchHelpCommand(operands[1]);
12551272
}
12561273
if (this._defaultCommandName) {
12571274
outputHelpIfRequested(this, unknown); // Run the help for default command from parent rather than passing to default command

tests/command.helpCommand.test.js

+37
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,41 @@ describe('help command processed on correct command', () => {
123123
program.parse('node test.js help'.split(' '));
124124
}).toThrow('program');
125125
});
126+
127+
test('when no long help flag then "help sub" works', () => {
128+
const program = new commander.Command();
129+
program.exitOverride();
130+
program.helpOption('-H');
131+
const sub = program.command('sub');
132+
// Patch help for easy way to check called.
133+
sub.help = () => { throw new Error('sub help'); };
134+
expect(() => {
135+
program.parse(['help', 'sub'], { from: 'user' });
136+
}).toThrow('sub help');
137+
});
138+
139+
test('when no help options in sub then "help sub" works', () => {
140+
const program = new commander.Command();
141+
program.exitOverride();
142+
const sub = program.command('sub')
143+
.helpOption(false);
144+
// Patch help for easy way to check called.
145+
sub.help = () => { throw new Error('sub help'); };
146+
expect(() => {
147+
program.parse(['help', 'sub'], { from: 'user' });
148+
}).toThrow('sub help');
149+
});
150+
151+
test('when different help options in sub then "help sub" works', () => {
152+
const program = new commander.Command();
153+
program.exitOverride();
154+
const sub = program.command('sub');
155+
program.helpOption('-h, --help');
156+
sub.helpOption('-a, --assist');
157+
// Patch help for easy way to check called.
158+
sub.help = () => { throw new Error('sub help'); };
159+
expect(() => {
160+
program.parse(['help', 'sub'], { from: 'user' });
161+
}).toThrow('sub help');
162+
});
126163
});

0 commit comments

Comments
 (0)