fumadocs-mdx 11.9.1 → 11.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/bin.cjs +1063 -0
  2. package/dist/bin.d.cts +1 -0
  3. package/dist/bin.d.ts +1 -0
  4. package/dist/bin.js +16 -0
  5. package/dist/{browser-CyU2Yl7A.d.cts → browser-B2G8uAF2.d.cts} +1 -1
  6. package/dist/{browser-DEsQvNRx.d.ts → browser-DrH7tKRi.d.ts} +1 -1
  7. package/dist/bun/index.cjs +669 -0
  8. package/dist/bun/index.d.cts +8 -0
  9. package/dist/bun/index.d.ts +8 -0
  10. package/dist/bun/index.js +53 -0
  11. package/dist/chunk-6Y5JDZHD.js +65 -0
  12. package/dist/chunk-CNKI574E.js +82 -0
  13. package/dist/{chunk-GX3THK2Q.js → chunk-IQAEAI4P.js} +25 -25
  14. package/dist/chunk-QJCCVMBJ.js +151 -0
  15. package/dist/{chunk-NUDEC6C5.js → chunk-UOOPSLFY.js} +1 -1
  16. package/dist/{chunk-COQ4VMK2.js → chunk-XXSKWWMB.js} +28 -61
  17. package/dist/config/index.d.cts +1 -1
  18. package/dist/config/index.d.ts +1 -1
  19. package/dist/config/zod-3.d.cts +1 -1
  20. package/dist/config/zod-3.d.ts +1 -1
  21. package/dist/{define-DnJzAZrj.d.cts → define-BH4bnHQl.d.cts} +6 -0
  22. package/dist/{define-DnJzAZrj.d.ts → define-BH4bnHQl.d.ts} +6 -0
  23. package/dist/loader-mdx.cjs +345 -265
  24. package/dist/loader-mdx.js +12 -80
  25. package/dist/next/index.cjs +15 -130
  26. package/dist/next/index.js +15 -33
  27. package/dist/node/loader.cjs +748 -0
  28. package/dist/node/loader.d.cts +5 -0
  29. package/dist/node/loader.d.ts +5 -0
  30. package/dist/node/loader.js +24 -0
  31. package/dist/postinstall-XV4WSHZP.js +9 -0
  32. package/dist/runtime/{async.cjs → next/async.cjs} +4 -4
  33. package/dist/runtime/{async.d.cts → next/async.d.cts} +3 -3
  34. package/dist/runtime/{async.d.ts → next/async.d.ts} +3 -3
  35. package/dist/runtime/{async.js → next/async.js} +6 -6
  36. package/dist/{index.cjs → runtime/next/index.cjs} +4 -6
  37. package/dist/{index.d.cts → runtime/next/index.d.cts} +3 -3
  38. package/dist/{index.d.ts → runtime/next/index.d.ts} +3 -3
  39. package/dist/{index.js → runtime/next/index.js} +1 -1
  40. package/dist/runtime/vite/browser.d.cts +2 -2
  41. package/dist/runtime/vite/browser.d.ts +2 -2
  42. package/dist/runtime/vite/server.d.cts +3 -3
  43. package/dist/runtime/vite/server.d.ts +3 -3
  44. package/dist/{types-WSHJKA8L.d.ts → types-DN9KrG7R.d.ts} +1 -1
  45. package/dist/{types-BmVgoqsr.d.cts → types-DT83Ijs6.d.cts} +1 -1
  46. package/dist/vite/index.cjs +440 -276
  47. package/dist/vite/index.d.cts +4 -1
  48. package/dist/vite/index.d.ts +4 -1
  49. package/dist/vite/index.js +19 -81
  50. package/package.json +24 -17
  51. package/bin.js +0 -5
  52. package/dist/chunk-UCY7OBZG.js +0 -12
