58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import z from "zod";
|
|
import { CommandExec } from "./cmdtypes.ts";
|
|
|
|
export interface CommandOptions {
|
|
key: string[],
|
|
subcommands?: Command[],
|
|
exec?: CommandExec,
|
|
zod?: z.ZodTuple,
|
|
help?: string
|
|
}
|
|
|
|
export default class Command {
|
|
|
|
subCmds: Command[];
|
|
key: string[];
|
|
exec: CommandExec | null;
|
|
validate: z.ZodTuple | null;
|
|
help: string | null;
|
|
#argsLength: number;
|
|
|
|
constructor(options: CommandOptions) {
|
|
this.subCmds = options.subcommands || [];
|
|
this.key = options.key;
|
|
this.exec = options.exec || null;
|
|
this.validate = options.zod || null;
|
|
this.help = options.help || null;
|
|
this.#argsLength = options.zod ? options.zod.def.items.length : 0;
|
|
}
|
|
|
|
getKey() {
|
|
return this.key;
|
|
}
|
|
|
|
dispatch(...args: unknown[]): unknown | Promise<unknown> {
|
|
const root = args[0] as string | undefined;
|
|
if (!root && this.exec)
|
|
return this.exec(...args);
|
|
else if (!root) return new Error('No execution target for this root');
|
|
|
|
const cmd = this.subCmds.find(cmd => cmd.getKey().includes(root));
|
|
if (cmd) {
|
|
const newArgs = args.slice(1);
|
|
if (cmd.#argsLength && newArgs.length !== cmd.#argsLength && cmd.help) return new Error(cmd.help);
|
|
if (cmd.validate) {
|
|
const res = cmd.validate.safeParse(newArgs);
|
|
if (res.success) return cmd.dispatch(...res.data);
|
|
else if (cmd.help) return new Error(cmd.help);
|
|
else if (cmd.#argsLength) return new Error(`'${root}' validation error: expected ${cmd.#argsLength} args, got ${newArgs.length}`);
|
|
else return new Error(`'${root}' validation error`);
|
|
}
|
|
}
|
|
|
|
if (this.exec)
|
|
return this.exec(...args);
|
|
else return new Error(`'${root}': Subcommand not found (args: "${args.join(" ")}")`);
|
|
}
|
|
|
|
} |