96 lines
3.3 KiB
TypeScript
Executable File
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(); |