// Lean+Mathlib provenance — loads `data/lean_status.json`, exposes per-theorem // badge HTML + a grouped table renderer for the Verification accordion. // Pure browser-only: just fetches a static JSON manifest. let _manifest = null; let _byName = null; export async function loadLeanManifest(url = "data/lean_status.json") { if (_manifest) return _manifest; const res = await fetch(url, { cache: "default" }); if (!res.ok) throw new Error(`lean manifest fetch failed: ${res.status}`); _manifest = await res.json(); _byName = {}; for (const g of _manifest.groups) { for (const t of g.theorems) { t._group = g.id; t._url = sourceUrl(_manifest, t); _byName[t.name] = t; } } return _manifest; } export function getManifest() { return _manifest; } export function getTheorem(name) { return _byName ? _byName[name] : null; } export function sourceUrl(manifest, theorem) { const repo = manifest.lean_repo; return `${repo.url}/blob/${repo.default_branch}/${theorem.file}#L${theorem.line}`; } const escapeHtml = (s) => String(s ?? "").replace(/[&<>"]/g, c => ({"&":"&","<":"<",">":">",'"':"""}[c])); const escapeAttr = (s) => String(s ?? "").replace(/"/g, """); export function badgeHtml(theoremName, label = "✓ Lean ↗") { const t = getTheorem(theoremName); if (!t) return ""; return `${escapeHtml(label)}`; } export function badgesForUiBinding(bindingKey) { // Returns concatenated badges for a UI binding (single string or array of names). const manifest = getManifest(); if (!manifest || !manifest.ui_bindings) return ""; const binding = manifest.ui_bindings[bindingKey]; if (!binding) return ""; const names = Array.isArray(binding) ? binding : [binding]; return names.map(n => badgeHtml(n, "✓ Lean")).filter(Boolean).join(" "); } export function renderTheoremTable() { const manifest = getManifest(); if (!manifest) return "
| Theorem | Claim | Tactic | Source | Lean |
|---|---|---|---|---|
${escapeHtml(t.name)} |
${escapeHtml(t.claim)} | ${escapeHtml(t.tactic || "")} |
${t.source ? renderSource(t.source) : "—"} | ${badgeHtml(t.name, "L" + t.line + " ↗")} |
${escapeHtml(src.doc)}`);
if (src.section) parts.push(escapeHtml(src.section));
if (src.line) parts.push(`L${src.line}`);
if (src.label) parts.push(`${escapeHtml(src.label)}`);
return parts.join(" · ");
}