blob: 42b718ea59df7c8710f06bbaaa450130f5edadf1 [file]
import { docs, blog } from "fumadocs-mdx:collections/server";
import { type InferPageType, loader } from "fumadocs-core/source";
import { lucideIconsPlugin } from "fumadocs-core/source/lucide-icons";
// Define proper types for page data
type PageData = {
title: string;
description?: string;
date?: string;
body: unknown;
toc?: Array<{
title: string;
url: string;
depth?: number;
items?: Array<{ title: string; url: string; depth?: number }>;
}>;
full?: boolean;
};
type FumadocsPageData = PageData & {
getText: (type: "raw" | "processed") => Promise<string>;
};
// Keep doc URLs flat so folder names stay out of the final pathname.
function flattenDocSlugs({ path }: { path: string }): string[] {
const segments = path.replace(/\\/g, "/").split("/").filter(Boolean);
const fileName = segments.pop() ?? "";
const baseName = fileName.replace(/\.[^/.]+$/, "");
if (baseName === "index") {
return segments.filter((segment) => segment !== "docs").map((segment) => encodeURI(segment));
}
return [encodeURI(baseName)];
}
// See https://fumadocs.dev/docs/headless/source-api for more info
export const source = loader({
baseUrl: "/docs",
source: docs.toFumadocsSource(),
slugs: flattenDocSlugs,
plugins: [lucideIconsPlugin()],
});
export const blogSource = loader({
baseUrl: "/blog",
source: blog.toFumadocsSource(),
plugins: [lucideIconsPlugin()],
});
export function getPageImage(page: InferPageType<typeof source>) {
const segments = [...page.slugs, "image.png"];
return {
segments,
url: `/og/docs/${segments.join("/")}`,
};
}
export async function getLLMText(page: InferPageType<typeof source>) {
const pageData = page.data as FumadocsPageData;
const raw = await pageData.getText("raw");
// Build metadata section
const metadata: string[] = [];
// Add page URL
metadata.push(`URL: ${page.url}`);
// Add source file URL on GitHub
const normalizedPath = page.path.startsWith("content/") ? page.path : `content/${page.path}`;
const sourceUrl = `https://github.com/casbin/casbin-website-v3/blob/master/${normalizedPath}`;
metadata.push(`Source: ${sourceUrl}`);
// Add description if available
if (pageData.description) {
metadata.push(`\n${pageData.description}`);
}
// Clean up raw MDX content: remove MDX component tags and excessive blank lines
// Only remove tags that are clearly MDX components (contain capital letters or hyphenated names)
const cleanedContent = raw
.replace(/<[A-Z][^>]*\/?>/g, "") // Remove MDX components starting with capital letter (e.g., <Feedback />, <Card>)
.trim()
.replace(/\n\s*\n\s*\n+/g, "\n\n");
return `# ${pageData.title}
${metadata.join("\n")}
${cleanedContent}`;
}