fumadocs-mdx 12.0.3 → 13.0.1

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 +1116 -359
  2. package/dist/bin.js +4 -4
  3. package/dist/build-mdx-CCNr86q6.d.ts +53 -0
  4. package/dist/build-mdx-D-r3_eQL.d.cts +53 -0
  5. package/dist/bun/index.cjs +196 -52
  6. package/dist/bun/index.d.cts +8 -3
  7. package/dist/bun/index.d.ts +8 -3
  8. package/dist/bun/index.js +19 -10
  9. package/dist/{chunk-QAUWMR5D.js → chunk-3J3WL7WN.js} +23 -5
  10. package/dist/{chunk-6Y5JDZHD.js → chunk-CXA4JO4Z.js} +1 -21
  11. package/dist/chunk-EELYB2XC.js +207 -0
  12. package/dist/{chunk-46UPKP5R.js → chunk-II3H5ZVZ.js} +5 -5
  13. package/dist/{chunk-LGYVNESJ.js → chunk-JVZFH6ND.js} +6 -22
  14. package/dist/{chunk-LMG6UWCL.js → chunk-K5ZLPEIQ.js} +56 -16
  15. package/dist/{chunk-OMAMTKDE.js → chunk-KILFIBVW.js} +3 -12
  16. package/dist/chunk-NVRDCY6Z.js +30 -0
  17. package/dist/{chunk-RMDXSZYE.js → chunk-XQ5O7IPO.js} +31 -24
  18. package/dist/chunk-XZY2AWJI.js +81 -0
  19. package/dist/{chunk-VXEBLM4X.js → chunk-YVCR6FUH.js} +1 -1
  20. package/dist/config/index.cjs +56 -16
  21. package/dist/config/index.d.cts +2 -1
  22. package/dist/config/index.d.ts +2 -1
  23. package/dist/config/index.js +1 -1
  24. package/dist/{define-DJbJduHy.d.ts → core-B6j6Fxse.d.cts} +89 -2
  25. package/dist/{define-DJbJduHy.d.cts → core-B6j6Fxse.d.ts} +89 -2
  26. package/dist/index.cjs +0 -109
  27. package/dist/index.d.cts +75 -9
  28. package/dist/index.d.ts +75 -9
  29. package/dist/index.js +0 -11
  30. package/dist/{load-UUXLUBHL.js → load-MNG3CLET.js} +1 -3
  31. package/dist/next/index.cjs +298 -234
  32. package/dist/next/index.d.cts +2 -11
  33. package/dist/next/index.d.ts +2 -11
  34. package/dist/next/index.js +177 -141
  35. package/dist/node/loader.cjs +228 -85
  36. package/dist/node/loader.js +19 -9
  37. package/dist/plugins/json-schema.cjs +162 -0
  38. package/dist/plugins/json-schema.d.cts +24 -0
  39. package/dist/plugins/json-schema.d.ts +24 -0
  40. package/dist/plugins/json-schema.js +78 -0
  41. package/dist/runtime/next/async.cjs +108 -70
  42. package/dist/runtime/next/async.d.cts +9 -6
  43. package/dist/runtime/next/async.d.ts +9 -6
  44. package/dist/runtime/next/async.js +8 -18
  45. package/dist/runtime/next/index.cjs +25 -14
  46. package/dist/runtime/next/index.d.cts +11 -8
  47. package/dist/runtime/next/index.d.ts +11 -8
  48. package/dist/runtime/next/index.js +2 -2
  49. package/dist/runtime/vite/browser.cjs +7 -3
  50. package/dist/runtime/vite/browser.d.cts +56 -7
  51. package/dist/runtime/vite/browser.d.ts +56 -7
  52. package/dist/runtime/vite/browser.js +2 -1
  53. package/dist/runtime/vite/server.cjs +40 -34
  54. package/dist/runtime/vite/server.d.cts +13 -10
  55. package/dist/runtime/vite/server.d.ts +13 -10
  56. package/dist/runtime/vite/server.js +8 -23
  57. package/dist/{types-TeHjsmja.d.ts → types-AGzTfBmf.d.ts} +3 -10
  58. package/dist/{types-BRx1QsIJ.d.cts → types-DKGMoay5.d.cts} +3 -10
  59. package/dist/vite/index.cjs +443 -249
  60. package/dist/vite/index.d.cts +23 -10
  61. package/dist/vite/index.d.ts +23 -10
  62. package/dist/vite/index.js +213 -36
  63. package/dist/{loader-mdx.cjs → webpack/index.cjs} +268 -82
  64. package/dist/{loader-mdx.d.ts → webpack/index.d.cts} +1 -0
  65. package/dist/{loader-mdx.d.cts → webpack/index.d.ts} +1 -0
  66. package/dist/webpack/index.js +44 -0
  67. package/loader-mdx.cjs +1 -1
  68. package/package.json +30 -16
  69. package/dist/browser-BupUnhpC.d.ts +0 -98
  70. package/dist/browser-R0x9IPaQ.d.cts +0 -98
  71. package/dist/chunk-ADR6R7HM.js +0 -29
  72. package/dist/chunk-IQAEAI4P.js +0 -66
  73. package/dist/chunk-XMFLD5J6.js +0 -30
  74. package/dist/chunk-ZLCSVXCD.js +0 -10
  75. package/dist/chunk-ZX7TM4AR.js +0 -127
  76. package/dist/loader-mdx.js +0 -25
  77. package/dist/postinstall-SCSXM4IM.js +0 -10
  78. package/dist/shared-CfiiRctw.d.ts +0 -70
  79. package/dist/shared-fFqiuWJC.d.cts +0 -70
  80. package/dist/watcher-HGOH3APP.js +0 -22
package/dist/bin.cjs CHANGED
@@ -30,6 +30,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
+ // src/loaders/config/index.ts
34
+ function findConfigFile() {
35
+ return import_node_path.default.resolve("source.config.ts");
36
+ }
37
+ var import_node_path, import_promises;
38
+ var init_config = __esm({
39
+ "src/loaders/config/index.ts"() {
40
+ "use strict";
41
+ import_node_path = __toESM(require("path"), 1);
42
+ import_promises = __toESM(require("fs/promises"), 1);
43
+ }
44
+ });
45
+
33
46
  // src/loaders/mdx/preset.ts
34
47
  var preset_exports = {};
