import type { APIRoute } from "astro"; import { getCollection, getEntry } from "astro:content"; import config from "virtual:starlight/user-config"; export const prerender = true; type SidebarItem = NonNullable[number]; type DocsEntry = Awaited>>[number]; type Link = { label: string; href: string }; const TRIM_SLASHES = /^\/|\/$/g; const ABSOLUTE_URL = /^https?:\/\//; export const GET: APIRoute = async ({ site }) => { // Pre-load the docs collection so autogenerated groups can resolve // without one `getEntry` call per page. const docs = await getCollection("docs"); const lang = config.defaultLocale.lang; const title = (lang ? config.title[lang] : undefined) ?? Object.values(config.title)[0] ?? ""; const lines: string[] = [`# ${title}`]; if (config.tagline) { lines.push("", `> ${config.tagline}`); } for (const item of config.sidebar ?? []) { const links = await resolveItem(item, docs); if (links.length === 0) continue; const groupLabel = typeof item !== "string" && "label" in item ? item.label : undefined; if (groupLabel && typeof item !== "string" && ("items" in item || "autogenerate" in item)) { lines.push("", `## ${groupLabel}`, ""); } else { lines.push(""); } for (const link of links) { lines.push(`- [${link.label}](${absUrl(link.href, site)})`); } } return new Response(lines.join("\n") + "\n", { headers: { "Content-Type": "text/plain; charset=utf-8" }, }); }; async function resolveItem(item: SidebarItem, docs: DocsEntry[]): Promise { // Shorthand: a string is a slug reference. if (typeof item === "string") { const entry = getEntry("docs", item); return entry ? [entryLink(entry)] : []; } if ("link" in item && item.link) { return [{ label: item.label, href: item.link }]; } if ("slug" in item && item.slug) { const entry = await getEntry("docs", item.slug); return entry ? [entryLink(entry, item.label)] : []; } if ("items" in item && item.items) { const out: Link[] = []; for (const child of item.items) { out.push(...(await resolveItem(child, docs))); } return out; } if ("autogenerate" in item && item.autogenerate) { const prefix = item.autogenerate.directory.replace(TRIM_SLASHES, "") + "/"; return docs .filter((entry) => entry.id.startsWith(prefix)) .toSorted((a, b) => a.id.localeCompare(b.id)) .map((entry) => entryLink(entry)); } return []; } function entryLink(entry: DocsEntry, override?: string): Link { const slug = entry.id === "index" ? "" : entry.id; const href = "/" + slug + (slug ? "/" : ""); const label = override ?? entry.data.sidebar?.label ?? entry.data.title; return { label, href }; } function absUrl(href: string, site: URL | undefined): string { if (ABSOLUTE_URL.test(href)) return href; if (!site) return href; return new URL(href, site).toString(); }