import { expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { globals, walk, type Output, type Site, type Spec } from "./build.ts";
/* SITE */
const site = () =>
({
config: {
title: "Demo",
root: "https://demo.test",
llms: {
about: "A demo tree.",
links: [
{ href: "/raw/README.md", name: "README", note: "the readme" },
{ href: "/git/", name: "Code", note: "the tree" },
{ href: "/nowhere/", name: "Nowhere" },
],
},
},
routes: [
{ route: "/", name: "Home", at: "2026-01-01" },
{ route: "/404.html", kind: "missing", hidden: true },
{ route: "/git/", kind: "gitdir", name: "demo", sitemap: true, at: "2026-02-02" },
{
route: "/git/README.md",
kind: "gitfile",
name: "README.md",
hidden: true,
sitemap: true,
at: "2026-03-03",
urls: [{ route: "/git/README.md" }, { route: "/raw/README.md" }],
},
],
}) as unknown as Site;
const made = async () => {
const out = await globals(site(), {} as unknown as Spec);
const find = (path: string) => (out.find((one: Output) => one.path === path)!.bytes as string);
return { sitemap: find("sitemap.xml"), robots: find("robots.txt"), llms: find("llms.txt") };
};
/* SITEMAP */
test("the sitemap carries every git route and every raw path with its own date", async () => {
const { sitemap } = await made();
expect(sitemap).toContain("https://demo.test/git/2026-02-02");
expect(sitemap).toContain("https://demo.test/git/README.md2026-03-03");
expect(sitemap).toContain("https://demo.test/raw/README.md2026-03-03");
expect(sitemap).toContain("https://demo.test/2026-01-01");
expect(sitemap).not.toContain("404.html");
expect(sitemap.match(//g)!.length).toBe(4);
});
/* ROBOTS */
test("robots names the crawlers it welcomes and points at the sitemap", async () => {
const { robots } = await made();
for (const agent of ["GPTBot", "ClaudeBot", "Claude-Web", "CCBot", "Google-Extended", "anthropic-ai", "PerplexityBot"]) {
expect(robots).toContain(`User-agent: ${agent}\nAllow: /`);
}
expect(robots).toContain("User-agent: *\nAllow: /");
expect(robots).toContain("Sitemap: https://demo.test/sitemap.xml");
});
/* LLMS */
test("llms.txt says what the site is and links only what the site publishes", async () => {
const { llms } = await made();
expect(llms).toContain("# Demo");
expect(llms).toContain("A demo tree.");
expect(llms).toContain("- [README](https://demo.test/raw/README.md): the readme");
expect(llms).toContain("- [Code](https://demo.test/git/): the tree");
expect(llms).not.toContain("Nowhere");
});
/* CSS */
const selectors = (css: string) => {
const out: string[] = [];
let depth = 0;
let buf = "";
for (const c of css.replace(/\/\*[\s\S]*?\*\//g, "")) {
if (c === "{") {
if (depth === 0) out.push(buf.trim().replace(/\s+/g, " "));
depth++;
buf = "";
} else if (c === "}") {
depth--;
buf = "";
} else if (depth === 0) buf += c;
}
return out;
};
test("the kit css never repeats a top-level selector with another rule between", () => {
const home = join(import.meta.dir, "..", "ui");
for (const file of walk(home, false).filter((f) => f.endsWith(".css"))) {
const list = selectors(readFileSync(file, "utf8"));
const last = new Map();
list.forEach((sel, n) => {
const was = last.get(sel);
if (was !== undefined && list.slice(was + 1, n).some((other) => other !== sel)) throw new Error(`${file}: '${sel}' at ${was} and ${n}`);
last.set(sel, n);
});
}
});