muse/src/index.ts

151 lines
3.5 KiB
TypeScript

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<number> {
// -- 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);
}