From d6e342d8ef2c488f438c32770ba2209cf8223342 Mon Sep 17 00:00:00 2001 From: Landon Yarrington <33426811+jly36963@users.noreply.github.com> Date: Sun, 9 Jan 2022 10:36:00 -0700 Subject: [PATCH] fix: failed command usage string is missing arg descriptions and optional args (#2105) --- lib/command.ts | 2 +- lib/usage.ts | 33 +++++++++++++++++++++------------ test/usage.cjs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/lib/command.ts b/lib/command.ts index 19d8053c6..b588b7e40 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -312,7 +312,7 @@ export class CommandInstance { // if this is the case, we should show the root usage instructions // rather than the usage instructions for the nested default command: if (isDefaultCommand) - innerYargs.getInternalMethods().getUsageInstance().unfreeze(); + innerYargs.getInternalMethods().getUsageInstance().unfreeze(true); if (this.shouldUpdateUsage(innerYargs)) { innerYargs .getInternalMethods() diff --git a/lib/usage.ts b/lib/usage.ts index 9374d2d16..cea2f7c22 100644 --- a/lib/usage.ts +++ b/lib/usage.ts @@ -707,22 +707,31 @@ export function usage(yargs: YargsInstance, shim: PlatformShim) { descriptions, }); }; - self.unfreeze = function unfreeze() { + self.unfreeze = function unfreeze(defaultCommand = false) { const frozen = frozens.pop(); // In the case of running a defaultCommand, we reset // usage early to ensure we receive the top level instructions. // unfreezing again should just be a noop: if (!frozen) return; - ({ - failMessage, - failureOutput, - usages, - usageDisabled, - epilogs, - examples, - commands, - descriptions, - } = frozen); + // Addresses: https://github.com/yargs/yargs/issues/2030 + if (defaultCommand) { + descriptions = {...frozen.descriptions, ...descriptions}; + commands = [...frozen.commands, ...commands]; + usages = [...frozen.usages, ...usages]; + examples = [...frozen.examples, ...examples]; + epilogs = [...frozen.epilogs, ...epilogs]; + } else { + ({ + failMessage, + failureOutput, + usages, + usageDisabled, + epilogs, + examples, + commands, + descriptions, + } = frozen); + } }; return self; @@ -759,7 +768,7 @@ export interface UsageInstance { showHelpOnFail(enabled?: boolean | string, message?: string): UsageInstance; showVersion(level?: 'error' | 'log' | ((message: string) => void)): void; stringifiedValues(values?: any[], separator?: string): string; - unfreeze(): void; + unfreeze(defaultCommand?: boolean): void; usage(msg: string | null, description?: string | false): UsageInstance; version(ver: any): void; wrap(cols: number | null | undefined): void; diff --git a/test/usage.cjs b/test/usage.cjs index 62b0d536d..1697364a6 100644 --- a/test/usage.cjs +++ b/test/usage.cjs @@ -3861,6 +3861,45 @@ describe('usage tests', () => { ' --uuid [required]', ]); }); + + // Addresses: https://github.com/yargs/yargs/issues/2030 + it('should display options (with descriptions) on failed default command', () => { + const r = checkUsage(() => + yargs('') + .command({ + command: '$0 ', + desc: 'default desc', + builder: yargs => + yargs + .option('arg1', { + type: 'string', + desc: 'arg1 desc', + demandOption: true, + }) + .option('arg2', { + type: 'string', + desc: 'arg2 desc', + }), + handler: noop, + }) + .strict() + .parse() + ); + console.log(r); + r.errors[0] + .split('\n') + .should.deep.equal([ + 'usage ', + '', + 'default desc', + '', + 'Options:', + ' --help Show help [boolean]', + ' --version Show version number [boolean]', + ' --arg1 arg1 desc [string] [required]', + ' --arg2 arg2 desc [string]', + ]); + }); }); describe('positional', () => {