UNPKG

fumadocs-mdx

Version:

The built-in source for Fumadocs

264 lines (261 loc) 9.79 kB
import { t as fumaMatter } from "./fuma-matter-CHgJa_-B.js"; import { n as ident, r as slash, t as createCodegen } from "./codegen-DleOVLNr.js"; import fs from "node:fs/promises"; import path from "node:path"; import { glob } from "tinyglobby"; import path$1 from "path"; import { createHash } from "crypto"; //#region src/utils/fs-cache.ts const map = /* @__PURE__ */ new Map(); function createFSCache() { return { read(file) { const fullPath = toFullPath(file); const cached = map.get(fullPath); if (cached) return cached; const read = fs.readFile(fullPath).then((s) => s.toString()); map.set(fullPath, read); return read; }, delete(file) { map.delete(toFullPath(file)); } }; } /** * make file paths relative to cwd */ function toFullPath(file) { if (path.isAbsolute(file)) return path.relative(process.cwd(), file); return file; } //#endregion //#region src/plugins/index-file.ts const indexFileCache = createFSCache(); function indexFile(options = {}) { const { target = "default", addJsExtension, browser = true, dynamic = true } = options; let dynamicCollections; function isDynamic(collection) { return collection.type === "docs" && collection.docs.dynamic || collection.type === "doc" && collection.dynamic; } function generateConfigs(core) { const serverOptions = {}; const typeConfigs = ["import(\"fumadocs-mdx/runtime/types\").InternalTypeConfig"]; const ctx = core.getPluginContext(); for (const plugin of core.getPlugins()) { const indexFilePlugin = plugin["index-file"]; if (!indexFilePlugin) continue; indexFilePlugin.serverOptions?.call(ctx, serverOptions); const config = indexFilePlugin.generateTypeConfig?.call(ctx); if (config) typeConfigs.push(config); } return { serverOptions, tc: typeConfigs.join(" & ") }; } return { name: "index-file", config() { dynamicCollections = this.core.getCollections().filter(isDynamic); }, configureServer(server) { if (!server.watcher) return; server.watcher.on("all", async (event, file) => { indexFileCache.delete(file); if (dynamicCollections.length === 0) { if (target === "vite") return; if (target === "default" && event === "change") return; } const updatedCollection = this.core.getCollections().find((collection) => collection.hasFile(file)); if (!updatedCollection) return; if (!isDynamic(updatedCollection)) { if (target === "vite") return; if (target === "default" && event === "change") return; } await this.core.emit({ filterPlugin: (plugin) => plugin.name === "index-file", filterWorkspace: () => false, write: true }); }); }, async emit() { const globCache = /* @__PURE__ */ new Map(); const { workspace, outDir } = this.core.getOptions(); const { serverOptions, tc } = generateConfigs(this.core); const toEmitEntry = async (path$2, content) => { const codegen = createCodegen({ target, outDir, jsExtension: addJsExtension, globCache }); await content({ core: this.core, codegen, serverOptions, tc, workspace: workspace?.name }); return { path: path$2, content: codegen.toString() }; }; const out = [toEmitEntry("server.ts", generateServerIndexFile)]; if (dynamic) out.push(toEmitEntry("dynamic.ts", generateDynamicIndexFile)); if (browser) out.push(toEmitEntry("browser.ts", generateBrowserIndexFile)); return await Promise.all(out); } }; } async function generateServerIndexFile(ctx) { const { core, codegen, serverOptions, tc } = ctx; codegen.lines.push(`import { server } from 'fumadocs-mdx/runtime/server';`, `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`, "", `const create = server<typeof Config, ${tc}>(${JSON.stringify(serverOptions)});`); async function generateCollectionObject(collection) { const base = getBase(collection); switch (collection.type) { case "docs": { if (collection.docs.dynamic) return; if (collection.docs.async) { const [metaGlob$1, headGlob, bodyGlob] = await Promise.all([ generateMetaCollectionGlob(ctx, collection.meta, true), generateDocCollectionFrontmatterGlob(ctx, collection.docs, true), generateDocCollectionGlob(ctx, collection.docs) ]); return `await create.docsLazy("${collection.name}", "${base}", ${metaGlob$1}, ${headGlob}, ${bodyGlob})`; } const [metaGlob, docGlob] = await Promise.all([generateMetaCollectionGlob(ctx, collection.meta, true), generateDocCollectionGlob(ctx, collection.docs, true)]); return `await create.docs("${collection.name}", "${base}", ${metaGlob}, ${docGlob})`; } case "doc": if (collection.dynamic) return; if (collection.async) { const [headGlob, bodyGlob] = await Promise.all([generateDocCollectionFrontmatterGlob(ctx, collection, true), generateDocCollectionGlob(ctx, collection)]); return `await create.docLazy("${collection.name}", "${base}", ${headGlob}, ${bodyGlob})`; } return `await create.doc("${collection.name}", "${base}", ${await generateDocCollectionGlob(ctx, collection, true)})`; case "meta": return `await create.meta("${collection.name}", "${base}", ${await generateMetaCollectionGlob(ctx, collection, true)})`; } } await codegen.pushAsync(core.getCollections().map(async (collection) => { const obj = await generateCollectionObject(collection); if (!obj) return; return `\nexport const ${collection.name} = ${obj};`; })); } async function generateDynamicIndexFile(ctx) { const { core, codegen, serverOptions, tc } = ctx; const { configPath, environment, outDir } = core.getOptions(); const partialOptions = { configPath, environment, outDir }; codegen.lines.push(`import { dynamic } from 'fumadocs-mdx/runtime/dynamic';`, `import * as Config from '${codegen.formatImportPath(configPath)}';`, "", `const create = await dynamic<typeof Config, ${tc}>(Config, ${JSON.stringify(partialOptions)}, ${JSON.stringify(serverOptions)});`); async function generateCollectionObjectEntry(collection, absolutePath) { const fullPath = path$1.relative(process.cwd(), absolutePath); const content = await indexFileCache.read(fullPath).catch(() => ""); const parsed = fumaMatter(content); const data = await core.transformFrontmatter({ collection, filePath: fullPath, source: content }, parsed.data); const hash = createHash("md5").update(content).digest("hex"); const infoStr = [`absolutePath: path.resolve(${JSON.stringify(fullPath)})`]; for (const [k, v] of Object.entries({ info: { fullPath, path: path$1.relative(collection.dir, absolutePath) }, data, hash })) infoStr.push(`${k}: ${JSON.stringify(v)}`); return `{ ${infoStr.join(", ")} }`; } async function generateCollectionObject(parent) { let collection; if (parent.type === "doc") collection = parent; else if (parent.type === "docs") collection = parent.docs; if (!collection || !collection.dynamic) return; const files = await glob(collection.patterns, { cwd: collection.dir, absolute: true }); const entries = await Promise.all(files.map((file) => generateCollectionObjectEntry(collection, file))); switch (parent.type) { case "docs": { const metaGlob = await generateMetaCollectionGlob(ctx, parent.meta, true); return `await create.docs("${parent.name}", "${getBase(parent)}", ${metaGlob}, ${entries.join(", ")})`; } case "doc": return `await create.doc("${collection.name}", "${getBase(collection)}", ${entries.join(", ")})`; } } await codegen.pushAsync(core.getCollections().map(async (collection) => { const obj = await generateCollectionObject(collection); if (!obj) return; return `\nexport const ${collection.name} = ${obj};`; })); } async function generateBrowserIndexFile(ctx) { const { core, codegen, tc } = ctx; codegen.lines.push(`import { browser } from 'fumadocs-mdx/runtime/browser';`, `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`, "", `const create = browser<typeof Config, ${tc}>();`); async function generateCollectionObject(collection) { switch (collection.type) { case "docs": if (collection.docs.dynamic) return; return generateCollectionObject(collection.docs); case "doc": if (collection.dynamic) return; return `create.doc("${collection.name}", ${await generateDocCollectionGlob(ctx, collection)})`; } } codegen.lines.push("const browserCollections = {"); await codegen.pushAsync(core.getCollections().map(async (collection) => { const obj = await generateCollectionObject(collection); if (!obj) return; return ident(`${collection.name}: ${obj},`); })); codegen.lines.push("};", "export default browserCollections;"); } function getBase(collection) { return slash(path$1.relative(process.cwd(), collection.dir)); } function generateDocCollectionFrontmatterGlob({ codegen, workspace }, collection, eager = false) { return codegen.generateGlobImport(collection.patterns, { query: { collection: collection.name, only: "frontmatter", workspace }, import: "frontmatter", base: collection.dir, eager }); } function generateDocCollectionGlob({ codegen, workspace }, collection, eager = false) { return codegen.generateGlobImport(collection.patterns, { query: { collection: collection.name, workspace }, base: collection.dir, eager }); } function generateMetaCollectionGlob({ codegen, workspace }, collection, eager = false) { return codegen.generateGlobImport(collection.patterns, { query: { collection: collection.name, workspace }, import: "default", base: collection.dir, eager }); } //#endregion export { indexFile as t }; //# sourceMappingURL=index-file-D9HsrWU_.js.map