From 63abdaca08fd72818989ac962429ffe727801724 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 22 Apr 2023 10:05:02 +1200 Subject: [PATCH] Have help command call help directly for subcommands, when possible (#1864) --- lib/command.js | 25 +++++++++++++++++---- tests/command.helpCommand.test.js | 37 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/command.js b/lib/command.js index 7a637cb77..0ff063685 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1084,6 +1084,26 @@ Expecting one of '${allowedValues.join("', '")}'`); return hookResult; } + /** + * Invoke help directly if possible, or dispatch if necessary. + * e.g. help foo + * + * @api private + */ + + _dispatchHelpCommand(subcommandName) { + if (!subcommandName) { + this.help(); + } + const subCommand = this._findCommand(subcommandName); + if (subCommand && !subCommand._executableHandler) { + subCommand.help(); + } + + // Fallback to parsing the help flag to invoke the help. + return this._dispatchSubcommand(subcommandName, [], [this._helpLongFlag]); + } + /** * Check this.args against expected this._args. * @@ -1248,10 +1268,7 @@ Expecting one of '${allowedValues.join("', '")}'`); return this._dispatchSubcommand(operands[0], operands.slice(1), unknown); } if (this._hasImplicitHelpCommand() && operands[0] === this._helpCommandName) { - if (operands.length === 1) { - this.help(); - } - return this._dispatchSubcommand(operands[1], [], [this._helpLongFlag]); + return this._dispatchHelpCommand(operands[1]); } if (this._defaultCommandName) { outputHelpIfRequested(this, unknown); // Run the help for default command from parent rather than passing to default command diff --git a/tests/command.helpCommand.test.js b/tests/command.helpCommand.test.js index 8699dff30..bbf9f4502 100644 --- a/tests/command.helpCommand.test.js +++ b/tests/command.helpCommand.test.js @@ -123,4 +123,41 @@ describe('help command processed on correct command', () => { program.parse('node test.js help'.split(' ')); }).toThrow('program'); }); + + test('when no long help flag then "help sub" works', () => { + const program = new commander.Command(); + program.exitOverride(); + program.helpOption('-H'); + const sub = program.command('sub'); + // Patch help for easy way to check called. + sub.help = () => { throw new Error('sub help'); }; + expect(() => { + program.parse(['help', 'sub'], { from: 'user' }); + }).toThrow('sub help'); + }); + + test('when no help options in sub then "help sub" works', () => { + const program = new commander.Command(); + program.exitOverride(); + const sub = program.command('sub') + .helpOption(false); + // Patch help for easy way to check called. + sub.help = () => { throw new Error('sub help'); }; + expect(() => { + program.parse(['help', 'sub'], { from: 'user' }); + }).toThrow('sub help'); + }); + + test('when different help options in sub then "help sub" works', () => { + const program = new commander.Command(); + program.exitOverride(); + const sub = program.command('sub'); + program.helpOption('-h, --help'); + sub.helpOption('-a, --assist'); + // Patch help for easy way to check called. + sub.help = () => { throw new Error('sub help'); }; + expect(() => { + program.parse(['help', 'sub'], { from: 'user' }); + }).toThrow('sub help'); + }); });