fumadocs-mdx 11.9.1 → 11.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{browser-CyU2Yl7A.d.cts → browser-B2G8uAF2.d.cts} +1 -1
- package/dist/{browser-DEsQvNRx.d.ts → browser-DrH7tKRi.d.ts} +1 -1
- package/dist/bun/index.cjs +667 -0
- package/dist/bun/index.d.cts +8 -0
- package/dist/bun/index.d.ts +8 -0
- package/dist/bun/index.js +50 -0
- package/dist/{chunk-766EAFX6.js → chunk-2HKRTQYP.js} +64 -0
- package/dist/chunk-5XJM5RPV.js +149 -0
- package/dist/chunk-NVX3U5YE.js +82 -0
- package/dist/config/index.d.cts +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/zod-3.d.cts +1 -1
- package/dist/config/zod-3.d.ts +1 -1
- package/dist/{define-DnJzAZrj.d.cts → define-BH4bnHQl.d.cts} +6 -0
- package/dist/{define-DnJzAZrj.d.ts → define-BH4bnHQl.d.ts} +6 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/loader-mdx.cjs +345 -265
- package/dist/loader-mdx.js +11 -80
- package/dist/next/index.js +4 -6
- package/dist/node/loader.cjs +748 -0
- package/dist/node/loader.d.cts +5 -0
- package/dist/node/loader.d.ts +5 -0
- package/dist/node/loader.js +23 -0
- package/dist/runtime/async.d.cts +2 -2
- package/dist/runtime/async.d.ts +2 -2
- package/dist/runtime/vite/browser.d.cts +2 -2
- package/dist/runtime/vite/browser.d.ts +2 -2
- package/dist/runtime/vite/server.d.cts +3 -3
- package/dist/runtime/vite/server.d.ts +3 -3
- package/dist/{types-WSHJKA8L.d.ts → types-DN9KrG7R.d.ts} +1 -1
- package/dist/{types-BmVgoqsr.d.cts → types-DT83Ijs6.d.cts} +1 -1
- package/dist/vite/index.cjs +356 -282
- package/dist/vite/index.js +12 -78
- package/package.json +17 -8
- package/dist/chunk-GX3THK2Q.js +0 -66
- package/dist/chunk-UCY7OBZG.js +0 -12
package/dist/loader-mdx.cjs
CHANGED
|
@@ -37,9 +37,9 @@ function remarkPostprocess({
|
|
|
37
37
|
return (tree, file) => {
|
|
38
38
|
let title;
|
|
39
39
|
const urls = [];
|
|
40
|
-
(0,
|
|
40
|
+
(0, import_unist_util_visit2.visit)(tree, ["heading", "link"], (node) => {
|
|
41
41
|
if (node.type === "heading" && node.depth === 1) {
|
|
42
|
-
title =
|
|
42
|
+
title = flattenNode2(node);
|
|
43
43
|
}
|
|
44
44
|
if (node.type !== "link") return;
|
|
45
45
|
urls.push({
|
|
@@ -58,9 +58,9 @@ function remarkPostprocess({
|
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function flattenNode2(node) {
|
|
62
62
|
if ("children" in node)
|
|
63
|
-
return node.children.map((child) =>
|
|
63
|
+
return node.children.map((child) => flattenNode2(child)).join("");
|
|
64
64
|
if ("value" in node) return node.value;
|
|
65
65
|
return "";
|
|
66
66
|
}
|
|
@@ -98,11 +98,11 @@ function getMdastExport(name, value) {
|
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
var
|
|
101
|
+
var import_unist_util_visit2, import_estree_util_value_to_estree;
|
|
102
102
|
var init_remark_postprocess = __esm({
|
|
103
103
|
"src/mdx-plugins/remark-postprocess.ts"() {
|
|
104
104
|
"use strict";
|
|
105
|
-
|
|
105
|
+
import_unist_util_visit2 = require("unist-util-visit");
|
|
106
106
|
import_estree_util_value_to_estree = require("estree-util-value-to-estree");
|
|
107
107
|
}
|
|
108
108
|
});
|
|
@@ -203,137 +203,91 @@ __export(loader_mdx_exports, {
|
|
|
203
203
|
default: () => loader
|
|
204
204
|
});
|
|
205
205
|
module.exports = __toCommonJS(loader_mdx_exports);
|
|
206
|
-
var path4 = __toESM(require("path"), 1);
|
|
207
|
-
var import_node_querystring = require("querystring");
|
|
208
206
|
|
|
209
|
-
// src/utils/
|
|
210
|
-
var
|
|
211
|
-
var
|
|
212
|
-
|
|
207
|
+
// src/utils/fuma-matter.ts
|
|
208
|
+
var import_js_yaml = require("js-yaml");
|
|
209
|
+
var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
|
|
210
|
+
function fumaMatter(input) {
|
|
211
|
+
const output = { matter: "", data: {}, content: input };
|
|
212
|
+
const match = regex.exec(input);
|
|
213
|
+
if (!match) {
|
|
214
|
+
return output;
|
|
215
|
+
}
|
|
216
|
+
output.matter = match[0];
|
|
217
|
+
output.content = input.slice(match[0].length);
|
|
218
|
+
const loaded = (0, import_js_yaml.load)(match[1]);
|
|
219
|
+
output.data = loaded ?? {};
|
|
220
|
+
return output;
|
|
221
|
+
}
|
|
213
222
|
|
|
214
|
-
// src/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
if (typeof v === "object" && "type" in v) {
|
|
223
|
-
if (v.type === "docs") {
|
|
224
|
-
collections.set(k, v);
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
if (v.type === "doc" || v.type === "meta") {
|
|
228
|
-
collections.set(k, v);
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
if (k === "default" && v) {
|
|
233
|
-
globalConfig = v;
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
throw new Error(
|
|
237
|
-
`Unknown export "${k}", you can only export collections from source configuration file.`
|
|
223
|
+
// src/utils/validation.ts
|
|
224
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
225
|
+
var ValidationError = class extends Error {
|
|
226
|
+
constructor(message, issues) {
|
|
227
|
+
super(
|
|
228
|
+
`${message}:
|
|
229
|
+
${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
|
|
238
230
|
);
|
|
231
|
+
this.title = message;
|
|
232
|
+
this.issues = issues;
|
|
239
233
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
234
|
+
toStringFormatted() {
|
|
235
|
+
return [
|
|
236
|
+
import_picocolors.default.bold(`[MDX] ${this.title}:`),
|
|
237
|
+
...this.issues.map(
|
|
238
|
+
(issue) => import_picocolors.default.redBright(
|
|
239
|
+
`- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
].join("\n");
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
async function validate(schema, data, context, errorMessage) {
|
|
246
|
+
if (typeof schema === "function" && !("~standard" in schema)) {
|
|
247
|
+
schema = schema(context);
|
|
248
|
+
}
|
|
249
|
+
if ("~standard" in schema) {
|
|
250
|
+
const result = await schema["~standard"].validate(
|
|
251
|
+
data
|
|
252
|
+
);
|
|
253
|
+
if (result.issues) {
|
|
254
|
+
throw new ValidationError(errorMessage, result.issues);
|
|
260
255
|
}
|
|
261
|
-
|
|
256
|
+
return result.value;
|
|
257
|
+
}
|
|
258
|
+
return data;
|
|
262
259
|
}
|
|
263
260
|
|
|
264
|
-
// src/utils/
|
|
265
|
-
var
|
|
266
|
-
|
|
261
|
+
// src/utils/git-timestamp.ts
|
|
262
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
263
|
+
var import_tinyexec = require("tinyexec");
|
|
264
|
+
var cache = /* @__PURE__ */ new Map();
|
|
265
|
+
async function getGitTimestamp(file) {
|
|
266
|
+
const cached = cache.get(file);
|
|
267
|
+
if (cached) return cached;
|
|
267
268
|
try {
|
|
268
|
-
const
|
|
269
|
-
|
|
269
|
+
const out = await (0, import_tinyexec.x)(
|
|
270
|
+
"git",
|
|
271
|
+
["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
|
|
272
|
+
{
|
|
273
|
+
throwOnError: true
|
|
274
|
+
}
|
|
270
275
|
);
|
|
271
|
-
const
|
|
272
|
-
|
|
276
|
+
const time = new Date(out.stdout);
|
|
277
|
+
cache.set(file, time);
|
|
278
|
+
return time;
|
|
273
279
|
} catch {
|
|
274
|
-
return
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
function createCompatZodPlugin() {
|
|
278
|
-
return {
|
|
279
|
-
name: "replace-zod-import",
|
|
280
|
-
async setup(build) {
|
|
281
|
-
const usingZod3 = await isZod3();
|
|
282
|
-
if (!usingZod3) return;
|
|
283
|
-
console.warn(
|
|
284
|
-
"[Fumadocs MDX] Noticed Zod v3 in your node_modules, we recommend upgrading to Zod v4 for better compatibility."
|
|
285
|
-
);
|
|
286
|
-
build.onResolve({ filter: /^fumadocs-mdx\/config$/ }, () => {
|
|
287
|
-
return {
|
|
288
|
-
path: "fumadocs-mdx/config/zod-3",
|
|
289
|
-
external: true
|
|
290
|
-
};
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
async function compileConfig(configPath, outDir) {
|
|
296
|
-
const { build } = await import("esbuild");
|
|
297
|
-
const transformed = await build({
|
|
298
|
-
entryPoints: [{ in: configPath, out: "source.config" }],
|
|
299
|
-
bundle: true,
|
|
300
|
-
outdir: outDir,
|
|
301
|
-
target: "node20",
|
|
302
|
-
write: true,
|
|
303
|
-
platform: "node",
|
|
304
|
-
format: "esm",
|
|
305
|
-
packages: "external",
|
|
306
|
-
plugins: [createCompatZodPlugin()],
|
|
307
|
-
outExtension: {
|
|
308
|
-
".js": ".mjs"
|
|
309
|
-
},
|
|
310
|
-
allowOverwrite: true
|
|
311
|
-
});
|
|
312
|
-
if (transformed.errors.length > 0) {
|
|
313
|
-
throw new Error("failed to compile configuration file");
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async function loadConfig(configPath, outDir, hash, build = false) {
|
|
317
|
-
if (cache && cache.hash === hash) {
|
|
318
|
-
return await cache.config;
|
|
280
|
+
return;
|
|
319
281
|
}
|
|
320
|
-
if (build) await compileConfig(configPath, outDir);
|
|
321
|
-
const url = (0, import_node_url.pathToFileURL)(path.resolve(outDir, "source.config.mjs"));
|
|
322
|
-
const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
|
|
323
|
-
return buildConfig(
|
|
324
|
-
// every call to `loadConfig` will cause the previous cache to be ignored
|
|
325
|
-
loaded
|
|
326
|
-
);
|
|
327
|
-
});
|
|
328
|
-
if (hash) cache = { config, hash };
|
|
329
|
-
return await config;
|
|
330
282
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
283
|
+
|
|
284
|
+
// src/utils/count-lines.ts
|
|
285
|
+
function countLines(s) {
|
|
286
|
+
let num = 0;
|
|
287
|
+
for (const c of s) {
|
|
288
|
+
if (c === "\n") num++;
|
|
335
289
|
}
|
|
336
|
-
|
|
290
|
+
return num;
|
|
337
291
|
}
|
|
338
292
|
|
|
339
293
|
// src/utils/build-mdx.ts
|
|
@@ -341,34 +295,16 @@ var import_mdx = require("@mdx-js/mdx");
|
|
|
341
295
|
|
|
342
296
|
// src/mdx-plugins/remark-include.ts
|
|
343
297
|
var import_unified = require("unified");
|
|
344
|
-
var
|
|
298
|
+
var import_unist_util_visit = require("unist-util-visit");
|
|
345
299
|
var path2 = __toESM(require("path"), 1);
|
|
346
|
-
var
|
|
347
|
-
|
|
348
|
-
// src/utils/fuma-matter.ts
|
|
349
|
-
var import_js_yaml = require("js-yaml");
|
|
350
|
-
var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
|
|
351
|
-
function fumaMatter(input) {
|
|
352
|
-
const output = { matter: "", data: {}, content: input };
|
|
353
|
-
const match = regex.exec(input);
|
|
354
|
-
if (!match) {
|
|
355
|
-
return output;
|
|
356
|
-
}
|
|
357
|
-
output.matter = match[0];
|
|
358
|
-
output.content = input.slice(match[0].length);
|
|
359
|
-
const loaded = (0, import_js_yaml.load)(match[1]);
|
|
360
|
-
output.data = loaded ?? {};
|
|
361
|
-
return output;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// src/mdx-plugins/remark-include.ts
|
|
300
|
+
var fs = __toESM(require("fs/promises"), 1);
|
|
365
301
|
var import_remark_parse = __toESM(require("remark-parse"), 1);
|
|
366
302
|
var import_remark_mdx = __toESM(require("remark-mdx"), 1);
|
|
367
303
|
var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
|
|
368
304
|
var baseProcessor = (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading);
|
|
369
|
-
function
|
|
305
|
+
function flattenNode(node) {
|
|
370
306
|
if ("children" in node)
|
|
371
|
-
return node.children.map((child) =>
|
|
307
|
+
return node.children.map((child) => flattenNode(child)).join("");
|
|
372
308
|
if ("value" in node) return node.value;
|
|
373
309
|
return "";
|
|
374
310
|
}
|
|
@@ -408,7 +344,7 @@ function remarkInclude() {
|
|
|
408
344
|
async function embedContent(file, heading, params, data) {
|
|
409
345
|
let content;
|
|
410
346
|
try {
|
|
411
|
-
content = (await
|
|
347
|
+
content = (await fs.readFile(file)).toString();
|
|
412
348
|
} catch (e) {
|
|
413
349
|
throw new Error(
|
|
414
350
|
`failed to read file ${file}
|
|
@@ -447,14 +383,14 @@ ${e instanceof Error ? e.message : String(e)}`,
|
|
|
447
383
|
}
|
|
448
384
|
async function update(tree, directory, data) {
|
|
449
385
|
const queue = [];
|
|
450
|
-
(0,
|
|
386
|
+
(0, import_unist_util_visit.visit)(
|
|
451
387
|
tree,
|
|
452
388
|
["mdxJsxFlowElement", "mdxJsxTextElement"],
|
|
453
389
|
(_node, _, parent) => {
|
|
454
390
|
const node = _node;
|
|
455
391
|
if (node.name !== TagName) return;
|
|
456
392
|
const params = {};
|
|
457
|
-
const specifier =
|
|
393
|
+
const specifier = flattenNode(node);
|
|
458
394
|
if (specifier.length === 0) return "skip";
|
|
459
395
|
for (const attr of node.attributes) {
|
|
460
396
|
if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
|
|
@@ -521,140 +457,284 @@ async function buildMDX(cacheKey, source, options) {
|
|
|
521
457
|
});
|
|
522
458
|
}
|
|
523
459
|
|
|
524
|
-
// src/
|
|
525
|
-
var
|
|
526
|
-
var
|
|
527
|
-
var
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
460
|
+
// src/loaders/mdx.ts
|
|
461
|
+
var import_zod = require("zod");
|
|
462
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
463
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
464
|
+
var import_node_crypto = require("crypto");
|
|
465
|
+
var querySchema = import_zod.z.object({
|
|
466
|
+
only: import_zod.z.literal(["frontmatter", "all"]).default("all"),
|
|
467
|
+
collection: import_zod.z.string().optional(),
|
|
468
|
+
hash: import_zod.z.string().describe(
|
|
469
|
+
"the hash of config, used for revalidation on Turbopack/Webpack."
|
|
470
|
+
).optional()
|
|
471
|
+
}).loose();
|
|
472
|
+
var cacheEntry = import_zod.z.object({
|
|
473
|
+
code: import_zod.z.string(),
|
|
474
|
+
map: import_zod.z.any().optional(),
|
|
475
|
+
hash: import_zod.z.string().optional()
|
|
476
|
+
});
|
|
477
|
+
function createMdxLoader(configLoader) {
|
|
478
|
+
return async ({
|
|
479
|
+
source: value,
|
|
480
|
+
development: isDevelopment,
|
|
481
|
+
query,
|
|
482
|
+
compiler,
|
|
483
|
+
filePath
|
|
484
|
+
}) => {
|
|
485
|
+
const matter = fumaMatter(value);
|
|
486
|
+
const parsed = querySchema.parse(query);
|
|
487
|
+
const loaded = await configLoader.getConfig(parsed.hash);
|
|
488
|
+
const cacheDir = isDevelopment ? void 0 : loaded.global.experimentalBuildCache;
|
|
489
|
+
const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
|
|
490
|
+
if (cacheDir) {
|
|
491
|
+
const cached = await import_promises.default.readFile(import_node_path2.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
|
|
492
|
+
if (cached && cached.hash === generateCacheHash(value)) return cached;
|
|
493
|
+
}
|
|
494
|
+
const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
|
|
495
|
+
let schema;
|
|
496
|
+
let mdxOptions;
|
|
497
|
+
switch (collection?.type) {
|
|
498
|
+
case "doc":
|
|
499
|
+
mdxOptions = collection.mdxOptions;
|
|
500
|
+
schema = collection.schema;
|
|
501
|
+
break;
|
|
502
|
+
case "docs":
|
|
503
|
+
mdxOptions = collection.docs.mdxOptions;
|
|
504
|
+
schema = collection.docs.schema;
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
if (schema) {
|
|
508
|
+
matter.data = await validate(
|
|
509
|
+
schema,
|
|
510
|
+
matter.data,
|
|
511
|
+
{
|
|
512
|
+
source: value,
|
|
513
|
+
path: filePath
|
|
514
|
+
},
|
|
515
|
+
`invalid frontmatter in ${filePath}`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
if (parsed.only === "frontmatter") {
|
|
519
|
+
return {
|
|
520
|
+
code: `export const frontmatter = ${JSON.stringify(matter.data)}`,
|
|
521
|
+
map: null
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
const data = {};
|
|
525
|
+
if (loaded.global.lastModifiedTime === "git") {
|
|
526
|
+
data.lastModified = (await getGitTimestamp(filePath))?.getTime();
|
|
527
|
+
}
|
|
528
|
+
const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
|
|
529
|
+
const compiled = await buildMDX(
|
|
530
|
+
`${parsed.hash ?? ""}:${parsed.collection ?? "global"}`,
|
|
531
|
+
"\n".repeat(lineOffset) + matter.content,
|
|
535
532
|
{
|
|
536
|
-
|
|
533
|
+
development: isDevelopment,
|
|
534
|
+
...mdxOptions ?? await loaded.getDefaultMDXOptions(),
|
|
535
|
+
data,
|
|
536
|
+
filePath,
|
|
537
|
+
frontmatter: matter.data,
|
|
538
|
+
_compiler: compiler
|
|
537
539
|
}
|
|
538
540
|
);
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
541
|
+
const out = {
|
|
542
|
+
code: String(compiled.value),
|
|
543
|
+
map: compiled.map
|
|
544
|
+
};
|
|
545
|
+
if (cacheDir) {
|
|
546
|
+
await import_promises.default.mkdir(cacheDir, { recursive: true });
|
|
547
|
+
await import_promises.default.writeFile(
|
|
548
|
+
import_node_path2.default.join(cacheDir, cacheKey),
|
|
549
|
+
JSON.stringify({
|
|
550
|
+
...out,
|
|
551
|
+
hash: generateCacheHash(value)
|
|
552
|
+
})
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
return out;
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function generateCacheHash(input) {
|
|
559
|
+
return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/utils/config.ts
|
|
563
|
+
var fs3 = __toESM(require("fs/promises"), 1);
|
|
564
|
+
var path4 = __toESM(require("path"), 1);
|
|
565
|
+
var import_node_url = require("url");
|
|
566
|
+
|
|
567
|
+
// src/config/build.ts
|
|
568
|
+
function buildConfig(config) {
|
|
569
|
+
const collections = /* @__PURE__ */ new Map();
|
|
570
|
+
let globalConfig = {};
|
|
571
|
+
for (const [k, v] of Object.entries(config)) {
|
|
572
|
+
if (!v) {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (typeof v === "object" && "type" in v) {
|
|
576
|
+
if (v.type === "docs") {
|
|
577
|
+
collections.set(k, v);
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
if (v.type === "doc" || v.type === "meta") {
|
|
581
|
+
collections.set(k, v);
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (k === "default" && v) {
|
|
586
|
+
globalConfig = v;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
throw new Error(
|
|
590
|
+
`Unknown export "${k}", you can only export collections from source configuration file.`
|
|
591
|
+
);
|
|
544
592
|
}
|
|
593
|
+
const mdxOptionsCache = /* @__PURE__ */ new Map();
|
|
594
|
+
return {
|
|
595
|
+
global: globalConfig,
|
|
596
|
+
collections,
|
|
597
|
+
async getDefaultMDXOptions(mode = "default") {
|
|
598
|
+
const cached = mdxOptionsCache.get(mode);
|
|
599
|
+
if (cached) return cached;
|
|
600
|
+
const input = this.global.mdxOptions;
|
|
601
|
+
async function uncached() {
|
|
602
|
+
const options = typeof input === "function" ? await input() : input;
|
|
603
|
+
const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
|
|
604
|
+
if (options?.preset === "minimal") return options;
|
|
605
|
+
return getDefaultMDXOptions2({
|
|
606
|
+
...options,
|
|
607
|
+
_withoutBundler: mode === "remote"
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
const result = uncached();
|
|
611
|
+
mdxOptionsCache.set(mode, result);
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
545
615
|
}
|
|
546
616
|
|
|
547
|
-
// src/utils/
|
|
548
|
-
var
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
|
|
617
|
+
// src/utils/config.ts
|
|
618
|
+
var cache3 = null;
|
|
619
|
+
async function isZod3() {
|
|
620
|
+
try {
|
|
621
|
+
const content = JSON.parse(
|
|
622
|
+
(await fs3.readFile("node_modules/zod/package.json")).toString()
|
|
554
623
|
);
|
|
555
|
-
|
|
556
|
-
|
|
624
|
+
const version = content.version;
|
|
625
|
+
return typeof version === "string" && version.startsWith("3.");
|
|
626
|
+
} catch {
|
|
627
|
+
return false;
|
|
557
628
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
629
|
+
}
|
|
630
|
+
function createCompatZodPlugin() {
|
|
631
|
+
return {
|
|
632
|
+
name: "replace-zod-import",
|
|
633
|
+
async setup(build) {
|
|
634
|
+
const usingZod3 = await isZod3();
|
|
635
|
+
if (!usingZod3) return;
|
|
636
|
+
console.warn(
|
|
637
|
+
"[Fumadocs MDX] Noticed Zod v3 in your node_modules, we recommend upgrading to Zod v4 for better compatibility."
|
|
638
|
+
);
|
|
639
|
+
build.onResolve({ filter: /^fumadocs-mdx\/config$/ }, () => {
|
|
640
|
+
return {
|
|
641
|
+
path: "fumadocs-mdx/config/zod-3",
|
|
642
|
+
external: true
|
|
643
|
+
};
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
async function compileConfig(configPath, outDir) {
|
|
649
|
+
const { build } = await import("esbuild");
|
|
650
|
+
const transformed = await build({
|
|
651
|
+
entryPoints: [{ in: configPath, out: "source.config" }],
|
|
652
|
+
bundle: true,
|
|
653
|
+
outdir: outDir,
|
|
654
|
+
target: "node20",
|
|
655
|
+
write: true,
|
|
656
|
+
platform: "node",
|
|
657
|
+
format: "esm",
|
|
658
|
+
packages: "external",
|
|
659
|
+
plugins: [createCompatZodPlugin()],
|
|
660
|
+
outExtension: {
|
|
661
|
+
".js": ".mjs"
|
|
662
|
+
},
|
|
663
|
+
allowOverwrite: true
|
|
664
|
+
});
|
|
665
|
+
if (transformed.errors.length > 0) {
|
|
666
|
+
throw new Error("failed to compile configuration file");
|
|
567
667
|
}
|
|
568
|
-
}
|
|
569
|
-
async function
|
|
570
|
-
if (
|
|
571
|
-
|
|
668
|
+
}
|
|
669
|
+
async function loadConfig(configPath, outDir, hash, build = false) {
|
|
670
|
+
if (cache3 && cache3.hash === hash) {
|
|
671
|
+
return await cache3.config;
|
|
572
672
|
}
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
|
|
673
|
+
if (build) await compileConfig(configPath, outDir);
|
|
674
|
+
const url = (0, import_node_url.pathToFileURL)(path4.resolve(outDir, "source.config.mjs"));
|
|
675
|
+
const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
|
|
676
|
+
return buildConfig(
|
|
677
|
+
// every call to `loadConfig` will cause the previous cache to be ignored
|
|
678
|
+
loaded
|
|
576
679
|
);
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
680
|
+
});
|
|
681
|
+
if (hash) cache3 = { config, hash };
|
|
682
|
+
return await config;
|
|
683
|
+
}
|
|
684
|
+
async function getConfigHash(configPath) {
|
|
685
|
+
const stats = await fs3.stat(configPath).catch(() => void 0);
|
|
686
|
+
if (stats) {
|
|
687
|
+
return stats.mtime.getTime().toString();
|
|
581
688
|
}
|
|
582
|
-
|
|
689
|
+
throw new Error("Cannot find config file");
|
|
583
690
|
}
|
|
584
691
|
|
|
585
|
-
// src/
|
|
586
|
-
function
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
692
|
+
// src/loaders/config-loader.ts
|
|
693
|
+
function dynamicConfig(configPath, outDir) {
|
|
694
|
+
return {
|
|
695
|
+
async getConfig(hash) {
|
|
696
|
+
return loadConfig(
|
|
697
|
+
configPath,
|
|
698
|
+
outDir,
|
|
699
|
+
hash ?? await getConfigHash(configPath)
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/loaders/adapter.ts
|
|
706
|
+
var import_node_url2 = require("url");
|
|
707
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
708
|
+
var import_node_querystring = require("querystring");
|
|
709
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
710
|
+
function toWebpack(loader2) {
|
|
711
|
+
return async function(source, callback) {
|
|
712
|
+
try {
|
|
713
|
+
const result = await loader2({
|
|
714
|
+
filePath: this.resourcePath,
|
|
715
|
+
query: (0, import_node_querystring.parse)(this.resourceQuery),
|
|
716
|
+
source,
|
|
717
|
+
development: this.mode === "development",
|
|
718
|
+
compiler: this
|
|
719
|
+
});
|
|
720
|
+
callback(void 0, result.code, result.map);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
if (error instanceof ValidationError) {
|
|
723
|
+
return callback(new Error(error.toStringFormatted()));
|
|
724
|
+
}
|
|
725
|
+
if (!(error instanceof Error)) throw error;
|
|
726
|
+
const fpath = import_node_path3.default.relative(this.context, this.resourcePath);
|
|
727
|
+
error.message = `${fpath}:${error.name}: ${error.message}`;
|
|
728
|
+
callback(error);
|
|
729
|
+
}
|
|
730
|
+
};
|
|
592
731
|
}
|
|
593
732
|
|
|
594
733
|
// src/loader-mdx.ts
|
|
734
|
+
var instance;
|
|
595
735
|
async function loader(source, callback) {
|
|
596
736
|
this.cacheable(true);
|
|
597
|
-
const context = this.context;
|
|
598
|
-
const filePath = this.resourcePath;
|
|
599
737
|
const { configPath, outDir } = this.getOptions();
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
hash: configHash = await getConfigHash(configPath),
|
|
603
|
-
collection: collectionId
|
|
604
|
-
} = (0, import_node_querystring.parse)(this.resourceQuery.slice(1));
|
|
605
|
-
const config = await loadConfig(configPath, outDir, configHash);
|
|
606
|
-
let collection = collectionId !== void 0 ? config.collections.get(collectionId) : void 0;
|
|
607
|
-
if (collection && collection.type === "docs") collection = collection.docs;
|
|
608
|
-
if (collection && collection.type !== "doc") {
|
|
609
|
-
collection = void 0;
|
|
610
|
-
}
|
|
611
|
-
let frontmatter = matter.data;
|
|
612
|
-
const mdxOptions = collection?.mdxOptions ?? await config.getDefaultMDXOptions();
|
|
613
|
-
if (collection?.schema) {
|
|
614
|
-
try {
|
|
615
|
-
frontmatter = await validate(
|
|
616
|
-
collection.schema,
|
|
617
|
-
frontmatter,
|
|
618
|
-
{
|
|
619
|
-
source,
|
|
620
|
-
path: filePath
|
|
621
|
-
},
|
|
622
|
-
`invalid frontmatter in ${filePath}`
|
|
623
|
-
);
|
|
624
|
-
} catch (e) {
|
|
625
|
-
if (e instanceof ValidationError) {
|
|
626
|
-
return callback(new Error(e.toStringFormatted()));
|
|
627
|
-
}
|
|
628
|
-
return callback(e);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
let timestamp;
|
|
632
|
-
if (config.global?.lastModifiedTime === "git") {
|
|
633
|
-
timestamp = (await getGitTimestamp(filePath))?.getTime();
|
|
634
|
-
}
|
|
635
|
-
try {
|
|
636
|
-
const lineOffset = "\n".repeat(
|
|
637
|
-
this.mode === "development" ? countLines(matter.matter) : 0
|
|
638
|
-
);
|
|
639
|
-
const file = await buildMDX(
|
|
640
|
-
`${configHash}:${collectionId ?? "global"}`,
|
|
641
|
-
lineOffset + matter.content,
|
|
642
|
-
{
|
|
643
|
-
development: this.mode === "development",
|
|
644
|
-
...mdxOptions,
|
|
645
|
-
filePath,
|
|
646
|
-
frontmatter,
|
|
647
|
-
data: {
|
|
648
|
-
lastModified: timestamp
|
|
649
|
-
},
|
|
650
|
-
_compiler: this
|
|
651
|
-
}
|
|
652
|
-
);
|
|
653
|
-
callback(void 0, String(file.value), file.map ?? void 0);
|
|
654
|
-
} catch (error) {
|
|
655
|
-
if (!(error instanceof Error)) throw error;
|
|
656
|
-
const fpath = path4.relative(context, filePath);
|
|
657
|
-
error.message = `${fpath}:${error.name}: ${error.message}`;
|
|
658
|
-
callback(error);
|
|
659
|
-
}
|
|
738
|
+
instance ??= toWebpack(createMdxLoader(dynamicConfig(configPath, outDir)));
|
|
739
|
+
await instance.call(this, source, callback);
|
|
660
740
|
}
|