@lodestar/utils
Version:
Utilities required across multiple lodestar packages
75 lines (68 loc) • 2.6 kB
text/typescript
import type {Argv, Options} from "yargs";
export interface CliExample {
command: string;
title?: string;
description?: string;
}
// biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
export interface CliOptionDefinition<T = any> extends Options {
example?: Omit<CliExample, "title">;
// Ensure `type` property matches type of `T`
type: T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends Array<unknown>
? "array"
: never;
}
export type CliCommandOptions<OwnArgs> = Required<{
[K in keyof OwnArgs]: undefined extends OwnArgs[K]
? CliOptionDefinition<OwnArgs[K]>
: // If arg cannot be undefined it must specify a default value or be provided by the user
CliOptionDefinition<OwnArgs[K]> & (Required<Pick<Options, "default">> | {demandOption: true});
}>;
// biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
export interface CliCommand<OwnArgs = Record<never, never>, ParentArgs = Record<never, never>, R = any> {
command: string;
describe: string;
/**
* The folder in docs/pages that the cli.md should be placed in. If not provided no
* cli flags page will be generated for the command
*/
docsFolder?: string;
examples?: CliExample[];
options?: CliCommandOptions<OwnArgs>;
// 1st arg: any = free own sub command options
// 2nd arg: subcommand parent options is = to this command options + parent options
// biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
subcommands?: CliCommand<any, OwnArgs & ParentArgs>[];
handler?: (args: OwnArgs & ParentArgs) => Promise<R>;
}
/**
* Register a CliCommand type to yargs. Recursively registers subcommands too.
* @param yargs
* @param cliCommand
*/
// biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
export function registerCommandToYargs(yargs: Argv, cliCommand: CliCommand<any, any>): void {
yargs.command({
command: cliCommand.command,
describe: cliCommand.describe,
builder: (yargsBuilder) => {
yargsBuilder.options(cliCommand.options ?? {});
for (const subcommand of cliCommand.subcommands ?? []) {
registerCommandToYargs(yargsBuilder, subcommand);
}
if (cliCommand.examples) {
for (const example of cliCommand.examples) {
yargsBuilder.example(`$0 ${example.command}`, example.description ?? "");
}
}
return yargs;
},
handler: cliCommand.handler ?? function emptyHandler(): void {},
});
}