35
48
  __export(preset_exports, {
@@ -173,6 +186,10 @@ var init_build = __esm({
173
186
  });
174
187
 
175
188
  // src/loaders/config/load.ts
189
+ var load_exports = {};
190
+ __export(load_exports, {
191
+ loadConfig: () => loadConfig
192
+ });
176
193
  async function compileConfig(configPath, outDir) {
177
194
  const { build } = await import("esbuild");
178
195
  const transformed = await build({
@@ -193,37 +210,53 @@ async function compileConfig(configPath, outDir) {
193
210
  throw new Error("failed to compile configuration file");
194
211
  }
195
212
  }
196
- async function loadConfig(configPath, outDir, hash, build = false) {
197
- if (cache && cache.hash === hash) {
198
- return await cache.config;
199
- }
213
+ async function loadConfig(configPath, outDir, build = false) {
200
214
  if (build) await compileConfig(configPath, outDir);
201
- const url = (0, import_node_url.pathToFileURL)(path.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) cache = { config, hash };
215
+ const url = (0, import_node_url.pathToFileURL)(path2.resolve(outDir, "source.config.mjs"));
216
+ url.searchParams.set("hash", Date.now().toString());
217
+ const config = import(url.href).then(
218
+ (loaded) => buildConfig(loaded)
219
+ );
209
220
  return await config;
210
221
  }
211
- async function getConfigHash(configPath) {
212
- const stats = await fs.stat(configPath).catch(() => void 0);
213
- if (stats) {
214
- return stats.mtime.getTime().toString();
215
- }
216
- throw new Error("Cannot find config file");
217
- }
218
- var fs, path, import_node_url, cache;
222
+ var path2, import_node_url;
219
223
  var init_load = __esm({
220
224
  "src/loaders/config/load.ts"() {
221
225
  "use strict";
222
- fs = __toESM(require("fs/promises"), 1);
223
- path = __toESM(require("path"), 1);
226
+ path2 = __toESM(require("path"), 1);
224
227
  import_node_url = require("url");
225
228
  init_build();
226
- cache = null;
229
+ }
230
+ });
231
+
232
+ // src/next/file-cache.ts
233
+ function toFullPath(file) {
234
+ if (import_node_path2.default.isAbsolute(file)) {
235
+ return import_node_path2.default.relative(process.cwd(), file);
236
+ }
237
+ return file;
238
+ }
239
+ async function readFileWithCache(file) {
240
+ const fullPath = toFullPath(file);
241
+ const cached = map.get(fullPath);
242
+ if (cached) return cached;
243
+ const read = import_promises2.default.readFile(fullPath).then((s) => s.toString());
244
+ map.set(fullPath, read);
245
+ return read;
246
+ }
247
+ function removeFileCache(file) {
248
+ map.delete(toFullPath(file));
249
+ }
250
+ var import_lru_cache, import_promises2, import_node_path2, map;
251
+ var init_file_cache = __esm({
252
+ "src/next/file-cache.ts"() {
253
+ "use strict";
254
+ import_lru_cache = require("lru-cache");
255
+ import_promises2 = __toESM(require("fs/promises"), 1);
256
+ import_node_path2 = __toESM(require("path"), 1);
257
+ map = new import_lru_cache.LRUCache({
258
+ max: 100
259
+ });
227
260
  }
228
261
  });
229
262
 
@@ -271,63 +304,32 @@ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
271
304
  }
272
305
  });
273
306
 
274
- // src/next/map/file-cache.ts
275
- function toFullPath(file) {
276
- if (import_node_path.default.isAbsolute(file)) {
277
- return import_node_path.default.relative(process.cwd(), file);
278
- }
279
- return file;
280
- }
281
- async function readFileWithCache(file) {
282
- const fullPath = toFullPath(file);
283
- const cached = map.get(fullPath);
284
- if (cached) return cached;
285
- const read = import_promises.default.readFile(fullPath).then((s) => s.toString());
286
- map.set(fullPath, read);
287
- return read;
288
- }
289
- function removeFileCache(file) {
290
- map.delete(toFullPath(file));
291
- }
292
- var import_lru_cache, import_promises, import_node_path, map;
293
- var init_file_cache = __esm({
294
- "src/next/map/file-cache.ts"() {
295
- "use strict";
296
- import_lru_cache = require("lru-cache");
297
- import_promises = __toESM(require("fs/promises"), 1);
298
- import_node_path = __toESM(require("path"), 1);
299
- map = new import_lru_cache.LRUCache({
300
- max: 100
301
- });
302
- }
303
- });
304
-
305
307
  // src/utils/git-timestamp.ts
306
308
  async function getGitTimestamp(file) {
307
- const cached = cache2.get(file);
309
+ const cached = cache.get(file);
308
310
  if (cached) return cached;
309
311
  try {
310
312
  const out = await (0, import_tinyexec.x)(
311
313
  "git",
312
- ["log", "-1", '--pretty="%ai"', import_node_path2.default.relative(process.cwd(), file)],
314
+ ["log", "-1", '--pretty="%ai"', import_node_path3.default.relative(process.cwd(), file)],
313
315
  {
314
316
  throwOnError: true
315
317
  }
316
318
  );
317
319
  const time = new Date(out.stdout);
318
- cache2.set(file, time);
320
+ cache.set(file, time);
319
321
  return time;
320
322
  } catch {
321
323
  return;
322
324
  }
323
325
  }
324
- var import_node_path2, import_tinyexec, cache2;
326
+ var import_node_path3, import_tinyexec, cache;
325
327
  var init_git_timestamp = __esm({
326
328
  "src/utils/git-timestamp.ts"() {
327
329
  "use strict";
328
- import_node_path2 = __toESM(require("path"), 1);
330
+ import_node_path3 = __toESM(require("path"), 1);
329
331
  import_tinyexec = require("tinyexec");
330
- cache2 = /* @__PURE__ */ new Map();
332
+ cache = /* @__PURE__ */ new Map();
331
333
  }
332
334
  });
333
335
 
@@ -368,7 +370,7 @@ function getImportCode(info) {
368
370
  return `import ${specifier}`;
369
371
  }
370
372
  function toImportPath(file, config) {
371
- const ext = import_node_path3.default.extname(file);
373
+ const ext = import_node_path4.default.extname(file);
372
374
  let filename;
373
375
  if (ext === ".ts" && config.jsExtension) {
374
376
  filename = file.substring(0, file.length - ext.length) + ".js";
@@ -379,51 +381,108 @@ function toImportPath(file, config) {
379
381
  }
380
382
  let importPath;
381
383
  if ("relativeTo" in config) {
382
- importPath = import_node_path3.default.relative(config.relativeTo, filename);
383
- if (!import_node_path3.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
384
+ importPath = import_node_path4.default.relative(config.relativeTo, filename);
385
+ if (!import_node_path4.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
384
386
  importPath = `./${importPath}`;
385
387
  }
386
388
  } else {
387
- importPath = import_node_path3.default.resolve(filename);
389
+ importPath = import_node_path4.default.resolve(filename);
388
390
  }
389
- return importPath.replaceAll(import_node_path3.default.sep, "/");
391
+ return importPath.replaceAll(import_node_path4.default.sep, "/");
390
392
  }
391
393
  function ident(code, tab = 1) {
392
394
  return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
393
395
  }
394
- var import_node_path3;
396
+ var import_node_path4;
395
397
  var init_import_formatter = __esm({
396
398
  "src/utils/import-formatter.ts"() {
397
399
  "use strict";
398
- import_node_path3 = __toESM(require("path"), 1);
400
+ import_node_path4 = __toESM(require("path"), 1);
399
401
  }
400
402
  });
401
403
 
402
404
  // src/utils/collections.ts
403
- function getSupportedFormats(collection) {
404
- return {
405
- doc: ["mdx", "md"],
406
- meta: ["json", "yaml"]
407
- }[collection.type];
408
- }
409
405
  function getGlobPatterns(collection) {
410
406
  if (collection.files) return collection.files;
411
- return [`**/*.{${getSupportedFormats(collection).join(",")}}`];
407
+ return [`**/*.{${SupportedFormats[collection.type].join(",")}}`];
412
408
  }
413
409
  function isFileSupported(filePath, collection) {
414
- for (const format of getSupportedFormats(collection)) {
415
- if (filePath.endsWith(`.${format}`)) return true;
416
- }
417
- return false;
410
+ return SupportedFormats[collection.type].some(
411
+ (format) => filePath.endsWith(`.${format}`)
412
+ );
413
+ }
414
+ async function getCollectionFiles(collection) {
415
+ const files = /* @__PURE__ */ new Map();
416
+ const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
417
+ const patterns = getGlobPatterns(collection);
418
+ await Promise.all(
419
+ dirs.map(async (dir) => {
420
+ const result = await (0, import_tinyglobby.glob)(patterns, {
421
+ cwd: import_node_path5.default.resolve(dir)
422
+ });
423
+ for (const item of result) {
424
+ if (!isFileSupported(item, collection)) continue;
425
+ const fullPath = import_node_path5.default.join(dir, item);
426
+ files.set(fullPath, {
427
+ path: item,
428
+ fullPath
429
+ });
430
+ }
431
+ })
432
+ );
433
+ return Array.from(files.values());
418
434
  }
435
+ var import_picomatch, import_tinyglobby, import_node_path5, SupportedFormats;
419
436
  var init_collections = __esm({
420
437
  "src/utils/collections.ts"() {
421
438
  "use strict";
439
+ import_picomatch = __toESM(require("picomatch"), 1);
440
+ import_tinyglobby = require("tinyglobby");
441
+ import_node_path5 = __toESM(require("path"), 1);
442
+ SupportedFormats = {
443
+ doc: ["mdx", "md"],
444
+ meta: ["json", "yaml"]
445
+ };
422
446
  }
423
447
  });
424
448
 
425
- // src/next/map/generate.ts
426
- async function generateJS(configPath, config, importPath, configHash = false) {
449
+ // src/plugins/next.ts
450
+ function next() {
451
+ let config;
452
+ let shouldEmitOnChange = false;
453
+ return {
454
+ name: "next",
455
+ config(v) {
456
+ config = v;
457
+ shouldEmitOnChange = false;
458
+ for (const collection of config.collections.values()) {
459
+ if (collection.type === "doc" && collection.async || collection.type === "docs" && collection.docs.async) {
460
+ shouldEmitOnChange = true;
461
+ }
462
+ }
463
+ },
464
+ configureServer(server) {
465
+ if (!server.watcher) return;
466
+ server.watcher.on("all", async () => {
467
+ if (!shouldEmitOnChange) return;
468
+ await this.core.emitAndWrite({
469
+ filterPlugin: (plugin) => plugin.name === "next"
470
+ });
471
+ });
472
+ },
473
+ async emit() {
474
+ return [
475
+ {
476
+ path: "index.ts",
477
+ content: await indexFile(this.configPath, config, {
478
+ relativeTo: this.outDir
479
+ })
480
+ }
481
+ ];
482
+ }
483
+ };
484
+ }
485
+ async function indexFile(configPath, config, importPath, configHash = false) {
427
486
  let asyncInit = false;
428
487
  const lines = [
429
488
  getImportCode({
@@ -525,18 +584,18 @@ async function generateJS(configPath, config, importPath, configHash = false) {
525
584
  }
526
585
  const declares = entries.map(async ([k, collection]) => {
527
586
  if (collection.type === "docs") {
528
- const docs2 = await getCollectionFiles(collection.docs);
587
+ const docs = await getCollectionFiles(collection.docs);
529
588
  const metas = await getCollectionFiles(collection.meta);
530
589
  const metaEntries = (await getMetaEntries(collection.meta, metas)).join(
531
590
  ", "
532
591
  );
533
592
  if (collection.docs.async) {
534
- const docsEntries2 = (await getAsyncEntries(collection.docs, docs2)).join(
593
+ const docsEntries2 = (await getAsyncEntries(collection.docs, docs)).join(
535
594
  ", "
536
595
  );
537
596
  return `export const ${k} = _runtimeAsync.docs<typeof _source.${k}>([${docsEntries2}], [${metaEntries}], "${k}", _sourceConfig)`;
538
597
  }
539
- const docsEntries = (await getDocEntries(k, docs2)).join(", ");
598
+ const docsEntries = (await getDocEntries(k, docs)).join(", ");
540
599
  return `export const ${k} = _runtime.docs<typeof _source.${k}>([${docsEntries}], [${metaEntries}])`;
541
600
  }
542
601
  const files = await getCollectionFiles(collection);
@@ -552,46 +611,24 @@ async function generateJS(configPath, config, importPath, configHash = false) {
552
611
  ...resolvedDeclares
553
612
  ].join("\n");
554
613
  }
555
- async function getCollectionFiles(collection) {
556
- const files = /* @__PURE__ */ new Map();
557
- const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
558
- const patterns = getGlobPatterns(collection);
559
- await Promise.all(
560
- dirs.map(async (dir) => {
561
- const result = await (0, import_tinyglobby.glob)(patterns, {
562
- cwd: path5.resolve(dir)
563
- });
564
- for (const item of result) {
565
- if (!isFileSupported(item, collection)) continue;
566
- const fullPath = path5.join(dir, item);
567
- files.set(fullPath, {
568
- path: item,
569
- fullPath
570
- });
571
- }
572
- })
573
- );
574
- return Array.from(files.values());
575
- }
576
614
  function parseMetaEntry(file, content) {
577
- const extname2 = path5.extname(file);
615
+ const extname4 = path7.extname(file);
578
616
  try {
579
- if (extname2 === ".json") return JSON.parse(content);
580
- if (extname2 === ".yaml") return (0, import_js_yaml2.load)(content);
617
+ if (extname4 === ".json") return JSON.parse(content);
618
+ if (extname4 === ".yaml") return (0, import_js_yaml2.load)(content);
581
619
  } catch (e) {
582
620
  throw new Error(`Failed to parse meta file: ${file}.`, {
583
621
  cause: e
584
622
  });
585
623
  }
586
- throw new Error(`Unknown meta file format: ${extname2}, in ${file}.`);
624
+ throw new Error(`Unknown meta file format: ${extname4}, in ${file}.`);
587
625
  }
588
- var path5, import_node_crypto, import_tinyglobby, import_js_yaml2;
589
- var init_generate = __esm({
590
- "src/next/map/generate.ts"() {
626
+ var path7, import_node_crypto, import_js_yaml2;
627
+ var init_next = __esm({
628
+ "src/plugins/next.ts"() {
591
629
  "use strict";
592
- path5 = __toESM(require("path"), 1);
630
+ path7 = __toESM(require("path"), 1);
593
631
  import_node_crypto = require("crypto");
594
- import_tinyglobby = require("tinyglobby");
595
632
  init_validation();
596
633
  init_file_cache();
597
634
  import_js_yaml2 = require("js-yaml");
@@ -602,133 +639,106 @@ var init_generate = __esm({
602
639
  }
603
640
  });
604
641
 
605
- // src/loaders/config/index.ts
606
- function findConfigFile() {
607
- return import_node_path4.default.resolve("source.config.ts");
608
- }
609
- var import_node_path4;
610
- var init_config = __esm({
611
- "src/loaders/config/index.ts"() {
612
- "use strict";
613
- import_node_path4 = __toESM(require("path"), 1);
614
- }
615
- });
616
-
617
- // src/next/map/watcher.ts
618
- var watcher_exports = {};
619
- __export(watcher_exports, {
620
- watcher: () => watcher
621
- });
622
- function watcher(configPath, config, ignored) {
623
- const watcher2 = new import_chokidar.FSWatcher({
624
- ignoreInitial: true,
625
- persistent: true,
626
- ignored
627
- });
628
- watcher2.add(configPath);
629
- for (const collection of config.collections.values()) {
630
- if (collection.type === "docs") {
631
- watcher2.add(collection.docs.dir);
632
- watcher2.add(collection.meta.dir);
633
- } else {
634
- watcher2.add(collection.dir);
635
- }
636
- }
637
- return watcher2;
638
- }
639
- var import_chokidar;
640
- var init_watcher = __esm({
641
- "src/next/map/watcher.ts"() {
642
- "use strict";
643
- import_chokidar = require("chokidar");
644
- }
645
- });
646
-
647
- // src/next/map/index.ts
648
- async function start(dev, configPath, outDir) {
649
- let configHash = await getConfigHash(configPath);
650
- let config = await loadConfig(configPath, outDir, configHash, true);
651
- const outPath = path7.resolve(outDir, `index.ts`);
652
- async function updateMapFile() {
653
- const start3 = performance.now();
654
- try {
655
- await fs3.writeFile(
656
- outPath,
657
- await generateJS(
658
- configPath,
659
- config,
660
- { relativeTo: outDir },
661
- configHash
662
- )
663
- );
664
- } catch (err) {
665
- if (err instanceof ValidationError) {
666
- console.error(err.toStringFormatted());
667
- } else {
668
- console.error(err);
642
+ // src/core.ts
643
+ function createCore(options, defaultPlugins = []) {
644
+ let config;
645
+ let plugins2;
646
+ return {
647
+ _options: options,
648
+ getPluginContext() {
649
+ return {
650
+ core: this,
651
+ ...options
652
+ };
653
+ },
654
+ /**
655
+ * Convenient cache store, reset when config changes
656
+ */
657
+ cache: /* @__PURE__ */ new Map(),
658
+ async init({ config: newConfig }) {
659
+ config = await newConfig;
660
+ this.cache.clear();
661
+ plugins2 = [];
662
+ for await (const option of [
663
+ ...defaultPlugins,
664
+ ...config.global.plugins ?? []
665
+ ]) {
666
+ if (!option) continue;
667
+ if (Array.isArray(option)) plugins2.push(...option);
668
+ else plugins2.push(option);
669
669
  }
670
- }
671
- console.log(`[MDX] updated map file in ${performance.now() - start3}ms`);
672
- }
673
- await updateMapFile();
674
- if (dev) {
675
- const { watcher: watcher2 } = await Promise.resolve().then(() => (init_watcher(), watcher_exports));
676
- const instance = watcher2(configPath, config, [outPath]);
677
- instance.on("ready", () => {
678
- console.log("[MDX] started dev server");
679
- });
680
- instance.on("all", (event, file) => {
681
- if (typeof file !== "string") return;
682
- const absolutePath = path7.resolve(file);
683
- const onUpdate = async () => {
684
- const isConfigFile = absolutePath === configPath;
685
- if (isConfigFile) {
686
- configHash = await getConfigHash(configPath);
687
- config = await loadConfig(configPath, outDir, configHash, true);
670
+ for (const plugin of plugins2) {
671
+ const out = await plugin.config?.call(this.getPluginContext(), config);
672
+ if (out) config = out;
673
+ }
674
+ return this;
675
+ },
676
+ getConfig() {
677
+ return config;
678
+ },
679
+ creatConfigLoader() {
680
+ return {
681
+ getConfig() {
682
+ return config;
688
683
  }
689
- if (event === "change") removeFileCache(absolutePath);
690
- await updateMapFile();
691
684
  };
692
- void onUpdate();
693
- });
694
- process.on("exit", () => {
695
- console.log("[MDX] closing dev server");
696
- void instance.close();
697
- });
698
- }
685
+ },
686
+ async initServer(server) {
687
+ for (const plugin of plugins2) {
688
+ await plugin.configureServer?.call(this.getPluginContext(), server);
689
+ }
690
+ },
691
+ async emitAndWrite({
692
+ filterPlugin = () => true
693
+ } = {}) {
694
+ const start2 = performance.now();
695
+ const out = await Promise.all(
696
+ plugins2.map((plugin) => {
697
+ if (!filterPlugin(plugin) || !plugin.emit) return [];
698
+ return plugin.emit.call(this.getPluginContext());
699
+ })
700
+ );
701
+ await Promise.all(
702
+ out.flat().map(async (entry) => {
703
+ const file = import_node_path6.default.join(options.outDir, entry.path);
704
+ await import_promises3.default.mkdir(import_node_path6.default.dirname(file), { recursive: true });
705
+ await import_promises3.default.writeFile(file, entry.content);
706
+ })
707
+ );
708
+ console.log(`[MDX] generated files in ${performance.now() - start2}ms`);
709
+ }
710
+ };
699
711
  }
700
- var path7, fs3;
701
- var init_map = __esm({
702
- "src/next/map/index.ts"() {
712
+ var import_node_path6, import_promises3;
713
+ var init_core = __esm({
714
+ "src/core.ts"() {
703
715
  "use strict";
704
- path7 = __toESM(require("path"), 1);
705
- fs3 = __toESM(require("fs/promises"), 1);
706
- init_load();
707
- init_generate();
708
- init_file_cache();
709
- init_validation();
716
+ import_node_path6 = __toESM(require("path"), 1);
717
+ import_promises3 = __toESM(require("fs/promises"), 1);
710
718
  }
711
719
  });
712
720
 
713
- // src/next/create.ts
714
- function createMDX({
715
- configPath = findConfigFile(),
716
- outDir = ".source"
717
- } = {}) {
721
+ // src/next/index.ts
722
+ var next_exports = {};
723
+ __export(next_exports, {
724
+ createMDX: () => createMDX,
725
+ postInstall: () => postInstall
726
+ });
727
+ function createMDX(createOptions = {}) {
728
+ const options = applyDefaults(createOptions);
729
+ const isDev = process.env.NODE_ENV === "development";
718
730
  if (process.env._FUMADOCS_MDX !== "1") {
719
731
  process.env._FUMADOCS_MDX = "1";
720
- void start(process.env.NODE_ENV === "development", configPath, outDir);
732
+ void init(isDev, options);
721
733
  }
722
734
  return (nextConfig = {}) => {
723
735
  const mdxLoaderOptions = {
724
- configPath,
725
- outDir
736
+ ...options,
737
+ isDev
726
738
  };
727
- const turbo = {
728
- ...nextConfig.experimental?.turbo,
739
+ const turbopack = {
729
740
  ...nextConfig.turbopack,
730
741
  rules: {
731
- ...nextConfig.experimental?.turbo?.rules,
732
742
  ...nextConfig.turbopack?.rules,
733
743
  "*.{md,mdx}": {
734
744
  loaders: [
@@ -741,17 +751,18 @@ function createMDX({
741
751
  }
742
752
  }
743
753
  };
744
- const updated = {
754
+ return {
745
755
  ...nextConfig,
756
+ turbopack,
746
757
  pageExtensions: nextConfig.pageExtensions ?? defaultPageExtensions,
747
- webpack: (config, options) => {
758
+ webpack: (config, options2) => {
748
759
  config.resolve ||= {};
749
760
  config.module ||= {};
750
761
  config.module.rules ||= [];
751
762
  config.module.rules.push({
752
763
  test: /\.mdx?$/,
753
764
  use: [
754
- options.defaultLoaders.babel,
765
+ options2.defaultLoaders.babel,
755
766
  {
756
767
  loader: "fumadocs-mdx/loader-mdx",
757
768
  options: mdxLoaderOptions
@@ -759,150 +770,768 @@ function createMDX({
759
770
  ]
760
771
  });
761
772
  config.plugins ||= [];
762
- return nextConfig.webpack?.(config, options) ?? config;
773
+ return nextConfig.webpack?.(config, options2) ?? config;
763
774
  }
764
775
  };
765
- if (isTurboExperimental) {
766
- updated.experimental = { ...updated.experimental, turbo };
767
- } else {
768
- updated.turbopack = turbo;
776
+ };
777
+ }
778
+ async function init(dev, options) {
779
+ const core = createNextCore(options);
780
+ async function initOrReload() {
781
+ await core.init({
782
+ config: loadConfig(options.configPath, options.outDir, true)
783
+ });
784
+ await core.emitAndWrite();
785
+ }
786
+ async function devServer() {
787
+ const { FSWatcher } = await import("chokidar");
788
+ const watcher = new FSWatcher({
789
+ ignoreInitial: true,
790
+ persistent: true,
791
+ ignored: [options.outDir]
792
+ });
793
+ watcher.add(options.configPath);
794
+ for (const collection of core.getConfig().collections.values()) {
795
+ if (collection.type === "docs") {
796
+ watcher.add(collection.docs.dir);
797
+ watcher.add(collection.meta.dir);
798
+ } else {
799
+ watcher.add(collection.dir);
800
+ }
769
801
  }
770
- return updated;
802
+ watcher.on("ready", () => {
803
+ console.log("[MDX] started dev server");
804
+ });
805
+ watcher.on("all", async (event, file) => {
806
+ const absolutePath = path9.resolve(file);
807
+ if (event === "change") removeFileCache(absolutePath);
808
+ if (absolutePath === path9.resolve(options.configPath)) {
809
+ watcher.removeAllListeners();
810
+ await watcher.close();
811
+ await initOrReload();
812
+ console.log("[MDX] restarting dev server");
813
+ await devServer();
814
+ }
815
+ });
816
+ process.on("exit", () => {
817
+ if (watcher.closed) return;
818
+ console.log("[MDX] closing dev server");
819
+ void watcher.close();
820
+ });
821
+ await core.initServer({ watcher });
822
+ }
823
+ await initOrReload();
824
+ if (dev) {
825
+ await devServer();
826
+ }
827
+ }
828
+ async function postInstall(configPath = findConfigFile(), outDir = ".source") {
829
+ const core = await createNextCore({
830
+ outDir,
831
+ configPath
832
+ }).init({
833
+ config: loadConfig(configPath, outDir, true)
834
+ });
835
+ await core.emitAndWrite();
836
+ }
837
+ function applyDefaults(options) {
838
+ return {
839
+ outDir: options.outDir ?? ".source",
840
+ configPath: options.configPath ?? findConfigFile()
771
841
  };
772
842
  }
773
- var import_node_fs, defaultPageExtensions, isTurboExperimental;
774
- var init_create = __esm({
775
- "src/next/create.ts"() {
843
+ function createNextCore({
844
+ outDir,
845
+ configPath
846
+ }) {
847
+ const core = createCore(
848
+ {
849
+ environment: "next",
850
+ outDir,
851
+ configPath
852
+ },
853
+ [next()]
854
+ );
855
+ return {
856
+ ...core,
857
+ async emitAndWrite(...args) {
858
+ try {
859
+ await core.emitAndWrite(...args);
860
+ } catch (err) {
861
+ if (err instanceof ValidationError) {
862
+ console.error(err.toStringFormatted());
863
+ } else {
864
+ console.error(err);
865
+ }
866
+ }
867
+ }
868
+ };
869
+ }
870
+ var path9, defaultPageExtensions;
871
+ var init_next2 = __esm({
872
+ "src/next/index.ts"() {
776
873
  "use strict";
777
874
  init_config();
778
- init_map();
779
- import_node_fs = require("fs");
875
+ path9 = __toESM(require("path"), 1);
876
+ init_load();
877
+ init_file_cache();
878
+ init_validation();
879
+ init_next();
880
+ init_core();
780
881
  defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
882
+ }
883
+ });
884
+
885
+ // src/loaders/mdx/remark-unravel.ts
886
+ function remarkMarkAndUnravel() {
887
+ return (tree) => {
888
+ (0, import_unist_util_visit.visit)(tree, function(node, index, parent) {
889
+ let offset = -1;
890
+ let all = true;
891
+ let oneOrMore = false;
892
+ if (parent && typeof index === "number" && node.type === "paragraph") {
893
+ const children = node.children;
894
+ while (++offset < children.length) {
895
+ const child = children[offset];
896
+ if (child.type === "mdxJsxTextElement" || child.type === "mdxTextExpression") {
897
+ oneOrMore = true;
898
+ } else if (child.type === "text" && child.value.trim().length === 0) {
899
+ } else {
900
+ all = false;
901
+ break;
902
+ }
903
+ }
904
+ if (all && oneOrMore) {
905
+ offset = -1;
906
+ const newChildren = [];
907
+ while (++offset < children.length) {
908
+ const child = children[offset];
909
+ if (child.type === "mdxJsxTextElement") {
910
+ child.type = "mdxJsxFlowElement";
911
+ }
912
+ if (child.type === "mdxTextExpression") {
913
+ child.type = "mdxFlowExpression";
914
+ }
915
+ if (child.type === "text" && /^[\t\r\n ]+$/.test(String(child.value))) {
916
+ } else {
917
+ newChildren.push(child);
918
+ }
919
+ }
920
+ parent.children.splice(index, 1, ...newChildren);
921
+ return index;
922
+ }
923
+ }
924
+ });
925
+ };
926
+ }
927
+ var import_unist_util_visit;
928
+ var init_remark_unravel = __esm({
929
+ "src/loaders/mdx/remark-unravel.ts"() {
930
+ "use strict";
931
+ import_unist_util_visit = require("unist-util-visit");
932
+ }
933
+ });
934
+
935
+ // src/loaders/mdx/remark-include.ts
936
+ function isElementLike(node) {
937
+ return ElementLikeTypes.includes(node.type);
938
+ }
939
+ function parseElementAttributes(element) {
940
+ if (Array.isArray(element.attributes)) {
941
+ const attributes = {};
942
+ for (const attr of element.attributes) {
943
+ if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
944
+ attributes[attr.name] = attr.value;
945
+ }
946
+ }
947
+ return attributes;
948
+ }
949
+ return element.attributes ?? {};
950
+ }
951
+ function flattenNode(node) {
952
+ if ("children" in node)
953
+ return node.children.map((child) => flattenNode(child)).join("");
954
+ if ("value" in node) return node.value;
955
+ return "";
956
+ }
957
+ function parseSpecifier(specifier) {
958
+ const idx = specifier.lastIndexOf("#");
959
+ if (idx === -1) return { file: specifier };
960
+ return {
961
+ file: specifier.slice(0, idx),
962
+ section: specifier.slice(idx + 1)
963
+ };
964
+ }
965
+ function extractSection(root, section) {
966
+ let nodes;
967
+ let capturingHeadingContent = false;
968
+ (0, import_unist_util_visit2.visit)(root, (node) => {
969
+ if (node.type === "heading") {
970
+ if (capturingHeadingContent) {
971
+ return false;
972
+ }
973
+ if (node.data?.hProperties?.id === section) {
974
+ capturingHeadingContent = true;
975
+ nodes = [node];
976
+ return "skip";
977
+ }
978
+ return;
979
+ }
980
+ if (capturingHeadingContent) {
981
+ nodes?.push(node);
982
+ return "skip";
983
+ }
984
+ if (isElementLike(node) && node.name === "section") {
985
+ const attributes = parseElementAttributes(node);
986
+ if (attributes.id === section) {
987
+ nodes = node.children;
988
+ return false;
989
+ }
990
+ }
991
+ });
992
+ if (nodes)
993
+ return {
994
+ type: "root",
995
+ children: nodes
996
+ };
997
+ }
998
+ function remarkInclude() {
999
+ const TagName = "include";
1000
+ const embedContent = async (file, heading, params, data) => {
1001
+ let content;
781
1002
  try {
782
- const content = (0, import_node_fs.readFileSync)("./node_modules/next/package.json").toString();
783
- const version = JSON.parse(content).version;
784
- isTurboExperimental = version.startsWith("15.0.") || version.startsWith("15.1.") || version.startsWith("15.2.");
785
- } catch {
786
- isTurboExperimental = false;
1003
+ content = (await fs4.readFile(file)).toString();
1004
+ } catch (e) {
1005
+ throw new Error(
1006
+ `failed to read file ${file}
1007
+ ${e instanceof Error ? e.message : String(e)}`,
1008
+ { cause: e }
1009
+ );
1010
+ }
1011
+ const ext = path10.extname(file);
1012
+ data._compiler?.addDependency(file);
1013
+ if (params.lang || ext !== ".md" && ext !== ".mdx") {
1014
+ const lang = params.lang ?? ext.slice(1);
1015
+ return {
1016
+ type: "code",
1017
+ lang,
1018
+ meta: params.meta,
1019
+ value: content,
1020
+ data: {}
1021
+ };
1022
+ }
1023
+ const parser = data._getProcessor ? data._getProcessor(ext === ".mdx" ? "mdx" : "md") : this;
1024
+ const parsed = fumaMatter(content);
1025
+ let mdast = parser.parse({
1026
+ path: file,
1027
+ value: parsed.content,
1028
+ data: { frontmatter: parsed.data }
1029
+ });
1030
+ const baseProcessor = (0, import_unified.unified)().use(remarkMarkAndUnravel);
1031
+ if (heading) {
1032
+ const extracted = extractSection(
1033
+ await baseProcessor.use(import_mdx_plugins.remarkHeading).run(mdast),
1034
+ heading
1035
+ );
1036
+ if (!extracted)
1037
+ throw new Error(
1038
+ `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.`
1039
+ );
1040
+ mdast = extracted;
1041
+ } else {
1042
+ mdast = await baseProcessor.run(mdast);
787
1043
  }
1044
+ await update(mdast, path10.dirname(file), data);
1045
+ return mdast;
1046
+ };
1047
+ async function update(tree, directory, data) {
1048
+ const queue = [];
1049
+ (0, import_unist_util_visit2.visit)(tree, ElementLikeTypes, (_node, _, parent) => {
1050
+ const node = _node;
1051
+ if (node.name !== TagName) return;
1052
+ const specifier = flattenNode(node);
1053
+ if (specifier.length === 0) return "skip";
1054
+ const attributes = parseElementAttributes(node);
1055
+ const { file: relativePath, section } = parseSpecifier(specifier);
1056
+ const file = path10.resolve(
1057
+ "cwd" in attributes ? process.cwd() : directory,
1058
+ relativePath
1059
+ );
1060
+ queue.push(
1061
+ embedContent(file, section, attributes, data).then((replace) => {
1062
+ Object.assign(
1063
+ parent && parent.type === "paragraph" ? parent : node,
1064
+ replace
1065
+ );
1066
+ })
1067
+ );
1068
+ return "skip";
1069
+ });
1070
+ await Promise.all(queue);
1071
+ }
1072
+ return async (tree, file) => {
1073
+ await update(tree, path10.dirname(file.path), file.data);
1074
+ };
1075
+ }
1076
+ var import_unified, import_unist_util_visit2, path10, fs4, import_mdx_plugins, ElementLikeTypes;
1077
+ var init_remark_include = __esm({
1078
+ "src/loaders/mdx/remark-include.ts"() {
1079
+ "use strict";
1080
+ import_unified = require("unified");
1081
+ import_unist_util_visit2 = require("unist-util-visit");
1082
+ path10 = __toESM(require("path"), 1);
1083
+ fs4 = __toESM(require("fs/promises"), 1);
1084
+ init_fuma_matter();
1085
+ import_mdx_plugins = require("fumadocs-core/mdx-plugins");
1086
+ init_remark_unravel();
1087
+ ElementLikeTypes = [
1088
+ "mdxJsxFlowElement",
1089
+ "mdxJsxTextElement",
1090
+ "containerDirective",
1091
+ "textDirective",
1092
+ "leafDirective"
1093
+ ];
788
1094
  }
789
1095
  });
790
1096
 
791
- // src/next/index.ts
792
- var next_exports = {};
793
- __export(next_exports, {
794
- createMDX: () => createMDX,
795
- postInstall: () => postInstall,
796
- start: () => start
1097
+ // src/loaders/mdx/remark-postprocess.ts
1098
+ function remarkPostprocess({
1099
+ _format,
1100
+ includeProcessedMarkdown = false,
1101
+ includeMDAST = false,
1102
+ valueToExport = []
1103
+ }) {
1104
+ let _stringifyProcessor;
1105
+ const getStringifyProcessor = () => {
1106
+ if (_format === "mdx") return this;
1107
+ return _stringifyProcessor ??= this().use(import_remark_mdx.default).freeze();
1108
+ };
1109
+ return (tree, file) => {
1110
+ let title;
1111
+ const urls = [];
1112
+ (0, import_unist_util_visit3.visit)(tree, ["heading", "link"], (node) => {
1113
+ if (node.type === "heading" && node.depth === 1) {
1114
+ title = flattenNode2(node);
1115
+ }
1116
+ if (node.type !== "link") return;
1117
+ urls.push({
1118
+ href: node.url
1119
+ });
1120
+ return "skip";
1121
+ });
1122
+ if (title) {
1123
+ file.data.frontmatter ??= {};
1124
+ if (!file.data.frontmatter.title) file.data.frontmatter.title = title;
1125
+ }
1126
+ file.data.extractedReferences = urls;
1127
+ if (includeProcessedMarkdown) {
1128
+ const processor = getStringifyProcessor();
1129
+ file.data._markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
1130
+ ...processor.data("settings"),
1131
+ // from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
1132
+ extensions: processor.data("toMarkdownExtensions") || []
1133
+ });
1134
+ }
1135
+ if (includeMDAST) {
1136
+ const options = includeMDAST === true ? {} : includeMDAST;
1137
+ file.data._mdast = JSON.stringify(
1138
+ options.removePosition ? (0, import_unist_util_remove_position.removePosition)(structuredClone(tree)) : tree
1139
+ );
1140
+ }
1141
+ for (const { name, value } of file.data["mdx-export"] ?? []) {
1142
+ tree.children.unshift(getMdastExport(name, value));
1143
+ }
1144
+ for (const name of valueToExport) {
1145
+ if (!(name in file.data)) continue;
1146
+ tree.children.unshift(getMdastExport(name, file.data[name]));
1147
+ }
1148
+ };
1149
+ }
1150
+ function getMdastExport(name, value) {
1151
+ return {
1152
+ type: "mdxjsEsm",
1153
+ value: "",
1154
+ data: {
1155
+ estree: {
1156
+ type: "Program",
1157
+ sourceType: "module",
1158
+ body: [
1159
+ {
1160
+ type: "ExportNamedDeclaration",
1161
+ attributes: [],
1162
+ specifiers: [],
1163
+ source: null,
1164
+ declaration: {
1165
+ type: "VariableDeclaration",
1166
+ kind: "let",
1167
+ declarations: [
1168
+ {
1169
+ type: "VariableDeclarator",
1170
+ id: {
1171
+ type: "Identifier",
1172
+ name
1173
+ },
1174
+ init: (0, import_estree_util_value_to_estree.valueToEstree)(value)
1175
+ }
1176
+ ]
1177
+ }
1178
+ }
1179
+ ]
1180
+ }
1181
+ }
1182
+ };
1183
+ }
1184
+ function flattenNode2(node) {
1185
+ if ("children" in node)
1186
+ return node.children.map((child) => flattenNode2(child)).join("");
1187
+ if ("value" in node) return node.value;
1188
+ return "";
1189
+ }
1190
+ var import_unist_util_visit3, import_mdast_util_to_markdown, import_estree_util_value_to_estree, import_unist_util_remove_position, import_remark_mdx;
1191
+ var init_remark_postprocess = __esm({
1192
+ "src/loaders/mdx/remark-postprocess.ts"() {
1193
+ "use strict";
1194
+ import_unist_util_visit3 = require("unist-util-visit");
1195
+ import_mdast_util_to_markdown = require("mdast-util-to-markdown");
1196
+ import_estree_util_value_to_estree = require("estree-util-value-to-estree");
1197
+ import_unist_util_remove_position = require("unist-util-remove-position");
1198
+ import_remark_mdx = __toESM(require("remark-mdx"), 1);
1199
+ }
797
1200
  });
798
- async function postInstall(configPath = findConfigFile(), outDir = ".source") {
799
- const config = await loadConfig(configPath, outDir, void 0, true);
800
- const outPath = import_node_path5.default.join(outDir, "index.ts");
801
- await import_promises2.default.rm(outDir, { recursive: true });
802
- await import_promises2.default.mkdir(outDir, { recursive: true });
803
- const hash = await getConfigHash(configPath);
804
- await import_promises2.default.writeFile(
805
- outPath,
806
- await generateJS(configPath, config, { relativeTo: outDir }, hash)
807
- );
808
- console.log("[MDX] types generated");
1201
+
1202
+ // src/loaders/mdx/build-mdx.ts
1203
+ async function buildMDX(cacheKey, source, options) {
1204
+ const { filePath, frontmatter, data, _compiler, ...rest } = options;
1205
+ function getProcessor(format) {
1206
+ const key = `${cacheKey}:${format}`;
1207
+ let processor = cache2.get(key);
1208
+ if (!processor) {
1209
+ processor = (0, import_mdx.createProcessor)({
1210
+ outputFormat: "program",
1211
+ ...rest,
1212
+ remarkPlugins: [
1213
+ remarkInclude,
1214
+ ...rest.remarkPlugins ?? [],
1215
+ [
1216
+ remarkPostprocess,
1217
+ {
1218
+ _format: format,
1219
+ ...options.postprocess,
1220
+ valueToExport: [
1221
+ ...options.postprocess?.valueToExport ?? [],
1222
+ "structuredData",
1223
+ "extractedReferences",
1224
+ "frontmatter",
1225
+ "lastModified",
1226
+ "_markdown",
1227
+ "_mdast"
1228
+ ]
1229
+ }
1230
+ ]
1231
+ ],
1232
+ format
1233
+ });
1234
+ cache2.set(key, processor);
1235
+ }
1236
+ return processor;
1237
+ }
1238
+ return getProcessor(
1239
+ options.format ?? (filePath.endsWith(".mdx") ? "mdx" : "md")
1240
+ ).process({
1241
+ value: source,
1242
+ path: filePath,
1243
+ data: {
1244
+ ...data,
1245
+ frontmatter,
1246
+ _compiler,
1247
+ _getProcessor: getProcessor
1248
+ }
1249
+ });
809
1250
  }
810
- var import_node_path5, import_promises2;
811
- var init_next = __esm({
812
- "src/next/index.ts"() {
1251
+ var import_mdx, cache2;
1252
+ var init_build_mdx = __esm({
1253
+ "src/loaders/mdx/build-mdx.ts"() {
813
1254
  "use strict";
814
- init_load();
815
- import_node_path5 = __toESM(require("path"), 1);
816
- import_promises2 = __toESM(require("fs/promises"), 1);
817
- init_generate();
818
- init_config();
819
- init_create();
1255
+ import_mdx = require("@mdx-js/mdx");
1256
+ init_remark_include();
1257
+ init_remark_postprocess();
1258
+ cache2 = /* @__PURE__ */ new Map();
820
1259
  }
821
1260
  });
822
1261
 
823
- // src/vite/generate-glob.ts
824
- function generateGlob(name, patterns, globOptions) {
825
- const options = {
826
- ...globOptions,
827
- query: {
828
- ...globOptions?.query,
829
- collection: name
1262
+ // src/loaders/mdx/index.ts
1263
+ function createMdxLoader(configLoader) {
1264
+ return async ({
1265
+ source: value,
1266
+ development: isDevelopment,
1267
+ query,
1268
+ compiler,
1269
+ filePath
1270
+ }) => {
1271
+ const matter = fumaMatter(value);
1272
+ const parsed = querySchema.parse(query);
1273
+ const config = await configLoader.getConfig();
1274
+ let after;
1275
+ if (!isDevelopment && config.global.experimentalBuildCache) {
1276
+ const cacheDir = config.global.experimentalBuildCache;
1277
+ const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
1278
+ const cached = await import_promises4.default.readFile(import_node_path7.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
1279
+ if (cached && cached.hash === generateCacheHash(value)) return cached;
1280
+ after = async () => {
1281
+ await import_promises4.default.mkdir(cacheDir, { recursive: true });
1282
+ await import_promises4.default.writeFile(
1283
+ import_node_path7.default.join(cacheDir, cacheKey),
1284
+ JSON.stringify({
1285
+ ...out,
1286
+ hash: generateCacheHash(value)
1287
+ })
1288
+ );
1289
+ };
1290
+ }
1291
+ const collection = parsed.collection ? config.collections.get(parsed.collection) : void 0;
1292
+ let docCollection;
1293
+ switch (collection?.type) {
1294
+ case "doc":
1295
+ docCollection = collection;
1296
+ break;
1297
+ case "docs":
1298
+ docCollection = collection.docs;
1299
+ break;
1300
+ }
1301
+ if (docCollection?.schema) {
1302
+ matter.data = await validate(
1303
+ docCollection.schema,
1304
+ matter.data,
1305
+ {
1306
+ source: value,
1307
+ path: filePath
1308
+ },
1309
+ `invalid frontmatter in ${filePath}`
1310
+ );
1311
+ }
1312
+ if (parsed.only === "frontmatter") {
1313
+ return {
1314
+ code: `export const frontmatter = ${JSON.stringify(matter.data)}`,
1315
+ map: null
1316
+ };
830
1317
  }
1318
+ const data = {};
1319
+ if (config.global.lastModifiedTime === "git") {
1320
+ data.lastModified = (await getGitTimestamp(filePath))?.getTime();
1321
+ }
1322
+ const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
1323
+ const compiled = await buildMDX(
1324
+ `${getConfigHash(config)}:${parsed.collection ?? "global"}`,
1325
+ "\n".repeat(lineOffset) + matter.content,
1326
+ {
1327
+ development: isDevelopment,
1328
+ ...docCollection?.mdxOptions ?? await config.getDefaultMDXOptions(),
1329
+ postprocess: docCollection?.postprocess,
1330
+ data,
1331
+ filePath,
1332
+ frontmatter: matter.data,
1333
+ _compiler: compiler
1334
+ }
1335
+ );
1336
+ const out = {
1337
+ code: String(compiled.value),
1338
+ map: compiled.map
1339
+ };
1340
+ await after?.();
1341
+ return out;
831
1342
  };
832
- return `import.meta.glob(${JSON.stringify(mapGlobPatterns(patterns))}, ${JSON.stringify(options, null, 2)})`;
833
1343
  }
834
- function mapGlobPatterns(patterns) {
835
- return patterns.map(enforceRelative);
1344
+ function getConfigHash(config) {
1345
+ let hash = hashes.get(config);
1346
+ if (hash) return hash;
1347
+ hash = Date.now().toString();
1348
+ hashes.set(config, hash);
1349
+ return hash;
836
1350
  }
837
- function enforceRelative(file) {
838
- if (file.startsWith("./")) return file;
839
- if (file.startsWith("/")) return `.${file}`;
840
- return `./${file}`;
1351
+ function generateCacheHash(input) {
1352
+ return (0, import_node_crypto2.createHash)("md5").update(input).digest("hex");
841
1353
  }
842
- function getGlobBase(collection) {
843
- let dir = collection.dir;
844
- if (Array.isArray(dir)) {
845
- if (dir.length !== 1)
846
- throw new Error(
847
- `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
848
- );
849
- dir = dir[0];
1354
+ function countLines(s) {
1355
+ let num = 0;
1356
+ for (const c of s) {
1357
+ if (c === "\n") num++;
850
1358
  }
851
- return enforceRelative(dir);
1359
+ return num;
852
1360
  }
853
- var init_generate_glob = __esm({
854
- "src/vite/generate-glob.ts"() {
1361
+ var import_zod, import_promises4, import_node_path7, import_node_crypto2, querySchema, cacheEntry, hashes;
1362
+ var init_mdx = __esm({
1363
+ "src/loaders/mdx/index.ts"() {
855
1364
  "use strict";
1365
+ init_fuma_matter();
1366
+ init_validation();
1367
+ init_git_timestamp();
1368
+ init_build_mdx();
1369
+ import_zod = require("zod");
1370
+ import_promises4 = __toESM(require("fs/promises"), 1);
1371
+ import_node_path7 = __toESM(require("path"), 1);
1372
+ import_node_crypto2 = require("crypto");
1373
+ querySchema = import_zod.z.object({
1374
+ only: import_zod.z.literal(["frontmatter", "all"]).default("all"),
1375
+ collection: import_zod.z.string().optional()
1376
+ }).loose();
1377
+ cacheEntry = import_zod.z.object({
1378
+ code: import_zod.z.string(),
1379
+ map: import_zod.z.any().optional(),
1380
+ hash: import_zod.z.string().optional()
1381
+ });
1382
+ hashes = /* @__PURE__ */ new WeakMap();
856
1383
  }
857
1384
  });
858
1385
 
859
- // src/vite/generate.ts
860
- function docs(name, collection) {
861
- const obj = [
862
- ident(`doc: ${doc(name, collection.docs)}`),
863
- ident(`meta: ${meta(name, collection.meta)}`)
864
- ].join(",\n");
865
- return `{
866
- ${obj}
867
- }`;
1386
+ // src/loaders/adapter.ts
1387
+ function toVite(loader) {
1388
+ return async function(file, query, value) {
1389
+ const result = await loader({
1390
+ filePath: file,
1391
+ query: (0, import_node_querystring.parse)(query),
1392
+ source: value,
1393
+ development: this.environment.mode === "dev",
1394
+ compiler: {
1395
+ addDependency: (file2) => {
1396
+ this.addWatchFile(file2);
1397
+ }
1398
+ }
1399
+ });
1400
+ return {
1401
+ code: result.code,
1402
+ map: result.map
1403
+ };
1404
+ };
868
1405
  }
869
- function doc(name, collection) {
870
- const patterns = getGlobPatterns(collection);
871
- const base = getGlobBase(collection);
872
- const docGlob = generateGlob(name, patterns, {
873
- base
1406
+ var import_node_url2, import_promises5, import_node_querystring, import_node_path8;
1407
+ var init_adapter = __esm({
1408
+ "src/loaders/adapter.ts"() {
1409
+ "use strict";
1410
+ import_node_url2 = require("url");
1411
+ import_promises5 = __toESM(require("fs/promises"), 1);
1412
+ import_node_querystring = require("querystring");
1413
+ init_validation();
1414
+ import_node_path8 = __toESM(require("path"), 1);
1415
+ }
1416
+ });
1417
+
1418
+ // src/utils/glob-import.ts
1419
+ function generateGlobImport(patterns, options) {
1420
+ let code = "{";
1421
+ const result = (0, import_tinyglobby2.globSync)(patterns, {
1422
+ cwd: options.base
874
1423
  });
875
- if (collection.async) {
876
- const headBlob = generateGlob(name, patterns, {
877
- query: {
878
- only: "frontmatter"
879
- },
880
- import: "frontmatter",
881
- base
882
- });
883
- return `create.docLazy("${name}", "${base}", ${headBlob}, ${docGlob})`;
1424
+ for (const item of result) {
1425
+ const fullPath = import_node_path9.default.join(options.base, item);
1426
+ const url = (0, import_node_url3.pathToFileURL)(fullPath);
1427
+ for (const [k, v] of Object.entries(options.query ?? {})) {
1428
+ url.searchParams.set(k, v);
1429
+ }
1430
+ let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(url.href)})`;
1431
+ if (options.import) {
1432
+ line += `.then(mod => mod[${JSON.stringify(options.import)}])`;
1433
+ }
1434
+ code += `${line}, `;
884
1435
  }
885
- return `create.doc("${name}", "${base}", ${docGlob})`;
1436
+ code += "}";
1437
+ return code;
886
1438
  }
887
- function meta(name, collection) {
888
- const patterns = getGlobPatterns(collection);
889
- const base = getGlobBase(collection);
890
- return `create.meta("${name}", "${base}", ${generateGlob(name, patterns, {
891
- import: "default",
892
- base
893
- })})`;
1439
+ var import_tinyglobby2, import_node_path9, import_node_url3;
1440
+ var init_glob_import = __esm({
1441
+ "src/utils/glob-import.ts"() {
1442
+ "use strict";
1443
+ import_tinyglobby2 = require("tinyglobby");
1444
+ import_node_path9 = __toESM(require("path"), 1);
1445
+ import_node_url3 = require("url");
1446
+ }
1447
+ });
1448
+
1449
+ // src/plugins/vite.ts
1450
+ function vite(options) {
1451
+ let config;
1452
+ return {
1453
+ config(v) {
1454
+ config = v;
1455
+ },
1456
+ emit() {
1457
+ return [
1458
+ {
1459
+ path: "index.ts",
1460
+ content: indexFile2(this.configPath, this.outDir, config, options)
1461
+ }
1462
+ ];
1463
+ }
1464
+ };
894
1465
  }
895
- function entry(configPath, config, outDir, jsExtension) {
1466
+ function indexFile2(configPath, outDir, config, options) {
1467
+ const { addJsExtension = false, runtime } = options;
896
1468
  const lines = [
897
1469
  '/// <reference types="vite/client" />',
898
1470
  `import { fromConfig } from 'fumadocs-mdx/runtime/vite';`,
899
1471
  `import type * as Config from '${toImportPath(configPath, {
900
1472
  relativeTo: outDir,
901
- jsExtension
1473
+ jsExtension: addJsExtension
902
1474
  })}';`,
903
1475
  "",
904
1476
  `export const create = fromConfig<typeof Config>();`
905
1477
  ];
1478
+ function docs(name, collection) {
1479
+ const obj = [
1480
+ ident(`doc: ${doc(name, collection.docs)}`),
1481
+ ident(`meta: ${meta(name, collection.meta)}`)
1482
+ ].join(",\n");
1483
+ return `{
1484
+ ${obj}
1485
+ }`;
1486
+ }
1487
+ function doc(name, collection) {
1488
+ const patterns = getGlobPatterns(collection);
1489
+ const base = getGlobBase(collection);
1490
+ const docGlob = generateGlob(patterns, {
1491
+ query: {
1492
+ collection: name
1493
+ },
1494
+ base
1495
+ });
1496
+ if (collection.async) {
1497
+ const headBlob = generateGlob(patterns, {
1498
+ query: {
1499
+ only: "frontmatter",
1500
+ collection: name
1501
+ },
1502
+ import: "frontmatter",
1503
+ base
1504
+ });
1505
+ return `create.docLazy("${name}", "${base}", ${headBlob}, ${docGlob})`;
1506
+ }
1507
+ return `create.doc("${name}", "${base}", ${docGlob})`;
1508
+ }
1509
+ function meta(name, collection) {
1510
+ const patterns = getGlobPatterns(collection);
1511
+ const base = getGlobBase(collection);
1512
+ return `create.meta("${name}", "${base}", ${generateGlob(patterns, {
1513
+ import: "default",
1514
+ base,
1515
+ query: {
1516
+ collection: name
1517
+ }
1518
+ })})`;
1519
+ }
1520
+ function generateGlob(patterns, options2) {
1521
+ patterns = mapGlobPatterns(patterns);
1522
+ if (runtime === "node" || runtime === "bun") {
1523
+ return generateGlobImport(patterns, options2);
1524
+ } else {
1525
+ return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(
1526
+ {
1527
+ ...options2,
1528
+ base: import_node_path10.default.relative(outDir, options2.base)
1529
+ },
1530
+ null,
1531
+ 2
1532
+ )})`;
1533
+ }
1534
+ }
906
1535
  for (const [name, collection] of config.collections.entries()) {
907
1536
  let body;
908
1537
  if (collection.type === "docs") {
@@ -917,55 +1546,183 @@ function entry(configPath, config, outDir, jsExtension) {
917
1546
  }
918
1547
  return lines.join("\n");
919
1548
  }
920
- var init_generate2 = __esm({
921
- "src/vite/generate.ts"() {
1549
+ function mapGlobPatterns(patterns) {
1550
+ return patterns.map(enforceRelative);
1551
+ }
1552
+ function enforceRelative(file) {
1553
+ if (file.startsWith("./")) return file;
1554
+ if (file.startsWith("/")) return `.${file}`;
1555
+ return `./${file}`;
1556
+ }
1557
+ function getGlobBase(collection) {
1558
+ let dir = collection.dir;
1559
+ if (Array.isArray(dir)) {
1560
+ if (dir.length !== 1)
1561
+ throw new Error(
1562
+ `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
1563
+ );
1564
+ dir = dir[0];
1565
+ }
1566
+ return enforceRelative(dir);
1567
+ }
1568
+ var import_node_path10;
1569
+ var init_vite = __esm({
1570
+ "src/plugins/vite.ts"() {
922
1571
  "use strict";
923
1572
  init_import_formatter();
924
- init_generate_glob();
925
1573
  init_collections();
1574
+ init_glob_import();
1575
+ import_node_path10 = __toESM(require("path"), 1);
926
1576
  }
927
1577
  });
928
1578
 
929
- // src/vite/postinstall.ts
930
- var postinstall_exports = {};
931
- __export(postinstall_exports, {
1579
+ // src/vite/index.ts
1580
+ var vite_exports = {};
1581
+ __export(vite_exports, {
1582
+ default: () => mdx,
932
1583
  postInstall: () => postInstall2
933
1584
  });
934
- async function postInstall2(configPath = findConfigFile(), outDir, addJsExtension = false) {
935
- const config = await loadConfig(configPath, "node_modules", void 0, true);
936
- const outFile = "source.generated.ts";
937
- if (outDir) {
938
- await import_promises3.default.mkdir(outDir, { recursive: true });
939
- }
940
- await import_promises3.default.writeFile(
941
- outDir ? import_node_path6.default.join(outDir, outFile) : outFile,
942
- entry(configPath, config, outDir ?? process.cwd(), addJsExtension)
1585
+ async function mdx(config, pluginOptions = {}) {
1586
+ const options = applyDefaults2(pluginOptions);
1587
+ const core = await createViteCore(options).init({
1588
+ config: buildConfig(config)
1589
+ });
1590
+ const mdxLoader = toVite(createMdxLoader(core.creatConfigLoader()));
1591
+ async function transformMeta(path16, query, value) {
1592
+ const isJson = path16.endsWith(".json");
1593
+ const parsed = (0, import_node_querystring2.parse)(query);
1594
+ const collection = parsed.collection ? core.getConfig().collections.get(parsed.collection) : void 0;
1595
+ if (!collection) return null;
1596
+ let schema;
1597
+ switch (collection.type) {
1598
+ case "meta":
1599
+ schema = collection.schema;
1600
+ break;
1601
+ case "docs":
1602
+ schema = collection.meta.schema;
1603
+ break;
1604
+ }
1605
+ if (!schema) return null;
1606
+ let data;
1607
+ try {
1608
+ data = isJson ? JSON.parse(value) : (0, import_js_yaml3.load)(value);
1609
+ } catch {
1610
+ return null;
1611
+ }
1612
+ const out = await validate(
1613
+ schema,
1614
+ data,
1615
+ { path: path16, source: value },
1616
+ `invalid data in ${path16}`
1617
+ );
1618
+ return {
1619
+ code: isJson ? JSON.stringify(out) : `export default ${JSON.stringify(out)}`,
1620
+ map: null
1621
+ };
1622
+ }
1623
+ return {
1624
+ name: "fumadocs-mdx",
1625
+ // needed, otherwise other plugins will be executed before our `transform`.
1626
+ enforce: "pre",
1627
+ config(config2) {
1628
+ if (!options.updateViteConfig) return config2;
1629
+ return (0, import_vite.mergeConfig)(config2, {
1630
+ optimizeDeps: {
1631
+ exclude: FumadocsDeps
1632
+ },
1633
+ resolve: {
1634
+ noExternal: FumadocsDeps,
1635
+ dedupe: FumadocsDeps
1636
+ }
1637
+ });
1638
+ },
1639
+ async buildStart() {
1640
+ await core.emitAndWrite();
1641
+ },
1642
+ async configureServer(server) {
1643
+ await core.initServer({
1644
+ watcher: server.watcher
1645
+ });
1646
+ },
1647
+ async transform(value, id) {
1648
+ const [file, query = ""] = id.split("?");
1649
+ const ext = path15.extname(file);
1650
+ try {
1651
+ if ([".yaml", ".json"].includes(ext))
1652
+ return await transformMeta(file, query, value);
1653
+ if ([".md", ".mdx"].includes(ext))
1654
+ return await mdxLoader.call(this, file, query, value);
1655
+ } catch (e) {
1656
+ if (e instanceof ValidationError) {
1657
+ throw new Error(e.toStringFormatted());
1658
+ }
1659
+ throw e;
1660
+ }
1661
+ }
1662
+ };
1663
+ }
1664
+ async function postInstall2(configPath = findConfigFile(), pluginOptions = {}) {
1665
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load(), load_exports));
1666
+ const options = applyDefaults2(pluginOptions);
1667
+ const core = await createViteCore(options).init({
1668
+ config: loadConfig2(configPath, options.outDir, true)
1669
+ });
1670
+ await core.emitAndWrite();
1671
+ }
1672
+ function createViteCore({
1673
+ configPath,
1674
+ outDir,
1675
+ generateIndexFile
1676
+ }) {
1677
+ return createCore(
1678
+ {
1679
+ environment: "vite",
1680
+ configPath,
1681
+ outDir
1682
+ },
1683
+ [
1684
+ generateIndexFile !== false && vite(typeof generateIndexFile === "object" ? generateIndexFile : {})
1685
+ ]
943
1686
  );
944
- console.log("[MDX] types generated");
945
1687
  }
946
- var import_promises3, import_node_path6;
947
- var init_postinstall = __esm({
948
- "src/vite/postinstall.ts"() {
1688
+ function applyDefaults2(options) {
1689
+ return {
1690
+ updateViteConfig: options.updateViteConfig ?? true,
1691
+ generateIndexFile: options.generateIndexFile ?? true,
1692
+ configPath: options.configPath ?? "source.config.ts",
1693
+ outDir: options.outDir ?? ".source"
1694
+ };
1695
+ }
1696
+ var import_vite, import_node_querystring2, path15, import_js_yaml3, FumadocsDeps;
1697
+ var init_vite2 = __esm({
1698
+ "src/vite/index.ts"() {
949
1699
  "use strict";
950
- init_load();
951
- import_promises3 = __toESM(require("fs/promises"), 1);
952
- import_node_path6 = __toESM(require("path"), 1);
953
- init_generate2();
1700
+ import_vite = require("vite");
1701
+ init_build();
1702
+ import_node_querystring2 = require("querystring");
1703
+ init_validation();
1704
+ path15 = __toESM(require("path"), 1);
1705
+ import_js_yaml3 = require("js-yaml");
1706
+ init_mdx();
954
1707
  init_config();
1708
+ init_adapter();
1709
+ init_vite();
1710
+ init_core();
1711
+ FumadocsDeps = ["fumadocs-core", "fumadocs-ui", "fumadocs-openapi"];
955
1712
  }
956
1713
  });
957
1714
 
958
1715
  // src/bin.ts
959
- var import_node_fs2 = require("fs");
960
- async function start2() {
961
- const args = process.argv.slice(2);
962
- const isNext = (0, import_node_fs2.existsSync)("next.config.js") || (0, import_node_fs2.existsSync)("next.config.mjs") || (0, import_node_fs2.existsSync)("next.config.ts");
1716
+ var import_node_fs = require("fs");
1717
+ async function start() {
1718
+ const [configPath] = process.argv.slice(2);
1719
+ const isNext = (0, import_node_fs.existsSync)("next.config.js") || (0, import_node_fs.existsSync)("next.config.mjs") || (0, import_node_fs.existsSync)("next.config.ts");
963
1720
  if (isNext) {
964
- const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_next(), next_exports));
965
- await postInstall3(...args);
1721
+ const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_next2(), next_exports));
1722
+ await postInstall3(configPath);
966
1723
  } else {
967
- const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_postinstall(), postinstall_exports));
968
- await postInstall3(...args);
1724
+ const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_vite2(), vite_exports));
1725
+ await postInstall3(configPath);
969
1726
  }
970
1727
  }
971
- void start2();
1728
+ void start();