fumadocs-mdx 13.0.8 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/bin.cjs +924 -901
  2. package/dist/bin.js +3 -3
  3. package/dist/build-mdx-6UAK5FF5.js +8 -0
  4. package/dist/bun/index.cjs +578 -471
  5. package/dist/bun/index.d.cts +3 -2
  6. package/dist/bun/index.d.ts +3 -2
  7. package/dist/bun/index.js +12 -12
  8. package/dist/chunk-4JSFLXXT.js +8 -0
  9. package/dist/chunk-5UMZCWKV.js +17 -0
  10. package/dist/chunk-5YXP7JLN.js +138 -0
  11. package/dist/{chunk-2E2JCOSO.js → chunk-6NISOLQ6.js} +16 -44
  12. package/dist/chunk-7L2KNF6B.js +180 -0
  13. package/dist/chunk-E5DJTSIM.js +86 -0
  14. package/dist/{chunk-K5ZLPEIQ.js → chunk-FBLMK4RS.js} +9 -6
  15. package/dist/{chunk-QXHN25N3.js → chunk-OXSRIWQW.js} +7 -8
  16. package/dist/chunk-PKI7ZDA5.js +29 -0
  17. package/dist/{chunk-3J3WL7WN.js → chunk-SLY7WXTX.js} +71 -58
  18. package/dist/{chunk-5FTSWCB4.js → chunk-SRSRFOVI.js} +8 -10
  19. package/dist/chunk-TYJDYTKH.js +85 -0
  20. package/dist/chunk-XHJCLBZ4.js +406 -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 +2 -1
  24. package/dist/config/index.d.ts +2 -1
  25. package/dist/config/index.js +5 -5
  26. package/dist/index-BlVBvy-z.d.ts +8 -0
  27. package/dist/{core-DB7TdlyC.d.cts → index-D7JdSMpp.d.cts} +99 -61
  28. package/dist/{core-DB7TdlyC.d.ts → index-D7JdSMpp.d.ts} +99 -61
  29. package/dist/index-P2NNUkHn.d.cts +8 -0
  30. package/dist/index.d.cts +3 -74
  31. package/dist/index.d.ts +3 -74
  32. package/dist/load-from-file-I3ALLIVB.js +8 -0
  33. package/dist/next/index.cjs +698 -476
  34. package/dist/next/index.d.cts +11 -1
  35. package/dist/next/index.d.ts +11 -1
  36. package/dist/next/index.js +78 -281
  37. package/dist/node/loader.cjs +704 -602
  38. package/dist/node/loader.js +10 -11
  39. package/dist/plugins/index-file.cjs +471 -0
  40. package/dist/plugins/index-file.d.cts +29 -0
  41. package/dist/plugins/index-file.d.ts +29 -0
  42. package/dist/plugins/index-file.js +8 -0
  43. package/dist/plugins/json-schema.d.cts +3 -2
  44. package/dist/plugins/json-schema.d.ts +3 -2
  45. package/dist/plugins/last-modified.cjs +75 -0
  46. package/dist/plugins/last-modified.d.cts +27 -0
  47. package/dist/plugins/last-modified.d.ts +27 -0
  48. package/dist/plugins/last-modified.js +44 -0
  49. package/dist/runtime/{vite/browser.cjs → browser.cjs} +40 -53
  50. package/dist/runtime/browser.d.cts +50 -0
  51. package/dist/runtime/browser.d.ts +50 -0
  52. package/dist/runtime/browser.js +68 -0
  53. package/dist/runtime/dynamic.cjs +985 -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 +78 -0
  57. package/dist/runtime/server.cjs +173 -0
  58. package/dist/runtime/server.d.cts +161 -0
  59. package/dist/runtime/server.d.ts +161 -0
  60. package/dist/runtime/server.js +8 -0
  61. package/dist/vite/index.cjs +934 -638
  62. package/dist/vite/index.d.cts +12 -22
  63. package/dist/vite/index.d.ts +12 -22
  64. package/dist/vite/index.js +30 -221
  65. package/dist/webpack/mdx.cjs +613 -515
  66. package/dist/webpack/mdx.d.cts +9 -1
  67. package/dist/webpack/mdx.d.ts +9 -1
  68. package/dist/webpack/mdx.js +12 -17
  69. package/dist/webpack/meta.cjs +327 -233
  70. package/dist/webpack/meta.d.cts +9 -1
  71. package/dist/webpack/meta.d.ts +9 -1
  72. package/dist/webpack/meta.js +13 -15
  73. package/package.json +15 -32
  74. package/dist/build-mdx-BjXOmv0b.d.cts +0 -53
  75. package/dist/build-mdx-CY5UldCO.d.ts +0 -53
  76. package/dist/chunk-2AQRQXSO.js +0 -119
  77. package/dist/chunk-CXA4JO4Z.js +0 -45
  78. package/dist/chunk-DMJ6I4C3.js +0 -76
  79. package/dist/chunk-FSZMKRVH.js +0 -80
  80. package/dist/chunk-II3H5ZVZ.js +0 -77
  81. package/dist/chunk-KILFIBVW.js +0 -75
  82. package/dist/chunk-NVRDCY6Z.js +0 -30
  83. package/dist/chunk-VUEZTR2H.js +0 -26
  84. package/dist/index-D7s7kCc2.d.cts +0 -7
  85. package/dist/index-D7s7kCc2.d.ts +0 -7
  86. package/dist/load-from-file-AVYOFOI7.js +0 -7
  87. package/dist/preset-ZMP6U62C.js +0 -6
  88. package/dist/runtime/next/async.cjs +0 -760
  89. package/dist/runtime/next/async.d.cts +0 -19
  90. package/dist/runtime/next/async.d.ts +0 -19
  91. package/dist/runtime/next/async.js +0 -86
  92. package/dist/runtime/next/index.cjs +0 -136
  93. package/dist/runtime/next/index.d.cts +0 -33
  94. package/dist/runtime/next/index.d.ts +0 -33
  95. package/dist/runtime/next/index.js +0 -11
  96. package/dist/runtime/vite/browser.d.cts +0 -59
  97. package/dist/runtime/vite/browser.d.ts +0 -59
  98. package/dist/runtime/vite/browser.js +0 -11
  99. package/dist/runtime/vite/server.cjs +0 -243
  100. package/dist/runtime/vite/server.d.cts +0 -30
  101. package/dist/runtime/vite/server.d.ts +0 -30
  102. package/dist/runtime/vite/server.js +0 -111
  103. package/dist/types-Bnh9n7mj.d.cts +0 -45
  104. 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,330 @@ 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);
