fumadocs-mdx 13.0.8 → 14.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 (111) hide show
  1. package/dist/bin.cjs +985 -893
  2. package/dist/bin.js +3 -3
  3. package/dist/build-mdx-6UAK5FF5.js +8 -0
  4. package/dist/bun/index.cjs +613 -471
  5. package/dist/bun/index.d.cts +9 -2
  6. package/dist/bun/index.d.ts +9 -2
  7. package/dist/bun/index.js +15 -14
  8. package/dist/chunk-4JSFLXXT.js +8 -0
  9. package/dist/chunk-5OBUOALK.js +141 -0
  10. package/dist/{chunk-2E2JCOSO.js → chunk-6NISOLQ6.js} +16 -44
  11. package/dist/chunk-7UKSZSPY.js +331 -0
  12. package/dist/chunk-BEBCWQC7.js +224 -0
  13. package/dist/chunk-E5DJTSIM.js +86 -0
  14. package/dist/{chunk-K5ZLPEIQ.js → chunk-FBLMK4RS.js} +9 -6
  15. package/dist/chunk-IQGEFL2B.js +17 -0
  16. package/dist/{chunk-5FTSWCB4.js → chunk-K6HCOGOX.js} +9 -11
  17. package/dist/{chunk-QXHN25N3.js → chunk-MTTISKQJ.js} +6 -6
  18. package/dist/{chunk-3J3WL7WN.js → chunk-SLY7WXTX.js} +71 -58
  19. package/dist/chunk-TYJDYTKH.js +85 -0
  20. package/dist/chunk-WBIHDYMN.js +126 -0
  21. package/dist/{chunk-2HXTGJBI.js → chunk-ZY6UZ7NH.js} +22 -19
  22. package/dist/config/index.cjs +79 -71
  23. package/dist/config/index.d.cts +7 -1
  24. package/dist/config/index.d.ts +7 -1
  25. package/dist/config/index.js +5 -5
  26. package/dist/core-B9ZoS6sA.d.ts +341 -0
  27. package/dist/core-DTuP23zu.d.cts +341 -0
  28. package/dist/index-BD8Woo4m.d.cts +8 -0
  29. package/dist/index-CNOvhtOn.d.ts +8 -0
  30. package/dist/index.d.cts +38 -56
  31. package/dist/index.d.ts +38 -56
  32. package/dist/load-from-file-5HUQN36V.js +8 -0
  33. package/dist/next/index.cjs +763 -473
  34. package/dist/next/index.d.cts +16 -1
  35. package/dist/next/index.d.ts +16 -1
  36. package/dist/next/index.js +80 -281
  37. package/dist/node/loader.cjs +764 -627
  38. package/dist/node/loader.js +10 -11
  39. package/dist/plugins/index-file.cjs +495 -0
  40. package/dist/plugins/index-file.d.cts +14 -0
  41. package/dist/plugins/index-file.d.ts +14 -0
  42. package/dist/plugins/index-file.js +8 -0
  43. package/dist/plugins/json-schema.d.cts +9 -2
  44. package/dist/plugins/json-schema.d.ts +9 -2
  45. package/dist/plugins/last-modified.cjs +110 -0
  46. package/dist/plugins/last-modified.d.cts +37 -0
  47. package/dist/plugins/last-modified.d.ts +37 -0
  48. package/dist/plugins/last-modified.js +74 -0
  49. package/dist/runtime/browser.cjs +93 -0
  50. package/dist/runtime/browser.d.cts +53 -0
  51. package/dist/runtime/browser.d.ts +53 -0
  52. package/dist/runtime/browser.js +67 -0
  53. package/dist/runtime/dynamic.cjs +1023 -0
  54. package/dist/runtime/dynamic.d.cts +27 -0
  55. package/dist/runtime/dynamic.d.ts +27 -0
  56. package/dist/runtime/dynamic.js +79 -0
  57. package/dist/runtime/server.cjs +176 -0
  58. package/dist/runtime/server.d.cts +14 -0
  59. package/dist/runtime/server.d.ts +14 -0
  60. package/dist/runtime/server.js +8 -0
  61. package/dist/runtime/types.cjs +18 -0
  62. package/dist/runtime/types.d.cts +61 -0
  63. package/dist/runtime/types.d.ts +61 -0
  64. package/dist/runtime/types.js +0 -0
  65. package/dist/vite/index.cjs +984 -621
  66. package/dist/vite/index.d.cts +17 -22
  67. package/dist/vite/index.d.ts +17 -22
  68. package/dist/vite/index.js +32 -222
  69. package/dist/webpack/mdx.cjs +647 -514
  70. package/dist/webpack/mdx.d.cts +15 -1
  71. package/dist/webpack/mdx.d.ts +15 -1
  72. package/dist/webpack/mdx.js +12 -17
  73. package/dist/webpack/meta.cjs +360 -231
  74. package/dist/webpack/meta.d.cts +15 -1
  75. package/dist/webpack/meta.d.ts +15 -1
  76. package/dist/webpack/meta.js +13 -15
  77. package/package.json +15 -32
  78. package/dist/build-mdx-BjXOmv0b.d.cts +0 -53
  79. package/dist/build-mdx-CY5UldCO.d.ts +0 -53
  80. package/dist/chunk-2AQRQXSO.js +0 -119
  81. package/dist/chunk-CXA4JO4Z.js +0 -45
  82. package/dist/chunk-DMJ6I4C3.js +0 -76
  83. package/dist/chunk-FSZMKRVH.js +0 -80
  84. package/dist/chunk-II3H5ZVZ.js +0 -77
  85. package/dist/chunk-KILFIBVW.js +0 -75
  86. package/dist/chunk-NVRDCY6Z.js +0 -30
  87. package/dist/chunk-VUEZTR2H.js +0 -26
  88. package/dist/core-DB7TdlyC.d.cts +0 -234
  89. package/dist/core-DB7TdlyC.d.ts +0 -234
  90. package/dist/index-D7s7kCc2.d.cts +0 -7
  91. package/dist/index-D7s7kCc2.d.ts +0 -7
  92. package/dist/load-from-file-AVYOFOI7.js +0 -7
  93. package/dist/preset-ZMP6U62C.js +0 -6
  94. package/dist/runtime/next/async.cjs +0 -760
  95. package/dist/runtime/next/async.d.cts +0 -19
  96. package/dist/runtime/next/async.d.ts +0 -19
  97. package/dist/runtime/next/async.js +0 -86
  98. package/dist/runtime/next/index.cjs +0 -136
  99. package/dist/runtime/next/index.d.cts +0 -33
  100. package/dist/runtime/next/index.d.ts +0 -33
  101. package/dist/runtime/next/index.js +0 -11
  102. package/dist/runtime/vite/browser.cjs +0 -107
  103. package/dist/runtime/vite/browser.d.cts +0 -59
  104. package/dist/runtime/vite/browser.d.ts +0 -59
  105. package/dist/runtime/vite/browser.js +0 -11
  106. package/dist/runtime/vite/server.cjs +0 -243
  107. package/dist/runtime/vite/server.d.cts +0 -30
  108. package/dist/runtime/vite/server.d.ts +0 -30
  109. package/dist/runtime/vite/server.js +0 -111
  110. package/dist/types-Bnh9n7mj.d.cts +0 -45
  111. package/dist/types-ey1AZqrg.d.ts +0 -45
