#!/usr/bin/env -S bun run import { $ } from "bun"; import { readdir } from "node:fs/promises" import { parseArgs } from "util"; import { JSDOM } from "jsdom"; import { Dirent } from "node:fs"; import { mkdir, stat } from "node:fs/promises"; function out_path(path: string) { } type LogLevel = "INFO"|"WARN"|"ERROR"|"FATAL" function log(level: LogLevel, message: any) { const p = Bun.argv[1]?.split("/").slice(-1)[0] ?? "build script"; switch (level) { case "INFO": console.log(`\x1b[90m${p}: \x1b[1;42;97m [INFO] \x1b[0m ${message}`); break; case "WARN": console.log(`\x1b[90m${p}: \x1b[1;48;5;208;97m [WARN] \x1b[0m ${message}`); break; case "ERROR": console.log(`\x1b[90m${p}: \x1b[1;41;97m [ERROR] \x1b[0m ${message}`); break; case "FATAL": console.log(`\x1b[90m${p}: \x1b[1;41;97m [FATAL] ${message} \x1b[0m`); process.exit(); break; } } async function build_typst_file(file: Dirent) { let path = file.parentPath + "/" + file.name let dir = "public_html" + file.parentPath.slice(3) let slug = path.slice(4, -4) let outfile = `public_html/${slug}.html` log("INFO", `Building ${path}`) await mkdir(dir, {recursive: true}) await $`typst c --features html --format html --root . ${path} ${outfile}` log("INFO", `Built ${path}`) } async function build_all_typst() { let files = await readdir("src", {withFileTypes: true, recursive: true}); let promises: Promise[] = []; for (let f of files) { if (f.isFile() && f.name.endsWith(".typ")) promises.push(build_typst_file(f)) } await Promise.all(promises) } async function copy_assets() { log("INFO", "Updating assets") await $`rm -rf public_html/assets/` await $`cp -r assets/ public_html/` } type IndexEntry = { id: string; title: string; body: string; tags: string;} async function collect_data(f:string) : Promise { let id = f.slice(12, -5) log("INFO", `collecting metadata for ${id}`) let dom = await JSDOM.fromFile(f) let body = "" let things = dom.window.document.getElementsByTagName("main") for (let thing of things) body += thing.textContent; let title = dom.window.document.getElementById("search-title")?.getAttribute("content") ?? "" let tags = dom.window.document.getElementById("search-tags")?.getAttribute("content") ?? "" return {id, title, body, tags} } async function gen_index() { let files = await readdir("public_html", {withFileTypes: true, recursive: true}) let promises : Promise[] = []; for (let f of files) { if (f.isFile() && f.name.endsWith(".html")) { promises.push(collect_data(f.parentPath + "/" + f.name)); } } let data : IndexEntry[] = await Promise.all(promises) await Bun.write("public_html/index.json", JSON.stringify(data), {mode: 0o644, createPath: true}) } const args = parseArgs({ args: Bun.argv, options: { "build": {type: "boolean", short: "b"}, "assets": {type: "boolean", short: "a"}, "index": { short: "i", type: "boolean" } }, allowPositionals: true }).values if (!args.build && !args.assets && !args.index) { await build_all_typst() await copy_assets() await gen_index() } if (args.build) await build_all_typst(); if (args.assets) await copy_assets(); if (args.index) await gen_index();