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
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
8
  var __export = (target, all) => {
12
9
  for (var name in all)
13
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -30,11 +27,22 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
27
  ));
31
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
29
 
33
- // src/loaders/mdx/preset.ts
34
- var preset_exports = {};
35
- __export(preset_exports, {
36
- getDefaultMDXOptions: () => getDefaultMDXOptions
30
+ // src/next/index.ts
31
+ var next_exports = {};
32
+ __export(next_exports, {
33
+ createMDX: () => createMDX,
34
+ postInstall: () => postInstall
37
35
  });
36
+ module.exports = __toCommonJS(next_exports);
37
+ var path5 = __toESM(require("path"), 1);
38
+
39
+ // src/config/load-from-file.ts
40
+ var import_node_url = require("url");
41
+
42
+ // src/config/build.ts
43
+ var import_picomatch = __toESM(require("picomatch"), 1);
44
+
45
+ // src/config/preset.ts
38
46
  function pluginOption(def, options = []) {
39
47
  const list = def(Array.isArray(options) ? options : []).filter(
40
48
  Boolean
@@ -44,94 +52,80 @@ function pluginOption(def, options = []) {
44
52
  }
45
53
  return list;
46
54
  }
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
55
+ function applyMdxPreset(options = {}) {
56
+ return async (environment = "bundler") => {
57
+ if (options.preset === "minimal") return options;
58
+ const plugins = await import("fumadocs-core/mdx-plugins");
59
+ const {
60
+ valueToExport = [],
61
+ rehypeCodeOptions,
62
+ remarkImageOptions,
63
+ remarkHeadingOptions,
64
+ remarkStructureOptions,
65
+ remarkCodeTabOptions,
66
+ remarkNpmOptions,
67
+ ...mdxOptions
68
+ } = options;
69
+ const remarkPlugins = pluginOption(
70
+ (v) => [
71
+ plugins.remarkGfm,
72
+ [
73
+ plugins.remarkHeading,
74
+ {
75
+ generateToc: false,
76
+ ...remarkHeadingOptions
77
+ }
78
+ ],
79
+ remarkImageOptions !== false && [
80
+ plugins.remarkImage,
81
+ {
82
+ ...remarkImageOptions,
83
+ useImport: remarkImageOptions?.useImport ?? environment === "bundler"
84
+ }
85
+ ],
86
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
87
+ plugins.remarkCodeTab,
88
+ remarkCodeTabOptions
89
+ ],
90
+ "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
91
+ ...v,
92
+ remarkStructureOptions !== false && [
93
+ plugins.remarkStructure,
94
+ remarkStructureOptions
95
+ ],
96
+ valueToExport.length > 0 && (() => {
97
+ return (_, file) => {
98
+ file.data["mdx-export"] ??= [];
99
+ for (const name of valueToExport) {
100
+ if (!(name in file.data)) continue;
101
+ file.data["mdx-export"].push({
102
+ name,
103
+ value: file.data[name]
104
+ });
105
+ }
106
+ };
107
+ })
78
108
  ],
79
- "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
80
- ...v,
81
- remarkStructureOptions !== false && [
82
- plugins.remarkStructure,
83
- remarkStructureOptions
109
+ mdxOptions.remarkPlugins
110
+ );
111
+ const rehypePlugins = pluginOption(
112
+ (v) => [
113
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
114
+ ...v,
115
+ plugins.rehypeToc
84
116
  ],
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
117
+ mdxOptions.rehypePlugins
118
+ );
119
+ return {
120
+ ...mdxOptions,
121
+ outputFormat: environment === "runtime" ? "function-body" : mdxOptions.outputFormat,
122
+ remarkPlugins,
123
+ rehypePlugins
124
+ };
110
125
  };
111
126
  }
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/next/index.ts
121
- var next_exports = {};
122
- __export(next_exports, {
123
- createMDX: () => createMDX,
124
- postInstall: () => postInstall
125
- });
126
- module.exports = __toCommonJS(next_exports);
127
- var path7 = __toESM(require("path"), 1);
128
-
129
- // src/config/load-from-file.ts
130
- var path = __toESM(require("path"), 1);
131
- var import_node_url = require("url");
132
127
 
133
128
  // src/config/build.ts
134
- var import_picomatch = __toESM(require("picomatch"), 1);
135
129
  var SupportedFormats = {
136
130
  doc: ["mdx", "md"],
137
131
  meta: ["json", "yaml"]
@@ -142,7 +136,10 @@ function buildCollection(name, config) {
142
136
  ...config,
143
137
  name,
144
138
  meta: buildPrimitiveCollection(name, config.meta),
145
- docs: buildPrimitiveCollection(name, config.docs)
139
+ docs: buildPrimitiveCollection(name, config.docs),
140
+ hasFile(filePath) {
141
+ return this.docs.hasFile(filePath) || this.meta.hasFile(filePath);
142
+ }
146
143
  };
147
144
  }
148
145
  return buildPrimitiveCollection(name, config);
@@ -196,11 +193,6 @@ function buildConfig(config) {
196
193
  `Unknown export "${k}", you can only export collections from source configuration file.`
197
194
  );
198
195
  }
199
- if (loaded.collections) {
200
- for (const [k, v] of Object.entries(loaded.collections)) {
201
- collections.set(k, buildCollection(k, v));
202
- }
203
- }
204
196
  const mdxOptionsCache = /* @__PURE__ */ new Map();
205
197
  return {
206
198
  global: loaded,
@@ -208,33 +200,34 @@ function buildConfig(config) {
208
200
  getCollection(name) {
209
201
  return collections.get(name);
210
202
  },
211
- async getDefaultMDXOptions(mode = "default") {
212
- const cached = mdxOptionsCache.get(mode);
203
+ getMDXOptions(collection, environment = "bundler") {
204
+ const key = collection ? `${environment}:${collection.name}` : environment;
205
+ const cached = mdxOptionsCache.get(key);
213
206
  if (cached) return cached;
214
- const input = this.global.mdxOptions;
215
- async function uncached() {
216
- const options = typeof input === "function" ? await input() : input;
217
- const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_preset(), preset_exports));
218
- if (options?.preset === "minimal") return options;
219
- return getDefaultMDXOptions2({
220
- ...options,
221
- _withoutBundler: mode === "remote"
222
- });
207
+ let result;
208
+ if (collection?.mdxOptions) {
209
+ const optionsFn = collection.mdxOptions;
210
+ result = typeof optionsFn === "function" ? optionsFn(environment) : optionsFn;
211
+ } else {
212
+ result = (async () => {
213
+ const optionsFn = this.global.mdxOptions;
214
+ const options = typeof optionsFn === "function" ? await optionsFn() : optionsFn;
215
+ return applyMdxPreset(options)(environment);
216
+ })();
223
217
  }
224
- const result = uncached();
225
- mdxOptionsCache.set(mode, result);
218
+ mdxOptionsCache.set(key, result);
226
219
  return result;
227
220
  }
228
221
  };
229
222
  }
230
223
 
231
224
  // src/config/load-from-file.ts
232
- async function compileConfig(configPath, outDir) {
225
+ async function compileConfig(core) {
233
226
  const { build } = await import("esbuild");
234
227
  const transformed = await build({
235
- entryPoints: [{ in: configPath, out: "source.config" }],
228
+ entryPoints: [{ in: core._options.configPath, out: "source.config" }],
236
229
  bundle: true,
237
- outdir: outDir,
230
+ outdir: core._options.outDir,
238
231
  target: "node20",
239
232
  write: true,
240
233
  platform: "node",
@@ -249,9 +242,9 @@ async function compileConfig(configPath, outDir) {
249
242
  throw new Error("failed to compile configuration file");
250
243
  }
251
244
  }
252
- async function loadConfig(configPath, outDir, build = false) {
253
- if (build) await compileConfig(configPath, outDir);
254
- const url = (0, import_node_url.pathToFileURL)(path.resolve(outDir, "source.config.mjs"));
245
+ async function loadConfig(core, build = false) {
246
+ if (build) await compileConfig(core);
247
+ const url = (0, import_node_url.pathToFileURL)(core.getCompiledConfigPath());
255
248
  url.searchParams.set("hash", Date.now().toString());
256
249
  const config = import(url.href).then(
257
250
  (loaded) => buildConfig(loaded)
@@ -259,33 +252,7 @@ async function loadConfig(configPath, outDir, build = false) {
259
252
  return await config;
260
253
  }
261
254
 
262
- // src/next/file-cache.ts
263
- var import_lru_cache = require("lru-cache");
264
- var import_promises = __toESM(require("fs/promises"), 1);
265
- var import_node_path = __toESM(require("path"), 1);
266
- var map = new import_lru_cache.LRUCache({
267
- max: 100
268
- });
269
- function toFullPath(file) {
270
- if (import_node_path.default.isAbsolute(file)) {
271
- return import_node_path.default.relative(process.cwd(), file);
272
- }
273
- return file;
274
- }
275
- async function readFileWithCache(file) {
276
- const fullPath = toFullPath(file);
277
- const cached = map.get(fullPath);
278
- if (cached) return cached;
279
- const read = import_promises.default.readFile(fullPath).then((s) => s.toString());
280
- map.set(fullPath, read);
281
- return read;
282
- }
283
- function removeFileCache(file) {
284
- map.delete(toFullPath(file));
285
- }
286
-
287
255
  // src/utils/validation.ts
288
- var import_picocolors = __toESM(require("picocolors"), 1);
289
256
  var ValidationError = class extends Error {
290
257
  constructor(message, issues) {
291
258
  super(
@@ -295,12 +262,13 @@ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
295
262
  this.title = message;
296
263
  this.issues = issues;
297
264
  }
298
- toStringFormatted() {
265
+ async toStringFormatted() {
266
+ const picocolors = await import("picocolors");
299
267
  return [
300
- import_picocolors.default.bold(`[MDX] ${this.title}:`),
268
+ picocolors.bold(`[MDX] ${this.title}:`),
301
269
  ...this.issues.map(
302
- (issue) => import_picocolors.default.redBright(
303
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
270
+ (issue) => picocolors.redBright(
271
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
304
272
  )
305
273
  )
306
274
  ].join("\n");
@@ -322,33 +290,299 @@ async function validate(schema, data, context, errorMessage) {
322
290
  return data;
323
291
  }
324
292
 
325
- // src/plugins/next.ts
326
- var path5 = __toESM(require("path"), 1);
327
- var import_node_crypto = require("crypto");
328
-
329
- // src/utils/git-timestamp.ts
293
+ // src/core.ts
330
294
  var import_node_path2 = __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);
295
+ var import_promises2 = __toESM(require("fs/promises"), 1);
296
+
297
+ // src/utils/codegen/cache.ts
298
+ var import_lru_cache = require("lru-cache");
299
+ var import_promises = __toESM(require("fs/promises"), 1);
300
+ var import_node_path = __toESM(require("path"), 1);
301
+ var map = new import_lru_cache.LRUCache({
302
+ max: 100
303
+ });
304
+ function toFullPath(file) {
305
+ if (import_node_path.default.isAbsolute(file)) {
306
+ return import_node_path.default.relative(process.cwd(), file);
307
+ }
308
+ return file;
309
+ }
310
+ async function readFileWithCache(file) {
311
+ const fullPath = toFullPath(file);
312
+ const cached = map.get(fullPath);
335
313
  if (cached) return cached;
336
- try {
337
- const out = await (0, import_tinyexec.x)(
338
- "git",
339
- ["log", "-1", '--pretty="%ai"', import_node_path2.default.relative(process.cwd(), file)],
340
- {
341
- throwOnError: true
314
+ const read = import_promises.default.readFile(fullPath).then((s) => s.toString());
315
+ map.set(fullPath, read);
316
+ return read;
317
+ }
318
+ function removeFileCache(file) {
319
+ map.delete(toFullPath(file));
320
+ }
321
+
322
+ // src/core.ts
323
+ var _Defaults = {
324
+ configPath: "source.config.ts",
325
+ outDir: ".source"
326
+ };
327
+ async function getPlugins(pluginOptions) {
328
+ const plugins = [];
329
+ for await (const option of pluginOptions) {
330
+ if (!option) continue;
331
+ if (Array.isArray(option)) plugins.push(...await getPlugins(option));
332
+ else plugins.push(option);
333
+ }
334
+ return plugins;
335
+ }
336
+ function createCore(options, defaultPlugins = []) {
337
+ let config;
338
+ let plugins;
339
+ async function transformMetadata({
340
+ collection,
341
+ filePath,
342
+ source
343
+ }, data) {
344
+ if (collection.schema) {
345
+ data = await validate(
346
+ collection.schema,
347
+ data,
348
+ { path: filePath, source },
349
+ collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`
350
+ );
351
+ }
352
+ return data;
353
+ }
354
+ const core = {
355
+ _options: options,
356
+ /**
357
+ * Convenient cache store, reset when config changes
358
+ */
359
+ cache: /* @__PURE__ */ new Map(),
360
+ async init({ config: newConfig }) {
361
+ config = await newConfig;
362
+ this.cache.clear();
363
+ plugins = await getPlugins([
364
+ ...defaultPlugins,
365
+ ...config.global.plugins ?? []
366
+ ]);
367
+ for (const plugin of plugins) {
368
+ const out = await plugin.config?.call(pluginContext, config);
369
+ if (out) config = out;
342
370
  }
343
- );
344
- const time = new Date(out.stdout);
345
- cache.set(file, time);
346
- return time;
347
- } catch {
348
- return;
371
+ return this;
372
+ },
373
+ getConfig() {
374
+ return config;
375
+ },
376
+ /**
377
+ * The file path of compiled config file, the file may not exist (e.g. on Vite, or still compiling)
378
+ */
379
+ getCompiledConfigPath() {
380
+ return import_node_path2.default.join(options.outDir, "source.config.mjs");
381
+ },
382
+ async initServer(server) {
383
+ server.watcher?.on("all", async (event, file) => {
384
+ if (event === "change") removeFileCache(file);
385
+ });
386
+ for (const plugin of plugins) {
387
+ await plugin.configureServer?.call(pluginContext, server);
388
+ }
389
+ },
390
+ async emit({ filterPlugin = () => true } = {}) {
391
+ return (await Promise.all(
392
+ plugins.map((plugin) => {
393
+ if (!filterPlugin(plugin) || !plugin.emit) return [];
394
+ return plugin.emit.call(pluginContext);
395
+ })
396
+ )).flat();
397
+ },
398
+ async emitAndWrite(emitOptions) {
399
+ const start = performance.now();
400
+ const out = await this.emit(emitOptions);
401
+ await Promise.all(
402
+ out.map(async (entry) => {
403
+ const file = import_node_path2.default.join(options.outDir, entry.path);
404
+ await import_promises2.default.mkdir(import_node_path2.default.dirname(file), { recursive: true });
405
+ await import_promises2.default.writeFile(file, entry.content);
406
+ })
407
+ );
408
+ console.log(`[MDX] generated files in ${performance.now() - start}ms`);
409
+ },
410
+ async transformMeta(options2, data) {
411
+ const ctx = {
412
+ ...pluginContext,
413
+ ...options2
414
+ };
415
+ data = await transformMetadata(options2, data);
416
+ for (const plugin of plugins) {
417
+ if (plugin.meta?.transform)
418
+ data = await plugin.meta.transform.call(ctx, data) ?? data;
419
+ }
420
+ return data;
421
+ },
422
+ async transformFrontmatter(options2, data) {
423
+ const ctx = {
424
+ ...pluginContext,
425
+ ...options2
426
+ };
427
+ data = await transformMetadata(options2, data);
428
+ for (const plugin of plugins) {
429
+ if (plugin.doc?.frontmatter)
430
+ data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
431
+ }
432
+ return data;
433
+ },
434
+ async transformVFile(options2, file) {
435
+ const ctx = {
436
+ ...pluginContext,
437
+ ...options2
438
+ };
439
+ for (const plugin of plugins) {
440
+ if (plugin.doc?.vfile)
441
+ file = await plugin.doc.vfile.call(ctx, file) ?? file;
442
+ }
443
+ return file;
444
+ }
445
+ };
446
+ const pluginContext = {
447
+ core,
448
+ ...options
449
+ };
450
+ return core;
451
+ }
452
+
453
+ // src/loaders/index.ts
454
+ var metaLoaderGlob = /\.(json|yaml)(\?.+?)?$/;
455
+ var mdxLoaderGlob = /\.mdx?(\?.+?)?$/;
456
+
457
+ // src/plugins/index-file.ts
458
+ var import_path = __toESM(require("path"), 1);
459
+
460
+ // src/utils/codegen/index.ts
461
+ var import_node_path3 = __toESM(require("path"), 1);
462
+ var import_tinyglobby = require("tinyglobby");
463
+ function createCodegen({
464
+ target = "default",
465
+ outDir = "",
466
+ jsExtension = false,
467
+ globCache = /* @__PURE__ */ new Map()
468
+ }) {
469
+ let eagerImportId = 0;
470
+ const banner = ["// @ts-nocheck"];
471
+ if (target === "vite") {
472
+ banner.push('/// <reference types="vite/client" />');
473
+ }
474
+ return {
475
+ options: {
476
+ target,
477
+ outDir
478
+ },
479
+ lines: [],
480
+ addImport(statement) {
481
+ this.lines.unshift(statement);
482
+ },
483
+ async pushAsync(insert) {
484
+ for (const line of await Promise.all(insert)) {
485
+ if (line === void 0) continue;
486
+ this.lines.push(line);
487
+ }
488
+ },
489
+ async generateGlobImport(patterns, options) {
490
+ if (target === "vite") {
491
+ return this.generateViteGlobImport(patterns, options);
492
+ }
493
+ return this.generateNodeGlobImport(patterns, options);
494
+ },
495
+ generateViteGlobImport(patterns, { base, ...rest }) {
496
+ patterns = (typeof patterns === "string" ? [patterns] : patterns).map(
497
+ normalizeViteGlobPath
498
+ );
499
+ return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(
500
+ {
501
+ base: normalizeViteGlobPath(import_node_path3.default.relative(outDir, base)),
502
+ ...rest
503
+ },
504
+ null,
505
+ 2
506
+ )})`;
507
+ },
508
+ async generateNodeGlobImport(patterns, {
509
+ base,
510
+ eager = false,
511
+ query = {},
512
+ import: importName
513
+ }) {
514
+ const cacheKey = JSON.stringify({ patterns, base });
515
+ let files = globCache.get(cacheKey);
516
+ if (!files) {
517
+ files = (0, import_tinyglobby.glob)(patterns, {
518
+ cwd: base
519
+ });
520
+ globCache.set(cacheKey, files);
521
+ }
522
+ let code = "{";
523
+ for (const item of await files) {
524
+ const fullPath = import_node_path3.default.join(base, item);
525
+ const searchParams = new URLSearchParams();
526
+ for (const [k, v] of Object.entries(query)) {
527
+ searchParams.set(k, v);
528
+ }
529
+ const importPath = this.formatImportPath(fullPath) + "?" + searchParams.toString();
530
+ if (eager) {
531
+ const name = `__fd_glob_${eagerImportId++}`;
532
+ this.lines.unshift(
533
+ importName ? `import { ${importName} as ${name} } from ${JSON.stringify(importPath)}` : `import * as ${name} from ${JSON.stringify(importPath)}`
534
+ );
535
+ code += `${JSON.stringify(item)}: ${name}, `;
536
+ } else {
537
+ let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(importPath)})`;
538
+ if (importName) {
539
+ line += `.then(mod => mod.${importName})`;
540
+ }
541
+ code += `${line}, `;
542
+ }
543
+ }
544
+ code += "}";
545
+ return code;
546
+ },
547
+ formatImportPath(file) {
548
+ const ext = import_node_path3.default.extname(file);
549
+ let filename;
550
+ if (ext === ".ts" && jsExtension) {
551
+ filename = file.substring(0, file.length - ext.length) + ".js";
552
+ } else if (ext === ".ts") {
553
+ filename = file.substring(0, file.length - ext.length);
554
+ } else {
555
+ filename = file;
556
+ }
557
+ const importPath = slash(import_node_path3.default.relative(outDir, filename));
558
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
559
+ },
560
+ toString() {
561
+ return [...banner, ...this.lines].join("\n");
562
+ }
563
+ };
564
+ }
565
+ function normalizeViteGlobPath(file) {
566
+ file = slash(file);
567
+ if (file.startsWith("./")) return file;
568
+ if (file.startsWith("/")) return `.${file}`;
569
+ return `./${file}`;
570
+ }
571
+ function slash(path6) {
572
+ const isExtendedLengthPath = path6.startsWith("\\\\?\\");
573
+ if (isExtendedLengthPath) {
574
+ return path6;
349
575
  }
576
+ return path6.replaceAll("\\", "/");
577
+ }
578
+ function ident(code, tab = 1) {
579
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
350
580
  }
351
581
 
582
+ // src/plugins/index-file.ts
583
+ var import_tinyglobby2 = require("tinyglobby");
584
+ var import_crypto = require("crypto");
585
+
352
586
  // src/utils/fuma-matter.ts
353
587
  var import_js_yaml = require("js-yaml");
354
588
  var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
@@ -365,323 +599,288 @@ function fumaMatter(input) {
365
599
  return output;
366
600
  }
367
601
 
368
- // src/utils/import-formatter.ts
369
- var import_node_path3 = __toESM(require("path"), 1);
370
- function getImportCode(info) {
371
- const specifier = JSON.stringify(info.specifier);
372
- if (info.type === "default") return `import ${info.name} from ${specifier}`;
373
- if (info.type === "namespace")
374
- return `import * as ${info.name} from ${specifier}`;
375
- if (info.type === "named") {
376
- const names = info.names.map(
377
- (name) => Array.isArray(name) ? `${name[0]} as ${name[1]}` : name
378
- );
379
- return `import { ${names.join(", ")} } from ${specifier}`;
380
- }
381
- return `import ${specifier}`;
382
- }
383
- function toImportPath(file, config) {
384
- const ext = import_node_path3.default.extname(file);
385
- let filename;
386
- if (ext === ".ts" && config.jsExtension) {
387
- filename = file.substring(0, file.length - ext.length) + ".js";
388
- } else if (ext === ".ts") {
389
- filename = file.substring(0, file.length - ext.length);
390
- } else {
391
- filename = file;
392
- }
393
- let importPath;
394
- if ("relativeTo" in config) {
395
- importPath = import_node_path3.default.relative(config.relativeTo, filename);
396
- if (!import_node_path3.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
397
- importPath = `./${importPath}`;
398
- }
399
- } else {
400
- importPath = import_node_path3.default.resolve(filename);
401
- }
402
- return importPath.replaceAll(import_node_path3.default.sep, "/");
403
- }
404
-
405
- // src/plugins/next.ts
406
- var import_js_yaml2 = require("js-yaml");
407
- function next() {
602
+ // src/plugins/index-file.ts
603
+ function indexFile(options = {}) {
604
+ const {
605
+ target = "default",
606
+ addJsExtension,
607
+ browser = true,
608
+ dynamic = true
609
+ } = options;
408
610
  let config;
409
- let shouldEmitOnChange = false;
611
+ let dynamicCollections;
612
+ function isDynamic(collection) {
613
+ return collection.type === "docs" && collection.docs.dynamic || collection.type === "doc" && collection.dynamic;
614
+ }
410
615
  return {
411
- name: "next",
616
+ name: "index-file",
412
617
  config(v) {
413
618
  config = v;
414
- shouldEmitOnChange = config.collectionList.some((collection) => {
415
- return collection.type === "doc" && collection.async || collection.type === "docs" || collection.type === "meta";
416
- });
619
+ dynamicCollections = config.collectionList.filter(isDynamic);
417
620
  },
418
621
  configureServer(server) {
419
622
  if (!server.watcher) return;
420
- server.watcher.on("all", async (event) => {
421
- if (event === "change" && !shouldEmitOnChange) return;
623
+ server.watcher.on("all", async (event, file) => {
624
+ if (dynamicCollections.length === 0) {
625
+ if (target === "vite") return;
626
+ if (target === "default" && event === "change") return;
627
+ }
628
+ const updatedCollection = config.collectionList.find(
629
+ (collection) => collection.hasFile(file)
630
+ );
631
+ if (!updatedCollection) return;
632
+ if (!isDynamic(updatedCollection)) {
633
+ if (target === "vite") return;
634
+ if (target === "default" && event === "change") return;
635
+ }
422
636
  await this.core.emitAndWrite({
423
- filterPlugin: (plugin) => plugin.name === "next"
637
+ filterPlugin: (plugin) => plugin.name === "index-file"
424
638
  });
425
639
  });
426
640
  },
427
641
  async emit() {
428
- return [
429
- {
430
- path: "index.ts",
431
- content: await indexFile(this.configPath, config, {
432
- relativeTo: this.outDir
433
- })
434
- }
642
+ const globCache = /* @__PURE__ */ new Map();
643
+ const makeCodeGen = () => createCodegen({
644
+ target,
645
+ outDir: this.outDir,
646
+ jsExtension: addJsExtension,
647
+ globCache
648
+ });
649
+ async function toEmitEntry(path6, content) {
650
+ return {
651
+ path: path6,
652
+ content: await content
653
+ };
654
+ }
655
+ const out = [
656
+ toEmitEntry(
657
+ "server.ts",
658
+ generateServerIndexFile(makeCodeGen(), config, this.configPath)
659
+ )
435
660
  ];
661
+ if (dynamic)
662
+ out.push(
663
+ toEmitEntry(
664
+ "dynamic.ts",
665
+ generateDynamicIndexFile(this.core, makeCodeGen())
666
+ )
667
+ );
668
+ if (browser)
669
+ out.push(
670
+ toEmitEntry(
671
+ "browser.ts",
672
+ generateBrowserIndexFile(makeCodeGen(), config, this.configPath)
673
+ )
674
+ );
675
+ return await Promise.all(out);
436
676
  }
437
677
  };
438
678
  }
439
- async function indexFile(configPath, config, importPath) {
440
- let asyncInit = false;
441
- const lines = [
442
- getImportCode({
443
- type: "named",
444
- names: ["_runtime"],
445
- specifier: "fumadocs-mdx/runtime/next"
446
- }),
447
- getImportCode({
448
- type: "namespace",
449
- specifier: toImportPath(configPath, importPath),
450
- name: "_source"
451
- })
452
- ];
453
- function getDocEntries(collection, files) {
454
- return files.map((file, i) => {
455
- const importId = `d_${collection.name}_${i}`;
456
- const params = [`collection=${collection.name}`];
457
- lines.unshift(
458
- getImportCode({
459
- type: "namespace",
460
- name: importId,
461
- specifier: `${toImportPath(file.fullPath, importPath)}?${params.join("&")}`
462
- })
463
- );
464
- return `{ info: ${JSON.stringify(file)}, data: ${importId} }`;
465
- });
466
- }
467
- async function getMetaEntries(collection, files) {
468
- const items = files.map(async (file) => {
469
- const source = await readFileWithCache(file.fullPath).catch(() => "");
470
- let data = source.length === 0 ? {} : parseMetaEntry(file.fullPath, source);
471
- if (collection?.schema) {
472
- data = await validate(
473
- collection.schema,
474
- data,
475
- {
476
- source,
477
- path: file.fullPath
478
- },
479
- `invalid data in ${file.fullPath}`
480
- );
679
+ async function generateServerIndexFile(codegen, config, configPath) {
680
+ codegen.lines.push(
681
+ `import { fromConfig } from 'fumadocs-mdx/runtime/server';`,
682
+ `import type * as Config from '${codegen.formatImportPath(configPath)}';`,
683
+ "",
684
+ `const create = fromConfig<typeof Config>();`
685
+ );
686
+ async function generateCollectionObject(collection) {
687
+ switch (collection.type) {
688
+ case "docs": {
689
+ if (collection.docs.dynamic) return;
690
+ if (collection.docs.async) {
691
+ const [metaGlob2, headGlob, bodyGlob] = await Promise.all([
692
+ generateMetaCollectionGlob(codegen, collection.meta, true),
693
+ generateDocCollectionFrontmatterGlob(
694
+ codegen,
695
+ collection.docs,
696
+ true
697
+ ),
698
+ generateDocCollectionGlob(codegen, collection.docs)
699
+ ]);
700
+ return `await create.docsLazy("${collection.name}", "${collection.dir}", ${metaGlob2}, ${headGlob}, ${bodyGlob})`;
701
+ }
702
+ const [metaGlob, docGlob] = await Promise.all([
703
+ generateMetaCollectionGlob(codegen, collection.meta, true),
704
+ generateDocCollectionGlob(codegen, collection.docs, true)
705
+ ]);
706
+ return `await create.docs("${collection.name}", "${collection.dir}", ${metaGlob}, ${docGlob})`;
481
707
  }
482
- return JSON.stringify({
483
- info: file,
484
- data
485
- });
486
- });
487
- return Promise.all(items);
708
+ case "doc":
709
+ if (collection.dynamic) return;
710
+ if (collection.async) {
711
+ const [headGlob, bodyGlob] = await Promise.all([
712
+ generateDocCollectionFrontmatterGlob(codegen, collection, true),
713
+ generateDocCollectionGlob(codegen, collection)
714
+ ]);
715
+ return `await create.docLazy("${collection.name}", "${collection.dir}", ${headGlob}, ${bodyGlob})`;
716
+ }
717
+ return `await create.doc("${collection.name}", "${collection.dir}", ${await generateDocCollectionGlob(
718
+ codegen,
719
+ collection,
720
+ true
721
+ )})`;
722
+ case "meta":
723
+ return `await create.meta("${collection.name}", "${collection.dir}", ${await generateMetaCollectionGlob(
724
+ codegen,
725
+ collection,
726
+ true
727
+ )})`;
728
+ }
488
729
  }
489
- async function getAsyncEntries(collection, files) {
490
- if (!asyncInit) {
491
- lines.unshift(
492
- getImportCode({
493
- type: "named",
494
- specifier: "fumadocs-mdx/runtime/async",
495
- names: ["_runtimeAsync", "buildConfig"]
496
- }),
497
- "const _sourceConfig = buildConfig(_source)",
498
- getImportCode({
499
- type: "default",
500
- name: "path",
501
- specifier: "node:path"
502
- })
503
- );
504
- asyncInit = true;
730
+ await codegen.pushAsync(
731
+ config.collectionList.map(async (collection) => {
732
+ const obj = await generateCollectionObject(collection);
733
+ if (!obj) return;
734
+ return `
735
+ export const ${collection.name} = ${obj};`;
736
+ })
737
+ );
738
+ return codegen.toString();
739
+ }
740
+ async function generateDynamicIndexFile(core, codegen) {
741
+ const { configPath } = core._options;
742
+ codegen.lines.push(
743
+ `import { fromConfigDynamic } from 'fumadocs-mdx/runtime/dynamic';`,
744
+ `import * as Config from '${codegen.formatImportPath(configPath)}';`,
745
+ "",
746
+ `const create = await fromConfigDynamic(Config);`
747
+ );
748
+ async function generateCollectionObjectEntry(collection, file) {
749
+ const fullPath = import_path.default.join(collection.dir, file);
750
+ const content = await readFileWithCache(fullPath).catch(() => "");
751
+ const parsed = fumaMatter(content);
752
+ const data = await core.transformFrontmatter(
753
+ {
754
+ collection,
755
+ filePath: fullPath,
756
+ source: content
757
+ },
758
+ parsed.data
759
+ );
760
+ const hash = (0, import_crypto.createHash)("md5").update(content).digest("hex");
761
+ const infoStr = [
762
+ // make sure it's included in vercel/nft
763
+ `absolutePath: path.resolve(${JSON.stringify(fullPath)})`
764
+ ];
765
+ for (const [k, v] of Object.entries({
766
+ info: {
767
+ fullPath,
768
+ path: file
769
+ },
770
+ data,
771
+ hash
772
+ })) {
773
+ infoStr.push(`${k}: ${JSON.stringify(v)}`);
505
774
  }
506
- const entries = files.map(async (file) => {
507
- const content = await readFileWithCache(file.fullPath).catch(() => "");
508
- const parsed = fumaMatter(content);
509
- let data = parsed.data;
510
- if (collection.schema) {
511
- data = await validate(
512
- collection.schema,
513
- parsed.data,
514
- { path: file.fullPath, source: parsed.content },
515
- `invalid frontmatter in ${file.fullPath}`
516
- );
517
- }
518
- let lastModified;
519
- if (config.global?.lastModifiedTime === "git") {
520
- lastModified = await getGitTimestamp(file.fullPath);
521
- }
522
- const hash = (0, import_node_crypto.createHash)("md5").update(content).digest("hex");
523
- const infoStr = [];
524
- for (const [k, v] of Object.entries({ ...file, hash })) {
525
- infoStr.push(`${k}: ${JSON.stringify(v)}`);
526
- }
527
- infoStr.push(
528
- `absolutePath: path.resolve(${JSON.stringify(file.fullPath)})`
529
- );
530
- return `{ info: { ${infoStr.join(", ")} }, lastModified: ${JSON.stringify(lastModified)}, data: ${JSON.stringify(data)} }`;
531
- });
532
- return Promise.all(entries);
775
+ return `{ ${infoStr.join(", ")} }`;
533
776
  }
534
- const declares = config.collectionList.map(async (collection) => {
535
- const k = collection.name;
536
- if (collection.type === "docs") {
537
- const docs = await globCollectionFiles(collection.docs);
538
- const metas = await globCollectionFiles(collection.meta);
539
- const metaEntries = (await getMetaEntries(collection.meta, metas)).join(
540
- ", "
541
- );
542
- if (collection.docs.async) {
543
- const docsEntries2 = (await getAsyncEntries(collection.docs, docs)).join(
544
- ", "
777
+ async function generateCollectionObject(parent) {
778
+ let collection;
779
+ if (parent.type === "doc") collection = parent;
780
+ else if (parent.type === "docs") collection = parent.docs;
781
+ if (!collection || !collection.dynamic) return;
782
+ const files = await (0, import_tinyglobby2.glob)(collection.patterns, {
783
+ cwd: collection.dir
784
+ });
785
+ const entries = await Promise.all(
786
+ files.map((file) => generateCollectionObjectEntry(collection, file))
787
+ );
788
+ switch (parent.type) {
789
+ case "docs": {
790
+ const metaGlob = await generateMetaCollectionGlob(
791
+ codegen,
792
+ parent.meta,
793
+ true
545
794
  );
546
- return `export const ${k} = _runtimeAsync.docs<typeof _source.${k}>([${docsEntries2}], [${metaEntries}], "${k}", _sourceConfig)`;
795
+ return `await create.docs("${parent.name}", "${parent.dir}", ${metaGlob}, ${entries.join(", ")})`;
547
796
  }
548
- const docsEntries = getDocEntries(collection.docs, docs).join(", ");
549
- return `export const ${k} = _runtime.docs<typeof _source.${k}>([${docsEntries}], [${metaEntries}])`;
797
+ case "doc":
798
+ return `await create.doc("${collection.name}", "${collection.dir}", ${entries.join(", ")})`;
550
799
  }
551
- const files = await globCollectionFiles(collection);
552
- if (collection.type === "meta") {
553
- return `export const ${k} = _runtime.meta<typeof _source.${k}>([${(await getMetaEntries(collection, files)).join(", ")}]);`;
554
- }
555
- if (collection.async) {
556
- return `export const ${k} = _runtimeAsync.doc<typeof _source.${k}>([${(await getAsyncEntries(collection, files)).join(", ")}], "${k}", _sourceConfig)`;
557
- }
558
- return `export const ${k} = _runtime.doc<typeof _source.${k}>([${getDocEntries(collection, files).join(", ")}]);`;
559
- });
560
- const resolvedDeclares = await Promise.all(declares);
561
- return [
562
- `// @ts-nocheck -- skip type checking`,
563
- ...lines,
564
- ...resolvedDeclares
565
- ].join("\n");
566
- }
567
- function parseMetaEntry(file, content) {
568
- const extname2 = path5.extname(file);
569
- try {
570
- if (extname2 === ".json") return JSON.parse(content);
571
- if (extname2 === ".yaml") return (0, import_js_yaml2.load)(content);
572
- } catch (e) {
573
- throw new Error(`Failed to parse meta file: ${file}.`, {
574
- cause: e
575
- });
576
800
  }
577
- throw new Error(`Unknown meta file format: ${extname2}, in ${file}.`);
801
+ await codegen.pushAsync(
802
+ core.getConfig().collectionList.map(async (collection) => {
803
+ const obj = await generateCollectionObject(collection);
804
+ if (!obj) return;
805
+ return `
806
+ export const ${collection.name} = ${obj};`;
807
+ })
808
+ );
809
+ return codegen.toString();
578
810
  }
579
- async function globCollectionFiles(collection) {
580
- const { glob } = await import("tinyglobby");
581
- const files = /* @__PURE__ */ new Map();
582
- const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
583
- await Promise.all(
584
- dirs.map(async (dir) => {
585
- const result = await glob(collection.patterns, {
586
- cwd: path5.resolve(dir)
587
- });
588
- for (const item of result) {
589
- if (!collection.isFileSupported(item)) continue;
590
- const fullPath = path5.join(dir, item);
591
- files.set(fullPath, {
592
- path: item,
593
- fullPath
594
- });
811
+ async function generateBrowserIndexFile(codegen, config, configPath) {
812
+ codegen.lines.push(
813
+ `import { fromConfig } from 'fumadocs-mdx/runtime/browser';`,
814
+ `import type * as Config from '${codegen.formatImportPath(configPath)}';`,
815
+ "",
816
+ `const create = fromConfig<typeof Config>();`
817
+ );
818
+ async function generateCollectionObject(collection) {
819
+ switch (collection.type) {
820
+ case "docs": {
821
+ if (collection.docs.dynamic) return;
822
+ return generateCollectionObject(collection.docs);
595
823
  }
824
+ case "doc":
825
+ if (collection.dynamic) return;
826
+ return `create.doc("${collection.name}", ${await generateDocCollectionGlob(codegen, collection)})`;
827
+ }
828
+ }
829
+ codegen.lines.push("const browserCollections = {");
830
+ await codegen.pushAsync(
831
+ config.collectionList.map(async (collection) => {
832
+ const obj = await generateCollectionObject(collection);
833
+ if (!obj) return;
834
+ return ident(`${collection.name}: ${obj},`);
596
835
  })
597
836
  );
598
- return Array.from(files.values());
599
- }
600
-
601
- // src/core.ts
602
- var import_node_path4 = __toESM(require("path"), 1);
603
- var import_promises2 = __toESM(require("fs/promises"), 1);
604
- function findConfigFile() {
605
- return import_node_path4.default.resolve("source.config.ts");
837
+ codegen.lines.push("};", "export default browserCollections;");
838
+ return codegen.toString();
606
839
  }
607
- function createCore(options, defaultPlugins = []) {
608
- let config;
609
- let plugins2;
610
- return {
611
- _options: options,
612
- getPluginContext() {
613
- return {
614
- core: this,
615
- ...options
616
- };
840
+ function generateDocCollectionFrontmatterGlob(codegen, collection, eager = false) {
841
+ return codegen.generateGlobImport(collection.patterns, {
842
+ query: {
843
+ collection: collection.name,
844
+ only: "frontmatter"
617
845
  },
618
- /**
619
- * Convenient cache store, reset when config changes
620
- */
621
- cache: /* @__PURE__ */ new Map(),
622
- async init({ config: newConfig }) {
623
- config = await newConfig;
624
- this.cache.clear();
625
- plugins2 = [];
626
- for await (const option of [
627
- ...defaultPlugins,
628
- ...config.global.plugins ?? []
629
- ]) {
630
- if (!option) continue;
631
- if (Array.isArray(option)) plugins2.push(...option);
632
- else plugins2.push(option);
633
- }
634
- for (const plugin of plugins2) {
635
- const out = await plugin.config?.call(this.getPluginContext(), config);
636
- if (out) config = out;
637
- }
638
- return this;
639
- },
640
- getConfig() {
641
- return config;
846
+ import: "frontmatter",
847
+ base: collection.dir,
848
+ eager
849
+ });
850
+ }
851
+ function generateDocCollectionGlob(codegen, collection, eager = false) {
852
+ return codegen.generateGlobImport(collection.patterns, {
853
+ query: {
854
+ collection: collection.name
642
855
  },
643
- async initServer(server) {
644
- for (const plugin of plugins2) {
645
- await plugin.configureServer?.call(this.getPluginContext(), server);
646
- }
856
+ base: collection.dir,
857
+ eager
858
+ });
859
+ }
860
+ function generateMetaCollectionGlob(codegen, collection, eager = false) {
861
+ return codegen.generateGlobImport(collection.patterns, {
862
+ query: {
863
+ collection: collection.name
647
864
  },
648
- async emitAndWrite({
649
- filterPlugin = () => true
650
- } = {}) {
651
- const start = performance.now();
652
- const out = await Promise.all(
653
- plugins2.map((plugin) => {
654
- if (!filterPlugin(plugin) || !plugin.emit) return [];
655
- return plugin.emit.call(this.getPluginContext());
656
- })
657
- );
658
- await Promise.all(
659
- out.flat().map(async (entry) => {
660
- const file = import_node_path4.default.join(options.outDir, entry.path);
661
- await import_promises2.default.mkdir(import_node_path4.default.dirname(file), { recursive: true });
662
- await import_promises2.default.writeFile(file, entry.content);
663
- })
664
- );
665
- console.log(`[MDX] generated files in ${performance.now() - start}ms`);
666
- }
667
- };
865
+ import: "default",
866
+ base: collection.dir,
867
+ eager
868
+ });
668
869
  }
669
870
 
670
- // src/loaders/index.ts
671
- var mdxLoaderGlob = /\.mdx?(\?.+?)?$/;
672
-
673
871
  // src/next/index.ts
674
872
  var defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
675
873
  function createMDX(createOptions = {}) {
676
- const options = applyDefaults(createOptions);
874
+ const core = createNextCore(applyDefaults(createOptions));
677
875
  const isDev = process.env.NODE_ENV === "development";
678
876
  if (process.env._FUMADOCS_MDX !== "1") {
679
877
  process.env._FUMADOCS_MDX = "1";
680
- void init(isDev, options);
878
+ void init(isDev, core);
681
879
  }
682
880
  return (nextConfig = {}) => {
683
881
  const loaderOptions = {
684
- ...options,
882
+ ...core._options,
883
+ compiledConfigPath: core.getCompiledConfigPath(),
685
884
  isDev
686
885
  };
687
886
  const turbopack = {
@@ -696,6 +895,24 @@ function createMDX(createOptions = {}) {
696
895
  }
697
896
  ],
698
897
  as: "*.js"
898
+ },
899
+ "*.json": {
900
+ loaders: [
901
+ {
902
+ loader: "fumadocs-mdx/loader-meta",
903
+ options: loaderOptions
904
+ }
905
+ ],
906
+ as: "*.json"
907
+ },
908
+ "*.yaml": {
909
+ loaders: [
910
+ {
911
+ loader: "fumadocs-mdx/loader-meta",
912
+ options: loaderOptions
913
+ }
914
+ ],
915
+ as: "*.js"
699
916
  }
700
917
  }
701
918
  };
@@ -703,31 +920,42 @@ function createMDX(createOptions = {}) {
703
920
  ...nextConfig,
704
921
  turbopack,
705
922
  pageExtensions: nextConfig.pageExtensions ?? defaultPageExtensions,
706
- webpack: (config, options2) => {
923
+ webpack: (config, options) => {
707
924
  config.resolve ||= {};
708
925
  config.module ||= {};
709
926
  config.module.rules ||= [];
710
- config.module.rules.push({
711
- test: mdxLoaderGlob,
712
- use: [
713
- options2.defaultLoaders.babel,
714
- {
715
- loader: "fumadocs-mdx/loader-mdx",
716
- options: loaderOptions
717
- }
718
- ]
719
- });
927
+ config.module.rules.push(
928
+ {
929
+ test: mdxLoaderGlob,
930
+ use: [
931
+ options.defaultLoaders.babel,
932
+ {
933
+ loader: "fumadocs-mdx/loader-mdx",
934
+ options: loaderOptions
935
+ }
936
+ ]
937
+ },
938
+ {
939
+ test: metaLoaderGlob,
940
+ use: [
941
+ options.defaultLoaders.babel,
942
+ {
943
+ loader: "fumadocs-mdx/loader-meta",
944
+ options: loaderOptions
945
+ }
946
+ ]
947
+ }
948
+ );
720
949
  config.plugins ||= [];
721
- return nextConfig.webpack?.(config, options2) ?? config;
950
+ return nextConfig.webpack?.(config, options) ?? config;
722
951
  }
723
952
  };
724
953
  };
725
954
  }
726
- async function init(dev, options) {
727
- const core = createNextCore(options);
955
+ async function init(dev, core) {
728
956
  async function initOrReload() {
729
957
  await core.init({
730
- config: loadConfig(options.configPath, options.outDir, true)
958
+ config: loadConfig(core, true)
731
959
  });
732
960
  await core.emitAndWrite();
733
961
  }
@@ -736,9 +964,9 @@ async function init(dev, options) {
736
964
  const watcher = new FSWatcher({
737
965
  ignoreInitial: true,
738
966
  persistent: true,
739
- ignored: [options.outDir]
967
+ ignored: [core._options.outDir]
740
968
  });
741
- watcher.add(options.configPath);
969
+ watcher.add(core._options.configPath);
742
970
  for (const collection of core.getConfig().collectionList) {
743
971
  if (collection.type === "docs") {
744
972
  watcher.add(collection.docs.dir);
@@ -750,10 +978,8 @@ async function init(dev, options) {
750
978
  watcher.on("ready", () => {
751
979
  console.log("[MDX] started dev server");
752
980
  });
753
- watcher.on("all", async (event, file) => {
754
- const absolutePath = path7.resolve(file);
755
- if (event === "change") removeFileCache(absolutePath);
756
- if (absolutePath === path7.resolve(options.configPath)) {
981
+ watcher.on("all", async (_event, file) => {
982
+ if (path5.resolve(file) === path5.resolve(core._options.configPath)) {
757
983
  watcher.removeAllListeners();
758
984
  await watcher.close();
759
985
  await initOrReload();
@@ -773,32 +999,28 @@ async function init(dev, options) {
773
999
  await devServer();
774
1000
  }
775
1001
  }
776
- async function postInstall(configPath = findConfigFile(), outDir = ".source") {
777
- const core = await createNextCore({
778
- outDir,
779
- configPath
780
- }).init({
781
- config: loadConfig(configPath, outDir, true)
1002
+ async function postInstall(options) {
1003
+ const core = createNextCore(applyDefaults(options));
1004
+ await core.init({
1005
+ config: loadConfig(core, true)
782
1006
  });
783
1007
  await core.emitAndWrite();
784
1008
  }
785
1009
  function applyDefaults(options) {
786
1010
  return {
787
- outDir: options.outDir ?? ".source",
788
- configPath: options.configPath ?? findConfigFile()
1011
+ index: {},
1012
+ outDir: options.outDir ?? _Defaults.outDir,
1013
+ configPath: options.configPath ?? _Defaults.configPath
789
1014
  };
790
1015
  }
791
- function createNextCore({
792
- outDir,
793
- configPath
794
- }) {
1016
+ function createNextCore(options) {
795
1017
  const core = createCore(
796
1018
  {
797
1019
  environment: "next",
798
- outDir,
799
- configPath
1020
+ outDir: options.outDir,
1021
+ configPath: options.configPath
800
1022
  },
801
- [next()]
1023
+ [options.index && indexFile(options.index)]
802
1024
  );
803
1025
  return {
804
1026
  ...core,
@@ -807,7 +1029,7 @@ function createNextCore({
807
1029
  await core.emitAndWrite(...args);
808
1030
  } catch (err) {
809
1031
  if (err instanceof ValidationError) {
810
- console.error(err.toStringFormatted());
1032
+ console.error(await err.toStringFormatted());
811
1033
  } else {
812
1034
  console.error(err);
813
1035
  }