import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { docsIndex, docsPage } from "./layout.js";
import { renderMarkdown } from "./markdown.js";
function versionMeta(version, rel) {
if (version.latest) return {};
return { noindex: true, canonical: version.latestPages.has(rel) ? `/docs${rel}` : undefined };
}
export async function buildDocs({ contentRoot, sidebar, base = "/docs", version }) {
const pages = new Map();
for (const group of sidebar) {
for (const item of group.items) {
const rel = item.link.replace(/^\/|\/$/g, "");
const file = [".md", ".mdx"].map((ext) => rel + ext).find((f) => existsSync(join(contentRoot, f)));
if (!file) throw new Error(`sidebar entry ${item.link} has no page in ${contentRoot}`);
const rendered = await renderMarkdown(readFileSync(join(contentRoot, file), "utf8"), { base });
pages.set(base + item.link, { ...rendered, title: rendered.title || item.label, path: base + item.link, file, label: item.label });
}
}
const order = [...pages.values()];
const out = order.map((page, i) => ({
meta: {
path: page.path,
title: `${page.title} · rws ${version.latest ? "docs" : `${version.key} docs`}`,
description: page.description || page.title,
...versionMeta(version, page.path.slice(base.length)),
},
render: () =>
docsPage({
page,
sidebar,
base,
version,
prev: order[i - 1] && { href: order[i - 1].path, label: order[i - 1].label },
next: order[i + 1] && { href: order[i + 1].path, label: order[i + 1].label },
}),
}));
out.unshift({
meta: {
path: `${base}/`,
title: version.latest ? "Documentation · rws" : `Documentation for ${version.key} · rws`,
description: "rust-web-server documentation: configuration, proxy, building apps, MCP, database and deployment.",
...versionMeta(version, "/"),
},
render: () => docsIndex({ path: `${base}/`, sidebar, base, pages, version }),
});
return out;
}