fumadocs-mdx 12.0.3 → 13.0.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.
Files changed (80) hide show
  1. package/dist/bin.cjs +1033 -308
  2. package/dist/bin.js +4 -4
  3. package/dist/build-mdx-BHG-_uxo.d.cts +53 -0
  4. package/dist/build-mdx-CzrQDBRZ.d.ts +53 -0
  5. package/dist/bun/index.cjs +92 -28
  6. package/dist/bun/index.js +6 -7
  7. package/dist/{chunk-QAUWMR5D.js → chunk-3J3WL7WN.js} +23 -5
  8. package/dist/chunk-4MAYA5QX.js +44 -0
  9. package/dist/{chunk-RMDXSZYE.js → chunk-CEA6MYJU.js} +13 -8
  10. package/dist/{chunk-IQAEAI4P.js → chunk-HI62EXSB.js} +63 -2
  11. package/dist/{chunk-46UPKP5R.js → chunk-II3H5ZVZ.js} +5 -5
  12. package/dist/{chunk-LGYVNESJ.js → chunk-JVZFH6ND.js} +6 -22
  13. package/dist/{chunk-LMG6UWCL.js → chunk-K5ZLPEIQ.js} +56 -16
  14. package/dist/{chunk-OMAMTKDE.js → chunk-KILFIBVW.js} +3 -12
  15. package/dist/chunk-NVRDCY6Z.js +30 -0
  16. package/dist/{chunk-VXEBLM4X.js → chunk-XV5Z4BFL.js} +1 -1
  17. package/dist/config/index.cjs +56 -16
  18. package/dist/config/index.d.cts +2 -1
  19. package/dist/config/index.d.ts +2 -1
  20. package/dist/config/index.js +1 -1
  21. package/dist/{define-DJbJduHy.d.ts → define-BCNh3n4O.d.cts} +40 -16
  22. package/dist/{define-DJbJduHy.d.cts → define-bck_EB4t.d.ts} +40 -16
  23. package/dist/index.cjs +0 -109
  24. package/dist/index.d.cts +73 -12
  25. package/dist/index.d.ts +73 -12
  26. package/dist/index.js +0 -11
  27. package/dist/{load-UUXLUBHL.js → load-MNG3CLET.js} +1 -3
  28. package/dist/loader-mdx.cjs +153 -60
  29. package/dist/loader-mdx.d.cts +1 -0
  30. package/dist/loader-mdx.d.ts +1 -0
  31. package/dist/loader-mdx.js +23 -9
  32. package/dist/next/index.cjs +213 -181
  33. package/dist/next/index.d.cts +2 -11
  34. package/dist/next/index.d.ts +2 -11
  35. package/dist/next/index.js +145 -117
  36. package/dist/node/loader.cjs +128 -70
  37. package/dist/node/loader.js +14 -9
  38. package/dist/plugins/index.cjs +78 -0
  39. package/dist/plugins/index.d.cts +7 -0
  40. package/dist/plugins/index.d.ts +7 -0
  41. package/dist/plugins/index.js +6 -0
  42. package/dist/plugins/json-schema.cjs +61 -0
  43. package/dist/plugins/json-schema.d.cts +16 -0
  44. package/dist/plugins/json-schema.d.ts +16 -0
  45. package/dist/plugins/json-schema.js +40 -0
  46. package/dist/remark-postprocess-K233ZVBK.d.cts +22 -0
  47. package/dist/remark-postprocess-K233ZVBK.d.ts +22 -0
  48. package/dist/runtime/next/async.cjs +108 -70
  49. package/dist/runtime/next/async.d.cts +9 -6
  50. package/dist/runtime/next/async.d.ts +9 -6
  51. package/dist/runtime/next/async.js +9 -19
  52. package/dist/runtime/next/index.cjs +25 -14
  53. package/dist/runtime/next/index.d.cts +11 -8
  54. package/dist/runtime/next/index.d.ts +11 -8
  55. package/dist/runtime/next/index.js +2 -2
  56. package/dist/runtime/vite/browser.cjs +7 -3
  57. package/dist/runtime/vite/browser.d.cts +56 -7
  58. package/dist/runtime/vite/browser.d.ts +56 -7
  59. package/dist/runtime/vite/browser.js +2 -1
  60. package/dist/runtime/vite/server.cjs +40 -34
  61. package/dist/runtime/vite/server.d.cts +13 -10
  62. package/dist/runtime/vite/server.d.ts +13 -10
  63. package/dist/runtime/vite/server.js +8 -23
  64. package/dist/{types-TeHjsmja.d.ts → types-1cCFEzWt.d.ts} +3 -10
  65. package/dist/{types-BRx1QsIJ.d.cts → types-D5NhXTJY.d.cts} +3 -10
  66. package/dist/vite/index.cjs +386 -224
  67. package/dist/vite/index.d.cts +23 -10
  68. package/dist/vite/index.d.ts +23 -10
  69. package/dist/vite/index.js +211 -37
  70. package/dist/{watcher-HGOH3APP.js → watcher-WXJDWRZY.js} +1 -1
  71. package/package.json +28 -15
  72. package/dist/browser-BupUnhpC.d.ts +0 -98
  73. package/dist/browser-R0x9IPaQ.d.cts +0 -98
  74. package/dist/chunk-ADR6R7HM.js +0 -29
  75. package/dist/chunk-XMFLD5J6.js +0 -30
  76. package/dist/chunk-ZLCSVXCD.js +0 -10
  77. package/dist/chunk-ZX7TM4AR.js +0 -127
  78. package/dist/postinstall-SCSXM4IM.js +0 -10
  79. package/dist/shared-CfiiRctw.d.ts +0 -70
  80. package/dist/shared-fFqiuWJC.d.cts +0 -70
