import fs from "node:fs"; import path from "node:path"; import { DOCS, DOC_GROUP_ORDER, type DocEntry, type DocGroup, } from "../../content/docs"; export type { DocEntry, DocGroup }; export { DOC_GROUP_ORDER }; // Build-time only. `output: "export"` means every one of these reads happens // during `next build`; nothing here runs per request. Mirrors the // readFileSync-from-cwd approach in export/app/changelog/page.tsx. // // Every path op on a cwd-derived path opts out of Turbopack's asset tracing // (plans/FACTS.md, "A path joined from `process.cwd()` …"). function docPath(entry: DocEntry): string { return path.join(/* turbopackIgnore: true */ process.cwd(), "content", "docs", entry.file); } // The manifest entries whose file actually exists. // // This filter is the whole safety property of the docs subsystem: it feeds BOTH // `generateStaticParams()` (with `dynamicParams = false`) AND the /docs/ index, // so a manifest entry with a missing file 404s quietly instead of crashing the // build, and the index can never link to a page that isn't there. Those two // facts have to come from the same call, or they will disagree. export function listDocs(): DocEntry[] { return DOCS.filter((entry) => { try { return fs.statSync(/* turbopackIgnore: true */ docPath(entry)).isFile(); } catch { return false; } }); } export function findDoc(slug: string): DocEntry | null { return listDocs().find((d) => d.slug === slug) ?? null; } // Read a doc's Markdown, minus its leading `# Title` line. The file keeps that // heading so it stands alone as a document; the page renders its own

from // the manifest, and two titles in a row reads as a mistake. export function readDoc(entry: DocEntry): string { const raw = fs.readFileSync(/* turbopackIgnore: true */ docPath(entry), "utf8"); return raw.replace(/^?\s*#[^\n#][^\n]*\n+/, ""); } // The index, grouped and ordered by the manifest. Groups with no surviving // entries are dropped rather than rendered empty. export function groupedDocs(): { label: string; docs: DocEntry[] }[] { const docs = listDocs(); return DOC_GROUP_ORDER.map((g) => ({ label: g.label, docs: docs.filter((d) => d.group === g.id), })).filter((g) => g.docs.length > 0); }