muse/src/index.ts
2025-04-01 13:20:43 -04:00

120 lines
2.8 KiB
TypeScript

import { watch } from "node:fs/promises";
import chalk from "chalk";
import {
CLIError,
MuseError,
compileMarkdownInPlaybill,
loadFromBinding,
resolveBindingPath,
} from "#lib";
import { renderPlaybillToHTML } from "#render/html";
import {
type CLIArguments,
getAbsoluteDirname,
parseCLIArguments,
USAGE,
} from "#util";
enum ExitCode {
Success = 0,
Error = 1,
}
async function processBinding({ inputFilePath, options }: CLIArguments) {
// Load the binding
const bindingPath = await resolveBindingPath(inputFilePath);
const binding = await loadFromBinding(bindingPath);
// If --check is specified, exit early
if (options.check) {
console.log(chalk.green("Playbill validated successfully"));
return ExitCode.Success;
}
if (options.markdown) {
await compileMarkdownInPlaybill(binding);
}
// Serialize (default: JSON)
let serializedPlaybill = "";
switch (options.renderer) {
case "json":
serializedPlaybill = binding.playbill.serialize();
break;
case "html":
serializedPlaybill = await renderPlaybillToHTML(binding);
break;
default:
throw new CLIError(`Unknown renderer: ${options.renderer}`);
}
// Write to disk if --outfile is specified
if (options.outfile !== "") {
await Bun.write(options.outfile, serializedPlaybill);
return ExitCode.Success;
}
// Otherwise, write to stdout
console.log(serializedPlaybill);
return ExitCode.Success;
}
async function main(): Promise<number> {
const cliArguments = parseCLIArguments(Bun.argv.slice(2));
const { options } = cliArguments;
// If --help is specified, print usage and exit
if (options.help) {
console.log(USAGE);
return ExitCode.Success;
}
let lastProcessResult = await processBinding(cliArguments);
if (options.watch) {
const watchDir = getAbsoluteDirname(cliArguments.inputFilePath);
console.log(`Watching ${watchDir} for changes...`);
const watcher = watch(watchDir, {
recursive: true,
});
for await (const event of watcher) {
console.log(
`Detected ${event.eventType} on ${event.filename}. Reprocessing...`,
);
try {
lastProcessResult = await processBinding(cliArguments);
if (lastProcessResult === ExitCode.Error) {
console.error(`Error processing ${event.filename}`);
} else {
console.log("Reprocessed changes");
}
} catch (error) {
console.error(`Error processing ${event.filename}`);
console.error(error);
}
}
return ExitCode.Success;
}
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);
}