703
445
  }
704
-
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
+ };
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 transformed = await build({
657
+ entryPoints: [{ in: core2._options.configPath, out: "source.config" }],
658
+ bundle: true,
659
+ outdir: core2._options.outDir,
660
+ target: "node20",
661
+ write: true,
662
+ platform: "node",
663
+ format: "esm",
664
+ packages: "external",
665
+ outExtension: {
666
+ ".js": ".mjs"
667
+ },
668
+ allowOverwrite: true
669
+ });
670
+ if (transformed.errors.length > 0) {
671
+ throw new Error("failed to compile configuration file");
672
+ }
673
+ }
674
+ async function loadConfig(core2, build = false) {
675
+ if (build) await compileConfig(core2);
676
+ const url = (0, import_node_url2.pathToFileURL)(core2.getCompiledConfigPath());
677
+ url.searchParams.set("hash", Date.now().toString());
678
+ const config = import(url.href).then(
679
+ (loaded) => buildConfig(loaded)
680
+ );
681
+ return await config;
682
+ }
683
+ var import_node_url2;
684
+ var init_load_from_file = __esm({
685
+ "src/config/load-from-file.ts"() {
686
+ "use strict";
687
+ import_node_url2 = require("url");
688
+ init_build();
689
+ }
690
+ });
691
+
692
+ // src/webpack/mdx.ts
693
+ var mdx_exports = {};
694
+ __export(mdx_exports, {
695
+ default: () => loader
696
+ });
697
+ module.exports = __toCommonJS(mdx_exports);
698
+
705
699
  // src/loaders/mdx/index.ts
700
+ init_fuma_matter();
706
701
  var import_zod = require("zod");
707
702
  var import_promises = __toESM(require("fs/promises"), 1);
708
- var import_node_path2 = __toESM(require("path"), 1);
703
+ var import_node_path = __toESM(require("path"), 1);
709
704
  var import_node_crypto = require("crypto");
710
705
 
711
706
  // src/loaders/index.ts
