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,251 +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
- });
38
- function pluginOption(def, options = []) {
39
- const list = def(Array.isArray(options) ? options : []).filter(
40
- Boolean
41
- );
42
- if (typeof options === "function") {
43
- return options(list);
44
- }
45
- return list;
46
- }
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
78
- ],
79
- "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
80
- ...v,
81
- remarkStructureOptions !== false && [
82
- plugins.remarkStructure,
83
- remarkStructureOptions
84
- ],
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
110
- };
111
- }
112
- var plugins;
113
- var init_preset = __esm({
114
- "src/loaders/mdx/preset.ts"() {
115
- "use strict";
116
- plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
117
- }
118
- });
119
-
120
- // src/config/build.ts
121
- function buildCollection(name, config) {
122
- if (config.type === "docs") {
123
- return {
124
- ...config,
125
- name,
126
- meta: buildPrimitiveCollection(name, config.meta),
127
- docs: buildPrimitiveCollection(name, config.docs)
128
- };
129
- }
130
- return buildPrimitiveCollection(name, config);
131
- }
132
- function buildPrimitiveCollection(name, { files, ...config }) {
133
- const supportedFormats = SupportedFormats[config.type];
134
- const patterns = files ?? [`**/*.{${supportedFormats.join(",")}}`];
135
- let matchers;
136
- return {
137
- ...config,
138
- name,
139
- patterns,
140
- isFileSupported(filePath) {
141
- return supportedFormats.some((format) => filePath.endsWith(`.${format}`));
142
- },
143
- hasFile(filePath) {
144
- matchers ??= (Array.isArray(config.dir) ? config.dir : [config.dir]).map(
145
- (dir) => (0, import_picomatch.default)(patterns, {
146
- cwd: dir
147
- })
148
- );
149
- return this.isFileSupported(filePath) && matchers.some((matcher) => matcher(filePath));
150
- }
151
- };
152
- }
153
- function buildConfig(config) {
154
- const collections = /* @__PURE__ */ new Map();
155
- const loaded = {};
156
- for (const [k, v] of Object.entries(config)) {
157
- if (!v) {
158
- continue;
159
- }
160
- if (typeof v === "object" && "type" in v) {
161
- if (v.type === "docs") {
162
- collections.set(k, buildCollection(k, v));
163
- continue;
164
- }
165
- if (v.type === "doc" || v.type === "meta") {
166
- collections.set(
167
- k,
168
- buildCollection(k, v)
169
- );
170
- continue;
171
- }
172
- }
173
- if (k === "default" && v) {
174
- Object.assign(loaded, v);
175
- continue;
176
- }
177
- throw new Error(
178
- `Unknown export "${k}", you can only export collections from source configuration file.`
179
- );
180
- }
181
- if (loaded.collections) {
182
- for (const [k, v] of Object.entries(loaded.collections)) {
183
- collections.set(k, buildCollection(k, v));
184
- }
185
- }
186
- const mdxOptionsCache = /* @__PURE__ */ new Map();
187
- return {
188
- global: loaded,
189
- collectionList: Array.from(collections.values()),
190
- getCollection(name) {
191
- return collections.get(name);
192
- },
193
- async getDefaultMDXOptions(mode = "default") {
194
- const cached = mdxOptionsCache.get(mode);
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
- });
205
- }
206
- const result = uncached();
207
- mdxOptionsCache.set(mode, result);
208
- return result;
209
- }
210
- };
211
- }
212
- var import_picomatch, SupportedFormats;
213
- var init_build = __esm({
214
- "src/config/build.ts"() {
215
- "use strict";
216
- import_picomatch = __toESM(require("picomatch"), 1);
217
- SupportedFormats = {
218
- doc: ["mdx", "md"],
219
- meta: ["json", "yaml"]
220
- };
221
- }
222
- });
223
-
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_url2.pathToFileURL)(path6.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 path6, import_node_url2;
259
- var init_load_from_file = __esm({
260
- "src/config/load-from-file.ts"() {
261
- "use strict";
262
- path6 = __toESM(require("path"), 1);
263
- import_node_url2 = require("url");
264
- init_build();
265
- }
266
- });
267
-
268
- // src/webpack/mdx.ts
269
- var mdx_exports = {};
270
- __export(mdx_exports, {
271
- default: () => loader
272
- });
273
- module.exports = __toCommonJS(mdx_exports);
274
-
275
33
  // src/utils/fuma-matter.ts
276
- var import_js_yaml = require("js-yaml");
277
- var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
278
34
  function fumaMatter(input) {
279
35
  const output = { matter: "", data: {}, content: input };
280
36
  const match = regex.exec(input);
@@ -287,80 +43,16 @@ function fumaMatter(input) {
287
43
  output.data = loaded ?? {};
288
44
  return output;
289
45
  }
290
-
291
- // src/utils/validation.ts
292
- var import_picocolors = __toESM(require("picocolors"), 1);
293
- var ValidationError = class extends Error {
294
- constructor(message, issues) {
295
- super(
296
- `${message}:
297
- ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
298
- );
299
- this.title = message;
300
- this.issues = issues;
301
- }
302
- toStringFormatted() {
303
- return [
304
- import_picocolors.default.bold(`[MDX] ${this.title}:`),
305
- ...this.issues.map(
306
- (issue) => import_picocolors.default.redBright(
307
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
308
- )
309
- )
310
- ].join("\n");
311
- }
312
- };
313
- async function validate(schema, data, context, errorMessage) {
314
- if (typeof schema === "function" && !("~standard" in schema)) {
315
- schema = schema(context);
316
- }
317
- if ("~standard" in schema) {
318
- const result = await schema["~standard"].validate(
319
- data
320
- );
321
- if (result.issues) {
322
- throw new ValidationError(errorMessage, result.issues);
323
- }
324
- return result.value;
325
- }
326
- return data;
327
- }
328
-
329
- // src/utils/git-timestamp.ts
330
- var import_node_path = __toESM(require("path"), 1);
331
- var import_tinyexec = require("tinyexec");
332
- var cache = /* @__PURE__ */ new Map();
333
- async function getGitTimestamp(file) {
334
- const cached = cache.get(file);
335
- if (cached) return cached;
336
- try {
337
- const out = await (0, import_tinyexec.x)(
338
- "git",
339
- ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
340
- {
341
- throwOnError: true
342
- }
343
- );
344
- const time = new Date(out.stdout);
345
- cache.set(file, time);
346
- return time;
347
- } catch {
348
- return;
46
+ var import_js_yaml, regex;
47
+ var init_fuma_matter = __esm({
48
+ "src/utils/fuma-matter.ts"() {
49
+ "use strict";
50
+ import_js_yaml = require("js-yaml");
51
+ regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
349
52
  }
350
- }
351
-
352
- // src/loaders/mdx/build-mdx.ts
353
- var import_mdx = require("@mdx-js/mdx");
354
-
355
- // src/loaders/mdx/remark-include.ts
356
- var import_unified = require("unified");
357
- var import_unist_util_visit2 = require("unist-util-visit");
358
- var path2 = __toESM(require("path"), 1);
359
- var fs = __toESM(require("fs/promises"), 1);
360
- var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
53
+ });
361
54
 
362
55
  // src/loaders/mdx/remark-unravel.ts
363
- var import_unist_util_visit = require("unist-util-visit");
364
56
  function remarkMarkAndUnravel() {
365
57
  return (tree) => {
366
58
  (0, import_unist_util_visit.visit)(tree, function(node, index, parent) {
@@ -402,15 +94,28 @@ function remarkMarkAndUnravel() {
402
94
  });
403
95
  };
404
96
  }
97
+ var import_unist_util_visit;
98
+ var init_remark_unravel = __esm({
99
+ "src/loaders/mdx/remark-unravel.ts"() {
100
+ "use strict";
101
+ import_unist_util_visit = require("unist-util-visit");
102
+ }
103
+ });
104
+
105
+ // src/loaders/mdx/mdast-utils.ts
106
+ function flattenNode(node) {
107
+ if ("children" in node)
108
+ return node.children.map((child) => flattenNode(child)).join("");
109
+ if ("value" in node) return node.value;
110
+ return "";
111
+ }
112
+ var init_mdast_utils = __esm({
113
+ "src/loaders/mdx/mdast-utils.ts"() {
114
+ "use strict";
115
+ }
116
+ });
405
117
 
406
118
  // src/loaders/mdx/remark-include.ts
407
- var ElementLikeTypes = [
408
- "mdxJsxFlowElement",
409
- "mdxJsxTextElement",
410
- "containerDirective",
411
- "textDirective",
412
- "leafDirective"
413
- ];
414
119
  function isElementLike(node) {
415
120
  return ElementLikeTypes.includes(node.type);
416
121
  }
@@ -426,12 +131,6 @@ function parseElementAttributes(element) {
426
131
  }
427
132
  return element.attributes ?? {};
428
133
  }
429
- function flattenNode(node) {
430
- if ("children" in node)
431
- return node.children.map((child) => flattenNode(child)).join("");
432
- if ("value" in node) return node.value;
433
- return "";
434
- }
435
134
  function parseSpecifier(specifier) {
436
135
  const idx = specifier.lastIndexOf("#");
437
136
  if (idx === -1) return { file: specifier };
@@ -486,7 +185,7 @@ ${e instanceof Error ? e.message : String(e)}`,
486
185
  { cause: e }
487
186
  );
488
187
  }
489
- const ext = path2.extname(file);
188
+ const ext = path.extname(file);
490
189
  data._compiler?.addDependency(file);
491
190
  if (params.lang || ext !== ".md" && ext !== ".mdx") {
492
191
  const lang = params.lang ?? ext.slice(1);
@@ -519,7 +218,7 @@ ${e instanceof Error ? e.message : String(e)}`,
519
218
  } else {
520
219
  mdast = await baseProcessor.run(mdast);
521
220
  }
522
- await update(mdast, path2.dirname(file), data);
221
+ await update(mdast, path.dirname(file), data);
523
222
  return mdast;
524
223
  };
525
224
  async function update(tree, directory, data) {
@@ -531,7 +230,7 @@ ${e instanceof Error ? e.message : String(e)}`,
531
230
  if (specifier.length === 0) return "skip";
532
231
  const attributes = parseElementAttributes(node);
533
232
  const { file: relativePath, section } = parseSpecifier(specifier);
534
- const file = path2.resolve(
233
+ const file = path.resolve(
535
234
  "cwd" in attributes ? process.cwd() : directory,
536
235
  relativePath
537
236
  );
@@ -548,62 +247,96 @@ ${e instanceof Error ? e.message : String(e)}`,
548
247
  await Promise.all(queue);
549
248
  }
550
249
  return async (tree, file) => {
551
- await update(tree, path2.dirname(file.path), file.data);
250
+ await update(tree, path.dirname(file.path), file.data);
552
251
  };
553
252
  }
253
+ var import_unified, import_unist_util_visit2, path, fs, import_mdx_plugins, ElementLikeTypes;
254
+ var init_remark_include = __esm({
255
+ "src/loaders/mdx/remark-include.ts"() {
256
+ "use strict";
257
+ import_unified = require("unified");
258
+ import_unist_util_visit2 = require("unist-util-visit");
259
+ path = __toESM(require("path"), 1);
260
+ fs = __toESM(require("fs/promises"), 1);
261
+ init_fuma_matter();
262
+ import_mdx_plugins = require("fumadocs-core/mdx-plugins");
263
+ init_remark_unravel();
264
+ init_mdast_utils();
265
+ ElementLikeTypes = [
266
+ "mdxJsxFlowElement",
267
+ "mdxJsxTextElement",
268
+ "containerDirective",
269
+ "textDirective",
270
+ "leafDirective"
271
+ ];
272
+ }
273
+ });
554
274
 
555
275
  // src/loaders/mdx/remark-postprocess.ts
556
- var import_unist_util_visit3 = require("unist-util-visit");
557
- var import_mdast_util_to_markdown = require("mdast-util-to-markdown");
558
- var import_estree_util_value_to_estree = require("estree-util-value-to-estree");
559
- var import_unist_util_remove_position = require("unist-util-remove-position");
560
- var import_remark_mdx = __toESM(require("remark-mdx"), 1);
561
276
  function remarkPostprocess({
562
277
  _format,
563
278
  includeProcessedMarkdown = false,
564
279
  includeMDAST = false,
280
+ extractLinkReferences = false,
565
281
  valueToExport = []
566
282
  }) {
567
283
  let _stringifyProcessor;
568
284
  const getStringifyProcessor = () => {
569
- if (_format === "mdx") return this;
570
- return _stringifyProcessor ??= this().use(import_remark_mdx.default).freeze();
285
+ return _stringifyProcessor ??= _format === "mdx" ? this : (
286
+ // force Markdown processor to stringify MDX nodes
287
+ this().use(import_remark_mdx.default).freeze()
288
+ );
571
289
  };
572
290
  return (tree, file) => {
573
- let title;
574
- const urls = [];
575
- (0, import_unist_util_visit3.visit)(tree, ["heading", "link"], (node) => {
576
- if (node.type === "heading" && node.depth === 1) {
577
- title = flattenNode2(node);
578
- }
579
- if (node.type !== "link") return;
580
- urls.push({
581
- href: node.url
291
+ const frontmatter = file.data.frontmatter ??= {};
292
+ if (!frontmatter.title) {
293
+ (0, import_unist_util_visit3.visit)(tree, "heading", (node) => {
294
+ if (node.depth === 1) {
295
+ frontmatter.title = flattenNode(node);
296
+ return false;
297
+ }
298
+ });
299
+ }
300
+ file.data["mdx-export"] ??= [];
301
+ if (extractLinkReferences) {
302
+ const urls = [];
303
+ (0, import_unist_util_visit3.visit)(tree, "link", (node) => {
304
+ urls.push({
305
+ href: node.url
306
+ });
307
+ return "skip";
308
+ });
309
+ file.data["mdx-export"].push({
310
+ name: "extractedReferences",
311
+ value: urls
582
312
  });
583
- return "skip";
584
- });
585
- if (title) {
586
- file.data.frontmatter ??= {};
587
- if (!file.data.frontmatter.title) file.data.frontmatter.title = title;
588
313
  }
589
- file.data.extractedReferences = urls;
590
314
  if (includeProcessedMarkdown) {
591
315
  const processor = getStringifyProcessor();
592
- file.data._markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
316
+ const markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
593
317
  ...processor.data("settings"),
594
318
  // from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
595
319
  extensions: processor.data("toMarkdownExtensions") || []
596
320
  });
321
+ file.data["mdx-export"].push({
322
+ name: "_markdown",
323
+ value: markdown
324
+ });
597
325
  }
598
326
  if (includeMDAST) {
599
327
  const options = includeMDAST === true ? {} : includeMDAST;
600
- file.data._mdast = JSON.stringify(
328
+ const mdast = JSON.stringify(
601
329
  options.removePosition ? (0, import_unist_util_remove_position.removePosition)(structuredClone(tree)) : tree
602
330
  );
331
+ file.data["mdx-export"].push({
332
+ name: "_mdast",
333
+ value: mdast
334
+ });
603
335
  }
604
- for (const { name, value } of file.data["mdx-export"] ?? []) {
336
+ for (const { name, value } of file.data["mdx-export"]) {
605
337
  tree.children.unshift(getMdastExport(name, value));
606
338
  }
339
+ file.data["mdx-export"] = [];
607
340
  for (const name of valueToExport) {
608
341
  if (!(name in file.data)) continue;
609
342
  tree.children.unshift(getMdastExport(name, file.data[name]));
@@ -644,68 +377,331 @@ function getMdastExport(name, value) {
644
377
  }
645
378
  };
646
379
  }
647
- function flattenNode2(node) {
648
- if ("children" in node)
649
- return node.children.map((child) => flattenNode2(child)).join("");
650
- if ("value" in node) return node.value;
651
- return "";
652
- }
380
+ var import_unist_util_visit3, import_mdast_util_to_markdown, import_estree_util_value_to_estree, import_unist_util_remove_position, import_remark_mdx;
381
+ var init_remark_postprocess = __esm({
382
+ "src/loaders/mdx/remark-postprocess.ts"() {
383
+ "use strict";
384
+ import_unist_util_visit3 = require("unist-util-visit");
385
+ import_mdast_util_to_markdown = require("mdast-util-to-markdown");
386
+ import_estree_util_value_to_estree = require("estree-util-value-to-estree");
387
+ import_unist_util_remove_position = require("unist-util-remove-position");
388
+ import_remark_mdx = __toESM(require("remark-mdx"), 1);
389
+ init_mdast_utils();
390
+ }
391
+ });
653
392
 
654
393
  // src/loaders/mdx/build-mdx.ts
655
- var cache2 = /* @__PURE__ */ new Map();
656
- async function buildMDX(cacheKey, source, options) {
657
- const { filePath, frontmatter, data, _compiler, ...rest } = options;
394
+ var build_mdx_exports = {};
395
+ __export(build_mdx_exports, {
396
+ buildMDX: () => buildMDX
397
+ });
398
+ async function buildMDX(core2, collection, {
399
+ filePath,
400
+ frontmatter,
401
+ source,
402
+ _compiler,
403
+ environment,
404
+ isDevelopment
405
+ }) {
406
+ const mdxOptions = await core2.getConfig().getMDXOptions(collection, environment);
658
407
  function getProcessor(format) {
659
- const key = `${cacheKey}:${format}`;
660
- let processor = cache2.get(key);
408
+ const cache = core2.cache;
409
+ const key = `build-mdx:${collection?.name ?? "global"}:${format}`;
410
+ let processor = cache.get(key);
661
411
  if (!processor) {
412
+ const postprocessOptions = {
413
+ _format: format,
414
+ ...collection?.postprocess,
415
+ valueToExport: [
416
+ ...collection?.postprocess?.valueToExport ?? [],
417
+ "structuredData",
418
+ "frontmatter"
419
+ ]
420
+ };
662
421
  processor = (0, import_mdx.createProcessor)({
663
422
  outputFormat: "program",
664
- ...rest,
423
+ development: isDevelopment,
424
+ ...mdxOptions,
665
425
  remarkPlugins: [
666
426
  remarkInclude,
667
- ...rest.remarkPlugins ?? [],
668
- [
669
- remarkPostprocess,
670
- {
671
- _format: format,
672
- ...options.postprocess,
673
- valueToExport: [
674
- ...options.postprocess?.valueToExport ?? [],
675
- "structuredData",
676
- "extractedReferences",
677
- "frontmatter",
678
- "lastModified",
679
- "_markdown",
680
- "_mdast"
681
- ]
682
- }
683
- ]
427
+ ...mdxOptions.remarkPlugins ?? [],
428
+ [remarkPostprocess, postprocessOptions]
684
429
  ],
685
430
  format
686
431
  });
687
- cache2.set(key, processor);
432
+ cache.set(key, processor);
688
433
  }
689
434
  return processor;
690
435
  }
691
- return getProcessor(
692
- options.format ?? (filePath.endsWith(".mdx") ? "mdx" : "md")
693
- ).process({
436
+ let vfile = new import_vfile.VFile({
694
437
  value: source,
695
438
  path: filePath,
696
- data: {
697
- ...data,
698
- frontmatter,
699
- _compiler,
700
- _getProcessor: getProcessor
701
- }
439
+ data: { frontmatter, _compiler, _getProcessor: getProcessor }
702
440
  });
441
+ if (collection) {
442
+ vfile = await core2.transformVFile({ collection, filePath, source }, vfile);
443
+ }
444
+ return getProcessor(filePath.endsWith(".mdx") ? "mdx" : "md").process(vfile);
445
+ }
446
+ var import_mdx, import_vfile;
447
+ var init_build_mdx = __esm({
448
+ "src/loaders/mdx/build-mdx.ts"() {
449
+ "use strict";
450
+ import_mdx = require("@mdx-js/mdx");
451
+ import_vfile = require("vfile");
452
+ init_remark_include();
453
+ init_remark_postprocess();
454
+ }
455
+ });
456
+
457
+ // src/config/preset.ts
458
+ function pluginOption(def, options = []) {
459
+ const list = def(Array.isArray(options) ? options : []).filter(
460
+ Boolean
461
+ );
462
+ if (typeof options === "function") {
463
+ return options(list);
464
+ }
465
+ return list;
466
+ }
467
+ function applyMdxPreset(options = {}) {
468
+ return async (environment = "bundler") => {
469
+ if (options.preset === "minimal") return options;
470
+ const plugins = await import("fumadocs-core/mdx-plugins");
471
+ const {
472
+ valueToExport = [],
473
+ rehypeCodeOptions,
474
+ remarkImageOptions,
475
+ remarkHeadingOptions,
476
+ remarkStructureOptions,
477
+ remarkCodeTabOptions,
478
+ remarkNpmOptions,
479
+ ...mdxOptions
480
+ } = options;
481
+ const remarkPlugins = pluginOption(
482
+ (v) => [
483
+ plugins.remarkGfm,
484
+ [
485
+ plugins.remarkHeading,
486
+ {
487
+ generateToc: false,
488
+ ...remarkHeadingOptions
489
+ }
490
+ ],
491
+ remarkImageOptions !== false && [
492
+ plugins.remarkImage,
493
+ {
494
+ ...remarkImageOptions,
495
+ useImport: remarkImageOptions?.useImport ?? environment === "bundler"
496
+ }
497
+ ],
498
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
499
+ plugins.remarkCodeTab,
500
+ remarkCodeTabOptions
501
+ ],
502
+ "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
503
+ ...v,
504
+ remarkStructureOptions !== false && [
505
+ plugins.remarkStructure,
506
+ remarkStructureOptions
507
+ ],
508
+ valueToExport.length > 0 && (() => {
509
+ return (_, file) => {
510
+ file.data["mdx-export"] ??= [];
511
+ for (const name of valueToExport) {
512
+ if (!(name in file.data)) continue;
513
+ file.data["mdx-export"].push({
514
+ name,
515
+ value: file.data[name]
516
+ });
517
+ }
518
+ };
519
+ })
520
+ ],
521
+ mdxOptions.remarkPlugins
522
+ );
523
+ const rehypePlugins = pluginOption(
524
+ (v) => [
525
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
526
+ ...v,
527
+ plugins.rehypeToc
528
+ ],
529
+ mdxOptions.rehypePlugins
530
+ );
531
+ return {
532
+ ...mdxOptions,
533
+ outputFormat: environment === "runtime" ? "function-body" : mdxOptions.outputFormat,
534
+ remarkPlugins,
535
+ rehypePlugins
536
+ };
537
+ };
538
+ }
539
+ var init_preset = __esm({
540
+ "src/config/preset.ts"() {
541
+ "use strict";
542
+ }
543
+ });
544
+
545
+ // src/config/build.ts
546
+ function buildCollection(name, config) {
547
+ if (config.type === "docs") {
548
+ return {
549
+ ...config,
550
+ name,
551
+ meta: buildPrimitiveCollection(name, config.meta),
552
+ docs: buildPrimitiveCollection(name, config.docs),
553
+ hasFile(filePath) {
554
+ return this.docs.hasFile(filePath) || this.meta.hasFile(filePath);
555
+ }
556
+ };
557
+ }
558
+ return buildPrimitiveCollection(name, config);
559
+ }
560
+ function buildPrimitiveCollection(name, { files, ...config }) {
561
+ const supportedFormats = SupportedFormats[config.type];
562
+ const patterns = files ?? [`**/*.{${supportedFormats.join(",")}}`];
563
+ let matchers;
564
+ return {
565
+ ...config,
566
+ name,
567
+ patterns,
568
+ isFileSupported(filePath) {
569
+ return supportedFormats.some((format) => filePath.endsWith(`.${format}`));
570
+ },
571
+ hasFile(filePath) {
572
+ matchers ??= (Array.isArray(config.dir) ? config.dir : [config.dir]).map(
573
+ (dir) => (0, import_picomatch.default)(patterns, {
574
+ cwd: dir
575
+ })
576
+ );
577
+ return this.isFileSupported(filePath) && matchers.some((matcher) => matcher(filePath));
578
+ }
579
+ };
580
+ }
581
+ function buildConfig(config) {
582
+ const collections = /* @__PURE__ */ new Map();
583
+ const loaded = {};
584
+ for (const [k, v] of Object.entries(config)) {
585
+ if (!v) {
586
+ continue;
587
+ }
588
+ if (typeof v === "object" && "type" in v) {
589
+ if (v.type === "docs") {
590
+ collections.set(k, buildCollection(k, v));
591
+ continue;
592
+ }
593
+ if (v.type === "doc" || v.type === "meta") {
594
+ collections.set(
595
+ k,
596
+ buildCollection(k, v)
597
+ );
598
+ continue;
599
+ }
600
+ }
601
+ if (k === "default" && v) {
602
+ Object.assign(loaded, v);
603
+ continue;
604
+ }
605
+ throw new Error(
606
+ `Unknown export "${k}", you can only export collections from source configuration file.`
607
+ );
608
+ }
609
+ const mdxOptionsCache = /* @__PURE__ */ new Map();
610
+ return {
611
+ global: loaded,
612
+ collectionList: Array.from(collections.values()),
613
+ getCollection(name) {
614
+ return collections.get(name);
615
+ },
616
+ getMDXOptions(collection, environment = "bundler") {
617
+ const key = collection ? `${environment}:${collection.name}` : environment;
618
+ const cached = mdxOptionsCache.get(key);
619
+ if (cached) return cached;
620
+ let result;
621
+ if (collection?.mdxOptions) {
622
+ const optionsFn = collection.mdxOptions;
623
+ result = typeof optionsFn === "function" ? optionsFn(environment) : optionsFn;
624
+ } else {
625
+ result = (async () => {
626
+ const optionsFn = this.global.mdxOptions;
627
+ const options = typeof optionsFn === "function" ? await optionsFn() : optionsFn;
628
+ return applyMdxPreset(options)(environment);
629
+ })();
630
+ }
631
+ mdxOptionsCache.set(key, result);
632
+ return result;
633
+ }
634
+ };
703
635
  }
636
+ var import_picomatch, SupportedFormats;
637
+ var init_build = __esm({
638
+ "src/config/build.ts"() {
639
+ "use strict";
640
+ import_picomatch = __toESM(require("picomatch"), 1);
641
+ init_preset();
642
+ SupportedFormats = {
643
+ doc: ["mdx", "md"],
644
+ meta: ["json", "yaml"]
645
+ };
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(core2) {
655
+ const { build } = await import("esbuild");
656
+ const { configPath, outDir } = core2.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
670
+ });
671
+ if (transformed.errors.length > 0) {
672
+ throw new Error("failed to compile configuration file");
673
+ }
674
+ }
675
+ async function loadConfig(core2, build = false) {
676
+ if (build) await compileConfig(core2);
677
+ const url = (0, import_node_url2.pathToFileURL)(core2.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/webpack/mdx.ts
694
+ var mdx_exports = {};
695
+ __export(mdx_exports, {
696
+ default: () => loader
697
+ });
698
+ module.exports = __toCommonJS(mdx_exports);
704
699
 
705
700
  // src/loaders/mdx/index.ts
701
+ init_fuma_matter();
706
702
  var import_zod = require("zod");
707
703
  var import_promises = __toESM(require("fs/promises"), 1);
708
- var import_node_path2 = __toESM(require("path"), 1);
704
+ var import_node_path = __toESM(require("path"), 1);
709
705
  var import_node_crypto = require("crypto");
710
706
 
711
707
  // src/loaders/index.ts
@@ -731,20 +727,20 @@ function createMdxLoader(configLoader) {
731
727
  compiler,
732
728
  filePath
733
729
  }) {
730
+ const config = await configLoader.getConfig();
734
731
  const value = await getSource();
735
732
  const matter = fumaMatter(value);
736
733
  const parsed = querySchema.parse(query);
737
- const config = await configLoader.getConfig();
738
734
  let after;
739
735
  if (!isDevelopment && config.global.experimentalBuildCache) {
740
736
  const cacheDir = config.global.experimentalBuildCache;
741
737
  const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
742
- const cached = await import_promises.default.readFile(import_node_path2.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
738
+ const cached = await import_promises.default.readFile(import_node_path.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
743
739
  if (cached && cached.hash === generateCacheHash(value)) return cached;
744
740
  after = async () => {
745
741
  await import_promises.default.mkdir(cacheDir, { recursive: true });
746
742
  await import_promises.default.writeFile(
747
- import_node_path2.default.join(cacheDir, cacheKey),
743
+ import_node_path.default.join(cacheDir, cacheKey),
748
744
  JSON.stringify({
749
745
  ...out,
750
746
  hash: generateCacheHash(value)
@@ -762,15 +758,10 @@ function createMdxLoader(configLoader) {
762
758
  docCollection = collection.docs;
763
759
  break;
764
760
  }
765
- if (docCollection?.schema) {
766
- matter.data = await validate(
767
- docCollection.schema,
768
- matter.data,
769
- {
770
- source: value,
771
- path: filePath
772
- },
773
- `invalid frontmatter in ${filePath}`
761
+ if (docCollection) {
762
+ matter.data = await configLoader.core.transformFrontmatter(
763
+ { collection: docCollection, filePath, source: value },
764
+ matter.data
774
765
  );
775
766
  }
776
767
  if (parsed.only === "frontmatter") {
@@ -779,24 +770,16 @@ function createMdxLoader(configLoader) {
779
770
  map: null
780
771
  };
781
772
  }
782
- const data = {};
783
- if (config.global.lastModifiedTime === "git") {
784
- data.lastModified = (await getGitTimestamp(filePath))?.getTime();
785
- }
786
773
  const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
787
- const compiled = await buildMDX(
788
- `${getConfigHash(config)}:${parsed.collection ?? "global"}`,
789
- "\n".repeat(lineOffset) + matter.content,
790
- {
791
- development: isDevelopment,
792
- ...docCollection?.mdxOptions ?? await config.getDefaultMDXOptions(),
793
- postprocess: docCollection?.postprocess,
794
- data,
795
- filePath,
796
- frontmatter: matter.data,
797
- _compiler: compiler
798
- }
799
- );
774
+ const { buildMDX: buildMDX2 } = await Promise.resolve().then(() => (init_build_mdx(), build_mdx_exports));
775
+ const compiled = await buildMDX2(configLoader.core, docCollection, {
776
+ isDevelopment,
777
+ source: "\n".repeat(lineOffset) + matter.content,
778
+ filePath,
779
+ frontmatter: matter.data,
780
+ _compiler: compiler,
781
+ environment: "bundler"
782
+ });
800
783
  const out = {
801
784
  code: String(compiled.value),
802
785
  map: compiled.map
@@ -806,14 +789,6 @@ function createMdxLoader(configLoader) {
806
789
  }
807
790
  };
808
791
  }
809
- var hashes = /* @__PURE__ */ new WeakMap();
810
- function getConfigHash(config) {
811
- let hash = hashes.get(config);
812
- if (hash) return hash;
813
- hash = Date.now().toString();
814
- hashes.set(config, hash);
815
- return hash;
816
- }
817
792
  function generateCacheHash(input) {
818
793
  return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
819
794
  }
@@ -829,7 +804,47 @@ function countLines(s) {
829
804
  var import_node_url = require("url");
830
805
  var import_promises2 = __toESM(require("fs/promises"), 1);
831
806
  var import_node_querystring = require("querystring");
832
- var import_node_path3 = __toESM(require("path"), 1);
807
+
808
+ // src/utils/validation.ts
809
+ var ValidationError = class extends Error {
810
+ constructor(message, issues) {
811
+ super(
812
+ `${message}:
813
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
814
+ );
815
+ this.title = message;
816
+ this.issues = issues;
817
+ }
818
+ async toStringFormatted() {
819
+ const picocolors = await import("picocolors");
820
+ return [
821
+ picocolors.bold(`[MDX] ${this.title}:`),
822
+ ...this.issues.map(
823
+ (issue) => picocolors.redBright(
824
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
825
+ )
826
+ )
827
+ ].join("\n");
828
+ }
829
+ };
830
+ async function validate(schema, data, context, errorMessage) {
831
+ if (typeof schema === "function" && !("~standard" in schema)) {
832
+ schema = schema(context);
833
+ }
834
+ if ("~standard" in schema) {
835
+ const result = await schema["~standard"].validate(
836
+ data
837
+ );
838
+ if (result.issues) {
839
+ throw new ValidationError(errorMessage, result.issues);
840
+ }
841
+ return result.value;
842
+ }
843
+ return data;
844
+ }
845
+
846
+ // src/loaders/adapter.ts
847
+ var import_node_path2 = __toESM(require("path"), 1);
833
848
  var import_node_fs = require("fs");
834
849
  function toWebpack(loader2) {
835
850
  return async function(source, callback) {
@@ -850,30 +865,92 @@ function toWebpack(loader2) {
850
865
  }
851
866
  } catch (error) {
852
867
  if (error instanceof ValidationError) {
853
- return callback(new Error(error.toStringFormatted()));
868
+ return callback(new Error(await error.toStringFormatted()));
854
869
  }
855
870
  if (!(error instanceof Error)) throw error;
856
- const fpath = import_node_path3.default.relative(this.context, this.resourcePath);
871
+ const fpath = import_node_path2.default.relative(this.context, this.resourcePath);
857
872
  error.message = `${fpath}:${error.name}: ${error.message}`;
858
873
  callback(error);
859
874
  }
860
875
  };
861
876
  }
862
877
 
878
+ // src/loaders/config.ts
879
+ var import_promises3 = __toESM(require("fs/promises"), 1);
880
+ function createStandaloneConfigLoader({
881
+ core: core2,
882
+ buildConfig: buildConfig2,
883
+ mode
884
+ }) {
885
+ let loaded;
886
+ async function getConfigHash() {
887
+ if (mode === "production") return "static";
888
+ const stats = await import_promises3.default.stat(core2.getOptions().configPath).catch(() => {
889
+ throw new Error("Cannot find config file");
890
+ });
891
+ return stats.mtime.getTime().toString();
892
+ }
893
+ async function newConfig() {
894
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load_from_file(), load_from_file_exports));
895
+ await core2.init({
896
+ config: loadConfig2(core2, buildConfig2)
897
+ });
898
+ return core2.getConfig();
899
+ }
900
+ return {
901
+ core: core2,
902
+ async getConfig() {
903
+ const hash = await getConfigHash();
904
+ if (loaded && loaded.hash === hash) return loaded.config;
905
+ loaded = {
906
+ hash,
907
+ config: newConfig()
908
+ };
909
+ return loaded.config;
910
+ }
911
+ };
912
+ }
913
+
863
914
  // src/core.ts
864
915
  var import_node_path4 = __toESM(require("path"), 1);
865
- var import_promises3 = __toESM(require("fs/promises"), 1);
916
+ var import_promises4 = __toESM(require("fs/promises"), 1);
917
+
918
+ // src/utils/codegen.ts
919
+ var import_node_path3 = __toESM(require("path"), 1);
920
+ var import_tinyglobby = require("tinyglobby");
921
+ function ident(code, tab = 1) {
922
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
923
+ }
924
+
925
+ // src/core.ts
926
+ async function getPlugins(pluginOptions) {
927
+ const plugins = [];
928
+ for await (const option of pluginOptions) {
929
+ if (!option) continue;
930
+ if (Array.isArray(option)) plugins.push(...await getPlugins(option));
931
+ else plugins.push(option);
932
+ }
933
+ return plugins;
934
+ }
866
935
  function createCore(options, defaultPlugins = []) {
867
936
  let config;
868
- let plugins2;
869
- return {
870
- _options: options,
871
- getPluginContext() {
872
- return {
873
- core: this,
874
- ...options
875
- };
876
- },
937
+ let plugins;
938
+ async function transformMetadata({
939
+ collection,
940
+ filePath,
941
+ source
942
+ }, data) {
943
+ if (collection.schema) {
944
+ data = await validate(
945
+ collection.schema,
946
+ data,
947
+ { path: filePath, source },
948
+ collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`
949
+ );
950
+ }
951
+ return data;
952
+ }
953
+ const core2 = {
877
954
  /**
878
955
  * Convenient cache store, reset when config changes
879
956
  */
@@ -881,108 +958,164 @@ function createCore(options, defaultPlugins = []) {
881
958
  async init({ config: newConfig }) {
882
959
  config = await newConfig;
883
960
  this.cache.clear();
884
- plugins2 = [];
885
- for await (const option of [
961
+ plugins = await getPlugins([
962
+ postprocessPlugin(),
886
963
  ...defaultPlugins,
887
964
  ...config.global.plugins ?? []
888
- ]) {
889
- if (!option) continue;
890
- if (Array.isArray(option)) plugins2.push(...option);
891
- else plugins2.push(option);
892
- }
893
- for (const plugin of plugins2) {
894
- const out = await plugin.config?.call(this.getPluginContext(), config);
965
+ ]);
966
+ for (const plugin of plugins) {
967
+ const out = await plugin.config?.call(pluginContext, config);
895
968
  if (out) config = out;
896
969
  }
897
- return this;
970
+ },
971
+ getOptions() {
972
+ return options;
898
973
  },
899
974
  getConfig() {
900
975
  return config;
901
976
  },
977
+ /**
978
+ * The file path of compiled config file, the file may not exist (e.g. on Vite, or still compiling)
979
+ */
980
+ getCompiledConfigPath() {
981
+ return import_node_path4.default.join(options.outDir, "source.config.mjs");
982
+ },
983
+ getPlugins() {
984
+ return plugins;
985
+ },
986
+ getPluginContext() {
987
+ return pluginContext;
988
+ },
902
989
  async initServer(server) {
903
- for (const plugin of plugins2) {
904
- await plugin.configureServer?.call(this.getPluginContext(), server);
990
+ for (const plugin of plugins) {
991
+ await plugin.configureServer?.call(pluginContext, server);
905
992
  }
906
993
  },
907
- async emitAndWrite({
908
- filterPlugin = () => true
909
- } = {}) {
910
- const start = performance.now();
911
- const out = await Promise.all(
912
- plugins2.map((plugin) => {
994
+ async emit({ filterPlugin = () => true } = {}) {
995
+ return (await Promise.all(
996
+ plugins.map((plugin) => {
913
997
  if (!filterPlugin(plugin) || !plugin.emit) return [];
914
- return plugin.emit.call(this.getPluginContext());
998
+ return plugin.emit.call(pluginContext);
915
999
  })
916
- );
1000
+ )).flat();
1001
+ },
1002
+ async emitAndWrite(emitOptions) {
1003
+ const start = performance.now();
1004
+ const out = await this.emit(emitOptions);
917
1005
  await Promise.all(
918
- out.flat().map(async (entry) => {
1006
+ out.map(async (entry) => {
919
1007
  const file = import_node_path4.default.join(options.outDir, entry.path);
920
- await import_promises3.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
921
- await import_promises3.default.writeFile(file, entry.content);
1008
+ await import_promises4.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
1009
+ await import_promises4.default.writeFile(file, entry.content);
922
1010
  })
923
1011
  );
924
1012
  console.log(`[MDX] generated files in ${performance.now() - start}ms`);
1013
+ },
1014
+ async transformMeta(options2, data) {
1015
+ const ctx = {
1016
+ ...pluginContext,
1017
+ ...options2
1018
+ };
1019
+ data = await transformMetadata(options2, data);
1020
+ for (const plugin of plugins) {
1021
+ if (plugin.meta?.transform)
1022
+ data = await plugin.meta.transform.call(ctx, data) ?? data;
1023
+ }
1024
+ return data;
1025
+ },
1026
+ async transformFrontmatter(options2, data) {
1027
+ const ctx = {
1028
+ ...pluginContext,
1029
+ ...options2
1030
+ };
1031
+ data = await transformMetadata(options2, data);
1032
+ for (const plugin of plugins) {
1033
+ if (plugin.doc?.frontmatter)
1034
+ data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
1035
+ }
1036
+ return data;
1037
+ },
1038
+ async transformVFile(options2, file) {
1039
+ const ctx = {
1040
+ ...pluginContext,
1041
+ ...options2
1042
+ };
1043
+ for (const plugin of plugins) {
1044
+ if (plugin.doc?.vfile)
1045
+ file = await plugin.doc.vfile.call(ctx, file) ?? file;
1046
+ }
1047
+ return file;
925
1048
  }
926
1049
  };
1050
+ const pluginContext = {
1051
+ core: core2,
1052
+ ...options
1053
+ };
1054
+ return core2;
927
1055
  }
928
-
929
- // src/loaders/config.ts
930
- var import_promises4 = __toESM(require("fs/promises"), 1);
931
- function createStandaloneConfigLoader({
932
- core,
933
- buildConfig: buildConfig2,
934
- mode
935
- }) {
936
- let loaded;
937
- async function getConfigHash2() {
938
- if (mode === "production") return "static";
939
- const stats = await import_promises4.default.stat(core._options.configPath).catch(() => {
940
- throw new Error("Cannot find config file");
941
- });
942
- return stats.mtime.getTime().toString();
943
- }
944
- async function newConfig() {
945
- const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load_from_file(), load_from_file_exports));
946
- await core.init({
947
- config: loadConfig2(
948
- core._options.configPath,
949
- core._options.outDir,
950
- buildConfig2
951
- )
952
- });
953
- return core.getConfig();
954
- }
1056
+ function postprocessPlugin() {
1057
+ const LinkReferenceTypes = `{
1058
+ /**
1059
+ * extracted references (e.g. hrefs, paths), useful for analyzing relationships between pages.
1060
+ */
1061
+ extractedReferences?: import('fumadocs-mdx').ExtractedReference[];
1062
+ }`;
955
1063
  return {
956
- async getConfig() {
957
- const hash = await getConfigHash2();
958
- if (loaded && loaded.hash === hash) return loaded.config;
959
- loaded = {
960
- hash,
961
- config: newConfig()
962
- };
963
- return loaded.config;
1064
+ "index-file": {
1065
+ generateTypeConfig() {
1066
+ const lines = [];
1067
+ lines.push("{");
1068
+ lines.push(" DocData: {");
1069
+ for (const collection of this.core.getConfig().collectionList) {
1070
+ let postprocessOptions;
1071
+ switch (collection.type) {
1072
+ case "doc":
1073
+ postprocessOptions = collection.postprocess;
1074
+ break;
1075
+ case "docs":
1076
+ postprocessOptions = collection.docs.postprocess;
1077
+ break;
1078
+ }
1079
+ if (postprocessOptions?.extractLinkReferences) {
1080
+ lines.push(ident(`${collection.name}: ${LinkReferenceTypes},`, 2));
1081
+ }
1082
+ }
1083
+ lines.push(" }");
1084
+ lines.push("}");
1085
+ return lines.join("\n");
1086
+ },
1087
+ serverOptions(options) {
1088
+ options.doc ??= {};
1089
+ options.doc.passthroughs ??= [];
1090
+ options.doc.passthroughs.push("extractedReferences");
1091
+ }
964
1092
  }
965
1093
  };
966
1094
  }
967
1095
 
1096
+ // src/webpack/index.ts
1097
+ var core;
1098
+ function getCore(options) {
1099
+ return core ??= createCore({
1100
+ environment: "webpack",
1101
+ outDir: options.outDir,
1102
+ configPath: options.configPath
1103
+ });
1104
+ }
1105
+
968
1106
  // src/webpack/mdx.ts
969
1107
  var instance;
970
1108
  async function loader(source, callback) {
971
- const { isDev, outDir, configPath } = this.getOptions();
1109
+ const options = this.getOptions();
972
1110
  this.cacheable(true);
973
- this.addDependency(configPath);
1111
+ this.addDependency(options.compiledConfigPath);
974
1112
  if (!instance) {
975
- const core = createCore({
976
- environment: "webpack",
977
- outDir,
978
- configPath
979
- });
980
1113
  instance = toWebpack(
981
1114
  createMdxLoader(
982
1115
  createStandaloneConfigLoader({
983
- core,
1116
+ core: getCore(options),
984
1117
  buildConfig: false,
985
- mode: isDev ? "dev" : "production"
1118
+ mode: options.isDev ? "dev" : "production"
986
1119
  })
987
1120
  )
988
1121
  );