import { spawnSync } from "node:child_process"; import { existsSync, readdirSync, readFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; export const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); export const talksDir = join(root, "talks"); export const templateDir = join(root, "template"); export const distDir = join(root, "dist"); /** Every directory in talks/ that has a slides.md, with its frontmatter title/date/video. */ export function listTalks() { return readdirSync(talksDir, { withFileTypes: true }) .filter((d) => d.isDirectory() && existsSync(join(talksDir, d.name, "slides.md"))) .map((d) => { const entry = join(talksDir, d.name, "slides.md"); const headmatter = readFileSync(entry, "utf8").match(/^---\n([\s\S]*?)\n---/)?.[1] ?? ""; const field = (name) => { const raw = headmatter.match(new RegExp(`^${name}:\\s*(.+)$`, "m"))?.[1].trim(); if (raw?.startsWith('"')) return JSON.parse(raw); return raw?.replace(/^'(.*)'$/, "$1"); }; // `video` is optional — the recording's URL, once there is one. const video = field("video"); if (video && !/^https?:\/\//.test(video)) { console.error(`talks/${d.name}: video must be an http(s) URL, got "${video}"`); process.exit(1); } return { slug: d.name, entry, title: field("title") ?? d.name, date: field("date"), video }; }) .sort((a, b) => (b.date ?? "").localeCompare(a.date ?? "") || a.slug.localeCompare(b.slug)); } /** Resolve a talk from a CLI arg; falls back to the only talk, else exits with the list. */ export function pickTalk(slug) { const talks = listTalks(); const talk = slug ? talks.find((t) => t.slug === slug) : talks.length === 1 ? talks[0] : undefined; if (talk) return talk; console.error(slug ? `No talk named "${slug}".` : "Which talk?"); console.error(talks.map((t) => ` ${t.slug}`).join("\n")); process.exit(1); } export function slidev(args) { const { status } = spawnSync(join(root, "node_modules/.bin/slidev"), args, { cwd: root, stdio: "inherit" }); if (status !== 0) process.exit(status ?? 1); }