@@ -731,20 +726,20 @@ function createMdxLoader(configLoader) {
731
726
  compiler,
732
727
  filePath
733
728
  }) {
729
+ const config = await configLoader.getConfig();
734
730
  const value = await getSource();
735
731
  const matter = fumaMatter(value);
736
732
  const parsed = querySchema.parse(query);
737
- const config = await configLoader.getConfig();
738
733
  let after;
739
734
  if (!isDevelopment && config.global.experimentalBuildCache) {
740
735
  const cacheDir = config.global.experimentalBuildCache;
741
736
  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);
737
+ 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
738
  if (cached && cached.hash === generateCacheHash(value)) return cached;
744
739
  after = async () => {
745
740
  await import_promises.default.mkdir(cacheDir, { recursive: true });
746
741
  await import_promises.default.writeFile(
747
- import_node_path2.default.join(cacheDir, cacheKey),
742
+ import_node_path.default.join(cacheDir, cacheKey),
748
743
  JSON.stringify({
749
744
  ...out,
750
745
  hash: generateCacheHash(value)
@@ -762,15 +757,10 @@ function createMdxLoader(configLoader) {
762
757
  docCollection = collection.docs;
763
758
  break;
764
759
  }
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}`
760
+ if (docCollection) {
761
+ matter.data = await configLoader.core.transformFrontmatter(
762
+ { collection: docCollection, filePath, source: value },
763
+ matter.data
774
764
  );
775
765
  }
776
766
  if (parsed.only === "frontmatter") {
@@ -779,24 +769,16 @@ function createMdxLoader(configLoader) {
779
769
  map: null
780
770
  };
781
771
  }
782
- const data = {};
783
- if (config.global.lastModifiedTime === "git") {
784
- data.lastModified = (await getGitTimestamp(filePath))?.getTime();
785
- }
786
772
  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
- );
773
+ const { buildMDX: buildMDX2 } = await Promise.resolve().then(() => (init_build_mdx(), build_mdx_exports));
774
+ const compiled = await buildMDX2(configLoader.core, docCollection, {
775
+ isDevelopment,
776
+ source: "\n".repeat(lineOffset) + matter.content,
777
+ filePath,
778
+ frontmatter: matter.data,
779
+ _compiler: compiler,
780
+ environment: "bundler"
781
+ });
800
782
  const out = {
801
783
  code: String(compiled.value),
802
784
  map: compiled.map
@@ -806,14 +788,6 @@ function createMdxLoader(configLoader) {
806
788
  }
807
789
  };
808
790
  }
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
791
  function generateCacheHash(input) {
818
792
  return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
819
793
  }
@@ -829,7 +803,47 @@ function countLines(s) {
829
803
  var import_node_url = require("url");
830
804
  var import_promises2 = __toESM(require("fs/promises"), 1);
831
805
  var import_node_querystring = require("querystring");
832
- var import_node_path3 = __toESM(require("path"), 1);
806
+
807
+ // src/utils/validation.ts
808
+ var ValidationError = class extends Error {
809
+ constructor(message, issues) {
810
+ super(
811
+ `${message}:
812
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
813
+ );
814
+ this.title = message;
815
+ this.issues = issues;
816
+ }
817
+ async toStringFormatted() {
818
+ const picocolors = await import("picocolors");
819
+ return [
820
+ picocolors.bold(`[MDX] ${this.title}:`),
821
+ ...this.issues.map(
822
+ (issue) => picocolors.redBright(
823
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
824
+ )
825
+ )
826
+ ].join("\n");
827
+ }
828
+ };
829
+ async function validate(schema, data, context, errorMessage) {
830
+ if (typeof schema === "function" && !("~standard" in schema)) {
831
+ schema = schema(context);
832
+ }
833
+ if ("~standard" in schema) {
834
+ const result = await schema["~standard"].validate(
835
+ data
836
+ );
837
+ if (result.issues) {
838
+ throw new ValidationError(errorMessage, result.issues);
839
+ }
840
+ return result.value;
841
+ }
842
+ return data;
843
+ }
844
+
845
+ // src/loaders/adapter.ts
846
+ var import_node_path2 = __toESM(require("path"), 1);
833
847
  var import_node_fs = require("fs");
834
848
  function toWebpack(loader2) {
835
849
  return async function(source, callback) {
@@ -850,30 +864,103 @@ function toWebpack(loader2) {
850
864
  }
851
865
  } catch (error) {
852
866
  if (error instanceof ValidationError) {
853
- return callback(new Error(error.toStringFormatted()));
867
+ return callback(new Error(await error.toStringFormatted()));
854
868
  }
855
869
  if (!(error instanceof Error)) throw error;
856
- const fpath = import_node_path3.default.relative(this.context, this.resourcePath);
870
+ const fpath = import_node_path2.default.relative(this.context, this.resourcePath);
857
871
  error.message = `${fpath}:${error.name}: ${error.message}`;
858
872
  callback(error);
859
873
  }
860
874
  };
861
875
  }
