// Finding an article's draft and generator, on the three workspace layouts // the live private sites use. // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import test from "node:test"; import { clearSourcesCache, names, siteWorkspaces, sourceFor } from "./sources.mjs"; async function put(file, text) { await mkdir(path.dirname(file), { recursive: true }); await writeFile(file, text); } async function fixture() { const root = await mkdtemp(path.join(tmpdir(), "umtool-sources-")); // candalyzer: drafts/.json with id polemic-; generator site/polemics.py; // a hand-written fact-check whose generator names it; a backup generator. await put(path.join(root, "candace/polemics/drafts/israel.json"), JSON.stringify({ id: "polemic-israel" })); await put(path.join(root, "candace/site/polemics.py"), 'OUT = ".../sites/candalyzer/reports"\nfor f in DRAFTS.glob("drafts/*.json"): rid = f"polemic-{slug}"\n'); await put(path.join(root, "candace/site/make-report.py"), 'SITE = "candalyzer"\nREPORT = "deconstruction-fact-check"\n'); await put(path.join(root, "candace/site/make-report.pre-2026-10-05.py"), 'REPORT = "polemic-israel" # candalyzer\n'); // jasolyzer-private: drafts/.json, generator polemics/make-site.py await put(path.join(root, "pirate/polemics/drafts/skg.json"), JSON.stringify({ id: "polemic-skg" })); await put(path.join(root, "pirate/polemics/make-site.py"), 'SITE = "jasolyzer-private"\nrid = f"polemic-{slug}" # from drafts\n'); // jeralyzer-private: the report id is BARE (`blame`), the draft id is polemic-blame await put(path.join(root, "quartering/polemics/drafts/blame.json"), JSON.stringify({ id: "polemic-blame" })); await put(path.join(root, "quartering/polemics/make-site.py"), 'SITE = "jeralyzer-private"\nrid = slug # drafts\n'); // a decoy: a public site's workspace with a same-named draft await put(path.join(root, "decoy/polemics/drafts/blame.json"), JSON.stringify({ id: "blame" })); await put(path.join(root, "decoy/polemics/make-site.py"), 'SITE = "jeralyzer"\n'); clearSourcesCache(); return root; } test("each layout finds its draft and generator", async () => { const root = await fixture(); const o = { reportsRoot: root }; const isr = await sourceFor("candalyzer", "polemic-israel", o); assert.equal(isr.draft, path.join(root, "candace/polemics/drafts/israel.json")); assert.equal(isr.generator, path.join(root, "candace/site/polemics.py")); assert.match(isr.how, /draft matched by id polemic-israel/); const fc = await sourceFor("candalyzer", "deconstruction-fact-check", o); assert.equal(fc.draft, undefined); assert.equal(fc.generator, path.join(root, "candace/site/make-report.py")); const skg = await sourceFor("jasolyzer-private", "polemic-skg", o); assert.equal(skg.draft, path.join(root, "pirate/polemics/drafts/skg.json")); assert.equal(skg.generator, path.join(root, "pirate/polemics/make-site.py")); // The decoy's draft id is exactly `blame`, but its workspace never names the site. const blame = await sourceFor("jeralyzer-private", "blame", o); assert.equal(blame.draft, path.join(root, "quartering/polemics/drafts/blame.json")); assert.equal(blame.generator, path.join(root, "quartering/polemics/make-site.py")); assert.match(blame.how, /preferred over 1 other/); assert.equal(await sourceFor("candalyzer", "no-such-report", o), null); assert.deepEqual(await siteWorkspaces("jasolyzer-private", ["polemic-skg"], o), [path.join(root, "pirate")]); await rm(root, { recursive: true }); }); test("names() matches whole ids only", () => { assert.equal(names('"jasolyzer-private"', "jasolyzer"), false); assert.equal(names("sites/jasolyzer/reports", "jasolyzer"), true); assert.equal(names("polemic-blame", "blame"), false); });