fumadocs-mdx 11.9.1 → 11.10.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 (37) hide show
  1. package/dist/{browser-CyU2Yl7A.d.cts → browser-B2G8uAF2.d.cts} +1 -1
  2. package/dist/{browser-DEsQvNRx.d.ts → browser-DrH7tKRi.d.ts} +1 -1
  3. package/dist/bun/index.cjs +667 -0
  4. package/dist/bun/index.d.cts +8 -0
  5. package/dist/bun/index.d.ts +8 -0
  6. package/dist/bun/index.js +50 -0
  7. package/dist/{chunk-766EAFX6.js → chunk-2HKRTQYP.js} +64 -0
  8. package/dist/chunk-5XJM5RPV.js +149 -0
  9. package/dist/chunk-NVX3U5YE.js +82 -0
  10. package/dist/config/index.d.cts +1 -1
  11. package/dist/config/index.d.ts +1 -1
  12. package/dist/config/zod-3.d.cts +1 -1
  13. package/dist/config/zod-3.d.ts +1 -1
  14. package/dist/{define-DnJzAZrj.d.cts → define-BH4bnHQl.d.cts} +6 -0
  15. package/dist/{define-DnJzAZrj.d.ts → define-BH4bnHQl.d.ts} +6 -0
  16. package/dist/index.d.cts +2 -2
  17. package/dist/index.d.ts +2 -2
  18. package/dist/loader-mdx.cjs +345 -265
  19. package/dist/loader-mdx.js +11 -80
  20. package/dist/next/index.js +4 -6
  21. package/dist/node/loader.cjs +748 -0
  22. package/dist/node/loader.d.cts +5 -0
  23. package/dist/node/loader.d.ts +5 -0
  24. package/dist/node/loader.js +23 -0
  25. package/dist/runtime/async.d.cts +2 -2
  26. package/dist/runtime/async.d.ts +2 -2
  27. package/dist/runtime/vite/browser.d.cts +2 -2
  28. package/dist/runtime/vite/browser.d.ts +2 -2
  29. package/dist/runtime/vite/server.d.cts +3 -3
  30. package/dist/runtime/vite/server.d.ts +3 -3
  31. package/dist/{types-WSHJKA8L.d.ts → types-DN9KrG7R.d.ts} +1 -1
  32. package/dist/{types-BmVgoqsr.d.cts → types-DT83Ijs6.d.cts} +1 -1
  33. package/dist/vite/index.cjs +356 -282
  34. package/dist/vite/index.js +12 -78
  35. package/package.json +17 -8
  36. package/dist/chunk-GX3THK2Q.js +0 -66
  37. package/dist/chunk-UCY7OBZG.js +0 -12