862
876
 
877
+ // src/loaders/config.ts
878
+ var import_promises3 = __toESM(require("fs/promises"), 1);
879
+ function createStandaloneConfigLoader({
880
+ core: core2,
881
+ buildConfig: buildConfig2,
882
+ mode
883
+ }) {
884
+ let loaded;
885
+ async function getConfigHash() {
886
+ if (mode === "production") return "static";
887
+ const stats = await import_promises3.default.stat(core2._options.configPath).catch(() => {
888
+ throw new Error("Cannot find config file");
889
+ });
890
+ return stats.mtime.getTime().toString();
891
+ }
892
+ async function newConfig() {
893
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load_from_file(), load_from_file_exports));
894
+ await core2.init({
895
+ config: loadConfig2(core2, buildConfig2)
896
+ });
897
+ return core2.getConfig();
898
+ }
899
+ return {
900
+ core: core2,
901
+ async getConfig() {
902
+ const hash = await getConfigHash();
903
+ if (loaded && loaded.hash === hash) return loaded.config;
904
+ loaded = {
905
+ hash,
906
+ config: newConfig()
907
+ };
908
+ return loaded.config;
909
+ }
910
+ };
911
+ }
912
+
863
913
  // src/core.ts
864
914
  var import_node_path4 = __toESM(require("path"), 1);
