fumadocs-mdx 13.0.8 → 14.0.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 (111) hide show
  1. package/dist/bin.cjs +985 -893
  2. package/dist/bin.js +3 -3
  3. package/dist/build-mdx-6UAK5FF5.js +8 -0
  4. package/dist/bun/index.cjs +613 -471
  5. package/dist/bun/index.d.cts +9 -2
  6. package/dist/bun/index.d.ts +9 -2
  7. package/dist/bun/index.js +15 -14
  8. package/dist/chunk-4JSFLXXT.js +8 -0
  9. package/dist/chunk-5OBUOALK.js +141 -0
  10. package/dist/{chunk-2E2JCOSO.js → chunk-6NISOLQ6.js} +16 -44
  11. package/dist/chunk-7UKSZSPY.js +331 -0
  12. package/dist/chunk-BEBCWQC7.js +224 -0
  13. package/dist/chunk-E5DJTSIM.js +86 -0
  14. package/dist/{chunk-K5ZLPEIQ.js → chunk-FBLMK4RS.js} +9 -6
  15. package/dist/chunk-IQGEFL2B.js +17 -0
  16. package/dist/{chunk-5FTSWCB4.js → chunk-K6HCOGOX.js} +9 -11
  17. package/dist/{chunk-QXHN25N3.js → chunk-MTTISKQJ.js} +6 -6
  18. package/dist/{chunk-3J3WL7WN.js → chunk-SLY7WXTX.js} +71 -58
  19. package/dist/chunk-TYJDYTKH.js +85 -0
  20. package/dist/chunk-WBIHDYMN.js +126 -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 +7 -1
  24. package/dist/config/index.d.ts +7 -1
  25. package/dist/config/index.js +5 -5
  26. package/dist/core-B9ZoS6sA.d.ts +341 -0
  27. package/dist/core-DTuP23zu.d.cts +341 -0
  28. package/dist/index-BD8Woo4m.d.cts +8 -0
  29. package/dist/index-CNOvhtOn.d.ts +8 -0
  30. package/dist/index.d.cts +38 -56
  31. package/dist/index.d.ts +38 -56
  32. package/dist/load-from-file-5HUQN36V.js +8 -0
  33. package/dist/next/index.cjs +763 -473
  34. package/dist/next/index.d.cts +16 -1
  35. package/dist/next/index.d.ts +16 -1
  36. package/dist/next/index.js +80 -281
  37. package/dist/node/loader.cjs +764 -627
  38. package/dist/node/loader.js +10 -11
  39. package/dist/plugins/index-file.cjs +495 -0
  40. package/dist/plugins/index-file.d.cts +14 -0
  41. package/dist/plugins/index-file.d.ts +14 -0
  42. package/dist/plugins/index-file.js +8 -0
  43. package/dist/plugins/json-schema.d.cts +9 -2
  44. package/dist/plugins/json-schema.d.ts +9 -2
  45. package/dist/plugins/last-modified.cjs +110 -0
  46. package/dist/plugins/last-modified.d.cts +37 -0
  47. package/dist/plugins/last-modified.d.ts +37 -0
  48. package/dist/plugins/last-modified.js +74 -0
  49. package/dist/runtime/browser.cjs +93 -0
  50. package/dist/runtime/browser.d.cts +53 -0
  51. package/dist/runtime/browser.d.ts +53 -0
  52. package/dist/runtime/browser.js +67 -0
  53. package/dist/runtime/dynamic.cjs +1023 -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 +79 -0
  57. package/dist/runtime/server.cjs +176 -0
  58. package/dist/runtime/server.d.cts +14 -0
  59. package/dist/runtime/server.d.ts +14 -0
  60. package/dist/runtime/server.js +8 -0
  61. package/dist/runtime/types.cjs +18 -0
  62. package/dist/runtime/types.d.cts +61 -0
  63. package/dist/runtime/types.d.ts +61 -0
  64. package/dist/runtime/types.js +0 -0
  65. package/dist/vite/index.cjs +984 -621
  66. package/dist/vite/index.d.cts +17 -22
  67. package/dist/vite/index.d.ts +17 -22
  68. package/dist/vite/index.js +32 -222
  69. package/dist/webpack/mdx.cjs +647 -514
  70. package/dist/webpack/mdx.d.cts +15 -1
  71. package/dist/webpack/mdx.d.ts +15 -1
  72. package/dist/webpack/mdx.js +12 -17
  73. package/dist/webpack/meta.cjs +360 -231
  74. package/dist/webpack/meta.d.cts +15 -1
  75. package/dist/webpack/meta.d.ts +15 -1
  76. package/dist/webpack/meta.js +13 -15
  77. package/package.json +15 -32
  78. package/dist/build-mdx-BjXOmv0b.d.cts +0 -53
  79. package/dist/build-mdx-CY5UldCO.d.ts +0 -53
  80. package/dist/chunk-2AQRQXSO.js +0 -119
  81. package/dist/chunk-CXA4JO4Z.js +0 -45
  82. package/dist/chunk-DMJ6I4C3.js +0 -76
  83. package/dist/chunk-FSZMKRVH.js +0 -80
  84. package/dist/chunk-II3H5ZVZ.js +0 -77
  85. package/dist/chunk-KILFIBVW.js +0 -75
  86. package/dist/chunk-NVRDCY6Z.js +0 -30
  87. package/dist/chunk-VUEZTR2H.js +0 -26
  88. package/dist/core-DB7TdlyC.d.cts +0 -234
  89. package/dist/core-DB7TdlyC.d.ts +0 -234
  90. package/dist/index-D7s7kCc2.d.cts +0 -7
  91. package/dist/index-D7s7kCc2.d.ts +0 -7
  92. package/dist/load-from-file-AVYOFOI7.js +0 -7
  93. package/dist/preset-ZMP6U62C.js +0 -6
  94. package/dist/runtime/next/async.cjs +0 -760
  95. package/dist/runtime/next/async.d.cts +0 -19
  96. package/dist/runtime/next/async.d.ts +0 -19
  97. package/dist/runtime/next/async.js +0 -86
  98. package/dist/runtime/next/index.cjs +0 -136
  99. package/dist/runtime/next/index.d.cts +0 -33
  100. package/dist/runtime/next/index.d.ts +0 -33
  101. package/dist/runtime/next/index.js +0 -11
  102. package/dist/runtime/vite/browser.cjs +0 -107
  103. package/dist/runtime/vite/browser.d.cts +0 -59
  104. package/dist/runtime/vite/browser.d.ts +0 -59
  105. package/dist/runtime/vite/browser.js +0 -11
  106. package/dist/runtime/vite/server.cjs +0 -243
  107. package/dist/runtime/vite/server.d.cts +0 -30
  108. package/dist/runtime/vite/server.d.ts +0 -30
  109. package/dist/runtime/vite/server.js +0 -111
  110. package/dist/types-Bnh9n7mj.d.cts +0 -45
  111. package/dist/types-ey1AZqrg.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,29 +200,31 @@ 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");