@@ -30,11 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/loaders/mdx/preset.ts
34
- var preset_exports = {};
35
- __export(preset_exports, {
36
- getDefaultMDXOptions: () => getDefaultMDXOptions
37
- });
33
+ // src/config/preset.ts
38
34
  function pluginOption(def, options = []) {
39
35
  const list = def(Array.isArray(options) ? options : []).filter(
40
36
  Boolean
@@ -44,76 +40,81 @@ function pluginOption(def, options = []) {
44
40
  }
45
41
  return list;
46
42
  }
47
- function getDefaultMDXOptions({
48
- valueToExport = [],
49
- rehypeCodeOptions,
50
- remarkImageOptions,
51
- remarkHeadingOptions,
52
- remarkStructureOptions,
53
- remarkCodeTabOptions,
54
- remarkNpmOptions,
55
- _withoutBundler = false,
56
- ...mdxOptions
57
- }) {
58
- const remarkPlugins = pluginOption(
59
- (v) => [
60
- plugins.remarkGfm,
61
- [
62
- plugins.remarkHeading,
63
- {
64
- generateToc: false,
65
- ...remarkHeadingOptions
66
- }
67
- ],
68
- remarkImageOptions !== false && [
69
- plugins.remarkImage,
70
- {
71
- ...remarkImageOptions,
72
- useImport: _withoutBundler ? false : remarkImageOptions?.useImport
73
- }
74
- ],
75
- "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
76
- plugins.remarkCodeTab,
77
- remarkCodeTabOptions
43
+ function applyMdxPreset(options = {}) {
44
+ return async (environment = "bundler") => {
45
+ if (options.preset === "minimal") return options;
46
+ const plugins = await import("fumadocs-core/mdx-plugins");
47
+ const {
48
+ valueToExport = [],
49
+ rehypeCodeOptions,
50
+ remarkImageOptions,
51
+ remarkHeadingOptions,
52
+ remarkStructureOptions,
53
+ remarkCodeTabOptions,
54
+ remarkNpmOptions,
55
+ ...mdxOptions
56
+ } = options;
57
+ const remarkPlugins = pluginOption(
58
+ (v) => [
59
+ plugins.remarkGfm,
60
+ [
61
+ plugins.remarkHeading,
62
+ {
63
+ generateToc: false,
64
+ ...remarkHeadingOptions
65
+ }
66
+ ],
67
+ remarkImageOptions !== false && [
68
+ plugins.remarkImage,
69
+ {
70
+ ...remarkImageOptions,
71
+ useImport: remarkImageOptions?.useImport ?? environment === "bundler"
72
+ }
73
+ ],
74
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
75
+ plugins.remarkCodeTab,
76
+ remarkCodeTabOptions
77
+ ],
78
+ "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
79
+ ...v,
80
+ remarkStructureOptions !== false && [
81
+ plugins.remarkStructure,
82
+ remarkStructureOptions
83
+ ],
84
+ valueToExport.length > 0 && (() => {
85
+ return (_, file) => {
86
+ file.data["mdx-export"] ??= [];
87
+ for (const name of valueToExport) {
88
+ if (!(name in file.data)) continue;
89
+ file.data["mdx-export"].push({
90
+ name,
91
+ value: file.data[name]
92
+ });
93
+ }
94
+ };
95
+ })
78
96
  ],
79
- "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
80
- ...v,
81
- remarkStructureOptions !== false && [
82
- plugins.remarkStructure,
83
- remarkStructureOptions
97
+ mdxOptions.remarkPlugins
98
+ );
99
+ const rehypePlugins = pluginOption(
100
+ (v) => [
101
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
102
+ ...v,
103
+ plugins.rehypeToc
84
104
  ],
85
- () => {
86
- return (_, file) => {
87
- file.data["mdx-export"] ??= [];
88
- for (const name of valueToExport) {
89
- if (name in file.data)
90
- file.data["mdx-export"].push({ name, value: file.data[name] });
91
- }
92
- };
93
- }
94
- ],
95
- mdxOptions.remarkPlugins
96
- );
97
- const rehypePlugins = pluginOption(
98
- (v) => [
99
- rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
100
- ...v,
101
- plugins.rehypeToc
102
- ],
103
- mdxOptions.rehypePlugins
104
- );
105
- return {
106
- ...mdxOptions,
107
- outputFormat: _withoutBundler ? "function-body" : mdxOptions.outputFormat,
108
- remarkPlugins,
109
- rehypePlugins
105
+ mdxOptions.rehypePlugins
106
+ );
107
+ return {
108
+ ...mdxOptions,
109
+ outputFormat: environment === "runtime" ? "function-body" : mdxOptions.outputFormat,
110
+ remarkPlugins,
111
+ rehypePlugins
112
+ };
110
113
  };
111
114
  }
112
- var plugins;
113
115
  var init_preset = __esm({
114
- "src/loaders/mdx/preset.ts"() {
116
+ "src/config/preset.ts"() {
115
117
  "use strict";
116
- plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
117
118
  }
118
119
  });
119
120
 
@@ -124,7 +125,10 @@ function buildCollection(name, config) {
124
125
  ...config,
125
126
  name,
126
127
  meta: buildPrimitiveCollection(name, config.meta),
127
- docs: buildPrimitiveCollection(name, config.docs)
128
+ docs: buildPrimitiveCollection(name, config.docs),
129
+ hasFile(filePath) {
130
+ return this.docs.hasFile(filePath) || this.meta.hasFile(filePath);
131
+ }
128
132
  };
129
133
  }
130
134
  return buildPrimitiveCollection(name, config);
@@ -178,11 +182,6 @@ function buildConfig(config) {
178
182
  `Unknown export "${k}", you can only export collections from source configuration file.`
179
183
  );
180
184
  }
181
- if (loaded.collections) {
182
- for (const [k, v] of Object.entries(loaded.collections)) {
183
- collections.set(k, buildCollection(k, v));
184
- }
185
- }
186
185
  const mdxOptionsCache = /* @__PURE__ */ new Map();
187
186
  return {
188
187
  global: loaded,
@@ -190,21 +189,22 @@ function buildConfig(config) {
190
189
  getCollection(name) {
191
190
  return collections.get(name);
192
191
  },
193
- async getDefaultMDXOptions(mode = "default") {
194
- const cached = mdxOptionsCache.get(mode);
192
+ getMDXOptions(collection, environment = "bundler") {
193
+ const key = collection ? `${environment}:${collection.name}` : environment;
194
+ const cached = mdxOptionsCache.get(key);
195
195
  if (cached) return cached;
196
- const input = this.global.mdxOptions;
197
- async function uncached() {
198
- const options = typeof input === "function" ? await input() : input;
199
- const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_preset(), preset_exports));
200
- if (options?.preset === "minimal") return options;
201
- return getDefaultMDXOptions2({
202
- ...options,
203
- _withoutBundler: mode === "remote"
204
- });
196
+ let result;
197
+ if (collection?.mdxOptions) {
198
+ const optionsFn = collection.mdxOptions;
199
+ result = typeof optionsFn === "function" ? optionsFn(environment) : optionsFn;
200
+ } else {
201
+ result = (async () => {
202
+ const optionsFn = this.global.mdxOptions;
203
+ const options = typeof optionsFn === "function" ? await optionsFn() : optionsFn;
204
+ return applyMdxPreset(options)(environment);
205
+ })();
205
206
  }
206
- const result = uncached();
207
- mdxOptionsCache.set(mode, result);
207
+ mdxOptionsCache.set(key, result);
208
208
  return result;
209
209
  }
210
210
  };
@@ -214,6 +214,7 @@ var init_build = __esm({
214
214
  "src/config/build.ts"() {
215
215
  "use strict";
216
216
  import_picomatch = __toESM(require("picomatch"), 1);
217
+ init_preset();
217
218
  SupportedFormats = {
218
219
  doc: ["mdx", "md"],
219
220
  meta: ["json", "yaml"]
@@ -221,101 +222,7 @@ var init_build = __esm({
221
222
  }
222
223
  });
223
224
 
224
- // src/config/load-from-file.ts
225
- var load_from_file_exports = {};
226
- __export(load_from_file_exports, {
227
- loadConfig: () => loadConfig
228
- });
229
- async function compileConfig(configPath, outDir) {
230
- const { build } = await import("esbuild");
231
- const transformed = await build({
232
- entryPoints: [{ in: configPath, out: "source.config" }],
233
- bundle: true,
234
- outdir: outDir,
235
- target: "node20",
236
- write: true,
237
- platform: "node",
238
- format: "esm",
239
- packages: "external",
240
- outExtension: {
241
- ".js": ".mjs"
242
- },
243
- allowOverwrite: true
244
- });
245
- if (transformed.errors.length > 0) {
246
- throw new Error("failed to compile configuration file");
247
- }
248
- }
249
- async function loadConfig(configPath, outDir, build = false) {
250
- if (build) await compileConfig(configPath, outDir);
251
- const url = (0, import_node_url3.pathToFileURL)(path9.resolve(outDir, "source.config.mjs"));
252
- url.searchParams.set("hash", Date.now().toString());
253
- const config = import(url.href).then(
254
- (loaded) => buildConfig(loaded)
255
- );
256
- return await config;
257
- }
258
- var path9, import_node_url3;
259
- var init_load_from_file = __esm({
260
- "src/config/load-from-file.ts"() {
261
- "use strict";
262
- path9 = __toESM(require("path"), 1);
263
- import_node_url3 = require("url");
264
- init_build();
265
- }
266
- });
267
-
268
- // src/vite/index.ts
269
- var vite_exports = {};
270
- __export(vite_exports, {
271
- default: () => mdx,
272
- postInstall: () => postInstall
273
- });
274
- module.exports = __toCommonJS(vite_exports);
275
- var import_vite = require("vite");
276
- init_build();
277
-
278
- // src/utils/validation.ts
279
- var import_picocolors = __toESM(require("picocolors"), 1);
280
- var ValidationError = class extends Error {
281
- constructor(message, issues) {
282
- super(
283
- `${message}:
284
- ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
285
- );
286
- this.title = message;
287
- this.issues = issues;
288
- }
289
- toStringFormatted() {
290
- return [
291
- import_picocolors.default.bold(`[MDX] ${this.title}:`),
292
- ...this.issues.map(
293
- (issue) => import_picocolors.default.redBright(
294
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
295
- )
296
- )
297
- ].join("\n");
298
- }
299
- };
300
- async function validate(schema, data, context, errorMessage) {
301
- if (typeof schema === "function" && !("~standard" in schema)) {
302
- schema = schema(context);
303
- }
304
- if ("~standard" in schema) {
305
- const result = await schema["~standard"].validate(
306
- data
307
- );
308
- if (result.issues) {
309
- throw new ValidationError(errorMessage, result.issues);
310
- }
311
- return result.value;
312
- }
313
- return data;
314
- }
315
-
316
225
  // src/utils/fuma-matter.ts
317
- var import_js_yaml = require("js-yaml");
318
- var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
319
226
  function fumaMatter(input) {
320
227
  const output = { matter: "", data: {}, content: input };
321
228
  const match = regex.exec(input);
@@ -328,42 +235,16 @@ function fumaMatter(input) {
328
235
  output.data = loaded ?? {};
329
236
  return output;
330
237
  }
331
-
332
- // src/utils/git-timestamp.ts
333
- var import_node_path = __toESM(require("path"), 1);
334
- var import_tinyexec = require("tinyexec");
335
- var cache = /* @__PURE__ */ new Map();
336
- async function getGitTimestamp(file) {
337
- const cached = cache.get(file);
338
- if (cached) return cached;
339
- try {
340
- const out = await (0, import_tinyexec.x)(
341
- "git",
342
- ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
343
- {
344
- throwOnError: true
345
- }
346
- );
347
- const time = new Date(out.stdout);
348
- cache.set(file, time);
349
- return time;
350
- } catch {
351
- return;
238
+ var import_js_yaml, regex;
239
+ var init_fuma_matter = __esm({
240
+ "src/utils/fuma-matter.ts"() {
241
+ "use strict";
242
+ import_js_yaml = require("js-yaml");
243
+ regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
352
244
  }
353
- }
354
-
355
- // src/loaders/mdx/build-mdx.ts
356
- var import_mdx = require("@mdx-js/mdx");
357
-
358
- // src/loaders/mdx/remark-include.ts
359
- var import_unified = require("unified");
360
- var import_unist_util_visit2 = require("unist-util-visit");
361
- var path2 = __toESM(require("path"), 1);
362
- var fs = __toESM(require("fs/promises"), 1);
363
- var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
245
+ });
364
246
 
365
247
  // src/loaders/mdx/remark-unravel.ts
366
- var import_unist_util_visit = require("unist-util-visit");
367
248
  function remarkMarkAndUnravel() {
368
249
  return (tree) => {
369
250
  (0, import_unist_util_visit.visit)(tree, function(node, index, parent) {
@@ -405,15 +286,28 @@ function remarkMarkAndUnravel() {
405
286
  });
406
287
  };
407
288
  }
289
+ var import_unist_util_visit;
290
+ var init_remark_unravel = __esm({
291
+ "src/loaders/mdx/remark-unravel.ts"() {
292
+ "use strict";
293
+ import_unist_util_visit = require("unist-util-visit");
294
+ }
295
+ });
296
+
297
+ // src/loaders/mdx/mdast-utils.ts
298
+ function flattenNode(node) {
299
+ if ("children" in node)
300
+ return node.children.map((child) => flattenNode(child)).join("");
301
+ if ("value" in node) return node.value;
302
+ return "";
303
+ }
304
+ var init_mdast_utils = __esm({
305
+ "src/loaders/mdx/mdast-utils.ts"() {
306
+ "use strict";
307
+ }
308
+ });
408
309
 
409
310
  // src/loaders/mdx/remark-include.ts
410
- var ElementLikeTypes = [
411
- "mdxJsxFlowElement",
412
- "mdxJsxTextElement",
413
- "containerDirective",
414
- "textDirective",
415
- "leafDirective"
416
- ];
417
311
  function isElementLike(node) {
418
312
  return ElementLikeTypes.includes(node.type);
419
313
  }
@@ -429,12 +323,6 @@ function parseElementAttributes(element) {
429
323
  }
430
324
  return element.attributes ?? {};
431
325
  }
432
- function flattenNode(node) {
433
- if ("children" in node)
434
- return node.children.map((child) => flattenNode(child)).join("");
435
- if ("value" in node) return node.value;
436
- return "";
437
- }
438
326
  function parseSpecifier(specifier) {
439
327
  const idx = specifier.lastIndexOf("#");
440
328
  if (idx === -1) return { file: specifier };
@@ -489,7 +377,7 @@ ${e instanceof Error ? e.message : String(e)}`,
489
377
  { cause: e }
490
378
  );
491
379
  }
492
- const ext = path2.extname(file);
380
+ const ext = path.extname(file);
493
381
  data._compiler?.addDependency(file);
494
382
  if (params.lang || ext !== ".md" && ext !== ".mdx") {
495
383
  const lang = params.lang ?? ext.slice(1);
@@ -522,7 +410,7 @@ ${e instanceof Error ? e.message : String(e)}`,
522
410
  } else {
523
411
  mdast = await baseProcessor.run(mdast);
524
412
  }
525
- await update(mdast, path2.dirname(file), data);
413
+ await update(mdast, path.dirname(file), data);
526
414
  return mdast;
527
415
  };
528
416
  async function update(tree, directory, data) {
@@ -534,7 +422,7 @@ ${e instanceof Error ? e.message : String(e)}`,
534
422
  if (specifier.length === 0) return "skip";
535
423
  const attributes = parseElementAttributes(node);
536
424
  const { file: relativePath, section } = parseSpecifier(specifier);
537
- const file = path2.resolve(
425
+ const file = path.resolve(
538
426
  "cwd" in attributes ? process.cwd() : directory,
539
427
  relativePath
540
428
  );
@@ -551,62 +439,96 @@ ${e instanceof Error ? e.message : String(e)}`,
551
439
  await Promise.all(queue);
552
440
  }
553
441
  return async (tree, file) => {
554
- await update(tree, path2.dirname(file.path), file.data);
442
+ await update(tree, path.dirname(file.path), file.data);
555
443
  };
556
444
  }
445
+ var import_unified, import_unist_util_visit2, path, fs, import_mdx_plugins, ElementLikeTypes;
446
+ var init_remark_include = __esm({
447
+ "src/loaders/mdx/remark-include.ts"() {
448
+ "use strict";
449
+ import_unified = require("unified");
450
+ import_unist_util_visit2 = require("unist-util-visit");
451
+ path = __toESM(require("path"), 1);
452
+ fs = __toESM(require("fs/promises"), 1);
453
+ init_fuma_matter();
454
+ import_mdx_plugins = require("fumadocs-core/mdx-plugins");
455
+ init_remark_unravel();
456
+ init_mdast_utils();
457
+ ElementLikeTypes = [
458
+ "mdxJsxFlowElement",
459
+ "mdxJsxTextElement",
460
+ "containerDirective",
461
+ "textDirective",
462
+ "leafDirective"
463
+ ];
464
+ }
465
+ });
557
466
 
558
467
  // src/loaders/mdx/remark-postprocess.ts
559
- var import_unist_util_visit3 = require("unist-util-visit");
560
- var import_mdast_util_to_markdown = require("mdast-util-to-markdown");
561
- var import_estree_util_value_to_estree = require("estree-util-value-to-estree");
562
- var import_unist_util_remove_position = require("unist-util-remove-position");
563
- var import_remark_mdx = __toESM(require("remark-mdx"), 1);
564
468
  function remarkPostprocess({
565
469
  _format,
566
470
  includeProcessedMarkdown = false,
567
471
  includeMDAST = false,
472
+ extractLinkReferences = false,
568
473
  valueToExport = []
569
474
  }) {
570
475
  let _stringifyProcessor;
571
476
  const getStringifyProcessor = () => {
572
- if (_format === "mdx") return this;
573
- return _stringifyProcessor ??= this().use(import_remark_mdx.default).freeze();
477
+ return _stringifyProcessor ??= _format === "mdx" ? this : (
478
+ // force Markdown processor to stringify MDX nodes
479
+ this().use(import_remark_mdx.default).freeze()
480
+ );
574
481
  };
575
482
  return (tree, file) => {
576
- let title;
577
- const urls = [];
578
- (0, import_unist_util_visit3.visit)(tree, ["heading", "link"], (node) => {
579
- if (node.type === "heading" && node.depth === 1) {
580
- title = flattenNode2(node);
581
- }
582
- if (node.type !== "link") return;
583
- urls.push({
584
- href: node.url
483
+ const frontmatter = file.data.frontmatter ??= {};
484
+ if (!frontmatter.title) {
485
+ (0, import_unist_util_visit3.visit)(tree, "heading", (node) => {
486
+ if (node.depth === 1) {
487
+ frontmatter.title = flattenNode(node);
488
+ return false;
489
+ }
490
+ });
491
+ }
492
+ file.data["mdx-export"] ??= [];
493
+ if (extractLinkReferences) {
494
+ const urls = [];
495
+ (0, import_unist_util_visit3.visit)(tree, "link", (node) => {
496
+ urls.push({
497
+ href: node.url
498
+ });
499
+ return "skip";
500
+ });
501
+ file.data["mdx-export"].push({
502
+ name: "extractedReferences",
503
+ value: urls
585
504
  });
586
- return "skip";
587
- });
588
- if (title) {
589
- file.data.frontmatter ??= {};
590
- if (!file.data.frontmatter.title) file.data.frontmatter.title = title;
591
505
  }
592
- file.data.extractedReferences = urls;
593
506
  if (includeProcessedMarkdown) {
594
507
  const processor = getStringifyProcessor();
595
- file.data._markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
508
+ const markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
596
509
  ...processor.data("settings"),
597
510
  // from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
598
511
  extensions: processor.data("toMarkdownExtensions") || []
599
512
  });
513
+ file.data["mdx-export"].push({
514
+ name: "_markdown",
515
+ value: markdown
516
+ });
600
517
  }
601
518
  if (includeMDAST) {
602
519
  const options = includeMDAST === true ? {} : includeMDAST;
603
- file.data._mdast = JSON.stringify(
520
+ const mdast = JSON.stringify(
604
521
  options.removePosition ? (0, import_unist_util_remove_position.removePosition)(structuredClone(tree)) : tree
605
522
  );
523
+ file.data["mdx-export"].push({
524
+ name: "_mdast",
525
+ value: mdast
526
+ });
606
527
  }
607
- for (const { name, value } of file.data["mdx-export"] ?? []) {
528
+ for (const { name, value } of file.data["mdx-export"]) {
608
529
  tree.children.unshift(getMdastExport(name, value));
609
530
  }
531
+ file.data["mdx-export"] = [];
610
532
  for (const name of valueToExport) {
611
533
  if (!(name in file.data)) continue;
612
534
  tree.children.unshift(getMdastExport(name, file.data[name]));
@@ -647,68 +569,180 @@ function getMdastExport(name, value) {
647
569
  }
648
570
  };
649
571
  }
650
- function flattenNode2(node) {
651
- if ("children" in node)
652
- return node.children.map((child) => flattenNode2(child)).join("");
653
- if ("value" in node) return node.value;
654
- return "";
655
- }
572
+ var import_unist_util_visit3, import_mdast_util_to_markdown, import_estree_util_value_to_estree, import_unist_util_remove_position, import_remark_mdx;
573
+ var init_remark_postprocess = __esm({
574
+ "src/loaders/mdx/remark-postprocess.ts"() {
575
+ "use strict";
576
+ import_unist_util_visit3 = require("unist-util-visit");
577
+ import_mdast_util_to_markdown = require("mdast-util-to-markdown");
578
+ import_estree_util_value_to_estree = require("estree-util-value-to-estree");
579
+ import_unist_util_remove_position = require("unist-util-remove-position");
580
+ import_remark_mdx = __toESM(require("remark-mdx"), 1);
581
+ init_mdast_utils();
582
+ }
583
+ });
656
584
 
657
585
  // src/loaders/mdx/build-mdx.ts
658
- var cache2 = /* @__PURE__ */ new Map();
659
- async function buildMDX(cacheKey, source, options) {
660
- const { filePath, frontmatter, data, _compiler, ...rest } = options;
586
+ var build_mdx_exports = {};
587
+ __export(build_mdx_exports, {
588
+ buildMDX: () => buildMDX
589
+ });
590
+ async function buildMDX(core, collection, {
591
+ filePath,
592
+ frontmatter,
593
+ source,
594
+ _compiler,
595
+ environment,
596
+ isDevelopment
597
+ }) {
598
+ const mdxOptions = await core.getConfig().getMDXOptions(collection, environment);
661
599
  function getProcessor(format) {
662
- const key = `${cacheKey}:${format}`;
663
- let processor = cache2.get(key);
600
+ const cache = core.cache;
601
+ const key = `build-mdx:${collection?.name ?? "global"}:${format}`;
602
+ let processor = cache.get(key);
664
603
  if (!processor) {
604
+ const postprocessOptions = {
605
+ _format: format,
606
+ ...collection?.postprocess,
607
+ valueToExport: [
608
+ ...collection?.postprocess?.valueToExport ?? [],
609
+ "structuredData",
610
+ "frontmatter"
611
+ ]
612
+ };
665
613
  processor = (0, import_mdx.createProcessor)({
666
614
  outputFormat: "program",
667
- ...rest,
615
+ development: isDevelopment,
616
+ ...mdxOptions,
668
617
  remarkPlugins: [
669
618
  remarkInclude,
670
- ...rest.remarkPlugins ?? [],
671
- [
672
- remarkPostprocess,
673
- {
674
- _format: format,
675
- ...options.postprocess,
676
- valueToExport: [
677
- ...options.postprocess?.valueToExport ?? [],
678
- "structuredData",
679
- "extractedReferences",
680
- "frontmatter",
681
- "lastModified",
682
- "_markdown",
683
- "_mdast"
684
- ]
685
- }
686
- ]
619
+ ...mdxOptions.remarkPlugins ?? [],
620
+ [remarkPostprocess, postprocessOptions]
687
621
  ],
688
622
  format
689
623
  });
690
- cache2.set(key, processor);
624
+ cache.set(key, processor);
691
625
  }
692
626
  return processor;
693
627
  }
694
- return getProcessor(
695
- options.format ?? (filePath.endsWith(".mdx") ? "mdx" : "md")
696
- ).process({
628
+ let vfile = new import_vfile.VFile({
697
629
  value: source,
698
630
  path: filePath,
699
- data: {
700
- ...data,
701
- frontmatter,
702
- _compiler,
703
- _getProcessor: getProcessor
704
- }
631
+ data: { frontmatter, _compiler, _getProcessor: getProcessor }
632
+ });
633
+ if (collection) {
634
+ vfile = await core.transformVFile({ collection, filePath, source }, vfile);
635
+ }
636
+ return getProcessor(filePath.endsWith(".mdx") ? "mdx" : "md").process(vfile);
637
+ }
638
+ var import_mdx, import_vfile;
639
+ var init_build_mdx = __esm({
640
+ "src/loaders/mdx/build-mdx.ts"() {
641
+ "use strict";
642
+ import_mdx = require("@mdx-js/mdx");
643
+ import_vfile = require("vfile");
644
+ init_remark_include();
645
+ init_remark_postprocess();
646
+ }
647
+ });
648
+
649
+ // src/config/load-from-file.ts
650
+ var load_from_file_exports = {};
651
+ __export(load_from_file_exports, {
652
+ loadConfig: () => loadConfig
653
+ });
654
+ async function compileConfig(core) {
655
+ const { build } = await import("esbuild");
656
+ const { configPath, outDir } = core.getOptions();
657
+ const transformed = await build({
658
+ entryPoints: [{ in: configPath, out: "source.config" }],
659
+ bundle: true,
660
+ outdir: outDir,
661
+ target: "node20",
662
+ write: true,
663
+ platform: "node",
664
+ format: "esm",
665
+ packages: "external",
666
+ outExtension: {
667
+ ".js": ".mjs"
668
+ },
669
+ allowOverwrite: true
705
670
  });
671
+ if (transformed.errors.length > 0) {
672
+ throw new Error("failed to compile configuration file");
673
+ }
674
+ }
675
+ async function loadConfig(core, build = false) {
676
+ if (build) await compileConfig(core);
677
+ const url = (0, import_node_url2.pathToFileURL)(core.getCompiledConfigPath());
678
+ url.searchParams.set("hash", Date.now().toString());
679
+ const config = import(url.href).then(
680
+ (loaded) => buildConfig(loaded)
681
+ );
682
+ return await config;
683
+ }
684
+ var import_node_url2;
685
+ var init_load_from_file = __esm({
686
+ "src/config/load-from-file.ts"() {
687
+ "use strict";
688
+ import_node_url2 = require("url");
689
+ init_build();
690
+ }
691
+ });
692
+
693
+ // src/vite/index.ts
694
+ var vite_exports = {};
695
+ __export(vite_exports, {
696
+ default: () => mdx,
697
+ postInstall: () => postInstall
698
+ });
699
+ module.exports = __toCommonJS(vite_exports);
700
+ var import_vite = require("vite");
701
+ init_build();
702
+
703
+ // src/utils/validation.ts
704
+ var ValidationError = class extends Error {
705
+ constructor(message, issues) {
706
+ super(
707
+ `${message}:
708
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
709
+ );
710
+ this.title = message;
711
+ this.issues = issues;
712
+ }
713
+ async toStringFormatted() {
714
+ const picocolors = await import("picocolors");
715
+ return [
716
+ picocolors.bold(`[MDX] ${this.title}:`),
717
+ ...this.issues.map(
718
+ (issue) => picocolors.redBright(
719
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
720
+ )
721
+ )
722
+ ].join("\n");
723
+ }
724
+ };
725
+ async function validate(schema, data, context, errorMessage) {
726
+ if (typeof schema === "function" && !("~standard" in schema)) {
727
+ schema = schema(context);
728
+ }
729
+ if ("~standard" in schema) {
730
+ const result = await schema["~standard"].validate(
731
+ data
732
+ );
733
+ if (result.issues) {
734
+ throw new ValidationError(errorMessage, result.issues);
735
+ }
736
+ return result.value;
737
+ }
738
+ return data;
706
739
  }
707
740
 
708
741
  // src/loaders/mdx/index.ts
742
+ init_fuma_matter();
709
743
  var import_zod = require("zod");
710
744
  var import_promises = __toESM(require("fs/promises"), 1);
711
- var import_node_path2 = __toESM(require("path"), 1);
745
+ var import_node_path = __toESM(require("path"), 1);
712
746
  var import_node_crypto = require("crypto");
713
747
 
714
748
  // src/loaders/index.ts
@@ -735,20 +769,20 @@ function createMdxLoader(configLoader) {
735
769
  compiler,
736
770
  filePath
737
771
  }) {
772
+ const config = await configLoader.getConfig();
738
773
  const value = await getSource();
739
774
  const matter = fumaMatter(value);
740
775
  const parsed = querySchema.parse(query);
741
- const config = await configLoader.getConfig();
742
776
  let after;
743
777
  if (!isDevelopment && config.global.experimentalBuildCache) {
744
778
  const cacheDir = config.global.experimentalBuildCache;
745
779
  const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
746
- const cached = await import_promises.default.readFile(import_node_path2.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
780
+ const cached = await import_promises.default.readFile(import_node_path.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
747
781
  if (cached && cached.hash === generateCacheHash(value)) return cached;
748
782
  after = async () => {
749
783
  await import_promises.default.mkdir(cacheDir, { recursive: true });
750
784
  await import_promises.default.writeFile(
751
- import_node_path2.default.join(cacheDir, cacheKey),
785
+ import_node_path.default.join(cacheDir, cacheKey),
752
786
  JSON.stringify({
753
787
  ...out,
754
788
  hash: generateCacheHash(value)
@@ -766,15 +800,10 @@ function createMdxLoader(configLoader) {
766
800
  docCollection = collection.docs;
767
801
  break;
768
802
  }
769
- if (docCollection?.schema) {
770
- matter.data = await validate(
771
- docCollection.schema,
772
- matter.data,
773
- {
774
- source: value,
775
- path: filePath
776
- },
777
- `invalid frontmatter in ${filePath}`
803
+ if (docCollection) {
804
+ matter.data = await configLoader.core.transformFrontmatter(
805
+ { collection: docCollection, filePath, source: value },
806
+ matter.data
778
807
  );
779
808
  }
780
809
  if (parsed.only === "frontmatter") {
@@ -783,24 +812,16 @@ function createMdxLoader(configLoader) {
783
812
  map: null
784
813
  };
785
814
  }
786
- const data = {};
787
- if (config.global.lastModifiedTime === "git") {
788
- data.lastModified = (await getGitTimestamp(filePath))?.getTime();
789
- }
790
815
  const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
791
- const compiled = await buildMDX(
792
- `${getConfigHash(config)}:${parsed.collection ?? "global"}`,
793
- "\n".repeat(lineOffset) + matter.content,
794
- {
795
- development: isDevelopment,
796
- ...docCollection?.mdxOptions ?? await config.getDefaultMDXOptions(),
797
- postprocess: docCollection?.postprocess,
798
- data,
799
- filePath,
800
- frontmatter: matter.data,
801
- _compiler: compiler
802
- }
803
- );
816
+ const { buildMDX: buildMDX2 } = await Promise.resolve().then(() => (init_build_mdx(), build_mdx_exports));
817
+ const compiled = await buildMDX2(configLoader.core, docCollection, {
818
+ isDevelopment,
819
+ source: "\n".repeat(lineOffset) + matter.content,
820
+ filePath,
821
+ frontmatter: matter.data,
822
+ _compiler: compiler,
823
+ environment: "bundler"
824
+ });
804
825
  const out = {
805
826
  code: String(compiled.value),
806
827
  map: compiled.map
@@ -810,14 +831,6 @@ function createMdxLoader(configLoader) {
810
831
  }
811
832
  };
812
833
  }
813
- var hashes = /* @__PURE__ */ new WeakMap();
814
- function getConfigHash(config) {
815
- let hash = hashes.get(config);
816
- if (hash) return hash;
817
- hash = Date.now().toString();
818
- hashes.set(config, hash);
819
- return hash;
820
- }
821
834
  function generateCacheHash(input) {
822
835
  return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
823
836
  }
@@ -833,7 +846,7 @@ function countLines(s) {
833
846
  var import_node_url = require("url");
834
847
  var import_promises2 = __toESM(require("fs/promises"), 1);
835
848
  var import_node_querystring = require("querystring");
836
- var import_node_path3 = __toESM(require("path"), 1);
849
+ var import_node_path2 = __toESM(require("path"), 1);
837
850
  var import_node_fs = require("fs");
838
851
  function toVite(loader) {
839
852
  return {
@@ -864,240 +877,165 @@ function toVite(loader) {
864
877
  };
865
878
  }
866
879
 
867
- // src/utils/import-formatter.ts
880
+ // src/core.ts
868
881
  var import_node_path4 = __toESM(require("path"), 1);
869
- function toImportPath(file, config) {
870
- const ext = import_node_path4.default.extname(file);
871
- let filename;
872
- if (ext === ".ts" && config.jsExtension) {
873
- filename = file.substring(0, file.length - ext.length) + ".js";
874
- } else if (ext === ".ts") {
875
- filename = file.substring(0, file.length - ext.length);
876
- } else {
877
- filename = file;
878
- }
879
- let importPath;
880
- if ("relativeTo" in config) {
881
- importPath = import_node_path4.default.relative(config.relativeTo, filename);
882
- if (!import_node_path4.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
883
- importPath = `./${importPath}`;
884
- }
885
- } else {
886
- importPath = import_node_path4.default.resolve(filename);
887
- }
888
- return importPath.replaceAll(import_node_path4.default.sep, "/");
889
- }
890
- function ident(code, tab = 1) {
891
- return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
892
- }
882
+ var import_promises3 = __toESM(require("fs/promises"), 1);
893
883
 
894
- // src/utils/glob-import.ts
884
+ // src/utils/codegen.ts
885
+ var import_node_path3 = __toESM(require("path"), 1);
895
886
  var import_tinyglobby = require("tinyglobby");
896
- var import_node_path5 = __toESM(require("path"), 1);
897
- var import_node_url2 = require("url");
898
- function generateGlobImport(patterns, options) {
899
- let code = "{";
900
- const result = (0, import_tinyglobby.globSync)(patterns, {
901
- cwd: options.base
902
- });
903
- for (const item of result) {
904
- const fullPath = import_node_path5.default.join(options.base, item);
905
- const url = (0, import_node_url2.pathToFileURL)(fullPath);
906
- for (const [k, v] of Object.entries(options.query ?? {})) {
907
- url.searchParams.set(k, v);
908
- }
909
- let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(url.href)})`;
910
- if (options.import) {
911
- line += `.then(mod => mod[${JSON.stringify(options.import)}])`;
912
- }
913
- code += `${line}, `;
914
- }
915
- code += "}";
916
- return code;
917
- }
918
-
919
- // src/plugins/vite.ts
920
- var import_node_path6 = __toESM(require("path"), 1);
921
- function vite({
922
- index
887
+ function createCodegen({
888
+ target = "default",
889
+ outDir = "",
890
+ jsExtension = false,
891
+ globCache = /* @__PURE__ */ new Map()
923
892
  }) {
924
- let config;
925
- let indexOptions;
926
- if (index === false) indexOptions = false;
927
- else indexOptions = applyDefaults(index === true ? {} : index);
893
+ let eagerImportId = 0;
894
+ const banner = ["// @ts-nocheck"];
895
+ if (target === "vite") {
896
+ banner.push('/// <reference types="vite/client" />');
897
+ }
928
898
  return {
929
- name: "vite",
930
- config(v) {
931
- config = v;
899
+ options: {
900
+ target,
901
+ outDir
932
902
  },
933
- configureServer(server) {
934
- if (!server.watcher || indexOptions === false || indexOptions.runtime === false)
935
- return;
936
- server.watcher.on("all", (event, file) => {
937
- if (event === "change") return;
938
- const isUpdated = config.collectionList.some((collection) => {
939
- if (collection.type === "docs")
940
- return collection.docs.hasFile(file) || collection.meta.hasFile(file);
941
- return collection.hasFile(file);
942
- });
943
- if (isUpdated) {
944
- this.core.emitAndWrite({
945
- filterPlugin: (plugin) => plugin.name === "vite"
946
- });
947
- }
948
- });
903
+ lines: [],
904
+ addImport(statement) {
905
+ this.lines.unshift(statement);
949
906
  },
950
- emit() {
951
- const out = [];
952
- if (indexOptions === false) return out;
953
- if (indexOptions.browser) {
954
- out.push({
955
- path: "browser.ts",
956
- content: indexFile(this, config, indexOptions, "browser")
957
- });
958
- }
959
- out.push({
960
- path: "index.ts",
961
- content: indexFile(
962
- this,
963
- config,
964
- indexOptions,
965
- indexOptions.browser ? "server" : "all"
966
- )
967
- });
968
- return out;
969
- }
970
- };
971
- }
972
- function applyDefaults(options) {
973
- return {
974
- addJsExtension: options.addJsExtension ?? false,
975
- browser: options.browser ?? false,
976
- runtime: options.runtime ?? false
977
- };
978
- }
979
- function indexFile({ configPath, outDir }, config, { addJsExtension, runtime }, environment) {
980
- const runtimePath = {
981
- all: "fumadocs-mdx/runtime/vite",
982
- server: "fumadocs-mdx/runtime/vite.server",
983
- browser: "fumadocs-mdx/runtime/vite.browser"
984
- }[environment];
985
- const lines = [
986
- '/// <reference types="vite/client" />',
987
- `import { fromConfig } from '${runtimePath}';`,
988
- `import type * as Config from '${toImportPath(configPath, {
989
- relativeTo: outDir,
990
- jsExtension: addJsExtension
991
- })}';`,
992
- "",
993
- `export const create = fromConfig<typeof Config>();`
994
- ];
995
- function generateCollectionGlob(collection) {
996
- if (collection.type === "docs") {
997
- const obj = [
998
- ident(`doc: ${generateCollectionGlob(collection.docs)}`),
999
- ident(`meta: ${generateCollectionGlob(collection.meta)}`)
1000
- ].join(",\n");
1001
- return `{
1002
- ${obj}
1003
- }`;
1004
- }
1005
- const dir = getCollectionDir(collection);
1006
- if (collection.type === "doc") {
1007
- const docGlob = generateGlob(collection.patterns, {
1008
- query: {
1009
- collection: collection.name
1010
- },
1011
- base: dir
1012
- });
1013
- if (collection.async) {
1014
- const headBlob = generateGlob(collection.patterns, {
1015
- query: {
1016
- only: "frontmatter",
1017
- collection: collection.name
1018
- },
1019
- import: "frontmatter",
1020
- base: dir
1021
- });
1022
- return `create.docLazy("${collection.name}", "${dir}", ${headBlob}, ${docGlob})`;
907
+ async pushAsync(insert) {
908
+ for (const line of await Promise.all(insert)) {
909
+ if (line === void 0) continue;
910
+ this.lines.push(line);
1023
911
  }
1024
- return `create.doc("${collection.name}", "${dir}", ${docGlob})`;
1025
- }
1026
- return `create.meta("${collection.name}", "${dir}", ${generateGlob(
1027
- collection.patterns,
1028
- {
1029
- import: "default",
1030
- base: dir,
1031
- query: {
1032
- collection: collection.name
1033
- }
912
+ },
913
+ async generateGlobImport(patterns, options) {
914
+ if (target === "vite") {
915
+ return this.generateViteGlobImport(patterns, options);
1034
916
  }
1035
- )})`;
1036
- }
1037
- function generateGlob(patterns, options) {
1038
- patterns = patterns.map(normalizeGlobPath);
1039
- if (runtime === "node" || runtime === "bun") {
1040
- return generateGlobImport(patterns, options);
1041
- } else {
917
+ return this.generateNodeGlobImport(patterns, options);
918
+ },
919
+ generateViteGlobImport(patterns, { base, ...rest }) {
920
+ patterns = (typeof patterns === "string" ? [patterns] : patterns).map(
921
+ normalizeViteGlobPath
922
+ );
1042
923
  return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(
1043
924
  {
1044
- ...options,
1045
- base: normalizeGlobPath(import_node_path6.default.relative(outDir, options.base))
925
+ base: normalizeViteGlobPath(import_node_path3.default.relative(outDir, base)),
926
+ ...rest
1046
927
  },
1047
928
  null,
1048
929
  2
1049
930
  )})`;
931
+ },
932
+ async generateNodeGlobImport(patterns, {
933
+ base,
934
+ eager = false,
935
+ query = {},
936
+ import: importName
937
+ }) {
938
+ const cacheKey = JSON.stringify({ patterns, base });
939
+ let files = globCache.get(cacheKey);
940
+ if (!files) {
941
+ files = (0, import_tinyglobby.glob)(patterns, {
942
+ cwd: base
943
+ });
944
+ globCache.set(cacheKey, files);
945
+ }
946
+ let code = "{";
947
+ for (const item of await files) {
948
+ const fullPath = import_node_path3.default.join(base, item);
949
+ const searchParams = new URLSearchParams();
950
+ for (const [k, v] of Object.entries(query)) {
951
+ searchParams.set(k, v);
952
+ }
953
+ const importPath = this.formatImportPath(fullPath) + "?" + searchParams.toString();
954
+ if (eager) {
955
+ const name = `__fd_glob_${eagerImportId++}`;
956
+ this.lines.unshift(
957
+ importName ? `import { ${importName} as ${name} } from ${JSON.stringify(importPath)}` : `import * as ${name} from ${JSON.stringify(importPath)}`
958
+ );
959
+ code += `${JSON.stringify(item)}: ${name}, `;
960
+ } else {
961
+ let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(importPath)})`;
962
+ if (importName) {
963
+ line += `.then(mod => mod.${importName})`;
964
+ }
965
+ code += `${line}, `;
966
+ }
967
+ }
968
+ code += "}";
969
+ return code;
970
+ },
971
+ formatImportPath(file) {
972
+ const ext = import_node_path3.default.extname(file);
973
+ let filename;
974
+ if (ext === ".ts" && jsExtension) {
975
+ filename = file.substring(0, file.length - ext.length) + ".js";
976
+ } else if (ext === ".ts") {
977
+ filename = file.substring(0, file.length - ext.length);
978
+ } else {
979
+ filename = file;
980
+ }
981
+ const importPath = slash(import_node_path3.default.relative(outDir, filename));
982
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
983
+ },
984
+ toString() {
985
+ return [...banner, ...this.lines].join("\n");
1050
986
  }
1051
- }
1052
- for (const collection of config.collectionList) {
1053
- lines.push("");
1054
- lines.push(
1055
- `export const ${collection.name} = ${generateCollectionGlob(collection)};`
1056
- );
1057
- }
1058
- return lines.join("\n");
987
+ };
1059
988
  }
1060
- function normalizeGlobPath(file) {
989
+ function normalizeViteGlobPath(file) {
1061
990
  file = slash(file);
1062
991
  if (file.startsWith("./")) return file;
1063
992
  if (file.startsWith("/")) return `.${file}`;
1064
993
  return `./${file}`;
1065
994
  }
1066
- function getCollectionDir({ dir }) {
1067
- if (Array.isArray(dir)) {
1068
- if (dir.length !== 1)
1069
- throw new Error(
1070
- `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
1071
- );
1072
- return dir[0];
1073
- }
1074
- return dir;
1075
- }
1076
- function slash(path10) {
1077
- const isExtendedLengthPath = path10.startsWith("\\\\?\\");
995
+ function slash(path8) {
996
+ const isExtendedLengthPath = path8.startsWith("\\\\?\\");
1078
997
  if (isExtendedLengthPath) {
1079
- return path10;
998
+ return path8;
1080
999
  }
1081
- return path10.replaceAll("\\", "/");
1000
+ return path8.replaceAll("\\", "/");
1001
+ }
1002
+ function ident(code, tab = 1) {
1003
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
1082
1004
  }
1083
1005
 
1084
1006
  // src/core.ts
1085
- var import_node_path7 = __toESM(require("path"), 1);
1086
- var import_promises3 = __toESM(require("fs/promises"), 1);
1087
- function findConfigFile() {
1088
- return import_node_path7.default.resolve("source.config.ts");
1007
+ var _Defaults = {
1008
+ configPath: "source.config.ts",
1009
+ outDir: ".source"
1010
+ };
1011
+ async function getPlugins(pluginOptions) {
1012
+ const plugins = [];
1013
+ for await (const option of pluginOptions) {
1014
+ if (!option) continue;
1015
+ if (Array.isArray(option)) plugins.push(...await getPlugins(option));
1016
+ else plugins.push(option);
1017
+ }
1018
+ return plugins;
1089
1019
  }
1090
1020
  function createCore(options, defaultPlugins = []) {
1091
1021
  let config;
1092
- let plugins2;
1093
- return {
1094
- _options: options,
1095
- getPluginContext() {
1096
- return {
1097
- core: this,
1098
- ...options
1099
- };
1100
- },
1022
+ let plugins;
1023
+ async function transformMetadata({
1024
+ collection,
1025
+ filePath,
1026
+ source
1027
+ }, data) {
1028
+ if (collection.schema) {
1029
+ data = await validate(
1030
+ collection.schema,
1031
+ data,
1032
+ { path: filePath, source },
1033
+ collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`
1034
+ );
1035
+ }
1036
+ return data;
1037
+ }
1038
+ const core = {
1101
1039
  /**
1102
1040
  * Convenient cache store, reset when config changes
1103
1041
  */
@@ -1105,47 +1043,137 @@ function createCore(options, defaultPlugins = []) {
1105
1043
  async init({ config: newConfig }) {
1106
1044
  config = await newConfig;
1107
1045
  this.cache.clear();
1108
- plugins2 = [];
1109
- for await (const option of [
1046
+ plugins = await getPlugins([
1047
+ postprocessPlugin(),
1110
1048
  ...defaultPlugins,
1111
1049
  ...config.global.plugins ?? []
1112
- ]) {
1113
- if (!option) continue;
1114
- if (Array.isArray(option)) plugins2.push(...option);
1115
- else plugins2.push(option);
1116
- }
1117
- for (const plugin of plugins2) {
1118
- const out = await plugin.config?.call(this.getPluginContext(), config);
1050
+ ]);
1051
+ for (const plugin of plugins) {
1052
+ const out = await plugin.config?.call(pluginContext, config);
1119
1053
  if (out) config = out;
1120
1054
  }
1121
- return this;
1055
+ },
1056
+ getOptions() {
1057
+ return options;
1122
1058
  },
1123
1059
  getConfig() {
1124
1060
  return config;
1125
1061
  },
1062
+ /**
1063
+ * The file path of compiled config file, the file may not exist (e.g. on Vite, or still compiling)
1064
+ */
1065
+ getCompiledConfigPath() {
1066
+ return import_node_path4.default.join(options.outDir, "source.config.mjs");
1067
+ },
1068
+ getPlugins() {
1069
+ return plugins;
1070
+ },
1071
+ getPluginContext() {
1072
+ return pluginContext;
1073
+ },
1126
1074
  async initServer(server) {
1127
- for (const plugin of plugins2) {
1128
- await plugin.configureServer?.call(this.getPluginContext(), server);
1075
+ for (const plugin of plugins) {
1076
+ await plugin.configureServer?.call(pluginContext, server);
1129
1077
  }
1130
1078
  },
1131
- async emitAndWrite({
1132
- filterPlugin = () => true
1133
- } = {}) {
1134
- const start = performance.now();
1135
- const out = await Promise.all(
1136
- plugins2.map((plugin) => {
1079
+ async emit({ filterPlugin = () => true } = {}) {
1080
+ return (await Promise.all(
1081
+ plugins.map((plugin) => {
1137
1082
  if (!filterPlugin(plugin) || !plugin.emit) return [];
1138
- return plugin.emit.call(this.getPluginContext());
1083
+ return plugin.emit.call(pluginContext);
1139
1084
  })
1140
- );
1085
+ )).flat();
1086
+ },
1087
+ async emitAndWrite(emitOptions) {
1088
+ const start = performance.now();
1089
+ const out = await this.emit(emitOptions);
1141
1090
  await Promise.all(
1142
- out.flat().map(async (entry) => {
1143
- const file = import_node_path7.default.join(options.outDir, entry.path);
1144
- await import_promises3.default.mkdir(import_node_path7.default.dirname(file), { recursive: true });
1091
+ out.map(async (entry) => {
1092
+ const file = import_node_path4.default.join(options.outDir, entry.path);
1093
+ await import_promises3.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
1145
1094
  await import_promises3.default.writeFile(file, entry.content);
1146
1095
  })
1147
1096
  );
1148
1097
  console.log(`[MDX] generated files in ${performance.now() - start}ms`);
1098
+ },
1099
+ async transformMeta(options2, data) {
1100
+ const ctx = {
1101
+ ...pluginContext,
1102
+ ...options2
1103
+ };
1104
+ data = await transformMetadata(options2, data);
1105
+ for (const plugin of plugins) {
1106
+ if (plugin.meta?.transform)
1107
+ data = await plugin.meta.transform.call(ctx, data) ?? data;
1108
+ }
1109
+ return data;
1110
+ },
1111
+ async transformFrontmatter(options2, data) {
1112
+ const ctx = {
1113
+ ...pluginContext,
1114
+ ...options2
1115
+ };
1116
+ data = await transformMetadata(options2, data);
1117
+ for (const plugin of plugins) {
1118
+ if (plugin.doc?.frontmatter)
1119
+ data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
1120
+ }
1121
+ return data;
1122
+ },
1123
+ async transformVFile(options2, file) {
1124
+ const ctx = {
1125
+ ...pluginContext,
1126
+ ...options2
1127
+ };
1128
+ for (const plugin of plugins) {
1129
+ if (plugin.doc?.vfile)
1130
+ file = await plugin.doc.vfile.call(ctx, file) ?? file;
1131
+ }
1132
+ return file;
1133
+ }
1134
+ };
1135
+ const pluginContext = {
1136
+ core,
1137
+ ...options
1138
+ };
1139
+ return core;
1140
+ }
1141
+ function postprocessPlugin() {
1142
+ const LinkReferenceTypes = `{
1143
+ /**
1144
+ * extracted references (e.g. hrefs, paths), useful for analyzing relationships between pages.
1145
+ */
1146
+ extractedReferences?: import('fumadocs-mdx').ExtractedReference[];
1147
+ }`;
1148
+ return {
1149
+ "index-file": {
1150
+ generateTypeConfig() {
1151
+ const lines = [];
1152
+ lines.push("{");
1153
+ lines.push(" DocData: {");
1154
+ for (const collection of this.core.getConfig().collectionList) {
1155
+ let postprocessOptions;
1156
+ switch (collection.type) {
1157
+ case "doc":
1158
+ postprocessOptions = collection.postprocess;
1159
+ break;
1160
+ case "docs":
1161
+ postprocessOptions = collection.docs.postprocess;
1162
+ break;
1163
+ }
1164
+ if (postprocessOptions?.extractLinkReferences) {
1165
+ lines.push(ident(`${collection.name}: ${LinkReferenceTypes},`, 2));
1166
+ }
1167
+ }
1168
+ lines.push(" }");
1169
+ lines.push("}");
1170
+ return lines.join("\n");
1171
+ },
1172
+ serverOptions(options) {
1173
+ options.doc ??= {};
1174
+ options.doc.passthroughs ??= [];
1175
+ options.doc.passthroughs.push("extractedReferences");
1176
+ }
1149
1177
  }
1150
1178
  };
1151
1179
  }
@@ -1154,6 +1182,7 @@ function createCore(options, defaultPlugins = []) {
1154
1182
  var import_promises4 = __toESM(require("fs/promises"), 1);
1155
1183
  function createIntegratedConfigLoader(core) {
1156
1184
  return {
1185
+ core,
1157
1186
  getConfig() {
1158
1187
  return core.getConfig();
1159
1188
  }
@@ -1166,73 +1195,405 @@ var import_zod2 = require("zod");
1166
1195
  var querySchema2 = import_zod2.z.object({
1167
1196
  collection: import_zod2.z.string().optional()
1168
1197
  }).loose();
1169
- function createMetaLoader(configLoader, resolve3 = {}) {
1170
- const { json: resolveJson = "js", yaml: resolveYaml = "js" } = resolve3;
1171
- function stringifyOutput(isJson, data) {
1172
- if (isJson) {
1173
- return resolveJson === "json" ? JSON.stringify(data) : `export default ${JSON.stringify(data)}`;
1174
- } else {
1175
- return resolveYaml === "yaml" ? (0, import_js_yaml2.dump)(data) : `export default ${JSON.stringify(data)}`;
1198
+ function createMetaLoader(configLoader, resolve2 = {}) {
1199
+ const { json: resolveJson = "js", yaml: resolveYaml = "js" } = resolve2;
1200
+ function parse2(filePath, source) {
1201
+ try {
1202
+ if (filePath.endsWith(".json")) return JSON.parse(source);
1203
+ if (filePath.endsWith(".yaml")) return (0, import_js_yaml2.load)(source);
1204
+ } catch (e) {
1205
+ throw new Error(`invalid data in ${filePath}`, { cause: e });
1176
1206
  }
1207
+ throw new Error("Unknown file type " + filePath);
1177
1208
  }
1178
- return {
1179
- test: metaLoaderGlob,
1180
- async load({ filePath, query, getSource }) {
1181
- const parsed = querySchema2.parse(query);
1182
- const collection = parsed.collection ? (await configLoader.getConfig()).getCollection(parsed.collection) : void 0;
1183
- if (!collection) return null;
1184
- const isJson = filePath.endsWith(".json");
1185
- const source = await getSource();
1186
- let data;
1187
- try {
1188
- data = isJson ? JSON.parse(source) : (0, import_js_yaml2.load)(source);
1189
- } catch (e) {
1190
- throw new Error(`invalid data in ${filePath}`, { cause: e });
1191
- }
1192
- let schema;
1209
+ function onMeta(source, { filePath, query }) {
1210
+ const parsed = querySchema2.safeParse(query);
1211
+ if (!parsed.success || !parsed.data.collection) return null;
1212
+ const collectionName = parsed.data.collection;
1213
+ return async () => {
1214
+ const config = await configLoader.getConfig();
1215
+ const collection = config.getCollection(collectionName);
1216
+ let metaCollection;
1193
1217
  switch (collection?.type) {
1194
1218
  case "meta":
1195
- schema = collection.schema;
1219
+ metaCollection = collection;
1196
1220
  break;
1197
1221
  case "docs":
1198
- schema = collection.meta.schema;
1222
+ metaCollection = collection.meta;
1199
1223
  break;
1200
1224
  }
1201
- if (schema) {
1202
- data = await validate(
1203
- schema,
1204
- data,
1205
- { path: filePath, source },
1206
- `invalid data in ${filePath}`
1207
- );
1225
+ const data = parse2(filePath, source);
1226
+ if (!metaCollection) return data;
1227
+ return configLoader.core.transformMeta(
1228
+ {
1229
+ collection: metaCollection,
1230
+ filePath,
1231
+ source
1232
+ },
1233
+ data
1234
+ );
1235
+ };
1236
+ }
1237
+ return {
1238
+ test: metaLoaderGlob,
1239
+ async load(input) {
1240
+ const result = onMeta(await input.getSource(), input);
1241
+ if (result === null) return null;
1242
+ const data = await result();
1243
+ if (input.filePath.endsWith(".json")) {
1244
+ return {
1245
+ code: resolveJson === "json" ? JSON.stringify(data) : `export default ${JSON.stringify(data)}`
1246
+ };
1247
+ } else {
1248
+ return {
1249
+ code: resolveYaml === "yaml" ? (0, import_js_yaml2.dump)(data) : `export default ${JSON.stringify(data)}`
1250
+ };
1208
1251
  }
1209
- return {
1210
- code: stringifyOutput(isJson, data)
1211
- };
1212
1252
  },
1213
1253
  bun: {
1214
- loadSync(source, { filePath }) {
1215
- const isJson = filePath.endsWith(".json");
1216
- let data;
1217
- try {
1218
- data = isJson ? JSON.parse(source) : (0, import_js_yaml2.load)(source);
1219
- } catch (e) {
1220
- throw new Error(`invalid data in ${filePath}`, { cause: e });
1254
+ load(source, input) {
1255
+ const result = onMeta(source, input);
1256
+ if (result === null)
1257
+ return {
1258
+ loader: "object",
1259
+ exports: parse2(input.filePath, source)
1260
+ };
1261
+ return result().then((data) => ({
1262
+ loader: "object",
1263
+ exports: { default: data }
1264
+ }));
1265
+ }
1266
+ }
1267
+ };
1268
+ }
1269
+
1270
+ // src/plugins/index-file.ts
1271
+ var import_path = __toESM(require("path"), 1);
1272
+ var import_tinyglobby2 = require("tinyglobby");
1273
+
1274
+ // src/utils/fs-cache.ts
1275
+ var import_lru_cache = require("lru-cache");
1276
+ var import_promises5 = __toESM(require("fs/promises"), 1);
1277
+ var import_node_path5 = __toESM(require("path"), 1);
1278
+ var map = new import_lru_cache.LRUCache({
1279
+ max: 100
1280
+ });
1281
+ function toFullPath(file) {
1282
+ if (import_node_path5.default.isAbsolute(file)) {
1283
+ return import_node_path5.default.relative(process.cwd(), file);
1284
+ }
1285
+ return file;
1286
+ }
1287
+ function readFileWithCache(file) {
1288
+ const fullPath = toFullPath(file);
1289
+ const cached = map.get(fullPath);
1290
+ if (cached) return cached;
1291
+ const read = import_promises5.default.readFile(fullPath).then((s) => s.toString());
1292
+ map.set(fullPath, read);
1293
+ return read;
1294
+ }
1295
+ function removeFileCache(file) {
1296
+ map.delete(toFullPath(file));
1297
+ }
1298
+
1299
+ // src/plugins/index-file.ts
1300
+ var import_crypto = require("crypto");
1301
+ init_fuma_matter();
1302
+ function indexFile(options = {}) {
1303
+ const {
1304
+ target = "default",
1305
+ addJsExtension,
1306
+ browser = true,
1307
+ dynamic = true
1308
+ } = options;
1309
+ let config;
1310
+ let dynamicCollections;
1311
+ function isDynamic(collection) {
1312
+ return collection.type === "docs" && collection.docs.dynamic || collection.type === "doc" && collection.dynamic;
1313
+ }
1314
+ function generateConfigs(core) {
1315
+ const serverOptions = {};
1316
+ const typeConfigs = [];
1317
+ const ctx = core.getPluginContext();
1318
+ for (const plugin of core.getPlugins()) {
1319
+ const indexFilePlugin = plugin["index-file"];
1320
+ if (!indexFilePlugin) continue;
1321
+ indexFilePlugin.serverOptions?.call(ctx, serverOptions);
1322
+ const config2 = indexFilePlugin.generateTypeConfig?.call(ctx);
1323
+ if (config2) typeConfigs.push(config2);
1324
+ }
1325
+ if (typeConfigs.length === 0) {
1326
+ typeConfigs.push("{ DocData: {} }");
1327
+ }
1328
+ return {
1329
+ serverOptions,
1330
+ tc: typeConfigs.join(" & ")
1331
+ };
1332
+ }
1333
+ return {
1334
+ name: "index-file",
1335
+ config(v) {
1336
+ config = v;
1337
+ dynamicCollections = config.collectionList.filter(isDynamic);
1338
+ },
1339
+ configureServer(server) {
1340
+ if (!server.watcher) return;
1341
+ server.watcher.on("all", async (event, file) => {
1342
+ removeFileCache(file);
1343
+ if (dynamicCollections.length === 0) {
1344
+ if (target === "vite") return;
1345
+ if (target === "default" && event === "change") return;
1346
+ }
1347
+ const updatedCollection = config.collectionList.find(
1348
+ (collection) => collection.hasFile(file)
1349
+ );
1350
+ if (!updatedCollection) return;
1351
+ if (!isDynamic(updatedCollection)) {
1352
+ if (target === "vite") return;
1353
+ if (target === "default" && event === "change") return;
1221
1354
  }
1355
+ await this.core.emitAndWrite({
1356
+ filterPlugin: (plugin) => plugin.name === "index-file"
1357
+ });
1358
+ });
1359
+ },
1360
+ async emit() {
1361
+ const globCache = /* @__PURE__ */ new Map();
1362
+ const { serverOptions, tc } = generateConfigs(this.core);
1363
+ const toEmitEntry = async (path8, content) => {
1364
+ const codegen = createCodegen({
1365
+ target,
1366
+ outDir: this.outDir,
1367
+ jsExtension: addJsExtension,
1368
+ globCache
1369
+ });
1370
+ await content({
1371
+ core: this.core,
1372
+ codegen,
1373
+ serverOptions,
1374
+ tc
1375
+ });
1222
1376
  return {
1223
- loader: "object",
1224
- exports: data
1377
+ path: path8,
1378
+ content: codegen.toString()
1225
1379
  };
1226
- }
1380
+ };
1381
+ const out = [
1382
+ toEmitEntry("server.ts", generateServerIndexFile)
1383
+ ];
1384
+ if (dynamic)
1385
+ out.push(toEmitEntry("dynamic.ts", generateDynamicIndexFile));
1386
+ if (browser)
1387
+ out.push(toEmitEntry("browser.ts", generateBrowserIndexFile));
1388
+ return await Promise.all(out);
1227
1389
  }
1228
1390
  };
1229
1391
  }
1392
+ async function generateServerIndexFile({
1393
+ core,
1394
+ codegen,
1395
+ serverOptions,
1396
+ tc
1397
+ }) {
1398
+ codegen.lines.push(
1399
+ `import { server } from 'fumadocs-mdx/runtime/server';`,
1400
+ `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
1401
+ "",
1402
+ `const create = server<typeof Config, ${tc}>(${JSON.stringify(serverOptions)});`
1403
+ );
1404
+ async function generateCollectionObject(collection) {
1405
+ switch (collection.type) {
1406
+ case "docs": {
1407
+ if (collection.docs.dynamic) return;
1408
+ if (collection.docs.async) {
1409
+ const [metaGlob2, headGlob, bodyGlob] = await Promise.all([
1410
+ generateMetaCollectionGlob(codegen, collection.meta, true),
1411
+ generateDocCollectionFrontmatterGlob(
1412
+ codegen,
1413
+ collection.docs,
1414
+ true
1415
+ ),
1416
+ generateDocCollectionGlob(codegen, collection.docs)
1417
+ ]);
1418
+ return `await create.docsLazy("${collection.name}", "${collection.dir}", ${metaGlob2}, ${headGlob}, ${bodyGlob})`;
1419
+ }
1420
+ const [metaGlob, docGlob] = await Promise.all([
1421
+ generateMetaCollectionGlob(codegen, collection.meta, true),
1422
+ generateDocCollectionGlob(codegen, collection.docs, true)
1423
+ ]);
1424
+ return `await create.docs("${collection.name}", "${collection.dir}", ${metaGlob}, ${docGlob})`;
1425
+ }
1426
+ case "doc":
1427
+ if (collection.dynamic) return;
1428
+ if (collection.async) {
1429
+ const [headGlob, bodyGlob] = await Promise.all([
1430
+ generateDocCollectionFrontmatterGlob(codegen, collection, true),
1431
+ generateDocCollectionGlob(codegen, collection)
1432
+ ]);
1433
+ return `await create.docLazy("${collection.name}", "${collection.dir}", ${headGlob}, ${bodyGlob})`;
1434
+ }
1435
+ return `await create.doc("${collection.name}", "${collection.dir}", ${await generateDocCollectionGlob(
1436
+ codegen,
1437
+ collection,
1438
+ true
1439
+ )})`;
1440
+ case "meta":
1441
+ return `await create.meta("${collection.name}", "${collection.dir}", ${await generateMetaCollectionGlob(
1442
+ codegen,
1443
+ collection,
1444
+ true
1445
+ )})`;
1446
+ }
1447
+ }
1448
+ await codegen.pushAsync(
1449
+ core.getConfig().collectionList.map(async (collection) => {
1450
+ const obj = await generateCollectionObject(collection);
1451
+ if (!obj) return;
1452
+ return `
1453
+ export const ${collection.name} = ${obj};`;
1454
+ })
1455
+ );
1456
+ }
1457
+ async function generateDynamicIndexFile({
1458
+ core,
1459
+ codegen,
1460
+ serverOptions,
1461
+ tc
1462
+ }) {
1463
+ const { configPath } = core.getOptions();
1464
+ codegen.lines.push(
1465
+ `import { dynamic } from 'fumadocs-mdx/runtime/dynamic';`,
1466
+ `import * as Config from '${codegen.formatImportPath(configPath)}';`,
1467
+ "",
1468
+ `const create = await dynamic<typeof Config, ${tc}>(Config, ${JSON.stringify(core.getOptions())}, ${JSON.stringify(serverOptions)});`
1469
+ );
1470
+ async function generateCollectionObjectEntry(collection, file) {
1471
+ const fullPath = import_path.default.join(collection.dir, file);
1472
+ const content = await readFileWithCache(fullPath).catch(() => "");
1473
+ const parsed = fumaMatter(content);
1474
+ const data = await core.transformFrontmatter(
1475
+ {
1476
+ collection,
1477
+ filePath: fullPath,
1478
+ source: content
1479
+ },
1480
+ parsed.data
1481
+ );
1482
+ const hash = (0, import_crypto.createHash)("md5").update(content).digest("hex");
1483
+ const infoStr = [
1484
+ // make sure it's included in vercel/nft
1485
+ `absolutePath: path.resolve(${JSON.stringify(fullPath)})`
1486
+ ];
1487
+ for (const [k, v] of Object.entries({
1488
+ info: {
1489
+ fullPath,
1490
+ path: file
1491
+ },
1492
+ data,
1493
+ hash
1494
+ })) {
1495
+ infoStr.push(`${k}: ${JSON.stringify(v)}`);
1496
+ }
1497
+ return `{ ${infoStr.join(", ")} }`;
1498
+ }
1499
+ async function generateCollectionObject(parent) {
1500
+ let collection;
1501
+ if (parent.type === "doc") collection = parent;
1502
+ else if (parent.type === "docs") collection = parent.docs;
1503
+ if (!collection || !collection.dynamic) return;
1504
+ const files = await (0, import_tinyglobby2.glob)(collection.patterns, {
1505
+ cwd: collection.dir
1506
+ });
1507
+ const entries = await Promise.all(
1508
+ files.map((file) => generateCollectionObjectEntry(collection, file))
1509
+ );
1510
+ switch (parent.type) {
1511
+ case "docs": {
1512
+ const metaGlob = await generateMetaCollectionGlob(
1513
+ codegen,
1514
+ parent.meta,
1515
+ true
1516
+ );
1517
+ return `await create.docs("${parent.name}", "${parent.dir}", ${metaGlob}, ${entries.join(", ")})`;
1518
+ }
1519
+ case "doc":
1520
+ return `await create.doc("${collection.name}", "${collection.dir}", ${entries.join(", ")})`;
1521
+ }
1522
+ }
1523
+ await codegen.pushAsync(
1524
+ core.getConfig().collectionList.map(async (collection) => {
1525
+ const obj = await generateCollectionObject(collection);
1526
+ if (!obj) return;
1527
+ return `
1528
+ export const ${collection.name} = ${obj};`;
1529
+ })
1530
+ );
1531
+ }
1532
+ async function generateBrowserIndexFile({ core, codegen, tc }) {
1533
+ codegen.lines.push(
1534
+ `import { browser } from 'fumadocs-mdx/runtime/browser';`,
1535
+ `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
1536
+ "",
1537
+ `const create = browser<typeof Config, ${tc}>();`
1538
+ );
1539
+ async function generateCollectionObject(collection) {
1540
+ switch (collection.type) {
1541
+ case "docs": {
1542
+ if (collection.docs.dynamic) return;
1543
+ return generateCollectionObject(collection.docs);
1544
+ }
1545
+ case "doc":
1546
+ if (collection.dynamic) return;
1547
+ return `create.doc("${collection.name}", ${await generateDocCollectionGlob(codegen, collection)})`;
1548
+ }
1549
+ }
1550
+ codegen.lines.push("const browserCollections = {");
1551
+ await codegen.pushAsync(
1552
+ core.getConfig().collectionList.map(async (collection) => {
1553
+ const obj = await generateCollectionObject(collection);
1554
+ if (!obj) return;
1555
+ return ident(`${collection.name}: ${obj},`);
1556
+ })
1557
+ );
1558
+ codegen.lines.push("};", "export default browserCollections;");
1559
+ }
1560
+ function generateDocCollectionFrontmatterGlob(codegen, collection, eager = false) {
1561
+ return codegen.generateGlobImport(collection.patterns, {
1562
+ query: {
1563
+ collection: collection.name,
1564
+ only: "frontmatter"
1565
+ },
1566
+ import: "frontmatter",
1567
+ base: collection.dir,
1568
+ eager
1569
+ });
1570
+ }
1571
+ function generateDocCollectionGlob(codegen, collection, eager = false) {
1572
+ return codegen.generateGlobImport(collection.patterns, {
1573
+ query: {
1574
+ collection: collection.name
1575
+ },
1576
+ base: collection.dir,
1577
+ eager
1578
+ });
1579
+ }
1580
+ function generateMetaCollectionGlob(codegen, collection, eager = false) {
1581
+ return codegen.generateGlobImport(collection.patterns, {
1582
+ query: {
1583
+ collection: collection.name
1584
+ },
1585
+ import: "default",
1586
+ base: collection.dir,
1587
+ eager
1588
+ });
1589
+ }
1230
1590
 
1231
1591
  // src/vite/index.ts
1232
1592
  var FumadocsDeps = ["fumadocs-core", "fumadocs-ui", "fumadocs-openapi"];
1233
1593
  async function mdx(config, pluginOptions = {}) {
1234
- const options = applyDefaults2(pluginOptions);
1235
- const core = await createViteCore(options).init({
1594
+ const options = applyDefaults(pluginOptions);
1595
+ const core = createViteCore(options);
1596
+ await core.init({
1236
1597
  config: buildConfig(config)
1237
1598
  });
1238
1599
  const configLoader = createIntegratedConfigLoader(core);
@@ -1277,26 +1638,27 @@ async function mdx(config, pluginOptions = {}) {
1277
1638
  }
1278
1639
  } catch (e) {
1279
1640
  if (e instanceof ValidationError) {
1280
- throw new Error(e.toStringFormatted());
1641
+ throw new Error(await e.toStringFormatted());
1281
1642
  }
1282
1643
  throw e;
1283
1644
  }
1284
1645
  }
1285
1646
  };
1286
1647
  }
1287
- async function postInstall(configPath = findConfigFile(), pluginOptions = {}) {
1648
+ async function postInstall(pluginOptions = {}) {
1288
1649
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load_from_file(), load_from_file_exports));
1289
- const options = applyDefaults2(pluginOptions);
1290
- const core = await createViteCore(options).init({
1291
- config: loadConfig2(configPath, options.outDir, true)
1650
+ const core = createViteCore(applyDefaults(pluginOptions));
1651
+ await core.init({
1652
+ config: loadConfig2(core, true)
1292
1653
  });
1293
1654
  await core.emitAndWrite();
1294
1655
  }
1295
1656
  function createViteCore({
1657
+ index,
1296
1658
  configPath,
1297
- outDir,
1298
- generateIndexFile
1659
+ outDir
1299
1660
  }) {
1661
+ if (index === true) index = {};
1300
1662
  return createCore(
1301
1663
  {
1302
1664
  environment: "vite",
@@ -1304,18 +1666,19 @@ function createViteCore({
1304
1666
  outDir
1305
1667
  },
1306
1668
  [
1307
- vite({
1308
- index: generateIndexFile
1669
+ index && indexFile({
1670
+ ...index,
1671
+ target: index.target ?? "vite"
1309
1672
  })
1310
1673
  ]
1311
1674
  );
1312
1675
  }
1313
- function applyDefaults2(options) {
1676
+ function applyDefaults(options) {
1314
1677
  return {
1315
1678
  updateViteConfig: options.updateViteConfig ?? true,
1316
- generateIndexFile: options.generateIndexFile ?? true,
1317
- configPath: options.configPath ?? "source.config.ts",
1318
- outDir: options.outDir ?? ".source"
1679
+ index: options.index ?? true,
1680
+ configPath: options.configPath ?? _Defaults.configPath,
1681
+ outDir: options.outDir ?? _Defaults.outDir
1319
1682
  };
1320
1683
  }
1321
1684
  // Annotate the CommonJS export names for ESM import in node: