fumadocs-mdx 13.0.7 → 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 +927 -904
  2. package/dist/bin.js +3 -3
  3. package/dist/build-mdx-6UAK5FF5.js +8 -0
  4. package/dist/bun/index.cjs +592 -481
  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-ETIN2W7C.js → chunk-SRSRFOVI.js} +22 -19
  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-HkAVGq_a.d.cts → index-D7JdSMpp.d.cts} +99 -61
  28. package/dist/{core-HkAVGq_a.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 +705 -603
  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 +935 -639
  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 +614 -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 +328 -234
  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-BnJhW5O1.d.cts +0 -53
  75. package/dist/build-mdx-DNzfRRlY.d.ts +0 -53
  76. package/dist/chunk-2AQRQXSO.js +0 -119
  77. package/dist/chunk-4757L6ST.js +0 -77
  78. package/dist/chunk-CXA4JO4Z.js +0 -45
  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-By6wKOnT.d.cts +0 -45
  104. package/dist/types-DgD5Omj2.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,48 @@ 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);
847
+ var import_node_fs = require("fs");
833
848
  function toWebpack(loader2) {
834
849
  return async function(source, callback) {
835
850
  try {
@@ -849,30 +864,103 @@ function toWebpack(loader2) {
849
864
  }
850
865
  } catch (error) {
851
866
  if (error instanceof ValidationError) {
852
- return callback(new Error(error.toStringFormatted()));
867
+ return callback(new Error(await error.toStringFormatted()));
853
868
  }
854
869
  if (!(error instanceof Error)) throw error;
855
- const fpath = import_node_path3.default.relative(this.context, this.resourcePath);
870
+ const fpath = import_node_path2.default.relative(this.context, this.resourcePath);
856
871
  error.message = `${fpath}:${error.name}: ${error.message}`;
857
872
  callback(error);
858
873
  }
859
874
  };
860
875
  }
861
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
+
862
913
  // src/core.ts
863
914
  var import_node_path4 = __toESM(require("path"), 1);
864
- 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
+ }
865
944
  function createCore(options, defaultPlugins = []) {
866
945
  let config;
867
- let plugins2;
868
- 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 = {
869
963
  _options: options,
870
- getPluginContext() {
871
- return {
872
- core: this,
873
- ...options
874
- };
875
- },
876
964
  /**
877
965
  * Convenient cache store, reset when config changes
878
966
  */
@@ -880,17 +968,12 @@ function createCore(options, defaultPlugins = []) {
880
968
  async init({ config: newConfig }) {
881
969
  config = await newConfig;
882
970
  this.cache.clear();
883
- plugins2 = [];
884
- for await (const option of [
971
+ plugins = await getPlugins([
885
972
  ...defaultPlugins,
886
973
  ...config.global.plugins ?? []
887
- ]) {
888
- if (!option) continue;
889
- if (Array.isArray(option)) plugins2.push(...option);
890
- else plugins2.push(option);
891
- }
892
- for (const plugin of plugins2) {
893
- 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);
894
977
  if (out) config = out;
895
978
  }
896
979
  return this;
@@ -898,90 +981,106 @@ function createCore(options, defaultPlugins = []) {
898
981
  getConfig() {
899
982
  return config;
900
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
+ },
901
990
  async initServer(server) {
902
- for (const plugin of plugins2) {
903
- 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);
904
996
  }
905
997
  },
906
- async emitAndWrite({
907
- filterPlugin = () => true
908
- } = {}) {
909
- const start = performance.now();
910
- const out = await Promise.all(
911
- plugins2.map((plugin) => {
998
+ async emit({ filterPlugin = () => true } = {}) {
999
+ return (await Promise.all(
1000
+ plugins.map((plugin) => {
912
1001
  if (!filterPlugin(plugin) || !plugin.emit) return [];
913
- return plugin.emit.call(this.getPluginContext());
1002
+ return plugin.emit.call(pluginContext);
914
1003
  })
915
- );
1004
+ )).flat();
1005
+ },
1006
+ async emitAndWrite(emitOptions) {
1007
+ const start = performance.now();
1008
+ const out = await this.emit(emitOptions);
916
1009
  await Promise.all(
917
- out.flat().map(async (entry) => {
1010
+ out.map(async (entry) => {
918
1011
  const file = import_node_path4.default.join(options.outDir, entry.path);
919
- await import_promises3.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
920
- 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);
921
1014
  })
922
1015
  );
923
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;
924
1052
  }
925
1053
  };
1054
+ const pluginContext = {
1055
+ core: core2,
1056
+ ...options
1057
+ };
1058
+ return core2;
926
1059
  }
927
1060
 
928
- // src/loaders/config.ts
929
- var import_promises4 = __toESM(require("fs/promises"), 1);
930
- function createStandaloneConfigLoader({
931
- core,
932
- buildConfig: buildConfig2,
933
- mode
934
- }) {
935
- let loaded;
936
- async function getConfigHash2() {
937
- if (mode === "production") return "static";
938
- const stats = await import_promises4.default.stat(core._options.configPath).catch(() => {
939
- throw new Error("Cannot find config file");
940
- });
941
- return stats.mtime.getTime().toString();
942
- }
943
- async function newConfig() {
944
- const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_load_from_file(), load_from_file_exports));
945
- await core.init({
946
- config: loadConfig2(
947
- core._options.configPath,
948
- core._options.outDir,
949
- buildConfig2
950
- )
951
- });
952
- return core.getConfig();
953
- }
954
- return {
955
- async getConfig() {
956
- const hash = await getConfigHash2();
957
- if (loaded && loaded.hash === hash) return loaded.config;
958
- loaded = {
959
- hash,
960
- config: newConfig()
961
- };
962
- return loaded.config;
963
- }
964
- };
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
+ });
965
1069
  }
966
1070
 
967
1071
  // src/webpack/mdx.ts
968
1072
  var instance;
969
1073
  async function loader(source, callback) {
970
- const { isDev, outDir, configPath } = this.getOptions();
1074
+ const options = this.getOptions();
971
1075
  this.cacheable(true);
972
- this.addDependency(configPath);
1076
+ this.addDependency(options.compiledConfigPath);
973
1077
  if (!instance) {
974
- const core = createCore({
975
- environment: "webpack",
976
- outDir,
977
- configPath
978
- });
979
1078
  instance = toWebpack(
980
1079
  createMdxLoader(
981
1080
  createStandaloneConfigLoader({
982
- core,
1081
+ core: getCore(options),
983
1082
  buildConfig: false,
984
- mode: isDev ? "dev" : "production"
1083
+ mode: options.isDev ? "dev" : "production"
985
1084
  })
986
1085
  )
987
1086
  );