wiki/build.ts
2026-01-18 16:46:44 +01:00

96 lines
3.3 KiB
TypeScript
Executable File

#!/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<void>[] = [];
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<IndexEntry> {
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<IndexEntry>[] = [];
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();