fumadocs-mdx
Version:
The built-in source for Fumadocs
212 lines (209 loc) • 6.63 kB
JavaScript
import { n as ident } from "./codegen-DleOVLNr.js";
import fs from "node:fs/promises";
import path from "node:path";
//#region src/utils/validation.ts
var ValidationError = class extends Error {
constructor(message, issues) {
super(`${message}:\n${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`);
this.title = message;
this.issues = issues;
}
async toStringFormatted() {
const picocolorsModule = await import("picocolors");
const picocolors = picocolorsModule.default ?? picocolorsModule;
return [picocolors.bold(`[MDX] ${this.title}:`), ...this.issues.map((issue) => picocolors.redBright(`- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`))].join("\n");
}
};
async function validate(schema, data, context, errorMessage) {
if (typeof schema === "function" && !("~standard" in schema)) schema = schema(context);
if ("~standard" in schema) {
const result = await schema["~standard"].validate(data);
if (result.issues) throw new ValidationError(errorMessage, result.issues);
return result.value;
}
return data;
}
//#endregion
//#region src/core.ts
const _Defaults = {
configPath: "source.config.ts",
outDir: ".source"
};
async function getPlugins(pluginOptions) {
const plugins = [];
for await (const option of pluginOptions) {
if (!option) continue;
if (Array.isArray(option)) plugins.push(...await getPlugins(option));
else plugins.push(option);
}
return plugins;
}
function createCore(options) {
let config;
let plugins;
const workspaces = /* @__PURE__ */ new Map();
async function transformMetadata({ collection, filePath, source }, data) {
if (collection.schema) data = await validate(collection.schema, data, {
path: filePath,
source
}, collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`);
return data;
}
return {
cache: /* @__PURE__ */ new Map(),
async init({ config: newConfig }) {
config = await newConfig;
this.cache.clear();
workspaces.clear();
plugins = await getPlugins([
postprocessPlugin(),
options.plugins,
config.global.plugins
]);
for (const plugin of plugins) {
const out = await plugin.config?.call(this.getPluginContext(), config);
if (out) config = out;
}
if (!options.workspace) await Promise.all(Object.entries(config.workspaces).map(async ([name, workspace]) => {
const core = createCore({
...options,
outDir: path.join(options.outDir, name),
workspace: {
name,
parent: this,
dir: workspace.dir
}
});
await core.init({ config: workspace.config });
workspaces.set(name, core);
}));
},
getWorkspaces() {
return workspaces;
},
getOptions() {
return options;
},
getConfig() {
return config;
},
getCompiledConfigPath() {
return path.join(options.outDir, "source.config.mjs");
},
getPlugins() {
return plugins;
},
getCollections() {
return Array.from(config.collections.values());
},
getCollection(name) {
return config.collections.get(name);
},
getPluginContext() {
return { core: this };
},
async initServer(server) {
const ctx = this.getPluginContext();
for (const plugin of plugins) await plugin.configureServer?.call(ctx, server);
for (const workspace of workspaces.values()) await workspace.initServer(server);
},
async emit(emitOptions = {}) {
const { filterPlugin, filterWorkspace, write = false } = emitOptions;
const start = performance.now();
const ctx = this.getPluginContext();
const added = /* @__PURE__ */ new Set();
const out = {
entries: [],
workspaces: {}
};
for (const li of await Promise.all(plugins.map((plugin) => {
if (filterPlugin && !filterPlugin(plugin) || !plugin.emit) return;
return plugin.emit.call(ctx);
}))) {
if (!li) continue;
for (const item of li) {
if (added.has(item.path)) continue;
out.entries.push(item);
added.add(item.path);
}
}
if (write) {
await Promise.all(out.entries.map(async (entry) => {
const file = path.join(options.outDir, entry.path);
await fs.mkdir(path.dirname(file), { recursive: true });
await fs.writeFile(file, entry.content);
}));
console.log(options.workspace ? `[MDX: ${options.workspace.name}] generated files in ${performance.now() - start}ms` : `[MDX] generated files in ${performance.now() - start}ms`);
}
for (const [name, workspace] of workspaces) {
if (filterWorkspace && !filterWorkspace(name)) continue;
out.workspaces[name] = (await workspace.emit(emitOptions)).entries;
}
return out;
},
async transformMeta(options$1, data) {
const ctx = {
...this.getPluginContext(),
...options$1
};
data = await transformMetadata(options$1, data);
for (const plugin of plugins) if (plugin.meta?.transform) data = await plugin.meta.transform.call(ctx, data) ?? data;
return data;
},
async transformFrontmatter(options$1, data) {
const ctx = {
...this.getPluginContext(),
...options$1
};
data = await transformMetadata(options$1, data);
for (const plugin of plugins) if (plugin.doc?.frontmatter) data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
return data;
},
async transformVFile(options$1, file) {
const ctx = {
...this.getPluginContext(),
...options$1
};
for (const plugin of plugins) if (plugin.doc?.vfile) file = await plugin.doc.vfile.call(ctx, file) ?? file;
return file;
}
};
}
function postprocessPlugin() {
const LinkReferenceTypes = `{
/**
* extracted references (e.g. hrefs, paths), useful for analyzing relationships between pages.
*/
extractedReferences: import("fumadocs-mdx").ExtractedReference[];
}`;
return { "index-file": {
generateTypeConfig() {
const lines = [];
lines.push("{");
lines.push(" DocData: {");
for (const collection of this.core.getCollections()) {
let postprocessOptions;
switch (collection.type) {
case "doc":
postprocessOptions = collection.postprocess;
break;
case "docs":
postprocessOptions = collection.docs.postprocess;
break;
}
if (postprocessOptions?.extractLinkReferences) lines.push(ident(`${collection.name}: ${LinkReferenceTypes},`, 2));
}
lines.push(" }");
lines.push("}");
return lines.join("\n");
},
serverOptions(options) {
options.doc ??= {};
options.doc.passthroughs ??= [];
options.doc.passthroughs.push("extractedReferences");
}
} };
}
//#endregion
export { createCore as n, ValidationError as r, _Defaults as t };
//# sourceMappingURL=core-DjldE3H9.js.map