From e6923db16dfdbe87d3f8437a06cf1d03374b5fef Mon Sep 17 00:00:00 2001 From: Max Koon Date: Sat, 26 Oct 2024 14:16:35 -0400 Subject: [PATCH] refactor: to use classes --- examples/basic/src/index.ts | 10 ++++- packages/cli/src/index.ts | 86 ++++++++++++++++++++++++++----------- packages/cli/src/util.ts | 20 +++++++++ 3 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 packages/cli/src/util.ts diff --git a/examples/basic/src/index.ts b/examples/basic/src/index.ts index d0c9162..6c9e97a 100644 --- a/examples/basic/src/index.ts +++ b/examples/basic/src/index.ts @@ -4,11 +4,13 @@ import z from "zod"; const cli = router({ add: router({ module: command() + .describe("Add a module") .input(z.object({ name: z.number() })) .fn(({ name }) => { console.log(`Name: ${name}`); }), package: command() + .describe("Add a package") .input( z.object({ name: z.string(), @@ -18,8 +20,12 @@ const cli = router({ console.log(`Package name: ${name}`); }), }), - help: command().fn(() => console.log("Help command")), - version: command().fn(() => console.log("Version 1.0")), + help: command() + .describe("Show help for the CLI") + .fn(() => console.log("Help command")), + version: command() + .describe("Show the CLI version") + .fn(() => console.log("Version 1.0")), }); run(cli); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 5b6193b..6de104e 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,23 +1,55 @@ -export type Command = { +import { z, ZodNever, ZodSchema, ZodTypeAny } from "zod"; +import { commands } from "./util"; + +class CommandBuilder { + private schema: ZodSchema | undefined; + private description: string | undefined; + + constructor(builder?: CommandBuilder) { + if (builder) { + this.schema = builder.schema; + this.description = builder.description; + } + } + + describe(description: string) { + this.description = description; + return this; + } + + input(schema: ZodSchema) { + this.schema = schema; + + return new CommandBuilder>(this); + } + + fn(fn: (input: T) => void): BuildCommand { + return { + _type: "command", + input: this.schema, + description: this.description, + fn, + }; + } +} + +export function command() { + return new CommandBuilder(); +} + +interface BuildCommand { _type: "command"; - fn: () => void; -}; + input?: ZodSchema; + description?: string; + fn: (input: T) => void; +} export type Commands = { _type: "cli"; commands: Record; }; -export type CLI = Command | Commands; - -function commands(input: CLI) { - if (input._type == "cli") { - console.log("Commands:"); - console.log(Object.keys(input.commands).join("\n")); - } else { - console.log("Command:", input); - } -} +export type CLI = BuildCommand | Commands; function next(input: CLI, current: string | undefined, args: string[]) { if (!current) return commands(input); @@ -30,7 +62,22 @@ function next(input: CLI, current: string | undefined, args: string[]) { } if (handler._type == "command") { - handler.fn(); + // @ts-ignore + const shape = handler.input?.shape; + const keys = Object.keys(shape); + + const remainingArgs = args.slice(1); + + const obj = keys.reduce( + (acc, key, index) => { + // @ts-ignore + acc[key] = remainingArgs[index]; + return acc; + }, + {} as Record, + ); + + handler.fn(obj); return; } else { const nextArg = args[1]; @@ -56,14 +103,3 @@ export const router = (commands: Commands["commands"]): Commands => { commands, }; }; - -export const command = () => { - return { - fn: (functionInput: () => void): Command => { - return { - _type: "command", - fn: functionInput, - }; - }, - }; -}; diff --git a/packages/cli/src/util.ts b/packages/cli/src/util.ts new file mode 100644 index 0000000..dc2c3ef --- /dev/null +++ b/packages/cli/src/util.ts @@ -0,0 +1,20 @@ +import { CLI } from "."; + +function commandDetails(command: CLI) { + if (command._type == "command") { + if (!command.description) return ""; + return `${command.description}`; + } else { + return "Menu"; + } + +} + +export function commands(input: CLI) { + if (input._type == "cli") { + console.log("Command List:"); + console.log(Object.entries(input.commands).map(([key, value]) => `${key}: ${commandDetails(value)}`).join("\n")); + } else { + console.log("Command:", input); + } +}