import { parseArgs } from "node:util"; import { z } from "zod"; import { CLIError, MuseError } from "#lib"; import chalk from "chalk"; import { version } from "../../package.json" with { type: "json" }; export const USAGE = ` ${chalk.bold("muse")} - Compile and validate Playbills for Proscenium ${chalk.dim(`v${version}`)} Usage: muse [/path/to/binding.yaml] Options: --check Only load and check the current binding and resources, but do not compile --outfile, -o Specify the output file path. If not specified, output to stdout --watch, -w Watch the directory for changes and recompile --renderer, -r Specify the output renderer. Options: json, html --help, -h Show this help message `.trim(); const Renderers = ["json", "html"] as const; const RendererSchema = z.enum(Renderers); type Renderer = z.infer; /** * A shape representing the arguments passed to the CLI */ export interface CLIArguments { inputFilePath: string; options: { check: boolean; outfile: string; help: boolean; renderer: Renderer; watch: boolean; }; } /** * Given an array of CLI arguments, parse them into a structured object * * @param argv The arguments to parse * @returns The parsed CLI arguments * * @throws {CLIError} if the arguments are invalid */ export function parseCLIArguments(argv: string[]): CLIArguments { const { values: options, positionals: args } = parseArgs({ args: argv, options: { check: { short: "c", type: "boolean", default: false, }, outfile: { short: "o", type: "string", default: "", }, help: { short: "h", default: false, type: "boolean", }, renderer: { short: "r", default: "json", type: "string", }, watch: { default: false, type: "boolean", }, }, strict: true, allowPositionals: true, }); // -- ARG VALIDATION -- // if (options.check && options.outfile !== "") { throw new CLIError("Cannot use --check and --outfile together"); } const parsedRenderer = RendererSchema.safeParse(options.renderer); if (!parsedRenderer.success) { throw new MuseError(`Invalid renderer: ${parsedRenderer.data}`); } return { inputFilePath: args[0] ?? "./binding.yaml", options: { check: options.check, outfile: options.outfile, help: options.help, renderer: parsedRenderer.data, watch: options.watch, }, }; }