package/dist/bin.cjs ADDED
@@ -0,0 +1,1063 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // src/mdx-plugins/remark-postprocess.ts
34
+ function remarkPostprocess({
35
+ injectExports
36
+ }) {
37
+ return (tree, file) => {
38
+ let title;
39
+ const urls = [];
40
+ (0, import_unist_util_visit.visit)(tree, ["heading", "link"], (node) => {
41
+ if (node.type === "heading" && node.depth === 1) {
42
+ title = flattenNode(node);
43
+ }
44
+ if (node.type !== "link") return;
45
+ urls.push({
46
+ href: node.url
47
+ });
48
+ return "skip";
49
+ });
50
+ if (title) {
51
+ file.data.frontmatter ??= {};
52
+ if (!file.data.frontmatter.title) file.data.frontmatter.title = title;
53
+ }
54
+ file.data.extractedReferences = urls;
55
+ for (const name of injectExports) {
56
+ if (!(name in file.data)) continue;
57
+ tree.children.unshift(getMdastExport(name, file.data[name]));
58
+ }
59
+ };
60
+ }
61
+ function flattenNode(node) {
62
+ if ("children" in node)
63
+ return node.children.map((child) => flattenNode(child)).join("");
64
+ if ("value" in node) return node.value;
65
+ return "";
66
+ }
67
+ function getMdastExport(name, value) {
68
+ return {
69
+ type: "mdxjsEsm",
70
+ value: "",
71
+ data: {
72
+ estree: {
73
+ type: "Program",
74
+ sourceType: "module",
75
+ body: [
76
+ {
77
+ type: "ExportNamedDeclaration",
78
+ attributes: [],
79
+ specifiers: [],
80
+ source: null,
81
+ declaration: {
82
+ type: "VariableDeclaration",
83
+ kind: "let",
84
+ declarations: [
85
+ {
86
+ type: "VariableDeclarator",
87
+ id: {
88
+ type: "Identifier",
89
+ name
90
+ },
91
+ init: (0, import_estree_util_value_to_estree.valueToEstree)(value)
92
+ }
93
+ ]
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ };
100
+ }
101
+ var import_unist_util_visit, import_estree_util_value_to_estree;
102
+ var init_remark_postprocess = __esm({
103
+ "src/mdx-plugins/remark-postprocess.ts"() {
104
+ "use strict";
105
+ import_unist_util_visit = require("unist-util-visit");
106
+ import_estree_util_value_to_estree = require("estree-util-value-to-estree");
107
+ }
108
+ });
109
+
110
+ // src/utils/mdx-options.ts
111
+ var mdx_options_exports = {};
112
+ __export(mdx_options_exports, {
113
+ getDefaultMDXOptions: () => getDefaultMDXOptions
114
+ });
115
+ function pluginOption(def, options = []) {
116
+ const list = def(Array.isArray(options) ? options : []).filter(
117
+ Boolean
118
+ );
119
+ if (typeof options === "function") {
120
+ return options(list);
121
+ }
122
+ return list;
123
+ }
124
+ function getDefaultMDXOptions({
125
+ valueToExport = [],
126
+ rehypeCodeOptions,
127
+ remarkImageOptions,
128
+ remarkHeadingOptions,
129
+ remarkStructureOptions,
130
+ remarkCodeTabOptions,
131
+ remarkNpmOptions,
132
+ _withoutBundler = false,
133
+ ...mdxOptions
134
+ }) {
135
+ const mdxExports = [
136
+ "structuredData",
137
+ "extractedReferences",
138
+ "frontmatter",
139
+ "lastModified",
140
+ ...valueToExport
141
+ ];
142
+ const remarkPlugins = pluginOption(
143
+ (v) => [
144
+ plugins.remarkGfm,
145
+ [
146
+ plugins.remarkHeading,
147
+ {
148
+ generateToc: false,
149
+ ...remarkHeadingOptions
150
+ }
151
+ ],
152
+ remarkImageOptions !== false && [
153
+ plugins.remarkImage,
154
+ {
155
+ ...remarkImageOptions,
156
+ useImport: _withoutBundler ? false : remarkImageOptions?.useImport
157
+ }
158
+ ],
159
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
160
+ plugins.remarkCodeTab,
161
+ remarkCodeTabOptions
162
+ ],
163
+ "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
164
+ ...v,
165
+ remarkStructureOptions !== false && [
166
+ plugins.remarkStructure,
167
+ remarkStructureOptions
168
+ ],
169
+ [
170
+ remarkPostprocess,
171
+ { injectExports: mdxExports }
172
+ ]
173
+ ],
174
+ mdxOptions.remarkPlugins
175
+ );
176
+ const rehypePlugins = pluginOption(
177
+ (v) => [
178
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
179
+ ...v,
180
+ plugins.rehypeToc
181
+ ],
182
+ mdxOptions.rehypePlugins
183
+ );
184
+ return {
185
+ ...mdxOptions,
186
+ outputFormat: _withoutBundler ? "function-body" : mdxOptions.outputFormat,
187
+ remarkPlugins,
188
+ rehypePlugins
189
+ };
190
+ }
191
+ var plugins;
192
+ var init_mdx_options = __esm({
193
+ "src/utils/mdx-options.ts"() {
194
+ "use strict";
195
+ plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
196
+ init_remark_postprocess();
197
+ }
198
+ });
199
+
200
+ // src/config/build.ts
201
+ function buildConfig(config) {
202
+ const collections = /* @__PURE__ */ new Map();
203
+ let globalConfig = {};
204
+ for (const [k, v] of Object.entries(config)) {
205
+ if (!v) {
206
+ continue;
207
+ }
208
+ if (typeof v === "object" && "type" in v) {
209
+ if (v.type === "docs") {
210
+ collections.set(k, v);
211
+ continue;
212
+ }
213
+ if (v.type === "doc" || v.type === "meta") {
214
+ collections.set(k, v);
215
+ continue;
216
+ }
217
+ }
218
+ if (k === "default" && v) {
219
+ globalConfig = v;
220
+ continue;
221
+ }
222
+ throw new Error(
223
+ `Unknown export "${k}", you can only export collections from source configuration file.`
224
+ );
225
+ }
226
+ const mdxOptionsCache = /* @__PURE__ */ new Map();
227
+ return {
228
+ global: globalConfig,
229
+ collections,
230
+ async getDefaultMDXOptions(mode = "default") {
231
+ const cached = mdxOptionsCache.get(mode);
232
+ if (cached) return cached;
233
+ const input = this.global.mdxOptions;
234
+ async function uncached() {
235
+ const options = typeof input === "function" ? await input() : input;
236
+ const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
237
+ if (options?.preset === "minimal") return options;
238
+ return getDefaultMDXOptions2({
239
+ ...options,
240
+ _withoutBundler: mode === "remote"
241
+ });
242
+ }
243
+ const result = uncached();
244
+ mdxOptionsCache.set(mode, result);
245
+ return result;
246
+ }
247
+ };
248
+ }
249
+ var init_build = __esm({
250
+ "src/config/build.ts"() {
251
+ "use strict";
252
+ }
253
+ });
254
+
255
+ // src/utils/config.ts
256
+ function findConfigFile() {
257
+ return path.resolve("source.config.ts");
258
+ }
259
+ async function isZod3() {
260
+ try {
261
+ const content = JSON.parse(
262
+ (await fs.readFile("node_modules/zod/package.json")).toString()
263
+ );
264
+ const version = content.version;
265
+ return typeof version === "string" && version.startsWith("3.");
266
+ } catch {
267
+ return false;
268
+ }
269
+ }
270
+ function createCompatZodPlugin() {
271
+ return {
272
+ name: "replace-zod-import",
273
+ async setup(build) {
274
+ const usingZod3 = await isZod3();
275
+ if (!usingZod3) return;
276
+ console.warn(
277
+ "[Fumadocs MDX] Noticed Zod v3 in your node_modules, we recommend upgrading to Zod v4 for better compatibility."
278
+ );
279
+ build.onResolve({ filter: /^fumadocs-mdx\/config$/ }, () => {
280
+ return {
281
+ path: "fumadocs-mdx/config/zod-3",
282
+ external: true
283
+ };
284
+ });
285
+ }
286
+ };
287
+ }
288
+ async function compileConfig(configPath, outDir) {
289
+ const { build } = await import("esbuild");
290
+ const transformed = await build({
291
+ entryPoints: [{ in: configPath, out: "source.config" }],
292
+ bundle: true,
293
+ outdir: outDir,
294
+ target: "node20",
295
+ write: true,
296
+ platform: "node",
297
+ format: "esm",
298
+ packages: "external",
299
+ plugins: [createCompatZodPlugin()],
300
+ outExtension: {
301
+ ".js": ".mjs"
302
+ },
303
+ allowOverwrite: true
304
+ });
305
+ if (transformed.errors.length > 0) {
306
+ throw new Error("failed to compile configuration file");
307
+ }
308
+ }
309
+ async function loadConfig(configPath, outDir, hash, build = false) {
310
+ if (cache && cache.hash === hash) {
311
+ return await cache.config;
312
+ }
313
+ if (build) await compileConfig(configPath, outDir);
314
+ const url = (0, import_node_url.pathToFileURL)(path.resolve(outDir, "source.config.mjs"));
315
+ const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
316
+ return buildConfig(
317
+ // every call to `loadConfig` will cause the previous cache to be ignored
318
+ loaded
319
+ );
320
+ });
321
+ if (hash) cache = { config, hash };
322
+ return await config;
323
+ }
324
+ async function getConfigHash(configPath) {
325
+ const stats = await fs.stat(configPath).catch(() => void 0);
326
+ if (stats) {
327
+ return stats.mtime.getTime().toString();
328
+ }
329
+ throw new Error("Cannot find config file");
330
+ }
331
+ var fs, path, import_node_url, cache;
332
+ var init_config = __esm({
333
+ "src/utils/config.ts"() {
334
+ "use strict";
335
+ fs = __toESM(require("fs/promises"), 1);
336
+ path = __toESM(require("path"), 1);
337
+ import_node_url = require("url");
338
+ init_build();
339
+ cache = null;
340
+ }
341
+ });
342
+
343
+ // src/utils/validation.ts
344
+ async function validate(schema, data, context, errorMessage) {
345
+ if (typeof schema === "function" && !("~standard" in schema)) {
346
+ schema = schema(context);
347
+ }
348
+ if ("~standard" in schema) {
349
+ const result = await schema["~standard"].validate(
350
+ data
351
+ );
352
+ if (result.issues) {
353
+ throw new ValidationError(errorMessage, result.issues);
354
+ }
355
+ return result.value;
356
+ }
357
+ return data;
358
+ }
359
+ var import_picocolors, ValidationError;
360
+ var init_validation = __esm({
361
+ "src/utils/validation.ts"() {
362
+ "use strict";
363
+ import_picocolors = __toESM(require("picocolors"), 1);
364
+ ValidationError = class extends Error {
365
+ constructor(message, issues) {
366
+ super(
367
+ `${message}:
368
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
369
+ );
370
+ this.title = message;
371
+ this.issues = issues;
372
+ }
373
+ toStringFormatted() {
374
+ return [
375
+ import_picocolors.default.bold(`[MDX] ${this.title}:`),
376
+ ...this.issues.map(
377
+ (issue) => import_picocolors.default.redBright(
378
+ `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
379
+ )
380
+ )
381
+ ].join("\n");
382
+ }
383
+ };
384
+ }
385
+ });
386
+
387
+ // src/map/file-cache.ts
388
+ var import_lru_cache, map, fileCache;
389
+ var init_file_cache = __esm({
390
+ "src/map/file-cache.ts"() {
391
+ "use strict";
392
+ import_lru_cache = require("lru-cache");
393
+ map = new import_lru_cache.LRUCache({
394
+ max: 200
395
+ });
396
+ fileCache = {
397
+ read(namespace, path8) {
398
+ return map.get(`${namespace}.${path8}`);
399
+ },
400
+ write(namespace, path8, data) {
401
+ map.set(`${namespace}.${path8}`, data);
402
+ },
403
+ removeCache(path8) {
404
+ for (const key of map.keys()) {
405
+ const keyPath = key.slice(key.indexOf(".") + 1);
406
+ if (keyPath === path8) map.delete(key);
407
+ }
408
+ }
409
+ };
410
+ }
411
+ });
412
+
413
+ // src/utils/git-timestamp.ts
414
+ async function getGitTimestamp(file) {
415
+ const cached = cache2.get(file);
416
+ if (cached) return cached;
417
+ try {
418
+ const out = await (0, import_tinyexec.x)(
419
+ "git",
420
+ ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
421
+ {
422
+ throwOnError: true
423
+ }
424
+ );
425
+ const time = new Date(out.stdout);
426
+ cache2.set(file, time);
427
+ return time;
428
+ } catch {
429
+ return;
430
+ }
431
+ }
432
+ var import_node_path, import_tinyexec, cache2;
433
+ var init_git_timestamp = __esm({
434
+ "src/utils/git-timestamp.ts"() {
435
+ "use strict";
436
+ import_node_path = __toESM(require("path"), 1);
437
+ import_tinyexec = require("tinyexec");
438
+ cache2 = /* @__PURE__ */ new Map();
439
+ }
440
+ });
441
+
442
+ // src/utils/fuma-matter.ts
443
+ function fumaMatter(input) {
444
+ const output = { matter: "", data: {}, content: input };
445
+ const match = regex.exec(input);
446
+ if (!match) {
447
+ return output;
448
+ }
449
+ output.matter = match[0];
450
+ output.content = input.slice(match[0].length);
451
+ const loaded = (0, import_js_yaml.load)(match[1]);
452
+ output.data = loaded ?? {};
453
+ return output;
454
+ }
455
+ var import_js_yaml, regex;
456
+ var init_fuma_matter = __esm({
457
+ "src/utils/fuma-matter.ts"() {
458
+ "use strict";
459
+ import_js_yaml = require("js-yaml");
460
+ regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
461
+ }
462
+ });
463
+
464
+ // src/utils/import-formatter.ts
465
+ function getImportCode(info) {
466
+ const specifier = JSON.stringify(info.specifier);
467
+ if (info.type === "default") return `import ${info.name} from ${specifier}`;
468
+ if (info.type === "namespace")
469
+ return `import * as ${info.name} from ${specifier}`;
470
+ if (info.type === "named") {
471
+ const names = info.names.map(
472
+ (name) => Array.isArray(name) ? `${name[0]} as ${name[1]}` : name
473
+ );
474
+ return `import { ${names.join(", ")} } from ${specifier}`;
475
+ }
476
+ return `import ${specifier}`;
477
+ }
478
+ function toImportPath(file, config) {
479
+ const ext = import_node_path2.default.extname(file);
480
+ let filename;
481
+ if (ext === ".ts" && config.jsExtension) {
482
+ filename = file.substring(0, file.length - ext.length) + ".js";
483
+ } else if (ext === ".ts") {
484
+ filename = file.substring(0, file.length - ext.length);
485
+ } else {
486
+ filename = file;
487
+ }
488
+ let importPath;
489
+ if ("relativeTo" in config) {
490
+ importPath = import_node_path2.default.relative(config.relativeTo, filename);
491
+ if (!import_node_path2.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
492
+ importPath = `./${importPath}`;
493
+ }
494
+ } else {
495
+ importPath = import_node_path2.default.resolve(filename);
496
+ }
497
+ return importPath.replaceAll(import_node_path2.default.sep, "/");
498
+ }
499
+ function ident(code, tab = 1) {
500
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
501
+ }
502
+ var import_node_path2;
503
+ var init_import_formatter = __esm({
504
+ "src/utils/import-formatter.ts"() {
505
+ "use strict";
506
+ import_node_path2 = __toESM(require("path"), 1);
507
+ }
508
+ });
509
+
510
+ // src/utils/collections.ts
511
+ function getSupportedFormats(collection) {
512
+ return {
513
+ doc: ["mdx", "md"],
514
+ meta: ["json", "yaml"]
515
+ }[collection.type];
516
+ }
517
+ function getGlobPatterns(collection) {
518
+ if (collection.files) return collection.files;
519
+ return [`**/*.{${getSupportedFormats(collection).join(",")}}`];
520
+ }
521
+ function isFileSupported(filePath, collection) {
522
+ for (const format of getSupportedFormats(collection)) {
523
+ if (filePath.endsWith(`.${format}`)) return true;
524
+ }
525
+ return false;
526
+ }
527
+ var init_collections = __esm({
528
+ "src/utils/collections.ts"() {
529
+ "use strict";
530
+ }
531
+ });
532
+
533
+ // src/map/generate.ts
534
+ async function readFileWithCache(file) {
535
+ const cached = fileCache.read("read-file", file);
536
+ if (cached) return cached;
537
+ return (await fs2.readFile(file)).toString();
538
+ }
539
+ async function generateJS(configPath, config, importPath, configHash = false) {
540
+ let asyncInit = false;
541
+ const lines = [
542
+ getImportCode({
543
+ type: "named",
544
+ names: ["_runtime"],
545
+ specifier: "fumadocs-mdx"
546
+ }),
547
+ getImportCode({
548
+ type: "namespace",
549
+ specifier: toImportPath(configPath, importPath),
550
+ name: "_source"
551
+ })
552
+ ];
553
+ const entries = Array.from(config.collections.entries());
554
+ async function getDocEntries(collectionName, files) {
555
+ const items = files.map(async (file, i) => {
556
+ const importId = `${collectionName}_${i}`;
557
+ const params = [`collection=${collectionName}`];
558
+ if (configHash) {
559
+ params.push(`hash=${configHash}`);
560
+ }
561
+ lines.unshift(
562
+ getImportCode({
563
+ type: "namespace",
564
+ name: importId,
565
+ specifier: `${toImportPath(file.absolutePath, importPath)}?${params.join("&")}`
566
+ })
567
+ );
568
+ return `{ info: ${JSON.stringify(file)}, data: ${importId} }`;
569
+ });
570
+ return Promise.all(items);
571
+ }
572
+ async function getMetaEntries(collection, files) {
573
+ const items = files.map(async (file) => {
574
+ const source = await readFileWithCache(file.absolutePath).catch(() => "");
575
+ let data = source.length === 0 ? {} : parseMetaEntry(file.absolutePath, source);
576
+ if (collection?.schema) {
577
+ data = await validate(
578
+ collection.schema,
579
+ data,
580
+ {
581
+ source,
582
+ path: file.absolutePath
583
+ },
584
+ `invalid data in ${file.absolutePath}`
585
+ );
586
+ }
587
+ return JSON.stringify({
588
+ info: file,
589
+ data
590
+ });
591
+ });
592
+ return Promise.all(items);
593
+ }
594
+ async function getAsyncEntries(collection, files) {
595
+ if (!asyncInit) {
596
+ lines.unshift(
597
+ getImportCode({
598
+ type: "named",
599
+ specifier: "fumadocs-mdx/runtime/async",
600
+ names: ["_runtimeAsync", "buildConfig"]
601
+ }),
602
+ "const _sourceConfig = buildConfig(_source)"
603
+ );
604
+ asyncInit = true;
605
+ }
606
+ const entries2 = files.map(async (file) => {
607
+ const parsed = fumaMatter(
608
+ await readFileWithCache(file.absolutePath).catch(() => "")
609
+ );
610
+ let data = parsed.data;
611
+ if (collection.schema) {
612
+ data = await validate(
613
+ collection.schema,
614
+ parsed.data,
615
+ { path: file.absolutePath, source: parsed.content },
616
+ `invalid frontmatter in ${file.absolutePath}`
617
+ );
618
+ }
619
+ let lastModified;
620
+ if (config.global?.lastModifiedTime === "git") {
621
+ lastModified = await getGitTimestamp(file.absolutePath);
622
+ }
623
+ return JSON.stringify({
624
+ info: file,
625
+ lastModified,
626
+ data,
627
+ content: { body: parsed.content, matter: parsed.matter }
628
+ });
629
+ });
630
+ return Promise.all(entries2);
631
+ }
632
+ const declares = entries.map(async ([k, collection]) => {
633
+ if (collection.type === "docs") {
634
+ const docs2 = await getCollectionFiles(collection.docs);
635
+ const metas = await getCollectionFiles(collection.meta);
636
+ const metaEntries = (await getMetaEntries(collection.meta, metas)).join(
637
+ ", "
638
+ );
639
+ if (collection.docs.async) {
640
+ const docsEntries2 = (await getAsyncEntries(collection.docs, docs2)).join(
641
+ ", "
642
+ );
643
+ return `export const ${k} = _runtimeAsync.docs<typeof _source.${k}>([${docsEntries2}], [${metaEntries}], "${k}", _sourceConfig)`;
644
+ }
645
+ const docsEntries = (await getDocEntries(k, docs2)).join(", ");
646
+ return `export const ${k} = _runtime.docs<typeof _source.${k}>([${docsEntries}], [${metaEntries}])`;
647
+ }
648
+ const files = await getCollectionFiles(collection);
649
+ if (collection.type === "doc" && collection.async) {
650
+ return `export const ${k} = _runtimeAsync.doc<typeof _source.${k}>([${(await getAsyncEntries(collection, files)).join(", ")}], "${k}", _sourceConfig)`;
651
+ }
652
+ return `export const ${k} = _runtime.${collection.type}<typeof _source.${k}>([${(await getDocEntries(k, files)).join(", ")}]);`;
653
+ });
654
+ const resolvedDeclares = await Promise.all(declares);
655
+ return [
656
+ `// @ts-nocheck -- skip type checking`,
657
+ ...lines,
658
+ ...resolvedDeclares
659
+ ].join("\n");
660
+ }
661
+ async function getCollectionFiles(collection) {
662
+ const files = /* @__PURE__ */ new Map();
663
+ const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
664
+ const patterns = getGlobPatterns(collection);
665
+ await Promise.all(
666
+ dirs.map(async (dir) => {
667
+ const result = await (0, import_tinyglobby.glob)(patterns, {
668
+ cwd: path4.resolve(dir),
669
+ absolute: true
670
+ });
671
+ for (const item of result) {
672
+ if (!isFileSupported(item, collection)) continue;
673
+ files.set(item, {
674
+ path: path4.relative(dir, item),
675
+ absolutePath: item
676
+ });
677
+ }
678
+ })
679
+ );
680
+ return Array.from(files.values());
681
+ }
682
+ function parseMetaEntry(file, content) {
683
+ const extname2 = path4.extname(file);
684
+ try {
685
+ if (extname2 === ".json") return JSON.parse(content);
686
+ if (extname2 === ".yaml") return (0, import_js_yaml2.load)(content);
687
+ } catch (e) {
688
+ throw new Error(`Failed to parse meta file: ${file}.`, {
689
+ cause: e
690
+ });
691
+ }
692
+ throw new Error(`Unknown meta file format: ${extname2}, in ${file}.`);
693
+ }
694
+ var path4, fs2, import_tinyglobby, import_js_yaml2;
695
+ var init_generate = __esm({
696
+ "src/map/generate.ts"() {
697
+ "use strict";
698
+ path4 = __toESM(require("path"), 1);
699
+ fs2 = __toESM(require("fs/promises"), 1);
700
+ import_tinyglobby = require("tinyglobby");
701
+ init_validation();
702
+ init_file_cache();
703
+ import_js_yaml2 = require("js-yaml");
704
+ init_git_timestamp();
705
+ init_fuma_matter();
706
+ init_import_formatter();
707
+ init_collections();
708
+ }
709
+ });
710
+
711
+ // src/map/watcher.ts
712
+ var watcher_exports = {};
713
+ __export(watcher_exports, {
714
+ watcher: () => watcher
715
+ });
716
+ function watcher(configPath, config, ignored) {
717
+ const watcher2 = new import_chokidar.FSWatcher({
718
+ ignoreInitial: true,
719
+ persistent: true,
720
+ ignored
721
+ });
722
+ watcher2.add(configPath);
723
+ for (const collection of config.collections.values()) {
724
+ if (collection.type === "docs") {
725
+ watcher2.add(collection.docs.dir);
726
+ watcher2.add(collection.meta.dir);
727
+ } else {
728
+ watcher2.add(collection.dir);
729
+ }
730
+ }
731
+ return watcher2;
732
+ }
733
+ var import_chokidar;
734
+ var init_watcher = __esm({
735
+ "src/map/watcher.ts"() {
736
+ "use strict";
737
+ import_chokidar = require("chokidar");
738
+ }
739
+ });
740
+
741
+ // src/map/index.ts
742
+ async function start(dev, configPath, outDir) {
743
+ let configHash = await getConfigHash(configPath);
744
+ let config = await loadConfig(configPath, outDir, configHash, true);
745
+ const outPath = path5.resolve(outDir, `index.ts`);
746
+ async function updateMapFile() {
747
+ const start3 = performance.now();
748
+ try {
749
+ await fs3.writeFile(
750
+ outPath,
751
+ await generateJS(
752
+ configPath,
753
+ config,
754
+ { relativeTo: outDir },
755
+ configHash
756
+ )
757
+ );
758
+ } catch (err) {
759
+ if (err instanceof ValidationError) {
760
+ console.error(err.toStringFormatted());
761
+ } else {
762
+ console.error(err);
763
+ }
764
+ }
765
+ console.log(`[MDX] updated map file in ${performance.now() - start3}ms`);
766
+ }
767
+ await updateMapFile();
768
+ if (dev) {
769
+ const { watcher: watcher2 } = await Promise.resolve().then(() => (init_watcher(), watcher_exports));
770
+ const instance = watcher2(configPath, config, [outPath]);
771
+ instance.on("ready", () => {
772
+ console.log("[MDX] started dev server");
773
+ });
774
+ instance.on("all", (event, file) => {
775
+ if (typeof file !== "string") return;
776
+ const absolutePath = path5.resolve(file);
777
+ const onUpdate = async () => {
778
+ const isConfigFile = absolutePath === configPath;
779
+ if (isConfigFile) {
780
+ configHash = await getConfigHash(configPath);
781
+ config = await loadConfig(configPath, outDir, configHash, true);
782
+ }
783
+ if (event === "change") fileCache.removeCache(absolutePath);
784
+ await updateMapFile();
785
+ };
786
+ void onUpdate();
787
+ });
788
+ process.on("exit", () => {
789
+ console.log("[MDX] closing dev server");
790
+ void instance.close();
791
+ });
792
+ }
793
+ }
794
+ var path5, fs3;
795
+ var init_map = __esm({
796
+ "src/map/index.ts"() {
797
+ "use strict";
798
+ path5 = __toESM(require("path"), 1);
799
+ fs3 = __toESM(require("fs/promises"), 1);
800
+ init_config();
801
+ init_generate();
802
+ init_file_cache();
803
+ init_validation();
804
+ }
805
+ });
806
+
807
+ // src/next/create.ts
808
+ function createMDX({
809
+ configPath = findConfigFile(),
810
+ outDir = ".source"
811
+ } = {}) {
812
+ if (process.env._FUMADOCS_MDX !== "1") {
813
+ process.env._FUMADOCS_MDX = "1";
814
+ void start(process.env.NODE_ENV === "development", configPath, outDir);
815
+ }
816
+ return (nextConfig = {}) => {
817
+ const mdxLoaderOptions = {
818
+ configPath,
819
+ outDir
820
+ };
821
+ const turbo = {
822
+ ...nextConfig.experimental?.turbo,
823
+ ...nextConfig.turbopack,
824
+ rules: {
825
+ ...nextConfig.experimental?.turbo?.rules,
826
+ ...nextConfig.turbopack?.rules,
827
+ "*.{md,mdx}": {
828
+ loaders: [
829
+ {
830
+ loader: "fumadocs-mdx/loader-mdx",
831
+ options: mdxLoaderOptions
832
+ }
833
+ ],
834
+ as: "*.js"
835
+ }
836
+ }
837
+ };
838
+ const updated = {
839
+ ...nextConfig,
840
+ pageExtensions: nextConfig.pageExtensions ?? defaultPageExtensions,
841
+ webpack: (config, options) => {
842
+ config.resolve ||= {};
843
+ config.module ||= {};
844
+ config.module.rules ||= [];
845
+ config.module.rules.push({
846
+ test: /\.mdx?$/,
847
+ use: [
848
+ options.defaultLoaders.babel,
849
+ {
850
+ loader: "fumadocs-mdx/loader-mdx",
851
+ options: mdxLoaderOptions
852
+ }
853
+ ]
854
+ });
855
+ config.plugins ||= [];
856
+ return nextConfig.webpack?.(config, options) ?? config;
857
+ }
858
+ };
859
+ if (isTurboExperimental) {
860
+ updated.experimental = { ...updated.experimental, turbo };
861
+ } else {
862
+ updated.turbopack = turbo;
863
+ }
864
+ return updated;
865
+ };
866
+ }
867
+ var import_node_fs, defaultPageExtensions, isTurboExperimental;
868
+ var init_create = __esm({
869
+ "src/next/create.ts"() {
870
+ "use strict";
871
+ init_config();
872
+ init_map();
873
+ import_node_fs = require("fs");
874
+ defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
875
+ try {
876
+ const content = (0, import_node_fs.readFileSync)("./node_modules/next/package.json").toString();
877
+ const version = JSON.parse(content).version;
878
+ isTurboExperimental = version.startsWith("15.0.") || version.startsWith("15.1.") || version.startsWith("15.2.");
879
+ } catch {
880
+ isTurboExperimental = false;
881
+ }
882
+ }
883
+ });
884
+
885
+ // src/next/index.ts
886
+ var next_exports = {};
887
+ __export(next_exports, {
888
+ createMDX: () => createMDX,
889
+ postInstall: () => postInstall,
890
+ start: () => start
891
+ });
892
+ async function postInstall(configPath = findConfigFile(), outDir = ".source") {
893
+ const config = await loadConfig(configPath, outDir, void 0, true);
894
+ const outPath = import_node_path3.default.join(outDir, "index.ts");
895
+ await import_promises.default.rm(outDir, { recursive: true });
896
+ await import_promises.default.mkdir(outDir, { recursive: true });
897
+ const hash = await getConfigHash(configPath);
898
+ await import_promises.default.writeFile(
899
+ outPath,
900
+ await generateJS(configPath, config, { relativeTo: outDir }, hash)
901
+ );
902
+ console.log("[MDX] types generated");
903
+ }
904
+ var import_node_path3, import_promises;
905
+ var init_next = __esm({
906
+ "src/next/index.ts"() {
907
+ "use strict";
908
+ init_config();
909
+ import_node_path3 = __toESM(require("path"), 1);
910
+ import_promises = __toESM(require("fs/promises"), 1);
911
+ init_generate();
912
+ init_create();
913
+ }
914
+ });
915
+
916
+ // src/vite/generate-glob.ts
917
+ function generateGlob(name, patterns, globOptions) {
918
+ const options = {
919
+ ...globOptions,
920
+ query: {
921
+ ...globOptions?.query,
922
+ collection: name
923
+ }
924
+ };
925
+ return `import.meta.glob(${JSON.stringify(mapGlobPatterns(patterns))}, ${JSON.stringify(options, null, 2)})`;
926
+ }
927
+ function mapGlobPatterns(patterns) {
928
+ return patterns.map(enforceRelative);
929
+ }
930
+ function enforceRelative(file) {
931
+ if (file.startsWith("./")) return file;
932
+ if (file.startsWith("/")) return `.${file}`;
933
+ return `./${file}`;
934
+ }
935
+ function getGlobBase(collection) {
936
+ let dir = collection.dir;
937
+ if (Array.isArray(dir)) {
938
+ if (dir.length !== 1)
939
+ throw new Error(
940
+ `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
941
+ );
942
+ dir = dir[0];
943
+ }
944
+ return enforceRelative(dir);
945
+ }
946
+ var init_generate_glob = __esm({
947
+ "src/vite/generate-glob.ts"() {
948
+ "use strict";
949
+ }
950
+ });
951
+
952
+ // src/vite/generate.ts
953
+ function docs(name, collection) {
954
+ const obj = [
955
+ ident(`doc: ${doc(name, collection.docs)}`),
956
+ ident(`meta: ${meta(name, collection.meta)}`)
957
+ ].join(",\n");
958
+ return `{
959
+ ${obj}
960
+ }`;
961
+ }
962
+ function doc(name, collection) {
963
+ const patterns = getGlobPatterns(collection);
964
+ const base = getGlobBase(collection);
965
+ const docGlob = generateGlob(name, patterns, {
966
+ base
967
+ });
968
+ if (collection.async) {
969
+ const headBlob = generateGlob(name, patterns, {
970
+ query: {
971
+ only: "frontmatter"
972
+ },
973
+ import: "frontmatter",
974
+ base
975
+ });
976
+ return `create.docLazy("${name}", "${base}", ${headBlob}, ${docGlob})`;
977
+ }
978
+ return `create.doc("${name}", "${base}", ${docGlob})`;
979
+ }
980
+ function meta(name, collection) {
981
+ const patterns = getGlobPatterns(collection);
982
+ const base = getGlobBase(collection);
983
+ return `create.meta("${name}", "${base}", ${generateGlob(name, patterns, {
984
+ import: "default",
985
+ base
986
+ })})`;
987
+ }
988
+ function entry(configPath, config, outDir, jsExtension) {
989
+ const lines = [
990
+ '/// <reference types="vite/client" />',
991
+ `import { fromConfig } from 'fumadocs-mdx/runtime/vite';`,
992
+ `import type * as Config from '${toImportPath(configPath, {
993
+ relativeTo: outDir,
994
+ jsExtension
995
+ })}';`,
996
+ "",
997
+ `export const create = fromConfig<typeof Config>();`
998
+ ];
999
+ for (const [name, collection] of config.collections.entries()) {
1000
+ let body;
1001
+ if (collection.type === "docs") {
1002
+ body = docs(name, collection);
1003
+ } else if (collection.type === "meta") {
1004
+ body = meta(name, collection);
1005
+ } else {
1006
+ body = doc(name, collection);
1007
+ }
1008
+ lines.push("");
1009
+ lines.push(`export const ${name} = ${body};`);
1010
+ }
1011
+ return lines.join("\n");
1012
+ }
1013
+ var init_generate2 = __esm({
1014
+ "src/vite/generate.ts"() {
1015
+ "use strict";
1016
+ init_import_formatter();
1017
+ init_generate_glob();
1018
+ init_collections();
1019
+ }
1020
+ });
1021
+
1022
+ // src/vite/postinstall.ts
1023
+ var postinstall_exports = {};
1024
+ __export(postinstall_exports, {
1025
+ postInstall: () => postInstall2
1026
+ });
1027
+ async function postInstall2(configPath = findConfigFile(), outDir, addJsExtension = false) {
1028
+ const config = await loadConfig(configPath, "node_modules", void 0, true);
1029
+ const outFile = "source.generated.ts";
1030
+ if (outDir) {
1031
+ await import_promises2.default.mkdir(outDir, { recursive: true });
1032
+ }
1033
+ await import_promises2.default.writeFile(
1034
+ outDir ? import_node_path4.default.join(outDir, outFile) : outFile,
1035
+ entry(configPath, config, outDir ?? process.cwd(), addJsExtension)
1036
+ );
1037
+ console.log("[MDX] types generated");
1038
+ }
1039
+ var import_promises2, import_node_path4;
1040
+ var init_postinstall = __esm({
1041
+ "src/vite/postinstall.ts"() {
1042
+ "use strict";
1043
+ init_config();
1044
+ import_promises2 = __toESM(require("fs/promises"), 1);
1045
+ import_node_path4 = __toESM(require("path"), 1);
1046
+ init_generate2();
1047
+ }
1048
+ });
1049
+
1050
+ // src/bin.ts
1051
+ var import_node_fs2 = require("fs");
1052
+ async function start2() {
1053
+ const args = process.argv.slice(2);
1054
+ const isNext = (0, import_node_fs2.existsSync)("next.config.js") || (0, import_node_fs2.existsSync)("next.config.mjs") || (0, import_node_fs2.existsSync)("next.config.ts");
1055
+ if (isNext) {
1056
+ const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_next(), next_exports));
1057
+ await postInstall3(...args);
1058
+ } else {
1059
+ const { postInstall: postInstall3 } = await Promise.resolve().then(() => (init_postinstall(), postinstall_exports));
1060
+ await postInstall3(...args);
1061
+ }
1062
+ }
1063
+ void start2();