865
- var import_promises3 = __toESM(require("fs/promises"), 1);
915
+ var import_promises5 = __toESM(require("fs/promises"), 1);
916
+
917
+ // src/utils/codegen/cache.ts
918
+ var import_lru_cache = require("lru-cache");
919
+ var import_promises4 = __toESM(require("fs/promises"), 1);
920
+ var import_node_path3 = __toESM(require("path"), 1);
921
+ var map = new import_lru_cache.LRUCache({
922
+ max: 100
923
+ });
924
+ function toFullPath(file) {
925
+ if (import_node_path3.default.isAbsolute(file)) {
926
+ return import_node_path3.default.relative(process.cwd(), file);
927
+ }
928
+ return file;
929
+ }
930
+ function removeFileCache(file) {
931
+ map.delete(toFullPath(file));
932
+ }
933
+
934
+ // src/core.ts
935
+ async function getPlugins(pluginOptions) {
936
+ const plugins = [];
937
+ for await (const option of pluginOptions) {
938
+ if (!option) continue;
939
+ if (Array.isArray(option)) plugins.push(...await getPlugins(option));
940
+ else plugins.push(option);
941
+ }
942
+ return plugins;
943
+ }
866
944
  function createCore(options, defaultPlugins = []) {
867
945
  let config;
868
- let plugins2;
869
- return {
946
+ let plugins;
947
+ async function transformMetadata({
948
+ collection,
949
+ filePath,
950
+ source
951
+ }, data) {
952
+ if (collection.schema) {
953
+ data = await validate(
954
+ collection.schema,
955
+ data,
956
+ { path: filePath, source },
957
+ collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`
958
+ );
959
+ }
960
+ return data;
961
+ }
962
+ const core2 = {
870
963
  _options: options,
871
- getPluginContext() {
872
- return {
873
- core: this,
874
- ...options
875
- };
876
- },
877
964
  /**
878
965
  * Convenient cache store, reset when config changes
879
966
  */
@@ -881,17 +968,12 @@ function createCore(options, defaultPlugins = []) {
881
968
  async init({ config: newConfig }) {
882
969
  config = await newConfig;
883
970
  this.cache.clear();
884
- plugins2 = [];
885
- for await (const option of [
971
+ plugins = await getPlugins([
886
972
  ...defaultPlugins,
887
973
  ...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);
974
+ ]);
975
+ for (const plugin of plugins) {
976
+ const out = await plugin.config?.call(pluginContext, config);
895
977
  if (out) config = out;
896
978
  }
897
979
  return this;
@@ -899,90 +981,106 @@ function createCore(options, defaultPlugins = []) {
899
981
  getConfig() {
900
982
  return config;
901
983
  },
984
+ /**
985
+ * The file path of compiled config file, the file may not exist (e.g. on Vite, or still compiling)
986
+ */
987
+ getCompiledConfigPath() {
988
+ return import_node_path4.default.join(options.outDir, "source.config.mjs");
989
+ },
902
990
  async initServer(server) {
903
- for (const plugin of plugins2) {
904
- await plugin.configureServer?.call(this.getPluginContext(), server);
991
+ server.watcher?.on("all", async (event, file) => {
992
+ if (event === "change") removeFileCache(file);
993
+ });
994
+ for (const plugin of plugins) {
995
+ await plugin.configureServer?.call(pluginContext, server);
905
996
  }
906
997
  },
907
- async emitAndWrite({
908
- filterPlugin = () => true
909
- } = {}) {
910
- const start = performance.now();
911
- const out = await Promise.all(
912
- plugins2.map((plugin) => {
998
+ async emit({ filterPlugin = () => true } = {}) {
999
+ return (await Promise.all(
1000
+ plugins.map((plugin) => {
913
1001
  if (!filterPlugin(plugin) || !plugin.emit) return [];
914
- return plugin.emit.call(this.getPluginContext());
1002
+ return plugin.emit.call(pluginContext);
915
1003
  })
916
- );
1004
+ )).flat();
1005
+ },
1006
+ async emitAndWrite(emitOptions) {
1007
+ const start = performance.now();
1008
+ const out = await this.emit(emitOptions);
917
1009
  await Promise.all(
918
- out.flat().map(async (entry) => {
1010
+ out.map(async (entry) => {
919
1011
  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);
1012
+ await import_promises5.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
1013
+ await import_promises5.default.writeFile(file, entry.content);
922
1014
  })
923
1015
  );
924
1016
  console.log(`[MDX] generated files in ${performance.now() - start}ms`);
1017
+ },
1018
+ async transformMeta(options2, data) {
1019
+ const ctx = {
1020
+ ...pluginContext,
1021
+ ...options2
1022
+ };
1023
+ data = await transformMetadata(options2, data);
1024
+ for (const plugin of plugins) {
1025
+ if (plugin.meta?.transform)
1026
+ data = await plugin.meta.transform.call(ctx, data) ?? data;
1027
+ }
1028
+ return data;
1029
+ },
1030
+ async transformFrontmatter(options2, data) {
1031
+ const ctx = {
1032
+ ...pluginContext,
1033
+ ...options2
1034
+ };
1035
+ data = await transformMetadata(options2, data);
1036
+ for (const plugin of plugins) {
1037
+ if (plugin.doc?.frontmatter)
1038
+ data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
1039
+ }
1040
+ return data;
1041
+ },
1042
+ async transformVFile(options2, file) {
1043
+ const ctx = {
1044
+ ...pluginContext,
1045
+ ...options2
1046
+ };
1047
+ for (const plugin of plugins) {
1048
+ if (plugin.doc?.vfile)
1049
+ file = await plugin.doc.vfile.call(ctx, file) ?? file;
1050
+ }
1051
+ return file;
925
1052
  }
926
1053
  };
1054
+ const pluginContext = {
1055
+ core: core2,
1056
+ ...options
1057
+ };
1058
+ return core2;
927
1059
  }
928
1060
 
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
- }
955
- 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;
964
- }
965
- };
1061
+ // src/webpack/index.ts
1062
+ var core;
1063
+ function getCore(options) {
1064
+ return core ??= createCore({
1065
+ environment: "webpack",
1066
+ outDir: options.outDir,
1067
+ configPath: options.configPath
1068
+ });
966
1069
  }
967
1070
 
968
1071
  // src/webpack/mdx.ts
969
1072
  var instance;
970
1073
  async function loader(source, callback) {
971
- const { isDev, outDir, configPath } = this.getOptions();
1074
+ const options = this.getOptions();
972
1075
  this.cacheable(true);
973
- this.addDependency(configPath);
1076
+ this.addDependency(options.compiledConfigPath);
974
1077
  if (!instance) {
975
- const core = createCore({
976
- environment: "webpack",
977
- outDir,
978
- configPath
979
- });
980
1078
  instance = toWebpack(
981
1079
  createMdxLoader(
982
1080
  createStandaloneConfigLoader({
983
- core,
1081
+ core: getCore(options),
984
1082
  buildConfig: false,
985
- mode: isDev ? "dev" : "production"
1083
+ mode: options.isDev ? "dev" : "production"
986
1084
  })
987
1085
  )
988
1086
  );