diff --git a/src/_utils.ts b/src/_utils.ts index 360c8ac..91471ff 100644 --- a/src/_utils.ts +++ b/src/_utils.ts @@ -1,4 +1,4 @@ -import type { Resolvable } from "./types"; +import type { CommandDef, Resolvable, SubCommandsDef } from "./types"; export function toArray(val: any) { if (Array.isArray(val)) { @@ -30,6 +30,25 @@ export function resolveValue(input: Resolvable): T | Promise { return typeof input === "function" ? (input as any)() : input; } +export async function getSubCommand( + subCommands: SubCommandsDef, + command: string, +): Promise> { + if (Object.keys(subCommands).includes(command)) { + return resolveValue(subCommands[command]); + } + + for (const subCommand of Object.values(subCommands)) { + const resolvedSubCommand = await resolveValue(subCommand); + for (const alias of toArray(resolvedSubCommand.alias)) { + if (alias === command) { + return resolvedSubCommand; + } + } + } + throw new CLIError(`Unknown command \`${command}\``, "E_UNKNOWN_COMMAND"); +} + export class CLIError extends Error { constructor( message: string, diff --git a/src/command.ts b/src/command.ts index 1abfe44..8f4f368 100644 --- a/src/command.ts +++ b/src/command.ts @@ -1,5 +1,5 @@ import type { CommandContext, CommandDef, ArgsDef } from "./types"; -import { CLIError, resolveValue } from "./_utils"; +import { CLIError, getSubCommand, resolveValue } from "./_utils"; import { parseArgs } from "./args"; export function defineCommand( @@ -43,13 +43,7 @@ export async function runCommand( ); const subCommandName = opts.rawArgs[subCommandArgIndex]; if (subCommandName) { - if (!subCommands[subCommandName]) { - throw new CLIError( - `Unknown command \`${subCommandName}\``, - "E_UNKNOWN_COMMAND", - ); - } - const subCommand = await resolveValue(subCommands[subCommandName]); + const subCommand = await getSubCommand(subCommands, subCommandName); if (subCommand) { await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1), diff --git a/src/types.ts b/src/types.ts index a622922..1b610e5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -90,6 +90,7 @@ export type SubCommandsDef = Record>>; export type CommandDef = { meta?: Resolvable; args?: Resolvable; + alias?: Resolvable; subCommands?: Resolvable; setup?: (context: CommandContext) => any | Promise; cleanup?: (context: CommandContext) => any | Promise;