refactor(cli): use Commander native APIs

This commit is contained in:
Peter Steinberger
2026-07-14 10:42:40 +01:00
parent 8acbf209cd
commit 673b163b72
5 changed files with 26 additions and 56 deletions
+19 -19
View File
@@ -44,6 +44,23 @@ const EXAMPLES = [
],
] as const;
export function formatProgramHelpOutput(str: string): string {
// Commander emits plain section labels; decorate them after command-specific help renders.
let output = str;
const isRootHelp = new RegExp(
`^Usage:\\s+${CLI_NAME_PATTERN}\\s+\\[options\\]\\s+\\[command\\]\\s*$`,
"m",
).test(output);
if (isRootHelp && /^Commands:/m.test(output)) {
output = output.replace(/^Commands:/m, `Commands:\n ${theme.muted(ROOT_COMMANDS_HINT)}`);
}
return output
.replace(/^Usage:/gm, theme.heading("Usage:"))
.replace(/^Options:/gm, theme.heading("Options:"))
.replace(/^Commands:/gm, theme.heading("Commands:"));
}
export function configureProgramHelp(
program: Command,
ctx: ProgramContext,
@@ -92,29 +109,12 @@ export function configureProgramHelp(
},
});
const formatHelpOutput = (str: string) => {
// Commander emits plain section labels; decorate them after command-specific help renders.
let output = str;
const isRootHelp = new RegExp(
`^Usage:\\s+${CLI_NAME_PATTERN}\\s+\\[options\\]\\s+\\[command\\]\\s*$`,
"m",
).test(output);
if (isRootHelp && /^Commands:/m.test(output)) {
output = output.replace(/^Commands:/m, `Commands:\n ${theme.muted(ROOT_COMMANDS_HINT)}`);
}
return output
.replace(/^Usage:/gm, theme.heading("Usage:"))
.replace(/^Options:/gm, theme.heading("Options:"))
.replace(/^Commands:/gm, theme.heading("Commands:"));
};
program.configureOutput({
writeOut: (str) => {
process.stdout.write(formatHelpOutput(str));
process.stdout.write(formatProgramHelpOutput(str));
},
writeErr: (str) => {
process.stderr.write(formatHelpOutput(str));
process.stderr.write(formatProgramHelpOutput(str));
},
outputError: (str, write) => write(formatCliParseErrorOutput(str, { argv: process.argv })),
});
+2 -11
View File
@@ -45,14 +45,6 @@ function shouldAllowInvalidConfigForAction(actionCommand: Command, commandPath:
);
}
function getRootCommand(command: Command): Command {
let current = command;
while (current.parent) {
current = current.parent;
}
return current;
}
function getActionCommandPath(actionCommand: Command): string[] {
const commandPath: string[] = [];
let current: Command | null = actionCommand;
@@ -64,11 +56,10 @@ function getActionCommandPath(actionCommand: Command): string[] {
}
function getCliLogLevel(actionCommand: Command): LogLevel | undefined {
const root = getRootCommand(actionCommand);
if (root.getOptionValueSource("logLevel") !== "cli") {
if (actionCommand.getOptionValueSourceWithGlobals("logLevel") !== "cli") {
return undefined;
}
const logLevel = root.getOptionValue("logLevel");
const logLevel = actionCommand.optsWithGlobals<{ logLevel?: unknown }>().logLevel;
return typeof logLevel === "string" ? (logLevel as LogLevel) : undefined;
}
+3 -12
View File
@@ -9,7 +9,7 @@ import {
collectUniqueCommandDescriptors,
} from "./command-descriptor-utils.js";
import { getCoreCliCommandDescriptors } from "./core-command-descriptors.js";
import { configureProgramHelp } from "./help.js";
import { configureProgramHelp, formatProgramHelpOutput } from "./help.js";
import { getSubCliEntries } from "./subcli-descriptors.js";
/** Options for rendering root help without fully registering the live CLI. */
@@ -60,17 +60,8 @@ async function buildRootHelpProgram(renderOptions?: RootHelpRenderOptions): Prom
export async function renderRootHelpText(renderOptions?: RootHelpRenderOptions): Promise<string> {
const program = await buildRootHelpProgram(renderOptions);
let output = "";
const originalWrite = process.stdout.write.bind(process.stdout);
const captureWrite: typeof process.stdout.write = ((chunk: string | Uint8Array) => {
output += String(chunk);
return true;
}) as typeof process.stdout.write;
process.stdout.write = captureWrite;
try {
program.outputHelp();
} finally {
process.stdout.write = originalWrite;
}
program.configureOutput({ writeOut: (chunk) => (output += formatProgramHelpOutput(chunk)) });
program.outputHelp();
return output;
}