227
+ const { configPath, outDir } = core.getOptions();
234
228
  const transformed = await build({
235
229
  entryPoints: [{ in: configPath, out: "source.config" }],
236
230
  bundle: true,
@@ -249,9 +243,9 @@ async function compileConfig(configPath, outDir) {
249
243
  throw new Error("failed to compile configuration file");
250
244
  }
251
245
  }
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"));
246
+ async function loadConfig(core, build = false) {
247
+ if (build) await compileConfig(core);
248
+ const url = (0, import_node_url.pathToFileURL)(core.getCompiledConfigPath());
255
249
  url.searchParams.set("hash", Date.now().toString());
256
250
  const config = import(url.href).then(
257
251
  (loaded) => buildConfig(loaded)
@@ -259,33 +253,7 @@ async function loadConfig(configPath, outDir, build = false) {
259
253
  return await config;
260
254
  }
261
255
 
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
256
  // src/utils/validation.ts
288
- var import_picocolors = __toESM(require("picocolors"), 1);
289
257
  var ValidationError = class extends Error {
290
258
  constructor(message, issues) {
291
259
  super(
@@ -295,12 +263,13 @@ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
295
263
  this.title = message;
296
264
  this.issues = issues;
297
265
  }
298
- toStringFormatted() {
266
+ async toStringFormatted() {
267
+ const picocolors = await import("picocolors");
299
268
  return [
300
- import_picocolors.default.bold(`[MDX] ${this.title}:`),
269
+ picocolors.bold(`[MDX] ${this.title}:`),
301
270
  ...this.issues.map(
302
- (issue) => import_picocolors.default.redBright(
303
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
271
+ (issue) => picocolors.redBright(
272
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
304
273
  )
305
274
  )
306
275
  ].join("\n");
@@ -322,32 +291,342 @@ async function validate(schema, data, context, errorMessage) {
322
291
  return data;
323
292
  }
324
293
 
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
294
+ // src/core.ts
330
295
  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);
335
- 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
296
+ var import_promises = __toESM(require("fs/promises"), 1);
297
+
298
+ // src/utils/codegen.ts
299
+ var import_node_path = __toESM(require("path"), 1);
300
+ var import_tinyglobby = require("tinyglobby");
301
+ function createCodegen({
302
+ target = "default",
303
+ outDir = "",
304
+ jsExtension = false,
305
+ globCache = /* @__PURE__ */ new Map()
306
+ }) {
307
+ let eagerImportId = 0;
308
+ const banner = ["// @ts-nocheck"];
309
+ if (target === "vite") {
310
+ banner.push('/// <reference types="vite/client" />');
311
+ }
312
+ return {
313
+ options: {
314
+ target,
315
+ outDir
316
+ },
317
+ lines: [],
318
+ addImport(statement) {
319
+ this.lines.unshift(statement);
320
+ },
321
+ async pushAsync(insert) {
322
+ for (const line of await Promise.all(insert)) {
323
+ if (line === void 0) continue;
324
+ this.lines.push(line);
342
325
  }
343
- );
344
- const time = new Date(out.stdout);
345
- cache.set(file, time);
346
- return time;
347
- } catch {
348
- return;
326
+ },
327
+ async generateGlobImport(patterns, options) {
328
+ if (target === "vite") {
329
+ return this.generateViteGlobImport(patterns, options);
330
+ }
331
+ return this.generateNodeGlobImport(patterns, options);
332
+ },
333
+ generateViteGlobImport(patterns, { base, ...rest }) {
334
+ patterns = (typeof patterns === "string" ? [patterns] : patterns).map(
335
+ normalizeViteGlobPath
336
+ );
337
+ return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(
338
+ {
339
+ base: normalizeViteGlobPath(import_node_path.default.relative(outDir, base)),
340
+ ...rest
341
+ },
342
+ null,
343
+ 2
344
+ )})`;
345
+ },
346
+ async generateNodeGlobImport(patterns, {
347
+ base,
348
+ eager = false,
349
+ query = {},
350
+ import: importName
351
+ }) {
352
+ const cacheKey = JSON.stringify({ patterns, base });
353
+ let files = globCache.get(cacheKey);
354
+ if (!files) {
355
+ files = (0, import_tinyglobby.glob)(patterns, {
356
+ cwd: base
357
+ });
358
+ globCache.set(cacheKey, files);
359
+ }
360
+ let code = "{";
361
+ for (const item of await files) {
362
+ const fullPath = import_node_path.default.join(base, item);
363
+ const searchParams = new URLSearchParams();
364
+ for (const [k, v] of Object.entries(query)) {
365
+ searchParams.set(k, v);
366
+ }
367
+ const importPath = this.formatImportPath(fullPath) + "?" + searchParams.toString();
368
+ if (eager) {
369
+ const name = `__fd_glob_${eagerImportId++}`;
370
+ this.lines.unshift(
371
+ importName ? `import { ${importName} as ${name} } from ${JSON.stringify(importPath)}` : `import * as ${name} from ${JSON.stringify(importPath)}`
372
+ );
373
+ code += `${JSON.stringify(item)}: ${name}, `;
374
+ } else {
375
+ let line = `${JSON.stringify(item)}: () => import(${JSON.stringify(importPath)})`;
376
+ if (importName) {
377
+ line += `.then(mod => mod.${importName})`;
378
+ }
379
+ code += `${line}, `;
380
+ }
381
+ }
382
+ code += "}";
383
+ return code;
384
+ },
385
+ formatImportPath(file) {
386
+ const ext = import_node_path.default.extname(file);
387
+ let filename;
388
+ if (ext === ".ts" && jsExtension) {
389
+ filename = file.substring(0, file.length - ext.length) + ".js";
390
+ } else if (ext === ".ts") {
391
+ filename = file.substring(0, file.length - ext.length);
392
+ } else {
393
+ filename = file;
394
+ }
395
+ const importPath = slash(import_node_path.default.relative(outDir, filename));
396
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
397
+ },
398
+ toString() {
399
+ return [...banner, ...this.lines].join("\n");
400
+ }
401
+ };
402
+ }
403
+ function normalizeViteGlobPath(file) {
404
+ file = slash(file);
405
+ if (file.startsWith("./")) return file;
406
+ if (file.startsWith("/")) return `.${file}`;
407
+ return `./${file}`;
408
+ }
409
+ function slash(path6) {
410
+ const isExtendedLengthPath = path6.startsWith("\\\\?\\");
411
+ if (isExtendedLengthPath) {
412
+ return path6;
413
+ }
414
+ return path6.replaceAll("\\", "/");
415
+ }
416
+ function ident(code, tab = 1) {
417
+ return code.split("\n").map((v) => " ".repeat(tab) + v).join("\n");
418
+ }
419
+
420
+ // src/core.ts
421
+ var _Defaults = {
422
+ configPath: "source.config.ts",
423
+ outDir: ".source"
424
+ };
425
+ async function getPlugins(pluginOptions) {
426
+ const plugins = [];
427
+ for await (const option of pluginOptions) {
428
+ if (!option) continue;
429
+ if (Array.isArray(option)) plugins.push(...await getPlugins(option));
430
+ else plugins.push(option);
431
+ }
432
+ return plugins;
433
+ }
434
+ function createCore(options, defaultPlugins = []) {
435
+ let config;
436
+ let plugins;
437
+ async function transformMetadata({
438
+ collection,
439
+ filePath,
440
+ source
441
+ }, data) {
442
+ if (collection.schema) {
443
+ data = await validate(
444
+ collection.schema,
445
+ data,
446
+ { path: filePath, source },
447
+ collection.type === "doc" ? `invalid frontmatter in ${filePath}` : `invalid data in ${filePath}`
448
+ );
449
+ }
450
+ return data;
451
+ }
452
+ const core = {
453
+ /**
454
+ * Convenient cache store, reset when config changes
455
+ */
456
+ cache: /* @__PURE__ */ new Map(),
457
+ async init({ config: newConfig }) {
458
+ config = await newConfig;
459
+ this.cache.clear();
460
+ plugins = await getPlugins([
461
+ postprocessPlugin(),
462
+ ...defaultPlugins,
463
+ ...config.global.plugins ?? []
464
+ ]);
465
+ for (const plugin of plugins) {
466
+ const out = await plugin.config?.call(pluginContext, config);
467
+ if (out) config = out;
468
+ }
469
+ },
470
+ getOptions() {
471
+ return options;
472
+ },
473
+ getConfig() {
474
+ return config;
475
+ },
476
+ /**
477
+ * The file path of compiled config file, the file may not exist (e.g. on Vite, or still compiling)
478
+ */
479
+ getCompiledConfigPath() {
480
+ return import_node_path2.default.join(options.outDir, "source.config.mjs");
481
+ },
482
+ getPlugins() {
483
+ return plugins;
484
+ },
485
+ getPluginContext() {
486
+ return pluginContext;
487
+ },
488
+ async initServer(server) {
489
+ for (const plugin of plugins) {
490
+ await plugin.configureServer?.call(pluginContext, server);
491
+ }
492
+ },
493
+ async emit({ filterPlugin = () => true } = {}) {
494
+ return (await Promise.all(
495
+ plugins.map((plugin) => {
496
+ if (!filterPlugin(plugin) || !plugin.emit) return [];
497
+ return plugin.emit.call(pluginContext);
498
+ })
499
+ )).flat();
500
+ },
501
+ async emitAndWrite(emitOptions) {
502
+ const start = performance.now();
503
+ const out = await this.emit(emitOptions);
504
+ await Promise.all(
505
+ out.map(async (entry) => {
506
+ const file = import_node_path2.default.join(options.outDir, entry.path);
507
+ await import_promises.default.mkdir(import_node_path2.default.dirname(file), { recursive: true });
508
+ await import_promises.default.writeFile(file, entry.content);
509
+ })
510
+ );
511
+ console.log(`[MDX] generated files in ${performance.now() - start}ms`);
512
+ },
513
+ async transformMeta(options2, data) {
514
+ const ctx = {
515
+ ...pluginContext,
516
+ ...options2
517
+ };
518
+ data = await transformMetadata(options2, data);
519
+ for (const plugin of plugins) {
520
+ if (plugin.meta?.transform)
521
+ data = await plugin.meta.transform.call(ctx, data) ?? data;
522
+ }
523
+ return data;
524
+ },
525
+ async transformFrontmatter(options2, data) {
526
+ const ctx = {
527
+ ...pluginContext,
528
+ ...options2
529
+ };
530
+ data = await transformMetadata(options2, data);
531
+ for (const plugin of plugins) {
532
+ if (plugin.doc?.frontmatter)
533
+ data = await plugin.doc.frontmatter.call(ctx, data) ?? data;
534
+ }
535
+ return data;
536
+ },
537
+ async transformVFile(options2, file) {
538
+ const ctx = {
539
+ ...pluginContext,
540
+ ...options2
541
+ };
542
+ for (const plugin of plugins) {
543
+ if (plugin.doc?.vfile)
544
+ file = await plugin.doc.vfile.call(ctx, file) ?? file;
545
+ }
546
+ return file;
547
+ }
548
+ };
549
+ const pluginContext = {
550
+ core,
551
+ ...options
552
+ };
553
+ return core;
554
+ }
555
+ function postprocessPlugin() {
556
+ const LinkReferenceTypes = `{
557
+ /**
558
+ * extracted references (e.g. hrefs, paths), useful for analyzing relationships between pages.
559
+ */
560
+ extractedReferences?: import('fumadocs-mdx').ExtractedReference[];
561
+ }`;
562
+ return {
563
+ "index-file": {
564
+ generateTypeConfig() {
565
+ const lines = [];
566
+ lines.push("{");
567
+ lines.push(" DocData: {");
568
+ for (const collection of this.core.getConfig().collectionList) {
569
+ let postprocessOptions;
570
+ switch (collection.type) {
571
+ case "doc":
572
+ postprocessOptions = collection.postprocess;
573
+ break;
574
+ case "docs":
575
+ postprocessOptions = collection.docs.postprocess;
576
+ break;
577
+ }
578
+ if (postprocessOptions?.extractLinkReferences) {
579
+ lines.push(ident(`${collection.name}: ${LinkReferenceTypes},`, 2));
580
+ }
581
+ }
582
+ lines.push(" }");
583
+ lines.push("}");
584
+ return lines.join("\n");
585
+ },
586
+ serverOptions(options) {
587
+ options.doc ??= {};
588
+ options.doc.passthroughs ??= [];
589
+ options.doc.passthroughs.push("extractedReferences");
590
+ }
591
+ }
592
+ };
593
+ }
594
+
595
+ // src/loaders/index.ts
596
+ var metaLoaderGlob = /\.(json|yaml)(\?.+?)?$/;
597
+ var mdxLoaderGlob = /\.mdx?(\?.+?)?$/;
598
+
599
+ // src/plugins/index-file.ts
600
+ var import_path = __toESM(require("path"), 1);
601
+ var import_tinyglobby2 = require("tinyglobby");
602
+
603
+ // src/utils/fs-cache.ts
604
+ var import_lru_cache = require("lru-cache");
605
+ var import_promises2 = __toESM(require("fs/promises"), 1);
606
+ var import_node_path3 = __toESM(require("path"), 1);
607
+ var map = new import_lru_cache.LRUCache({
608
+ max: 100
609
+ });
610
+ function toFullPath(file) {
611
+ if (import_node_path3.default.isAbsolute(file)) {
612
+ return import_node_path3.default.relative(process.cwd(), file);
349
613
  }
614
+ return file;
350
615
  }
616
+ function readFileWithCache(file) {
617
+ const fullPath = toFullPath(file);
618
+ const cached = map.get(fullPath);
619
+ if (cached) return cached;
620
+ const read = import_promises2.default.readFile(fullPath).then((s) => s.toString());
621
+ map.set(fullPath, read);
622
+ return read;
623
+ }
624
+ function removeFileCache(file) {
625
+ map.delete(toFullPath(file));
626
+ }
627
+
628
+ // src/plugins/index-file.ts
629
+ var import_crypto = require("crypto");
351
630
 
352
631
  // src/utils/fuma-matter.ts
353
632
  var import_js_yaml = require("js-yaml");
@@ -365,323 +644,309 @@ function fumaMatter(input) {
365
644
  return output;
366
645
  }
367
646
 
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;
647
+ // src/plugins/index-file.ts
648
+ function indexFile(options = {}) {
649
+ const {
650
+ target = "default",
651
+ addJsExtension,
652
+ browser = true,
653
+ dynamic = true
654
+ } = options;
655
+ let config;
656
+ let dynamicCollections;
657
+ function isDynamic(collection) {
658
+ return collection.type === "docs" && collection.docs.dynamic || collection.type === "doc" && collection.dynamic;
392
659
  }
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}`;
660
+ function generateConfigs(core) {
661
+ const serverOptions = {};
662
+ const typeConfigs = [];
663
+ const ctx = core.getPluginContext();
664
+ for (const plugin of core.getPlugins()) {
665
+ const indexFilePlugin = plugin["index-file"];
666
+ if (!indexFilePlugin) continue;
667
+ indexFilePlugin.serverOptions?.call(ctx, serverOptions);
668
+ const config2 = indexFilePlugin.generateTypeConfig?.call(ctx);
669
+ if (config2) typeConfigs.push(config2);
398
670
  }
399
- } else {
400
- importPath = import_node_path3.default.resolve(filename);
671
+ if (typeConfigs.length === 0) {
672
+ typeConfigs.push("{ DocData: {} }");
673
+ }
674
+ return {
675
+ serverOptions,
676
+ tc: typeConfigs.join(" & ")
677
+ };
401
678
  }
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() {
408
- let config;
409
- let shouldEmitOnChange = false;
410
679
  return {
411
- name: "next",
680
+ name: "index-file",
412
681
  config(v) {
413
682
  config = v;
414
- shouldEmitOnChange = config.collectionList.some((collection) => {
415
- return collection.type === "doc" && collection.async || collection.type === "docs" || collection.type === "meta";
416
- });
683
+ dynamicCollections = config.collectionList.filter(isDynamic);
417
684
  },
418
685
  configureServer(server) {
419
686
  if (!server.watcher) return;
420
- server.watcher.on("all", async (event) => {
421
- if (event === "change" && !shouldEmitOnChange) return;
687
+ server.watcher.on("all", async (event, file) => {
688
+ removeFileCache(file);
689
+ if (dynamicCollections.length === 0) {
690
+ if (target === "vite") return;
691
+ if (target === "default" && event === "change") return;
692
+ }
693
+ const updatedCollection = config.collectionList.find(
694
+ (collection) => collection.hasFile(file)
695
+ );
696
+ if (!updatedCollection) return;
697
+ if (!isDynamic(updatedCollection)) {
698
+ if (target === "vite") return;
699
+ if (target === "default" && event === "change") return;
700
+ }
422
701
  await this.core.emitAndWrite({
423
- filterPlugin: (plugin) => plugin.name === "next"
702
+ filterPlugin: (plugin) => plugin.name === "index-file"
424
703
  });
425
704
  });
426
705
  },
427
706
  async emit() {
428
- return [
429
- {
430
- path: "index.ts",
431
- content: await indexFile(this.configPath, config, {
432
- relativeTo: this.outDir
433
- })
434
- }
707
+ const globCache = /* @__PURE__ */ new Map();
708
+ const { serverOptions, tc } = generateConfigs(this.core);
709
+ const toEmitEntry = async (path6, content) => {
710
+ const codegen = createCodegen({
711
+ target,
712
+ outDir: this.outDir,
713
+ jsExtension: addJsExtension,
714
+ globCache
715
+ });
716
+ await content({
717
+ core: this.core,
718
+ codegen,
719
+ serverOptions,
720
+ tc
721
+ });
722
+ return {
723
+ path: path6,
724
+ content: codegen.toString()
725
+ };
726
+ };
727
+ const out = [
728
+ toEmitEntry("server.ts", generateServerIndexFile)
435
729
  ];
730
+ if (dynamic)
731
+ out.push(toEmitEntry("dynamic.ts", generateDynamicIndexFile));
732
+ if (browser)
733
+ out.push(toEmitEntry("browser.ts", generateBrowserIndexFile));
734
+ return await Promise.all(out);
436
735
  }
437
736
  };
438
737
  }
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
- );
738
+ async function generateServerIndexFile({
739
+ core,
740
+ codegen,
741
+ serverOptions,
742
+ tc
743
+ }) {
744
+ codegen.lines.push(
745
+ `import { server } from 'fumadocs-mdx/runtime/server';`,
746
+ `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
747
+ "",
748
+ `const create = server<typeof Config, ${tc}>(${JSON.stringify(serverOptions)});`
749
+ );
750
+ async function generateCollectionObject(collection) {
751
+ switch (collection.type) {
752
+ case "docs": {
753
+ if (collection.docs.dynamic) return;
754
+ if (collection.docs.async) {
755
+ const [metaGlob2, headGlob, bodyGlob] = await Promise.all([
756
+ generateMetaCollectionGlob(codegen, collection.meta, true),
757
+ generateDocCollectionFrontmatterGlob(
758
+ codegen,
759
+ collection.docs,
760
+ true
761
+ ),
762
+ generateDocCollectionGlob(codegen, collection.docs)
763
+ ]);
764
+ return `await create.docsLazy("${collection.name}", "${collection.dir}", ${metaGlob2}, ${headGlob}, ${bodyGlob})`;
765
+ }
766
+ const [metaGlob, docGlob] = await Promise.all([
767
+ generateMetaCollectionGlob(codegen, collection.meta, true),
768
+ generateDocCollectionGlob(codegen, collection.docs, true)
769
+ ]);
770
+ return `await create.docs("${collection.name}", "${collection.dir}", ${metaGlob}, ${docGlob})`;
481
771
  }
482
- return JSON.stringify({
483
- info: file,
484
- data
485
- });
486
- });
487
- return Promise.all(items);
772
+ case "doc":
773
+ if (collection.dynamic) return;
774
+ if (collection.async) {
775
+ const [headGlob, bodyGlob] = await Promise.all([
776
+ generateDocCollectionFrontmatterGlob(codegen, collection, true),
777
+ generateDocCollectionGlob(codegen, collection)
778
+ ]);
779
+ return `await create.docLazy("${collection.name}", "${collection.dir}", ${headGlob}, ${bodyGlob})`;
780
+ }
781
+ return `await create.doc("${collection.name}", "${collection.dir}", ${await generateDocCollectionGlob(
782
+ codegen,
783
+ collection,
784
+ true
785
+ )})`;
786
+ case "meta":
787
+ return `await create.meta("${collection.name}", "${collection.dir}", ${await generateMetaCollectionGlob(
788
+ codegen,
789
+ collection,
790
+ true
791
+ )})`;
792
+ }
488
793
  }
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;
794
+ await codegen.pushAsync(
795
+ core.getConfig().collectionList.map(async (collection) => {
796
+ const obj = await generateCollectionObject(collection);
797
+ if (!obj) return;
798
+ return `
799
+ export const ${collection.name} = ${obj};`;
800
+ })
801
+ );
802
+ }
803
+ async function generateDynamicIndexFile({
804
+ core,
805
+ codegen,
806
+ serverOptions,
807
+ tc
808
+ }) {
809
+ const { configPath } = core.getOptions();
810
+ codegen.lines.push(
811
+ `import { dynamic } from 'fumadocs-mdx/runtime/dynamic';`,
812
+ `import * as Config from '${codegen.formatImportPath(configPath)}';`,
813
+ "",
814
+ `const create = await dynamic<typeof Config, ${tc}>(Config, ${JSON.stringify(core.getOptions())}, ${JSON.stringify(serverOptions)});`
815
+ );
816
+ async function generateCollectionObjectEntry(collection, file) {
817
+ const fullPath = import_path.default.join(collection.dir, file);
818
+ const content = await readFileWithCache(fullPath).catch(() => "");
819
+ const parsed = fumaMatter(content);
820
+ const data = await core.transformFrontmatter(
821
+ {
822
+ collection,
823
+ filePath: fullPath,
824
+ source: content
825
+ },
826
+ parsed.data
827
+ );
828
+ const hash = (0, import_crypto.createHash)("md5").update(content).digest("hex");
829
+ const infoStr = [
830
+ // make sure it's included in vercel/nft
831
+ `absolutePath: path.resolve(${JSON.stringify(fullPath)})`
832
+ ];
833
+ for (const [k, v] of Object.entries({
834
+ info: {
835
+ fullPath,
836
+ path: file
837
+ },
838
+ data,
839
+ hash
840
+ })) {
841
+ infoStr.push(`${k}: ${JSON.stringify(v)}`);
505
842
  }
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);
843
+ return `{ ${infoStr.join(", ")} }`;
533
844
  }
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
- ", "
845
+ async function generateCollectionObject(parent) {
846
+ let collection;
847
+ if (parent.type === "doc") collection = parent;
848
+ else if (parent.type === "docs") collection = parent.docs;
849
+ if (!collection || !collection.dynamic) return;
850
+ const files = await (0, import_tinyglobby2.glob)(collection.patterns, {
851
+ cwd: collection.dir
852
+ });
853
+ const entries = await Promise.all(
854
+ files.map((file) => generateCollectionObjectEntry(collection, file))
855
+ );
856
+ switch (parent.type) {
857
+ case "docs": {
858
+ const metaGlob = await generateMetaCollectionGlob(
859
+ codegen,
860
+ parent.meta,
861
+ true
545
862
  );
546
- return `export const ${k} = _runtimeAsync.docs<typeof _source.${k}>([${docsEntries2}], [${metaEntries}], "${k}", _sourceConfig)`;
863
+ return `await create.docs("${parent.name}", "${parent.dir}", ${metaGlob}, ${entries.join(", ")})`;
547
864
  }
548
- const docsEntries = getDocEntries(collection.docs, docs).join(", ");
549
- return `export const ${k} = _runtime.docs<typeof _source.${k}>([${docsEntries}], [${metaEntries}])`;
550
- }
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(", ")}]);`;
865
+ case "doc":
866
+ return `await create.doc("${collection.name}", "${collection.dir}", ${entries.join(", ")})`;
554
867
  }
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
868
  }
577
- throw new Error(`Unknown meta file format: ${extname2}, in ${file}.`);
869
+ await codegen.pushAsync(
870
+ core.getConfig().collectionList.map(async (collection) => {
871
+ const obj = await generateCollectionObject(collection);
872
+ if (!obj) return;
873
+ return `
874
+ export const ${collection.name} = ${obj};`;
875
+ })
876
+ );
578
877
  }
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
- });
878
+ async function generateBrowserIndexFile({ core, codegen, tc }) {
879
+ codegen.lines.push(
880
+ `import { browser } from 'fumadocs-mdx/runtime/browser';`,
881
+ `import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
882
+ "",
883
+ `const create = browser<typeof Config, ${tc}>();`
884
+ );
885
+ async function generateCollectionObject(collection) {
886
+ switch (collection.type) {
887
+ case "docs": {
888
+ if (collection.docs.dynamic) return;
889
+ return generateCollectionObject(collection.docs);
595
890
  }
891
+ case "doc":
892
+ if (collection.dynamic) return;
893
+ return `create.doc("${collection.name}", ${await generateDocCollectionGlob(codegen, collection)})`;
894
+ }
895
+ }
896
+ codegen.lines.push("const browserCollections = {");
897
+ await codegen.pushAsync(
898
+ core.getConfig().collectionList.map(async (collection) => {
899
+ const obj = await generateCollectionObject(collection);
900
+ if (!obj) return;
901
+ return ident(`${collection.name}: ${obj},`);
596
902
  })
597
903
  );
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");
904
+ codegen.lines.push("};", "export default browserCollections;");
606
905
  }
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
- };
906
+ function generateDocCollectionFrontmatterGlob(codegen, collection, eager = false) {
907
+ return codegen.generateGlobImport(collection.patterns, {
908
+ query: {
909
+ collection: collection.name,
910
+ only: "frontmatter"
617
911
  },
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;
912
+ import: "frontmatter",
913
+ base: collection.dir,
914
+ eager
915
+ });
916
+ }
917
+ function generateDocCollectionGlob(codegen, collection, eager = false) {
918
+ return codegen.generateGlobImport(collection.patterns, {
919
+ query: {
920
+ collection: collection.name
642
921
  },
643
- async initServer(server) {
644
- for (const plugin of plugins2) {
645
- await plugin.configureServer?.call(this.getPluginContext(), server);
646
- }
922
+ base: collection.dir,
923
+ eager
924
+ });
925
+ }
926
+ function generateMetaCollectionGlob(codegen, collection, eager = false) {
927
+ return codegen.generateGlobImport(collection.patterns, {
928
+ query: {
929
+ collection: collection.name
647
930
  },
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
- };
931
+ import: "default",
932
+ base: collection.dir,
933
+ eager
934
+ });
668
935
  }
669
936
 
670
- // src/loaders/index.ts
671
- var mdxLoaderGlob = /\.mdx?(\?.+?)?$/;
672
-
673
937
  // src/next/index.ts
674
938
  var defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
675
939
  function createMDX(createOptions = {}) {
676
- const options = applyDefaults(createOptions);
940
+ const core = createNextCore(applyDefaults(createOptions));
677
941
  const isDev = process.env.NODE_ENV === "development";
678
942
  if (process.env._FUMADOCS_MDX !== "1") {
679
943
  process.env._FUMADOCS_MDX = "1";
680
- void init(isDev, options);
944
+ void init(isDev, core);
681
945
  }
682
946
  return (nextConfig = {}) => {
683
947
  const loaderOptions = {
684
- ...options,
948
+ ...core.getOptions(),
949
+ compiledConfigPath: core.getCompiledConfigPath(),
685
950
  isDev
686
951
  };
687
952
  const turbopack = {
@@ -696,6 +961,24 @@ function createMDX(createOptions = {}) {
696
961
  }
697
962
  ],
698
963
  as: "*.js"
964
+ },
965
+ "*.json": {
966
+ loaders: [
967
+ {
968
+ loader: "fumadocs-mdx/loader-meta",
969
+ options: loaderOptions
970
+ }
971
+ ],
972
+ as: "*.json"
973
+ },
974
+ "*.yaml": {
975
+ loaders: [
976
+ {
977
+ loader: "fumadocs-mdx/loader-meta",
978
+ options: loaderOptions
979
+ }
980
+ ],
981
+ as: "*.js"
699
982
  }
700
983
  }
701
984
  };
@@ -703,42 +986,54 @@ function createMDX(createOptions = {}) {
703
986
  ...nextConfig,
704
987
  turbopack,
705
988
  pageExtensions: nextConfig.pageExtensions ?? defaultPageExtensions,
706
- webpack: (config, options2) => {
989
+ webpack: (config, options) => {
707
990
  config.resolve ||= {};
708
991
  config.module ||= {};
709
992
  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
- });
993
+ config.module.rules.push(
994
+ {
995
+ test: mdxLoaderGlob,
996
+ use: [
997
+ options.defaultLoaders.babel,
998
+ {
999
+ loader: "fumadocs-mdx/loader-mdx",
1000
+ options: loaderOptions
1001
+ }
1002
+ ]
1003
+ },
1004
+ {
1005
+ test: metaLoaderGlob,
1006
+ use: [
1007
+ options.defaultLoaders.babel,
1008
+ {
1009
+ loader: "fumadocs-mdx/loader-meta",
1010
+ options: loaderOptions
1011
+ }
1012
+ ]
1013
+ }
1014
+ );
720
1015
  config.plugins ||= [];
721
- return nextConfig.webpack?.(config, options2) ?? config;
1016
+ return nextConfig.webpack?.(config, options) ?? config;
722
1017
  }
723
1018
  };
724
1019
  };
725
1020
  }
726
- async function init(dev, options) {
727
- const core = createNextCore(options);
1021
+ async function init(dev, core) {
728
1022
  async function initOrReload() {
729
1023
  await core.init({
730
- config: loadConfig(options.configPath, options.outDir, true)
1024
+ config: loadConfig(core, true)
731
1025
  });
732
1026
  await core.emitAndWrite();
733
1027
  }
734
1028
  async function devServer() {
735
1029
  const { FSWatcher } = await import("chokidar");
1030
+ const { configPath, outDir } = core.getOptions();
736
1031
  const watcher = new FSWatcher({
737
1032
  ignoreInitial: true,
738
1033
  persistent: true,
739
- ignored: [options.outDir]
1034
+ ignored: [outDir]
740
1035
  });
741
- watcher.add(options.configPath);
1036
+ watcher.add(configPath);
742
1037
  for (const collection of core.getConfig().collectionList) {
743
1038
  if (collection.type === "docs") {
744
1039
  watcher.add(collection.docs.dir);
@@ -750,10 +1045,9 @@ async function init(dev, options) {
750
1045
  watcher.on("ready", () => {
751
1046
  console.log("[MDX] started dev server");
752
1047
  });
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)) {
1048
+ const absoluteConfigPath = path5.resolve(configPath);
1049
+ watcher.on("all", async (_event, file) => {
1050
+ if (path5.resolve(file) === absoluteConfigPath) {
757
1051
  watcher.removeAllListeners();
758
1052
  await watcher.close();
759
1053
  await initOrReload();
@@ -773,32 +1067,28 @@ async function init(dev, options) {
773
1067
  await devServer();
774
1068
  }
775
1069
  }
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)
1070
+ async function postInstall(options) {
1071
+ const core = createNextCore(applyDefaults(options));
1072
+ await core.init({
1073
+ config: loadConfig(core, true)
782
1074
  });
783
1075
  await core.emitAndWrite();
784
1076
  }
785
1077
  function applyDefaults(options) {
786
1078
  return {
787
- outDir: options.outDir ?? ".source",
788
- configPath: options.configPath ?? findConfigFile()
1079
+ index: {},
1080
+ outDir: options.outDir ?? _Defaults.outDir,
1081
+ configPath: options.configPath ?? _Defaults.configPath
789
1082
  };
790
1083
  }
791
- function createNextCore({
792
- outDir,
793
- configPath
794
- }) {
1084
+ function createNextCore(options) {
795
1085
  const core = createCore(
796
1086
  {
797
1087
  environment: "next",
798
- outDir,
799
- configPath
1088
+ outDir: options.outDir,
1089
+ configPath: options.configPath
800
1090
  },
801
- [next()]
1091
+ [options.index && indexFile(options.index)]
802
1092
  );
803
1093
  return {
804
1094
  ...core,
@@ -807,7 +1097,7 @@ function createNextCore({
807
1097
  await core.emitAndWrite(...args);
808
1098
  } catch (err) {
809
1099
  if (err instanceof ValidationError) {
810
- console.error(err.toStringFormatted());
1100
+ console.error(await err.toStringFormatted());
811
1101
  } else {
812
1102
  console.error(err);
813
1103
  }