import { parseArgs } from "node:util"; import { serializePlaybill, ValidatedPlaybillSchema, } from "@proscenium/playbill"; import chalk from "chalk"; import { loadFromBinding, resolveBindingPath } from "./binding"; import { usage } from "./usage"; import { CLIError, MuseError } from "./errors"; import { renderAsHTML } from "./renderers/html"; enum ExitCode { Success = 0, Error = 1, } async function main(): Promise { // -- ARGUMENT PARSING -- // const { values: options, positionals: args } = parseArgs({ args: Bun.argv.slice(2), options: { write: { short: "w", type: "boolean", default: false, }, check: { short: "c", type: "boolean", default: false, }, outfile: { short: "o", type: "string", default: "playbill.json", }, help: { short: "h", default: false, type: "boolean", }, verbose: { short: "v", default: false, type: "boolean", }, minify: { short: "m", default: false, type: "boolean", }, renderer: { short: "r", default: "json", type: "string", }, }, strict: true, allowPositionals: true, }); // -- HELP TEXT -- // if (options.help) { console.log(usage); return ExitCode.Success; } // -- ARG VALIDATION -- // if (options.check && options.write) { throw new CLIError("Cannot use --check and --write together"); } const VERBOSE = options.verbose; /** * Log a message if the vervose flag has been set * @param msg - The message to log */ function verboseLog(msg: string) { if (VERBOSE) { console.log(chalk.dim(msg)); } } // -- BINDING FILE -- // const bindingPathInput = args[0] ?? "./binding.yaml"; const bindingPath = await resolveBindingPath(bindingPathInput); verboseLog(`Building Playbill with binding: ${bindingPath}`); const binding = await loadFromBinding(bindingPath); verboseLog( `↳ Binding loaded with ${binding.includedFiles.length} associated resources`, ); // -- VALDATE PLAYBILL -- // verboseLog("Validating playbill"); const validatedPlaybill = ValidatedPlaybillSchema.safeParse(binding.playbill); if (!validatedPlaybill.success) { console.error("Error validating playbill"); console.error(validatedPlaybill.error.errors); return ExitCode.Error; } verboseLog("Playbill validated"); // -- EXIT EARLY IF JUST CHECKING VALIDATION --// if (options.check) { console.log(chalk.green("Playbill validated successfully")); return ExitCode.Success; } // -- SERIALIZE USING RENDERER --// let serializedPlaybill = ""; switch (options.renderer) { case "json": serializedPlaybill = serializePlaybill(validatedPlaybill.data); break; case "html": serializedPlaybill = await renderAsHTML(validatedPlaybill.data, binding); break; default: throw new CLIError(`Unknown renderer: ${options.renderer}`); } // -- WRITE TO DISK OR STDOUT --// if (options.write) { await Bun.write(options.outfile, serializedPlaybill); return ExitCode.Success; } console.log(serializedPlaybill); return ExitCode.Success; } try { const exitCode = await main(); process.exit(exitCode); } catch (error) { if (error instanceof MuseError) { console.error(chalk.red(error.fmt())); } else { console.error("An unexpected error occurred"); console.error(error); } process.exit(1); }