@@ -37,9 +37,9 @@ function remarkPostprocess({
37
37
  return (tree, file) => {
38
38
  let title;
39
39
  const urls = [];
40
- (0, import_unist_util_visit.visit)(tree, ["heading", "link"], (node) => {
40
+ (0, import_unist_util_visit2.visit)(tree, ["heading", "link"], (node) => {
41
41
  if (node.type === "heading" && node.depth === 1) {
42
- title = flattenNode(node);
42
+ title = flattenNode2(node);
43
43
  }
44
44
  if (node.type !== "link") return;
45
45
  urls.push({
@@ -58,9 +58,9 @@ function remarkPostprocess({
58
58
  }
59
59
  };
60
60
  }
61
- function flattenNode(node) {
61
+ function flattenNode2(node) {
62
62
  if ("children" in node)
63
- return node.children.map((child) => flattenNode(child)).join("");
63
+ return node.children.map((child) => flattenNode2(child)).join("");
64
64
  if ("value" in node) return node.value;
65
65
  return "";
66
66
  }
@@ -98,11 +98,11 @@ function getMdastExport(name, value) {
98
98
  }
99
99
  };
100
100
  }
101
- var import_unist_util_visit, import_estree_util_value_to_estree;
101
+ var import_unist_util_visit2, import_estree_util_value_to_estree;
102
102
  var init_remark_postprocess = __esm({
103
103
  "src/mdx-plugins/remark-postprocess.ts"() {
104
104
  "use strict";
105
- import_unist_util_visit = require("unist-util-visit");
105
+ import_unist_util_visit2 = require("unist-util-visit");
106
106
  import_estree_util_value_to_estree = require("estree-util-value-to-estree");
107
107
  }
108
108
  });
@@ -203,137 +203,91 @@ __export(loader_mdx_exports, {
203
203
  default: () => loader
204
204
  });
205
205
  module.exports = __toCommonJS(loader_mdx_exports);
206
- var path4 = __toESM(require("path"), 1);
207
- var import_node_querystring = require("querystring");
208
206
 
209
- // src/utils/config.ts
210
- var fs = __toESM(require("fs/promises"), 1);
211
- var path = __toESM(require("path"), 1);
212
- var import_node_url = require("url");
207
+ // src/utils/fuma-matter.ts
208
+ var import_js_yaml = require("js-yaml");
209
+ var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
210
+ function fumaMatter(input) {
211
+ const output = { matter: "", data: {}, content: input };
212
+ const match = regex.exec(input);
213
+ if (!match) {
214
+ return output;
215
+ }
216
+ output.matter = match[0];
217
+ output.content = input.slice(match[0].length);
218
+ const loaded = (0, import_js_yaml.load)(match[1]);
219
+ output.data = loaded ?? {};
220
+ return output;
221
+ }
213
222
 
214
- // src/config/build.ts
215
- function buildConfig(config) {
216
- const collections = /* @__PURE__ */ new Map();
217
- let globalConfig = {};
218
- for (const [k, v] of Object.entries(config)) {
219
- if (!v) {
220
- continue;
221
- }
222
- if (typeof v === "object" && "type" in v) {
223
- if (v.type === "docs") {
224
- collections.set(k, v);
225
- continue;
226
- }
227
- if (v.type === "doc" || v.type === "meta") {
228
- collections.set(k, v);
229
- continue;
230
- }
231
- }
232
- if (k === "default" && v) {
233
- globalConfig = v;
234
- continue;
235
- }
236
- throw new Error(
237
- `Unknown export "${k}", you can only export collections from source configuration file.`
223
+ // src/utils/validation.ts
224
+ var import_picocolors = __toESM(require("picocolors"), 1);
225
+ var ValidationError = class extends Error {
226
+ constructor(message, issues) {
227
+ super(
228
+ `${message}:
229
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
238
230
  );
231
+ this.title = message;
232
+ this.issues = issues;
239
233
  }
240
- const mdxOptionsCache = /* @__PURE__ */ new Map();
241
- return {
242
- global: globalConfig,
243
- collections,
244
- async getDefaultMDXOptions(mode = "default") {
245
- const cached = mdxOptionsCache.get(mode);
246
- if (cached) return cached;
247
- const input = this.global.mdxOptions;
248
- async function uncached() {
249
- const options = typeof input === "function" ? await input() : input;
250
- const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
251
- if (options?.preset === "minimal") return options;
252
- return getDefaultMDXOptions2({
253
- ...options,
254
- _withoutBundler: mode === "remote"
255
- });
256
- }
257
- const result = uncached();
258
- mdxOptionsCache.set(mode, result);
259
- return result;
234
+ toStringFormatted() {
235
+ return [
236
+ import_picocolors.default.bold(`[MDX] ${this.title}:`),
237
+ ...this.issues.map(
238
+ (issue) => import_picocolors.default.redBright(
239
+ `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
240
+ )
241
+ )
242
+ ].join("\n");
243
+ }
244
+ };
245
+ async function validate(schema, data, context, errorMessage) {
246
+ if (typeof schema === "function" && !("~standard" in schema)) {
247
+ schema = schema(context);
248
+ }
249
+ if ("~standard" in schema) {
250
+ const result = await schema["~standard"].validate(
251
+ data
252
+ );
253
+ if (result.issues) {
254
+ throw new ValidationError(errorMessage, result.issues);
260
255
  }
261
- };
256
+ return result.value;
257
+ }
258
+ return data;
262
259
  }
263
260
 
264
- // src/utils/config.ts
265
- var cache = null;
266
- async function isZod3() {
261
+ // src/utils/git-timestamp.ts
262
+ var import_node_path = __toESM(require("path"), 1);
263
+ var import_tinyexec = require("tinyexec");
264
+ var cache = /* @__PURE__ */ new Map();
265
+ async function getGitTimestamp(file) {
266
+ const cached = cache.get(file);
267
+ if (cached) return cached;
267
268
  try {
268
- const content = JSON.parse(
269
- (await fs.readFile("node_modules/zod/package.json")).toString()
269
+ const out = await (0, import_tinyexec.x)(
270
+ "git",
271
+ ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
272
+ {
273
+ throwOnError: true
274
+ }
270
275
  );
271
- const version = content.version;
272
- return typeof version === "string" && version.startsWith("3.");
276
+ const time = new Date(out.stdout);
277
+ cache.set(file, time);
278
+ return time;
273
279
  } catch {
274
- return false;
275
- }
276
- }
277
- function createCompatZodPlugin() {
278
- return {
279
- name: "replace-zod-import",
280
- async setup(build) {
281
- const usingZod3 = await isZod3();
282
- if (!usingZod3) return;
283
- console.warn(
284
- "[Fumadocs MDX] Noticed Zod v3 in your node_modules, we recommend upgrading to Zod v4 for better compatibility."
285
- );
286
- build.onResolve({ filter: /^fumadocs-mdx\/config$/ }, () => {
287
- return {
288
- path: "fumadocs-mdx/config/zod-3",
289
- external: true
290
- };
291
- });
292
- }
293
- };
294
- }
295
- async function compileConfig(configPath, outDir) {
296
- const { build } = await import("esbuild");
297
- const transformed = await build({
298
- entryPoints: [{ in: configPath, out: "source.config" }],
299
- bundle: true,
300
- outdir: outDir,
301
- target: "node20",
302
- write: true,
303
- platform: "node",
304
- format: "esm",
305
- packages: "external",
306
- plugins: [createCompatZodPlugin()],
307
- outExtension: {
308
- ".js": ".mjs"
309
- },
310
- allowOverwrite: true
311
- });
312
- if (transformed.errors.length > 0) {
313
- throw new Error("failed to compile configuration file");
314
- }
315
- }
316
- async function loadConfig(configPath, outDir, hash, build = false) {
317
- if (cache && cache.hash === hash) {
318
- return await cache.config;
280
+ return;
319
281
  }
320
- if (build) await compileConfig(configPath, outDir);
321
- const url = (0, import_node_url.pathToFileURL)(path.resolve(outDir, "source.config.mjs"));
322
- const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
323
- return buildConfig(
324
- // every call to `loadConfig` will cause the previous cache to be ignored
325
- loaded
326
- );
327
- });
328
- if (hash) cache = { config, hash };
329
- return await config;
330
282
  }
331
- async function getConfigHash(configPath) {
332
- const stats = await fs.stat(configPath).catch(() => void 0);
333
- if (stats) {
334
- return stats.mtime.getTime().toString();
283
+
284
+ // src/utils/count-lines.ts
285
+ function countLines(s) {
286
+ let num = 0;
287
+ for (const c of s) {
288
+ if (c === "\n") num++;
335
289
  }
336
- throw new Error("Cannot find config file");
290
+ return num;
337
291
  }
338
292
 
339
293
  // src/utils/build-mdx.ts
@@ -341,34 +295,16 @@ var import_mdx = require("@mdx-js/mdx");
341
295
 
342
296
  // src/mdx-plugins/remark-include.ts
343
297
  var import_unified = require("unified");
344
- var import_unist_util_visit2 = require("unist-util-visit");
298
+ var import_unist_util_visit = require("unist-util-visit");
345
299
  var path2 = __toESM(require("path"), 1);
346
- var fs2 = __toESM(require("fs/promises"), 1);
347
-
348
- // src/utils/fuma-matter.ts
349
- var import_js_yaml = require("js-yaml");
350
- var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
351
- function fumaMatter(input) {
352
- const output = { matter: "", data: {}, content: input };
353
- const match = regex.exec(input);
354
- if (!match) {
355
- return output;
356
- }
357
- output.matter = match[0];
358
- output.content = input.slice(match[0].length);
359
- const loaded = (0, import_js_yaml.load)(match[1]);
360
- output.data = loaded ?? {};
361
- return output;
362
- }
363
-
364
- // src/mdx-plugins/remark-include.ts
300
+ var fs = __toESM(require("fs/promises"), 1);
365
301
  var import_remark_parse = __toESM(require("remark-parse"), 1);
366
302
  var import_remark_mdx = __toESM(require("remark-mdx"), 1);
367
303
  var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
368
304
  var baseProcessor = (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading);
369
- function flattenNode2(node) {
305
+ function flattenNode(node) {
370
306
  if ("children" in node)
371
- return node.children.map((child) => flattenNode2(child)).join("");
307
+ return node.children.map((child) => flattenNode(child)).join("");
372
308
  if ("value" in node) return node.value;
373
309
  return "";
374
310
  }
@@ -408,7 +344,7 @@ function remarkInclude() {
408
344
  async function embedContent(file, heading, params, data) {
409
345
  let content;
410
346
  try {
411
- content = (await fs2.readFile(file)).toString();
347
+ content = (await fs.readFile(file)).toString();
412
348
  } catch (e) {
413
349
  throw new Error(
414
350
  `failed to read file ${file}
@@ -447,14 +383,14 @@ ${e instanceof Error ? e.message : String(e)}`,
447
383
  }
448
384
  async function update(tree, directory, data) {
449
385
  const queue = [];
450
- (0, import_unist_util_visit2.visit)(
386
+ (0, import_unist_util_visit.visit)(
451
387
  tree,
452
388
  ["mdxJsxFlowElement", "mdxJsxTextElement"],
453
389
  (_node, _, parent) => {
454
390
  const node = _node;
455
391
  if (node.name !== TagName) return;
456
392
  const params = {};
457
- const specifier = flattenNode2(node);
393
+ const specifier = flattenNode(node);
458
394
  if (specifier.length === 0) return "skip";
459
395
  for (const attr of node.attributes) {
460
396
  if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
@@ -521,140 +457,284 @@ async function buildMDX(cacheKey, source, options) {
521
457
  });
522
458
  }
523
459
 
524
- // src/utils/git-timestamp.ts
525
- var import_node_path = __toESM(require("path"), 1);
526
- var import_tinyexec = require("tinyexec");
527
- var cache3 = /* @__PURE__ */ new Map();
528
- async function getGitTimestamp(file) {
529
- const cached = cache3.get(file);
530
- if (cached) return cached;
531
- try {
532
- const out = await (0, import_tinyexec.x)(
533
- "git",
534
- ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
460
+ // src/loaders/mdx.ts
461
+ var import_zod = require("zod");
462
+ var import_promises = __toESM(require("fs/promises"), 1);
463
+ var import_node_path2 = __toESM(require("path"), 1);
464
+ var import_node_crypto = require("crypto");
465
+ var querySchema = import_zod.z.object({
466
+ only: import_zod.z.literal(["frontmatter", "all"]).default("all"),
467
+ collection: import_zod.z.string().optional(),
468
+ hash: import_zod.z.string().describe(
469
+ "the hash of config, used for revalidation on Turbopack/Webpack."
470
+ ).optional()
471
+ }).loose();
472
+ var cacheEntry = import_zod.z.object({
473
+ code: import_zod.z.string(),
474
+ map: import_zod.z.any().optional(),
475
+ hash: import_zod.z.string().optional()
476
+ });
477
+ function createMdxLoader(configLoader) {
478
+ return async ({
479
+ source: value,
480
+ development: isDevelopment,
481
+ query,
482
+ compiler,
483
+ filePath
484
+ }) => {
485
+ const matter = fumaMatter(value);
486
+ const parsed = querySchema.parse(query);
487
+ const loaded = await configLoader.getConfig(parsed.hash);
488
+ const cacheDir = isDevelopment ? void 0 : loaded.global.experimentalBuildCache;
489
+ const cacheKey = `${parsed.hash}_${parsed.collection ?? "global"}_${generateCacheHash(filePath)}`;
490
+ if (cacheDir) {
491
+ const cached = await import_promises.default.readFile(import_node_path2.default.join(cacheDir, cacheKey)).then((content) => cacheEntry.parse(JSON.parse(content.toString()))).catch(() => null);
492
+ if (cached && cached.hash === generateCacheHash(value)) return cached;
493
+ }
494
+ const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
495
+ let schema;
496
+ let mdxOptions;
497
+ switch (collection?.type) {
498
+ case "doc":
499
+ mdxOptions = collection.mdxOptions;
500
+ schema = collection.schema;
501
+ break;
502
+ case "docs":
503
+ mdxOptions = collection.docs.mdxOptions;
504
+ schema = collection.docs.schema;
505
+ break;
506
+ }
507
+ if (schema) {
508
+ matter.data = await validate(
509
+ schema,
510
+ matter.data,
511
+ {
512
+ source: value,
513
+ path: filePath
514
+ },
515
+ `invalid frontmatter in ${filePath}`
516
+ );
517
+ }
518
+ if (parsed.only === "frontmatter") {
519
+ return {
520
+ code: `export const frontmatter = ${JSON.stringify(matter.data)}`,
521
+ map: null
522
+ };
523
+ }
524
+ const data = {};
525
+ if (loaded.global.lastModifiedTime === "git") {
526
+ data.lastModified = (await getGitTimestamp(filePath))?.getTime();
527
+ }
528
+ const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
529
+ const compiled = await buildMDX(
530
+ `${parsed.hash ?? ""}:${parsed.collection ?? "global"}`,
531
+ "\n".repeat(lineOffset) + matter.content,
535
532
  {
536
- throwOnError: true
533
+ development: isDevelopment,
534
+ ...mdxOptions ?? await loaded.getDefaultMDXOptions(),
535
+ data,
536
+ filePath,
537
+ frontmatter: matter.data,
538
+ _compiler: compiler
537
539
  }
538
540
  );
539
- const time = new Date(out.stdout);
540
- cache3.set(file, time);
541
- return time;
542
- } catch {
543
- return;
541
+ const out = {
542
+ code: String(compiled.value),
543
+ map: compiled.map
544
+ };
545
+ if (cacheDir) {
546
+ await import_promises.default.mkdir(cacheDir, { recursive: true });
547
+ await import_promises.default.writeFile(
548
+ import_node_path2.default.join(cacheDir, cacheKey),
549
+ JSON.stringify({
550
+ ...out,
551
+ hash: generateCacheHash(value)
552
+ })
553
+ );
554
+ }
555
+ return out;
556
+ };
557
+ }
558
+ function generateCacheHash(input) {
559
+ return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
560
+ }
561
+
562
+ // src/utils/config.ts
563
+ var fs3 = __toESM(require("fs/promises"), 1);
564
+ var path4 = __toESM(require("path"), 1);
565
+ var import_node_url = require("url");
566
+
567
+ // src/config/build.ts
568
+ function buildConfig(config) {
569
+ const collections = /* @__PURE__ */ new Map();
570
+ let globalConfig = {};
571
+ for (const [k, v] of Object.entries(config)) {
572
+ if (!v) {
573
+ continue;
574
+ }
575
+ if (typeof v === "object" && "type" in v) {
576
+ if (v.type === "docs") {
577
+ collections.set(k, v);
578
+ continue;
579
+ }
580
+ if (v.type === "doc" || v.type === "meta") {
581
+ collections.set(k, v);
582
+ continue;
583
+ }
584
+ }
585
+ if (k === "default" && v) {
586
+ globalConfig = v;
587
+ continue;
588
+ }
589
+ throw new Error(
590
+ `Unknown export "${k}", you can only export collections from source configuration file.`
591
+ );
544
592
  }
593
+ const mdxOptionsCache = /* @__PURE__ */ new Map();
594
+ return {
595
+ global: globalConfig,
596
+ collections,
597
+ async getDefaultMDXOptions(mode = "default") {
598
+ const cached = mdxOptionsCache.get(mode);
599
+ if (cached) return cached;
600
+ const input = this.global.mdxOptions;
601
+ async function uncached() {
602
+ const options = typeof input === "function" ? await input() : input;
603
+ const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
604
+ if (options?.preset === "minimal") return options;
605
+ return getDefaultMDXOptions2({
606
+ ...options,
607
+ _withoutBundler: mode === "remote"
608
+ });
609
+ }
610
+ const result = uncached();
611
+ mdxOptionsCache.set(mode, result);
612
+ return result;
613
+ }
614
+ };
545
615
  }
546
616
 
547
- // src/utils/validation.ts
548
- var import_picocolors = __toESM(require("picocolors"), 1);
549
- var ValidationError = class extends Error {
550
- constructor(message, issues) {
551
- super(
552
- `${message}:
553
- ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
617
+ // src/utils/config.ts
618
+ var cache3 = null;
619
+ async function isZod3() {
620
+ try {
621
+ const content = JSON.parse(
622
+ (await fs3.readFile("node_modules/zod/package.json")).toString()
554
623
  );
555
- this.title = message;
556
- this.issues = issues;
624
+ const version = content.version;
625
+ return typeof version === "string" && version.startsWith("3.");
626
+ } catch {
627
+ return false;
557
628
  }
558
- toStringFormatted() {
559
- return [
560
- import_picocolors.default.bold(`[MDX] ${this.title}:`),
561
- ...this.issues.map(
562
- (issue) => import_picocolors.default.redBright(
563
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
564
- )
565
- )
566
- ].join("\n");
629
+ }
630
+ function createCompatZodPlugin() {
631
+ return {
632
+ name: "replace-zod-import",
633
+ async setup(build) {
634
+ const usingZod3 = await isZod3();
635
+ if (!usingZod3) return;
636
+ console.warn(
637
+ "[Fumadocs MDX] Noticed Zod v3 in your node_modules, we recommend upgrading to Zod v4 for better compatibility."
638
+ );
639
+ build.onResolve({ filter: /^fumadocs-mdx\/config$/ }, () => {
640
+ return {
641
+ path: "fumadocs-mdx/config/zod-3",
642
+ external: true
643
+ };
644
+ });
645
+ }
646
+ };
647
+ }
648
+ async function compileConfig(configPath, outDir) {
649
+ const { build } = await import("esbuild");
650
+ const transformed = await build({
651
+ entryPoints: [{ in: configPath, out: "source.config" }],
652
+ bundle: true,
653
+ outdir: outDir,
654
+ target: "node20",
655
+ write: true,
656
+ platform: "node",
657
+ format: "esm",
658
+ packages: "external",
659
+ plugins: [createCompatZodPlugin()],
660
+ outExtension: {
661
+ ".js": ".mjs"
662
+ },
663
+ allowOverwrite: true
664
+ });
665
+ if (transformed.errors.length > 0) {
666
+ throw new Error("failed to compile configuration file");
567
667
  }
568
- };
569
- async function validate(schema, data, context, errorMessage) {
570
- if (typeof schema === "function" && !("~standard" in schema)) {
571
- schema = schema(context);
668
+ }
669
+ async function loadConfig(configPath, outDir, hash, build = false) {
670
+ if (cache3 && cache3.hash === hash) {
671
+ return await cache3.config;
572
672
  }
573
- if ("~standard" in schema) {
574
- const result = await schema["~standard"].validate(
575
- data
673
+ if (build) await compileConfig(configPath, outDir);
674
+ const url = (0, import_node_url.pathToFileURL)(path4.resolve(outDir, "source.config.mjs"));
675
+ const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
676
+ return buildConfig(
677
+ // every call to `loadConfig` will cause the previous cache to be ignored
678
+ loaded
576
679
  );
577
- if (result.issues) {
578
- throw new ValidationError(errorMessage, result.issues);
579
- }
580
- return result.value;
680
+ });
681
+ if (hash) cache3 = { config, hash };
682
+ return await config;
683
+ }
684
+ async function getConfigHash(configPath) {
685
+ const stats = await fs3.stat(configPath).catch(() => void 0);
686
+ if (stats) {
687
+ return stats.mtime.getTime().toString();
581
688
  }
582
- return data;
689
+ throw new Error("Cannot find config file");
583
690
  }
584
691
 
585
- // src/utils/count-lines.ts
586
- function countLines(s) {
587
- let num = 0;
588
- for (const c of s) {
589
- if (c === "\n") num++;
590
- }
591
- return num;
692
+ // src/loaders/config-loader.ts
693
+ function dynamicConfig(configPath, outDir) {
694
+ return {
695
+ async getConfig(hash) {
696
+ return loadConfig(
697
+ configPath,
698
+ outDir,
699
+ hash ?? await getConfigHash(configPath)
700
+ );
701
+ }
702
+ };
703
+ }
704
+
705
+ // src/loaders/adapter.ts
706
+ var import_node_url2 = require("url");
707
+ var import_promises2 = __toESM(require("fs/promises"), 1);
708
+ var import_node_querystring = require("querystring");
709
+ var import_node_path3 = __toESM(require("path"), 1);
710
+ function toWebpack(loader2) {
711
+ return async function(source, callback) {
712
+ try {
713
+ const result = await loader2({
714
+ filePath: this.resourcePath,
715
+ query: (0, import_node_querystring.parse)(this.resourceQuery),
716
+ source,
717
+ development: this.mode === "development",
718
+ compiler: this
719
+ });
720
+ callback(void 0, result.code, result.map);
721
+ } catch (error) {
722
+ if (error instanceof ValidationError) {
723
+ return callback(new Error(error.toStringFormatted()));
724
+ }
725
+ if (!(error instanceof Error)) throw error;
726
+ const fpath = import_node_path3.default.relative(this.context, this.resourcePath);
727
+ error.message = `${fpath}:${error.name}: ${error.message}`;
728
+ callback(error);
729
+ }
730
+ };
592
731
  }
593
732
 
594
733
  // src/loader-mdx.ts
734
+ var instance;
595
735
  async function loader(source, callback) {
596
736
  this.cacheable(true);
597
- const context = this.context;
598
- const filePath = this.resourcePath;
599
737
  const { configPath, outDir } = this.getOptions();
600
- const matter = fumaMatter(source);
601
- const {
602
- hash: configHash = await getConfigHash(configPath),
603
- collection: collectionId
604
- } = (0, import_node_querystring.parse)(this.resourceQuery.slice(1));
605
- const config = await loadConfig(configPath, outDir, configHash);
606
- let collection = collectionId !== void 0 ? config.collections.get(collectionId) : void 0;
607
- if (collection && collection.type === "docs") collection = collection.docs;
608
- if (collection && collection.type !== "doc") {
609
- collection = void 0;
610
- }
611
- let frontmatter = matter.data;
612
- const mdxOptions = collection?.mdxOptions ?? await config.getDefaultMDXOptions();
613
- if (collection?.schema) {
614
- try {
615
- frontmatter = await validate(
616
- collection.schema,
617
- frontmatter,
618
- {
619
- source,
620
- path: filePath
621
- },
622
- `invalid frontmatter in ${filePath}`
623
- );
624
- } catch (e) {
625
- if (e instanceof ValidationError) {
626
- return callback(new Error(e.toStringFormatted()));
627
- }
628
- return callback(e);
629
- }
630
- }
631
- let timestamp;
632
- if (config.global?.lastModifiedTime === "git") {
633
- timestamp = (await getGitTimestamp(filePath))?.getTime();
634
- }
635
- try {
636
- const lineOffset = "\n".repeat(
637
- this.mode === "development" ? countLines(matter.matter) : 0
638
- );
639
- const file = await buildMDX(
640
- `${configHash}:${collectionId ?? "global"}`,
641
- lineOffset + matter.content,
642
- {
643
- development: this.mode === "development",
644
- ...mdxOptions,
645
- filePath,
646
- frontmatter,
647
- data: {
648
- lastModified: timestamp
649
- },
650
- _compiler: this
651
- }
652
- );
653
- callback(void 0, String(file.value), file.map ?? void 0);
654
- } catch (error) {
655
- if (!(error instanceof Error)) throw error;
656
- const fpath = path4.relative(context, filePath);
657
- error.message = `${fpath}:${error.name}: ${error.message}`;
658
- callback(error);
659
- }
738
+ instance ??= toWebpack(createMdxLoader(dynamicConfig(configPath, outDir)));
739
+ await instance.call(this, source, callback);
660
740
  }