From ee72af7a7c3326e396a3c6de928af7dcb20f0806 Mon Sep 17 00:00:00 2001 From: "saeta.eth" Date: Fri, 27 Sep 2024 18:02:07 -0300 Subject: [PATCH] feat(cli): Enhance CLI command help (#1418) --- packages/cli/src/util/commands-config.ts | 5 ++ .../cli/src/util/format-command-help.test.ts | 53 +++++++++++++++++++ packages/cli/src/util/format-command-help.ts | 37 +++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 packages/cli/src/util/format-command-help.test.ts create mode 100644 packages/cli/src/util/format-command-help.ts diff --git a/packages/cli/src/util/commands-config.ts b/packages/cli/src/util/commands-config.ts index d9c6bf1f3..1d39bf219 100644 --- a/packages/cli/src/util/commands-config.ts +++ b/packages/cli/src/util/commands-config.ts @@ -1,4 +1,5 @@ import { Command } from 'commander'; +import { formatCommandHelp } from './format-command-help'; import { parsePackageArguments, parsePackagesArguments } from './params'; import type { Command as CommandConfig } from '../commands/config/types'; @@ -50,5 +51,9 @@ export const applyCommandsConfig = (command: Command, config: CommandConfig) => }); } + // override the help output to add a header for anvil and forge options + const originalHelpInformation = command.helpInformation.bind(command); + command.helpInformation = () => formatCommandHelp(originalHelpInformation()); + return command; }; diff --git a/packages/cli/src/util/format-command-help.test.ts b/packages/cli/src/util/format-command-help.test.ts new file mode 100644 index 000000000..6c21c13b2 --- /dev/null +++ b/packages/cli/src/util/format-command-help.test.ts @@ -0,0 +1,53 @@ +import { formatCommandHelp } from './format-command-help'; + +describe('formatCommandHelp', () => { + it('should group Anvil options', () => { + const input = ` + --option1 Description1 + --anvil.option1 AnvilDescription1 + --anvil.option2 AnvilDescription2 + --option2 Description2 + `; + const result = formatCommandHelp(input); + expect(result).toContain('Anvil Options:'); + expect(result.indexOf('--anvil.option1')).toBeGreaterThan(result.indexOf('Anvil Options:')); + expect(result.indexOf('--anvil.option2')).toBeGreaterThan(result.indexOf('Anvil Options:')); + }); + + it('should group Forge options', () => { + const input = ` + --option1 Description1 + --forge.option1 ForgeDescription1 + --forge.option2 ForgeDescription2 + --option2 Description2 + `; + const result = formatCommandHelp(input); + expect(result).toContain('Forge Options:'); + expect(result.indexOf('--forge.option1')).toBeGreaterThan(result.indexOf('Forge Options:')); + expect(result.indexOf('--forge.option2')).toBeGreaterThan(result.indexOf('Forge Options:')); + }); + + it('should place help option after the last main option', () => { + const input = ` + --option1 Description1 + --option2 Description2 + --anvil.option1 AnvilDescription1 + -h, --help Show help + `; + const result = formatCommandHelp(input); + const helpIndex = result.indexOf('-h, --help'); + const option2Index = result.indexOf('--option2'); + const anvilOptionIndex = result.indexOf('--anvil.option1'); + expect(helpIndex).toBeGreaterThan(option2Index); + expect(helpIndex).toBeLessThan(anvilOptionIndex); + }); + + it('should handle input with no special options', () => { + const input = ` + --option1 Description1 + --option2 Description2 + `; + const result = formatCommandHelp(input); + expect(result).toBe(input); + }); +}); diff --git a/packages/cli/src/util/format-command-help.ts b/packages/cli/src/util/format-command-help.ts new file mode 100644 index 000000000..d624c2e1c --- /dev/null +++ b/packages/cli/src/util/format-command-help.ts @@ -0,0 +1,37 @@ +export function formatCommandHelp(inputText: string): string { + const lines = inputText.split('\n'); + const optionGroups = [ + { prefix: '--anvil.', header: 'Anvil Options:' }, + { prefix: '--forge.', header: 'Forge Options:' }, + ]; + + const result: string[] = []; + let helpLine: string | null = null; + let lastMainOptionIndex = -1; + + lines.forEach((line) => { + const trimmedLine = line.trim(); + + if (trimmedLine.startsWith('-h, --help')) { + helpLine = line; + return; + } + + const group = optionGroups.find((g) => trimmedLine.startsWith(g.prefix)); + if (group) { + if (!result.includes(group.header)) { + result.push('', group.header); + } + } else if (trimmedLine.startsWith('-')) { + lastMainOptionIndex = result.length; + } + + result.push(line); + }); + + if (helpLine) { + result.splice(lastMainOptionIndex + 1, 0, helpLine); + } + + return result.join('\n'); +}