@@ -173,6 +173,10 @@ var init_build = __esm({
173
173
  });
174
174
 
175
175
  // src/loaders/config/load.ts
176
+ var load_exports = {};
177
+ __export(load_exports, {
178
+ loadConfig: () => loadConfig
179
+ });
176
180
  async function compileConfig(configPath, outDir) {
177
181
  const { build } = await import("esbuild");
178
182
  const transformed = await build({
@@ -193,30 +197,22 @@ async function compileConfig(configPath, outDir) {
193
197
  throw new Error("failed to compile configuration file");
194
198
  }
195
199
  }
196
- async function loadConfig(configPath, outDir, hash, build = false) {
197
- if (cache3 && cache3.hash === hash) {
198
- return await cache3.config;
199
- }
200
+ async function loadConfig(configPath, outDir, build = false) {
200
201
  if (build) await compileConfig(configPath, outDir);
201
- const url = (0, import_node_url2.pathToFileURL)(path7.resolve(outDir, "source.config.mjs"));
202
- const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
203
- return buildConfig(
204
- // every call to `loadConfig` will cause the previous cache to be ignored
205
- loaded
206
- );
207
- });
208
- if (hash) cache3 = { config, hash };
202
+ const url = (0, import_node_url3.pathToFileURL)(path10.resolve(outDir, "source.config.mjs"));
203
+ url.searchParams.set("hash", Date.now().toString());
204
+ const config = import(url.href).then(
205
+ (loaded) => buildConfig(loaded)
206
+ );
209
207
  return await config;
210
208
  }
211
- var fs4, path7, import_node_url2, cache3;
209
+ var path10, import_node_url3;
212
210
  var init_load = __esm({
213
211
  "src/loaders/config/load.ts"() {
214
212
  "use strict";
215
- fs4 = __toESM(require("fs/promises"), 1);
216
- path7 = __toESM(require("path"), 1);
217
- import_node_url2 = require("url");
213
+ path10 = __toESM(require("path"), 1);
214
+ import_node_url3 = require("url");
218
215
  init_build();
219
- cache3 = null;
220
216
  }
221
217
  });
222
218
 
@@ -270,142 +266,9 @@ async function validate(schema, data, context, errorMessage) {
270
266
  }
271
267
 
272
268
  // src/vite/index.ts
273
- var fs6 = __toESM(require("fs/promises"), 1);
274
- var path9 = __toESM(require("path"), 1);
269
+ var path11 = __toESM(require("path"), 1);
275
270
  var import_js_yaml2 = require("js-yaml");
276
271
 
277
- // src/utils/import-formatter.ts
278
- var import_node_path = __toESM(require("path"), 1);
279
- function toImportPath(file, config) {
280
- const ext = import_node_path.default.extname(file);
281
- let filename;
282
- if (ext === ".ts" && config.jsExtension) {
283
- filename = file.substring(0, file.length - ext.length) + ".js";
284
- } else if (ext === ".ts") {
285
- filename = file.substring(0, file.length - ext.length);
286
- } else {
287
- filename = file;
288
- }
289
- let importPath;
290
- if ("relativeTo" in config) {
291
- importPath = import_node_path.default.relative(config.relativeTo, filename);
292
- if (!import_node_path.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
293
- importPath = `./${importPath}`;
294
- }
295
- } else {
296
- importPath = import_node_path.default.resolve(filename);
297
- }
298
- return importPath.replaceAll(import_node_path.default.sep, "/");
299
- }
300
- function ident(code, tab = 1) {
301
- return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
302
- }
303
-
304
- // src/vite/generate-glob.ts
305
- function generateGlob(name, patterns, globOptions) {
306
- const options = {
307
- ...globOptions,
308
- query: {
309
- ...globOptions?.query,
310
- collection: name
311
- }
312
- };
313
- return `import.meta.glob(${JSON.stringify(mapGlobPatterns(patterns))}, ${JSON.stringify(options, null, 2)})`;
314
- }
315
- function mapGlobPatterns(patterns) {
316
- return patterns.map(enforceRelative);
317
- }
318
- function enforceRelative(file) {
319
- if (file.startsWith("./")) return file;
320
- if (file.startsWith("/")) return `.${file}`;
321
- return `./${file}`;
322
- }
323
- function getGlobBase(collection) {
324
- let dir = collection.dir;
325
- if (Array.isArray(dir)) {
326
- if (dir.length !== 1)
327
- throw new Error(
328
- `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
329
- );
330
- dir = dir[0];
331
- }
332
- return enforceRelative(dir);
333
- }
334
-
335
- // src/utils/collections.ts
336
- function getSupportedFormats(collection) {
337
- return {
338
- doc: ["mdx", "md"],
339
- meta: ["json", "yaml"]
340
- }[collection.type];
341
- }
342
- function getGlobPatterns(collection) {
343
- if (collection.files) return collection.files;
344
- return [`**/*.{${getSupportedFormats(collection).join(",")}}`];
345
- }
346
-
347
- // src/vite/generate.ts
348
- function docs(name, collection) {
349
- const obj = [
350
- ident(`doc: ${doc(name, collection.docs)}`),
351
- ident(`meta: ${meta(name, collection.meta)}`)
352
- ].join(",\n");
353
- return `{
354
- ${obj}
355
- }`;
356
- }
357
- function doc(name, collection) {
358
- const patterns = getGlobPatterns(collection);
359
- const base = getGlobBase(collection);
360
- const docGlob = generateGlob(name, patterns, {
361
- base
362
- });
363
- if (collection.async) {
364
- const headBlob = generateGlob(name, patterns, {
365
- query: {
366
- only: "frontmatter"
367
- },
368
- import: "frontmatter",
369
- base
370
- });
371
- return `create.docLazy("${name}", "${base}", ${headBlob}, ${docGlob})`;
372
- }
373
- return `create.doc("${name}", "${base}", ${docGlob})`;
374
- }
375
- function meta(name, collection) {
376
- const patterns = getGlobPatterns(collection);
377
- const base = getGlobBase(collection);
378
- return `create.meta("${name}", "${base}", ${generateGlob(name, patterns, {
379
- import: "default",
380
- base
381
- })})`;
382
- }
383
- function entry(configPath, config, outDir, jsExtension) {
384
- const lines = [
385
- '/// <reference types="vite/client" />',
386
- `import { fromConfig } from 'fumadocs-mdx/runtime/vite';`,
387
- `import type * as Config from '${toImportPath(configPath, {
388
- relativeTo: outDir,
389
- jsExtension
390
- })}';`,
391
- "",
392
- `export const create = fromConfig<typeof Config>();`
393
- ];
394
- for (const [name, collection] of config.collections.entries()) {
395
- let body;
396
- if (collection.type === "docs") {
397
- body = docs(name, collection);
398
- } else if (collection.type === "meta") {
399
- body = meta(name, collection);
400
- } else {
401
- body = doc(name, collection);
402
- }
403
- lines.push("");
404
- lines.push(`export const ${name} = ${body};`);
405
- }
406
- return lines.join("\n");
407
- }
408
-
409
272
  // src/utils/fuma-matter.ts
410
273
  var import_js_yaml = require("js-yaml");
411
274
  var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
@@ -423,7 +286,7 @@ function fumaMatter(input) {
423
286
  }
424
287
 
425
288
  // src/utils/git-timestamp.ts
426
- var import_node_path2 = __toESM(require("path"), 1);
289
+ var import_node_path = __toESM(require("path"), 1);
427
290
  var import_tinyexec = require("tinyexec");
428
291
  var cache = /* @__PURE__ */ new Map();
429
292
  async function getGitTimestamp(file) {
@@ -432,7 +295,7 @@ async function getGitTimestamp(file) {
432
295
  try {
433
296
  const out = await (0, import_tinyexec.x)(
434
297
  "git",
435
- ["log", "-1", '--pretty="%ai"', import_node_path2.default.relative(process.cwd(), file)],
298
+ ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
436
299
  {
437
300
  throwOnError: true
438
301
  }
@@ -450,12 +313,56 @@ var import_mdx = require("@mdx-js/mdx");
450
313
 
451
314
  // src/loaders/mdx/remark-include.ts
452
315
  var import_unified = require("unified");
453
- var import_unist_util_visit = require("unist-util-visit");
454
- var path3 = __toESM(require("path"), 1);
316
+ var import_unist_util_visit2 = require("unist-util-visit");
317
+ var path2 = __toESM(require("path"), 1);
455
318
  var fs = __toESM(require("fs/promises"), 1);
456
- var import_remark_parse = __toESM(require("remark-parse"), 1);
457
- var import_remark_mdx = __toESM(require("remark-mdx"), 1);
458
319
  var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
320
+
321
+ // src/loaders/mdx/remark-unravel.ts
322
+ var import_unist_util_visit = require("unist-util-visit");
323
+ function remarkMarkAndUnravel() {
324
+ return (tree) => {
325
+ (0, import_unist_util_visit.visit)(tree, function(node, index, parent) {
326
+ let offset = -1;
327
+ let all = true;
328
+ let oneOrMore = false;
329
+ if (parent && typeof index === "number" && node.type === "paragraph") {
330
+ const children = node.children;
331
+ while (++offset < children.length) {
332
+ const child = children[offset];
333
+ if (child.type === "mdxJsxTextElement" || child.type === "mdxTextExpression") {
334
+ oneOrMore = true;
335
+ } else if (child.type === "text" && child.value.trim().length === 0) {
336
+ } else {
337
+ all = false;
338
+ break;
339
+ }
340
+ }
341
+ if (all && oneOrMore) {
342
+ offset = -1;
343
+ const newChildren = [];
344
+ while (++offset < children.length) {
345
+ const child = children[offset];
346
+ if (child.type === "mdxJsxTextElement") {
347
+ child.type = "mdxJsxFlowElement";
348
+ }
349
+ if (child.type === "mdxTextExpression") {
350
+ child.type = "mdxFlowExpression";
351
+ }
352
+ if (child.type === "text" && /^[\t\r\n ]+$/.test(String(child.value))) {
353
+ } else {
354
+ newChildren.push(child);
355
+ }
356
+ }
357
+ parent.children.splice(index, 1, ...newChildren);
358
+ return index;
359
+ }
360
+ }
361
+ });
362
+ };
363
+ }
364
+
365
+ // src/loaders/mdx/remark-include.ts
459
366
  var ElementLikeTypes = [
460
367
  "mdxJsxFlowElement",
461
368
  "mdxJsxTextElement",
@@ -495,7 +402,7 @@ function parseSpecifier(specifier) {
495
402
  function extractSection(root, section) {
496
403
  let nodes;
497
404
  let capturingHeadingContent = false;
498
- (0, import_unist_util_visit.visit)(root, (node) => {
405
+ (0, import_unist_util_visit2.visit)(root, (node) => {
499
406
  if (node.type === "heading") {
500
407
  if (capturingHeadingContent) {
501
408
  return false;
@@ -527,7 +434,7 @@ function extractSection(root, section) {
527
434
  }
528
435
  function remarkInclude() {
529
436
  const TagName = "include";
530
- async function embedContent(file, heading, params, data) {
437
+ const embedContent = async (file, heading, params, data) => {
531
438
  let content;
532
439
  try {
533
440
  content = (await fs.readFile(file)).toString();
@@ -538,7 +445,7 @@ ${e instanceof Error ? e.message : String(e)}`,
538
445
  { cause: e }
539
446
  );
540
447
  }
541
- const ext = path3.extname(file);
448
+ const ext = path2.extname(file);
542
449
  data._compiler?.addDependency(file);
543
450
  if (params.lang || ext !== ".md" && ext !== ".mdx") {
544
451
  const lang = params.lang ?? ext.slice(1);
@@ -550,18 +457,17 @@ ${e instanceof Error ? e.message : String(e)}`,
550
457
  data: {}
551
458
  };
552
459
  }
553
- const parser = (data._getProcessor ?? getDefaultProcessor)(
554
- ext === ".mdx" ? "mdx" : "md"
555
- );
460
+ const parser = data._getProcessor ? data._getProcessor(ext === ".mdx" ? "mdx" : "md") : this;
556
461
  const parsed = fumaMatter(content);
557
462
  let mdast = parser.parse({
558
463
  path: file,
559
464
  value: parsed.content,
560
465
  data: { frontmatter: parsed.data }
561
466
  });
467
+ const baseProcessor = (0, import_unified.unified)().use(remarkMarkAndUnravel);
562
468
  if (heading) {
563
469
  const extracted = extractSection(
564
- await (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading).run(mdast),
470
+ await baseProcessor.use(import_mdx_plugins.remarkHeading).run(mdast),
565
471
  heading
566
472
  );
567
473
  if (!extracted)
@@ -569,20 +475,22 @@ ${e instanceof Error ? e.message : String(e)}`,
569
475
  `Cannot find section ${heading} in ${file}, make sure you have encapsulated the section in a <section id="${heading}"> tag, or a :::section directive with remark-directive configured.`
570
476
  );
571
477
  mdast = extracted;
478
+ } else {
479
+ mdast = await baseProcessor.run(mdast);
572
480
  }
573
- await update(mdast, path3.dirname(file), data);
481
+ await update(mdast, path2.dirname(file), data);
574
482
  return mdast;
575
- }
483
+ };
576
484
  async function update(tree, directory, data) {
577
485
  const queue = [];
578
- (0, import_unist_util_visit.visit)(tree, ElementLikeTypes, (_node, _, parent) => {
486
+ (0, import_unist_util_visit2.visit)(tree, ElementLikeTypes, (_node, _, parent) => {
579
487
  const node = _node;
580
488
  if (node.name !== TagName) return;
581
489
  const specifier = flattenNode(node);
582
490
  if (specifier.length === 0) return "skip";
583
491
  const attributes = parseElementAttributes(node);
584
492
  const { file: relativePath, section } = parseSpecifier(specifier);
585
- const file = path3.resolve(
493
+ const file = path2.resolve(
586
494
  "cwd" in attributes ? process.cwd() : directory,
587
495
  relativePath
588
496
  );
@@ -599,27 +507,31 @@ ${e instanceof Error ? e.message : String(e)}`,
599
507
  await Promise.all(queue);
600
508
  }
601
509
  return async (tree, file) => {
602
- await update(tree, path3.dirname(file.path), file.data);
510
+ await update(tree, path2.dirname(file.path), file.data);
603
511
  };
604
512
  }
605
- function getDefaultProcessor(format) {
606
- const mdProcessor = (0, import_unified.unified)().use(import_remark_parse.default);
607
- if (format === "md") return mdProcessor;
608
- return mdProcessor.use(import_remark_mdx.default);
609
- }
610
513
 
611
514
  // src/loaders/mdx/remark-postprocess.ts
612
- var import_unist_util_visit2 = require("unist-util-visit");
515
+ var import_unist_util_visit3 = require("unist-util-visit");
613
516
  var import_mdast_util_to_markdown = require("mdast-util-to-markdown");
614
517
  var import_estree_util_value_to_estree = require("estree-util-value-to-estree");
518
+ var import_unist_util_remove_position = require("unist-util-remove-position");
519
+ var import_remark_mdx = __toESM(require("remark-mdx"), 1);
615
520
  function remarkPostprocess({
521
+ _format,
616
522
  includeProcessedMarkdown = false,
523
+ includeMDAST = false,
617
524
  valueToExport = []
618
- } = {}) {
525
+ }) {
526
+ let _stringifyProcessor;
527
+ const getStringifyProcessor = () => {
528
+ if (_format === "mdx") return this;
529
+ return _stringifyProcessor ??= this().use(import_remark_mdx.default).freeze();
530
+ };
619
531
  return (tree, file) => {
620
532
  let title;
621
533
  const urls = [];
622
- (0, import_unist_util_visit2.visit)(tree, ["heading", "link"], (node) => {
534
+ (0, import_unist_util_visit3.visit)(tree, ["heading", "link"], (node) => {
623
535
  if (node.type === "heading" && node.depth === 1) {
624
536
  title = flattenNode2(node);
625
537
  }
@@ -635,12 +547,19 @@ function remarkPostprocess({
635
547
  }
636
548
  file.data.extractedReferences = urls;
637
549
  if (includeProcessedMarkdown) {
550
+ const processor = getStringifyProcessor();
638
551
  file.data._markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
639
- ...this.data("settings"),
552
+ ...processor.data("settings"),
640
553
  // from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
641
- extensions: this.data("toMarkdownExtensions") || []
554
+ extensions: processor.data("toMarkdownExtensions") || []
642
555
  });
643
556
  }
557
+ if (includeMDAST) {
558
+ const options = includeMDAST === true ? {} : includeMDAST;
559
+ file.data._mdast = JSON.stringify(
560
+ options.removePosition ? (0, import_unist_util_remove_position.removePosition)(structuredClone(tree)) : tree
561
+ );
562
+ }
644
563
  for (const { name, value } of file.data["mdx-export"] ?? []) {
645
564
  tree.children.unshift(getMdastExport(name, value));
646
565
  }
@@ -708,6 +627,7 @@ async function buildMDX(cacheKey, source, options) {
708
627
  [
709
628
  remarkPostprocess,
710
629
  {
630
+ _format: format,
711
631
  ...options.postprocess,
712
632
  valueToExport: [
713
633
  ...options.postprocess?.valueToExport ?? [],
@@ -715,7 +635,8 @@ async function buildMDX(cacheKey, source, options) {
715
635
  "extractedReferences",
716
636
  "frontmatter",
717
637
  "lastModified",
718
- "_markdown"
638
+ "_markdown",
639
+ "_mdast"
719
640
  ]
720
641
  }
721
642
  ]
@@ -743,20 +664,25 @@ async function buildMDX(cacheKey, source, options) {
743
664
  // src/loaders/mdx/index.ts
744
665
  var import_zod = require("zod");
745
666
  var import_promises = __toESM(require("fs/promises"), 1);
746
- var import_node_path3 = __toESM(require("path"), 1);
667
+ var import_node_path2 = __toESM(require("path"), 1);
747
668
  var import_node_crypto = require("crypto");
748
669
  var querySchema = import_zod.z.object({
749
670
  only: import_zod.z.literal(["frontmatter", "all"]).default("all"),
750
- collection: import_zod.z.string().optional(),
751
- hash: import_zod.z.string().describe(
752
- "the hash of config, used for revalidation on Turbopack/Webpack."
753
- ).optional()
671
+ collection: import_zod.z.string().optional()
754
672
  }).loose();
755
673
  var cacheEntry = import_zod.z.object({
756
674
  code: import_zod.z.string(),
757
675
  map: import_zod.z.any().optional(),
758
676
  hash: import_zod.z.string().optional()
759
677
  });
678
+ var hashes = /* @__PURE__ */ new WeakMap();
679
+ function getConfigHash(config) {
680
+ let hash = hashes.get(config);
681
+ if (hash) return hash;
682
+ hash = Date.now().toString();
683
+ hashes.set(config, hash);
684
+ return hash;
685
+ }
760
686
  function createMdxLoader(configLoader) {
761
687
  return async ({
762
688
  source: value,
@@ -767,11 +693,11 @@ function createMdxLoader(configLoader) {
767
693
  }) => {
768
694
  const matter = fumaMatter(value);
769
695
  const parsed = querySchema.parse(query);
770
- const loaded = await configLoader.getConfig(parsed.hash);
696
+ const loaded = await configLoader.getConfig();
771
697
  const cacheDir = isDevelopment ? void 0 : loaded.global.experimentalBuildCache;
772
698
  const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
773
699
  if (cacheDir) {
774
- const cached = await import_promises.default.readFile(import_node_path3.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
700
+ const cached = await import_promises.default.readFile(import_node_path2.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
775
701
  if (cached && cached.hash === generateCacheHash(value)) return cached;
776
702
  }
777
703
  const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
@@ -807,7 +733,7 @@ function createMdxLoader(configLoader) {
807
733
  }
808
734
  const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
809
735
  const compiled = await buildMDX(
810
- `${parsed.hash ?? ""}:${parsed.collection ?? "global"}`,
736
+ `${getConfigHash(loaded)}:${parsed.collection ?? "global"}`,
811
737
  "\n".repeat(lineOffset) + matter.content,
812
738
  {
813
739
  development: isDevelopment,
@@ -826,7 +752,7 @@ function createMdxLoader(configLoader) {
826
752
  if (cacheDir) {
827
753
  await import_promises.default.mkdir(cacheDir, { recursive: true });
828
754
  await import_promises.default.writeFile(
829
- import_node_path3.default.join(cacheDir, cacheKey),
755
+ import_node_path2.default.join(cacheDir, cacheKey),
830
756
  JSON.stringify({
831
757
  ...out,
832
758
  hash: generateCacheHash(value)
@@ -848,9 +774,10 @@ function countLines(s) {
848
774
  }
849
775
 
850
776
  // src/loaders/config/index.ts
851
- var import_node_path4 = __toESM(require("path"), 1);
777
+ var import_node_path3 = __toESM(require("path"), 1);
778
+ var import_promises2 = __toESM(require("fs/promises"), 1);
852
779
  function findConfigFile() {
853
- return import_node_path4.default.resolve("source.config.ts");
780
+ return import_node_path3.default.resolve("source.config.ts");
854
781
  }
855
782
  function resolvedConfig(loaded) {
856
783
  return {
@@ -862,9 +789,9 @@ function resolvedConfig(loaded) {
862
789
 
863
790
  // src/loaders/adapter.ts
864
791
  var import_node_url = require("url");
865
- var import_promises2 = __toESM(require("fs/promises"), 1);
792
+ var import_promises3 = __toESM(require("fs/promises"), 1);
866
793
  var import_node_querystring = require("querystring");
867
- var import_node_path5 = __toESM(require("path"), 1);
794
+ var import_node_path4 = __toESM(require("path"), 1);
868
795
  function toVite(loader) {
869
796
  return async function(file, query, value) {
870
797
  const result = await loader({
@@ -885,35 +812,243 @@ function toVite(loader) {
885
812
  };
886
813
  }
887
814
 
888
- // src/vite/postinstall.ts
889
- init_load();
890
- var import_promises3 = __toESM(require("fs/promises"), 1);
815
+ // src/utils/import-formatter.ts
816
+ var import_node_path5 = __toESM(require("path"), 1);
817
+ function toImportPath(file, config) {
818
+ const ext = import_node_path5.default.extname(file);
819
+ let filename;
820
+ if (ext === ".ts" && config.jsExtension) {
821
+ filename = file.substring(0, file.length - ext.length) + ".js";
822
+ } else if (ext === ".ts") {
823
+ filename = file.substring(0, file.length - ext.length);
824
+ } else {
825
+ filename = file;
826
+ }
827
+ let importPath;
828
+ if ("relativeTo" in config) {
829
+ importPath = import_node_path5.default.relative(config.relativeTo, filename);
830
+ if (!import_node_path5.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
831
+ importPath = `./${importPath}`;
832
+ }
833
+ } else {
834
+ importPath = import_node_path5.default.resolve(filename);
835
+ }
836
+ return importPath.replaceAll(import_node_path5.default.sep, "/");
837
+ }
838
+ function ident(code, tab = 1) {
839
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
840
+ }
841
+
842
+ // src/utils/collections.ts
843
+ function getSupportedFormats(collection) {
844
+ return {
845
+ doc: ["mdx", "md"],
846
+ meta: ["json", "yaml"]
847
+ }[collection.type];
848
+ }
849
+ function getGlobPatterns(collection) {
850
+ if (collection.files) return collection.files;
851
+ return [`**/*.{${getSupportedFormats(collection).join(",")}}`];
852
+ }
853
+
854
+ // src/utils/glob-import.ts
855
+ var import_tinyglobby = require("tinyglobby");
891
856
  var import_node_path6 = __toESM(require("path"), 1);
892
- async function postInstall(configPath = findConfigFile(), outDir, addJsExtension = false) {
893
- const config = await loadConfig(configPath, "node_modules", void 0, true);
894
- const outFile = "source.generated.ts";
895
- if (outDir) {
896
- await import_promises3.default.mkdir(outDir, { recursive: true });
857
+ var import_node_url2 = require("url");
858
+ function generateGlobImport(patterns, options) {
859
+ let code = "{";
860
+ const result = (0, import_tinyglobby.globSync)(patterns, {
861
+ cwd: options.base
862
+ });
863
+ for (const item of result) {
864
+ const fullPath = import_node_path6.default.join(options.base, item);
865
+ const url = (0, import_node_url2.pathToFileURL)(fullPath);
866
+ for (const [k, v] of Object.entries(options.query ?? {})) {
867
+ url.searchParams.set(k, v);
868
+ }
869
+ let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(url.href)})`;
870
+ if (options.import) {
871
+ line += `.then(mod => mod[${JSON.stringify(options.import)}])`;
872
+ }
873
+ code += `${line}, `;
897
874
  }
898
- await import_promises3.default.writeFile(
899
- outDir ? import_node_path6.default.join(outDir, outFile) : outFile,
900
- entry(configPath, config, outDir ?? process.cwd(), addJsExtension)
901
- );
902
- console.log("[MDX] types generated");
875
+ code += "}";
876
+ return code;
877
+ }
878
+
879
+ // src/plugins/vite.ts
880
+ var import_node_path7 = __toESM(require("path"), 1);
881
+ function vite(options) {
882
+ let config;
883
+ return {
884
+ config(v) {
885
+ config = v;
886
+ },
887
+ emit() {
888
+ console.log("[Fumadocs MDX] Generating index files");
889
+ return [
890
+ {
891
+ path: "index.ts",
892
+ content: indexFile(this.configPath, this.outDir, config, options)
893
+ }
894
+ ];
895
+ }
896
+ };
897
+ }
898
+ function indexFile(configPath, outDir, config, options) {
899
+ const { addJsExtension = false, runtime } = options;
900
+ const lines = [
901
+ '/// <reference types="vite/client" />',
902
+ `import { fromConfig } from 'fumadocs-mdx/runtime/vite';`,
903
+ `import type * as Config from '${toImportPath(configPath, {
904
+ relativeTo: outDir,
905
+ jsExtension: addJsExtension
906
+ })}';`,
907
+ "",
908
+ `export const create = fromConfig<typeof Config>();`
909
+ ];
910
+ function docs(name, collection) {
911
+ const obj = [
912
+ ident(`doc: ${doc(name, collection.docs)}`),
913
+ ident(`meta: ${meta(name, collection.meta)}`)
914
+ ].join(",\n");
915
+ return `{
916
+ ${obj}
917
+ }`;
918
+ }
919
+ function doc(name, collection) {
920
+ const patterns = getGlobPatterns(collection);
921
+ const base = getGlobBase(collection);
922
+ const docGlob = generateGlob(patterns, {
923
+ query: {
924
+ collection: name
925
+ },
926
+ base
927
+ });
928
+ if (collection.async) {
929
+ const headBlob = generateGlob(patterns, {
930
+ query: {
931
+ only: "frontmatter",
932
+ collection: name
933
+ },
934
+ import: "frontmatter",
935
+ base
936
+ });
937
+ return `create.docLazy("${name}", "${base}", ${headBlob}, ${docGlob})`;
938
+ }
939
+ return `create.doc("${name}", "${base}", ${docGlob})`;
940
+ }
941
+ function meta(name, collection) {
942
+ const patterns = getGlobPatterns(collection);
943
+ const base = getGlobBase(collection);
944
+ return `create.meta("${name}", "${base}", ${generateGlob(patterns, {
945
+ import: "default",
946
+ base,
947
+ query: {
948
+ collection: name
949
+ }
950
+ })})`;
951
+ }
952
+ function generateGlob(patterns, options2) {
953
+ patterns = mapGlobPatterns(patterns);
954
+ if (runtime === "node" || runtime === "bun") {
955
+ return generateGlobImport(patterns, options2);
956
+ } else {
957
+ return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(
958
+ {
959
+ ...options2,
960
+ base: import_node_path7.default.relative(outDir, options2.base)
961
+ },
962
+ null,
963
+ 2
964
+ )})`;
965
+ }
966
+ }
967
+ for (const [name, collection] of config.collections.entries()) {
968
+ let body;
969
+ if (collection.type === "docs") {
970
+ body = docs(name, collection);
971
+ } else if (collection.type === "meta") {
972
+ body = meta(name, collection);
973
+ } else {
974
+ body = doc(name, collection);
975
+ }
976
+ lines.push("");
977
+ lines.push(`export const ${name} = ${body};`);
978
+ }
979
+ return lines.join("\n");
980
+ }
981
+ function mapGlobPatterns(patterns) {
982
+ return patterns.map(enforceRelative);
983
+ }
984
+ function enforceRelative(file) {
985
+ if (file.startsWith("./")) return file;
986
+ if (file.startsWith("/")) return `.${file}`;
987
+ return `./${file}`;
988
+ }
989
+ function getGlobBase(collection) {
990
+ let dir = collection.dir;
991
+ if (Array.isArray(dir)) {
992
+ if (dir.length !== 1)
993
+ throw new Error(
994
+ `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
995
+ );
996
+ dir = dir[0];
997
+ }
998
+ return enforceRelative(dir);
999
+ }
1000
+
1001
+ // src/plugins/index.ts
1002
+ var import_node_path8 = __toESM(require("path"), 1);
1003
+ var import_promises4 = __toESM(require("fs/promises"), 1);
1004
+ function createPluginHandler(context, defaultPlugins = []) {
1005
+ const plugins2 = [];
1006
+ async function write(entry) {
1007
+ const file = import_node_path8.default.join(context.outDir, entry.path);
1008
+ await import_promises4.default.mkdir(import_node_path8.default.dirname(file), { recursive: true });
1009
+ await import_promises4.default.writeFile(file, entry.content);
1010
+ }
1011
+ return {
1012
+ async init(config) {
1013
+ if (config.global.plugins) {
1014
+ defaultPlugins.push(...config.global.plugins);
1015
+ }
1016
+ for await (const option of defaultPlugins) {
1017
+ if (!option) continue;
1018
+ if (Array.isArray(option)) plugins2.push(...option);
1019
+ else plugins2.push(option);
1020
+ }
1021
+ for (const plugin of plugins2) {
1022
+ const out = await plugin.config?.call(context, config);
1023
+ if (out) config = out;
1024
+ }
1025
+ return config;
1026
+ },
1027
+ async emit() {
1028
+ const out = await Promise.all(
1029
+ plugins2.map((plugin) => {
1030
+ return plugin.emit?.call(context) ?? [];
1031
+ })
1032
+ );
1033
+ return out.flat();
1034
+ },
1035
+ async emitAndWrite() {
1036
+ const entries = await this.emit();
1037
+ await Promise.all(entries.map(write));
1038
+ }
1039
+ };
903
1040
  }
904
1041
 
905
1042
  // src/vite/index.ts
906
1043
  var FumadocsDeps = ["fumadocs-core", "fumadocs-ui", "fumadocs-openapi"];
907
- function mdx(config, options = {}) {
908
- const {
909
- generateIndexFile = true,
910
- updateViteConfig = true,
911
- configPath = "source.config.ts"
912
- } = options;
913
- const loaded = buildConfig(config);
1044
+ async function mdx(config, pluginOptions = {}) {
1045
+ const options = applyDefaults(pluginOptions);
1046
+ const { updateViteConfig } = options;
1047
+ const pluginHandler = createVitePluginHandler(options);
1048
+ const loaded = await pluginHandler.init(buildConfig(config));
914
1049
  const mdxLoader = toVite(createMdxLoader(resolvedConfig(loaded)));
915
- async function transformMeta(path10, query, value) {
916
- const isJson = path10.endsWith(".json");
1050
+ async function transformMeta(path12, query, value) {
1051
+ const isJson = path12.endsWith(".json");
917
1052
  const parsed = (0, import_node_querystring2.parse)(query);
918
1053
  const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
919
1054
  if (!collection) return null;
@@ -936,8 +1071,8 @@ function mdx(config, options = {}) {
936
1071
  const out = await validate(
937
1072
  schema,
938
1073
  data,
939
- { path: path10, source: value },
940
- `invalid data in ${path10}`
1074
+ { path: path12, source: value },
1075
+ `invalid data in ${path12}`
941
1076
  );
942
1077
  return {
943
1078
  code: isJson ? JSON.stringify(out) : `export default ${JSON.stringify(out)}`,
@@ -961,16 +1096,11 @@ function mdx(config, options = {}) {
961
1096
  });
962
1097
  },
963
1098
  async buildStart() {
964
- if (!generateIndexFile) return;
965
- const { out = "source.generated.ts", addJsExtension } = typeof generateIndexFile === "object" ? generateIndexFile : {};
966
- console.log("[Fumadocs MDX] Generating index files");
967
- const dir = path9.dirname(out);
968
- await fs6.mkdir(dir, { recursive: true });
969
- await fs6.writeFile(out, entry(configPath, loaded, dir, addJsExtension));
1099
+ await pluginHandler.emitAndWrite();
970
1100
  },
971
1101
  async transform(value, id) {
972
1102
  const [file, query = ""] = id.split("?");
973
- const ext = path9.extname(file);
1103
+ const ext = path11.extname(file);
974
1104
  try {
975
1105
  if ([".yaml", ".json"].includes(ext))
976
1106
  return await transformMeta(file, query, value);
@@ -985,6 +1115,38 @@ function mdx(config, options = {}) {
985
1115
  }
986
1116
  };
987
1117
  }
1118
+ async function postInstall(configPath = findConfigFile(), pluginOptions = {}) {
1119
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load(), load_exports));
1120
+ const options = applyDefaults(pluginOptions);
1121
+ const pluginHandler = createVitePluginHandler(options);
1122
+ await pluginHandler.init(await loadConfig2(configPath, options.outDir, true));
1123
+ await pluginHandler.emitAndWrite();
1124
+ console.log("[MDX] types generated");
1125
+ }
1126
+ function createVitePluginHandler({
1127
+ configPath,
1128
+ outDir,
1129
+ generateIndexFile
1130
+ }) {
1131
+ return createPluginHandler(
1132
+ {
1133
+ environment: "vite",
1134
+ configPath,
1135
+ outDir
1136
+ },
1137
+ [
1138
+ generateIndexFile !== false && vite(typeof generateIndexFile === "object" ? generateIndexFile : {})
1139
+ ]
1140
+ );
1141
+ }
1142
+ function applyDefaults(options) {
1143
+ return {
1144
+ updateViteConfig: options.updateViteConfig ?? true,
1145
+ generateIndexFile: options.generateIndexFile ?? true,
1146
+ configPath: options.configPath ?? "source.config.ts",
1147
+ outDir: options.outDir ?? ".source"
1148
+ };
1149
+ }
988
1150
  // Annotate the CommonJS export names for ESM import in node:
989
1151
  0 && (module.exports = {
990
1152
  postInstall