fumadocs-mdx 11.6.0 → 13.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 (93) hide show
  1. package/dist/bin.cjs +1728 -0
  2. package/dist/bin.d.cts +1 -0
  3. package/dist/bin.d.ts +1 -0
  4. package/dist/bin.js +16 -0
  5. package/dist/build-mdx-CCNr86q6.d.ts +53 -0
  6. package/dist/build-mdx-D-r3_eQL.d.cts +53 -0
  7. package/dist/bun/index.cjs +857 -0
  8. package/dist/bun/index.d.cts +13 -0
  9. package/dist/bun/index.d.ts +13 -0
  10. package/dist/bun/index.js +62 -0
  11. package/dist/chunk-3J3WL7WN.js +160 -0
  12. package/dist/chunk-CXA4JO4Z.js +45 -0
  13. package/dist/chunk-EELYB2XC.js +207 -0
  14. package/dist/chunk-FSZMKRVH.js +80 -0
  15. package/dist/chunk-II3H5ZVZ.js +77 -0
  16. package/dist/chunk-JVZFH6ND.js +40 -0
  17. package/dist/chunk-K5ZLPEIQ.js +207 -0
  18. package/dist/{chunk-VFALQK6O.js → chunk-KILFIBVW.js} +21 -12
  19. package/dist/chunk-NVRDCY6Z.js +30 -0
  20. package/dist/chunk-U4MQ44TS.js +53 -0
  21. package/dist/chunk-VWJKRQZR.js +19 -0
  22. package/dist/chunk-XQ5O7IPO.js +128 -0
  23. package/dist/chunk-XZY2AWJI.js +81 -0
  24. package/dist/chunk-YVCR6FUH.js +82 -0
  25. package/dist/config/index.cjs +232 -128
  26. package/dist/config/index.d.cts +4 -6
  27. package/dist/config/index.d.ts +4 -6
  28. package/dist/config/index.js +26 -19
  29. package/dist/core-B6j6Fxse.d.cts +218 -0
  30. package/dist/core-B6j6Fxse.d.ts +218 -0
  31. package/dist/index.cjs +0 -76
  32. package/dist/index.d.cts +73 -20
  33. package/dist/index.d.ts +73 -20
  34. package/dist/index.js +0 -10
  35. package/dist/load-MNG3CLET.js +7 -0
  36. package/dist/next/index.cjs +567 -314
  37. package/dist/next/index.d.cts +9 -12
  38. package/dist/next/index.d.ts +9 -12
  39. package/dist/next/index.js +238 -211
  40. package/dist/node/loader.cjs +922 -0
  41. package/dist/node/loader.d.cts +5 -0
  42. package/dist/node/loader.d.ts +5 -0
  43. package/dist/node/loader.js +33 -0
  44. package/dist/plugins/json-schema.cjs +162 -0
  45. package/dist/plugins/json-schema.d.cts +24 -0
  46. package/dist/plugins/json-schema.d.ts +24 -0
  47. package/dist/plugins/json-schema.js +78 -0
  48. package/dist/{mdx-options-CAU273O3.js → preset-ZMP6U62C.js} +1 -1
  49. package/dist/runtime/next/async.cjs +715 -0
  50. package/dist/runtime/next/async.d.cts +21 -0
  51. package/dist/runtime/next/async.d.ts +21 -0
  52. package/dist/runtime/next/async.js +89 -0
  53. package/dist/runtime/next/index.cjs +136 -0
  54. package/dist/runtime/next/index.d.cts +33 -0
  55. package/dist/runtime/next/index.d.ts +33 -0
  56. package/dist/runtime/next/index.js +11 -0
  57. package/dist/runtime/vite/browser.cjs +107 -0
  58. package/dist/runtime/vite/browser.d.cts +59 -0
  59. package/dist/runtime/vite/browser.d.ts +59 -0
  60. package/dist/runtime/vite/browser.js +11 -0
  61. package/dist/runtime/vite/server.cjs +243 -0
  62. package/dist/runtime/vite/server.d.cts +30 -0
  63. package/dist/runtime/vite/server.d.ts +30 -0
  64. package/dist/runtime/vite/server.js +111 -0
  65. package/dist/types-AGzTfBmf.d.ts +45 -0
  66. package/dist/types-DKGMoay5.d.cts +45 -0
  67. package/dist/vite/index.cjs +1185 -0
  68. package/dist/vite/index.d.cts +45 -0
  69. package/dist/vite/index.d.ts +45 -0
  70. package/dist/vite/index.js +297 -0
  71. package/dist/webpack/index.cjs +957 -0
  72. package/dist/{loader-mdx.d.cts → webpack/index.d.cts} +3 -6
  73. package/dist/{loader-mdx.d.ts → webpack/index.d.ts} +3 -6
  74. package/dist/webpack/index.js +44 -0
  75. package/loader-mdx.cjs +1 -1
  76. package/package.json +86 -29
  77. package/bin.js +0 -5
  78. package/dist/chunk-2ZOW45YZ.js +0 -63
  79. package/dist/chunk-DRVUBK5B.js +0 -39
  80. package/dist/chunk-HFLDWPJA.js +0 -62
  81. package/dist/chunk-IOENRFUX.js +0 -112
  82. package/dist/chunk-MK7EXW7O.js +0 -75
  83. package/dist/define-BaW0PQDJ.d.cts +0 -201
  84. package/dist/define-BaW0PQDJ.d.ts +0 -201
  85. package/dist/loader-mdx.cjs +0 -527
  86. package/dist/loader-mdx.js +0 -162
  87. package/dist/runtime/async.cjs +0 -269
  88. package/dist/runtime/async.d.cts +0 -18
  89. package/dist/runtime/async.d.ts +0 -18
  90. package/dist/runtime/async.js +0 -73
  91. package/dist/types-BNrQHCj5.d.cts +0 -100
  92. package/dist/types-DEduCvIT.d.ts +0 -100
  93. package/dist/watcher-IAZDSTU7.js +0 -24
@@ -30,59 +30,97 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/map/watcher.ts
34
- var watcher_exports = {};
35
- __export(watcher_exports, {
36
- watcher: () => watcher
33
+ // src/loaders/mdx/preset.ts
34
+ var preset_exports = {};
35
+ __export(preset_exports, {
36
+ getDefaultMDXOptions: () => getDefaultMDXOptions
37
37
  });
38
- function watcher(configPath, config) {
39
- const deps = [configPath];
40
- function add(dir) {
41
- if (Array.isArray(dir)) deps.push(...dir);
42
- else deps.push(dir);
43
- }
44
- for (const collection of config.collections.values()) {
45
- if (collection.type === "docs") {
46
- add(collection.docs.dir);
47
- add(collection.meta.dir);
48
- } else {
49
- add(collection.dir);
50
- }
38
+ function pluginOption(def, options = []) {
39
+ const list = def(Array.isArray(options) ? options : []).filter(
40
+ Boolean
41
+ );
42
+ if (typeof options === "function") {
43
+ return options(list);
51
44
  }
52
- return (0, import_chokidar.watch)(deps, {
53
- ignoreInitial: true,
54
- persistent: true
55
- });
45
+ return list;
56
46
  }
57
- var import_chokidar;
58
- var init_watcher = __esm({
59
- "src/map/watcher.ts"() {
47
+ function getDefaultMDXOptions({
48
+ valueToExport = [],
49
+ rehypeCodeOptions,
50
+ remarkImageOptions,
51
+ remarkHeadingOptions,
52
+ remarkStructureOptions,
53
+ remarkCodeTabOptions,
54
+ remarkNpmOptions,
55
+ _withoutBundler = false,
56
+ ...mdxOptions
57
+ }) {
58
+ const remarkPlugins = pluginOption(
59
+ (v) => [
60
+ plugins.remarkGfm,
61
+ [
62
+ plugins.remarkHeading,
63
+ {
64
+ generateToc: false,
65
+ ...remarkHeadingOptions
66
+ }
67
+ ],
68
+ remarkImageOptions !== false && [
69
+ plugins.remarkImage,
70
+ {
71
+ ...remarkImageOptions,
72
+ useImport: _withoutBundler ? false : remarkImageOptions?.useImport
73
+ }
74
+ ],
75
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && [
76
+ plugins.remarkCodeTab,
77
+ remarkCodeTabOptions
78
+ ],
79
+ "remarkNpm" in plugins && remarkNpmOptions !== false && [plugins.remarkNpm, remarkNpmOptions],
80
+ ...v,
81
+ remarkStructureOptions !== false && [
82
+ plugins.remarkStructure,
83
+ remarkStructureOptions
84
+ ],
85
+ () => {
86
+ return (_, file) => {
87
+ file.data["mdx-export"] ??= [];
88
+ for (const name of valueToExport) {
89
+ if (name in file.data)
90
+ file.data["mdx-export"].push({ name, value: file.data[name] });
91
+ }
92
+ };
93
+ }
94
+ ],
95
+ mdxOptions.remarkPlugins
96
+ );
97
+ const rehypePlugins = pluginOption(
98
+ (v) => [
99
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
100
+ ...v,
101
+ plugins.rehypeToc
102
+ ],
103
+ mdxOptions.rehypePlugins
104
+ );
105
+ return {
106
+ ...mdxOptions,
107
+ outputFormat: _withoutBundler ? "function-body" : mdxOptions.outputFormat,
108
+ remarkPlugins,
109
+ rehypePlugins
110
+ };
111
+ }
112
+ var plugins;
113
+ var init_preset = __esm({
114
+ "src/loaders/mdx/preset.ts"() {
60
115
  "use strict";
61
- import_chokidar = require("chokidar");
116
+ plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
62
117
  }
63
118
  });
64
119
 
65
- // src/next/index.ts
66
- var next_exports = {};
67
- __export(next_exports, {
68
- createMDX: () => createMDX,
69
- postInstall: () => postInstall,
70
- start: () => start
71
- });
72
- module.exports = __toCommonJS(next_exports);
73
-
74
- // src/next/create.ts
75
- var import_node_path2 = __toESM(require("path"), 1);
76
-
77
- // src/utils/config.ts
78
- var fs = __toESM(require("fs/promises"), 1);
79
- var path = __toESM(require("path"), 1);
80
- var import_node_url = require("url");
81
-
82
120
  // src/config/build.ts
83
121
  function buildConfig(config) {
84
122
  const collections = /* @__PURE__ */ new Map();
85
- let globalConfig;
123
+ let globalConfig = {};
86
124
  for (const [k, v] of Object.entries(config)) {
87
125
  if (!v) {
88
126
  continue;
@@ -97,36 +135,51 @@ function buildConfig(config) {
97
135
  continue;
98
136
  }
99
137
  }
100
- if (k === "default") {
138
+ if (k === "default" && v) {
101
139
  globalConfig = v;
102
140
  continue;
103
141
  }
104
- return [
105
- `Unknown export "${k}", you can only export collections from source configuration file.`,
106
- null
107
- ];
142
+ throw new Error(
143
+ `Unknown export "${k}", you can only export collections from source configuration file.`
144
+ );
108
145
  }
109
- return [
110
- null,
111
- {
112
- global: globalConfig,
113
- collections
146
+ const mdxOptionsCache = /* @__PURE__ */ new Map();
147
+ return {
148
+ global: globalConfig,
149
+ collections,
150
+ async getDefaultMDXOptions(mode = "default") {
151
+ const cached = mdxOptionsCache.get(mode);
152
+ if (cached) return cached;
153
+ const input = this.global.mdxOptions;
154
+ async function uncached() {
155
+ const options = typeof input === "function" ? await input() : input;
156
+ const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_preset(), preset_exports));
157
+ if (options?.preset === "minimal") return options;
158
+ return getDefaultMDXOptions2({
159
+ ...options,
160
+ _withoutBundler: mode === "remote"
161
+ });
162
+ }
163
+ const result = uncached();
164
+ mdxOptionsCache.set(mode, result);
165
+ return result;
114
166
  }
115
- ];
167
+ };
116
168
  }
169
+ var init_build = __esm({
170
+ "src/config/build.ts"() {
171
+ "use strict";
172
+ }
173
+ });
117
174
 
118
- // src/utils/config.ts
119
- function findConfigFile() {
120
- return path.resolve("source.config.ts");
121
- }
122
- var cache = null;
123
- async function compileConfig(configPath, outDir2) {
175
+ // src/loaders/config/load.ts
176
+ async function compileConfig(configPath, outDir) {
124
177
  const { build } = await import("esbuild");
125
178
  const transformed = await build({
126
179
  entryPoints: [{ in: configPath, out: "source.config" }],
127
180
  bundle: true,
128
- outdir: outDir2,
129
- target: "node18",
181
+ outdir: outDir,
182
+ target: "node20",
130
183
  write: true,
131
184
  platform: "node",
132
185
  format: "esm",
@@ -140,89 +193,89 @@ async function compileConfig(configPath, outDir2) {
140
193
  throw new Error("failed to compile configuration file");
141
194
  }
142
195
  }
143
- async function loadConfig(configPath, hash, build = false) {
144
- if (cache && cache.hash === hash) {
145
- return await cache.config;
146
- }
147
- if (build) await compileConfig(configPath, ".source");
148
- const url = (0, import_node_url.pathToFileURL)(path.resolve(".source/source.config.mjs"));
149
- const config = import(`${url.href}?hash=${hash}`).then((loaded) => {
150
- const [err, config2] = buildConfig(
151
- // every call to `loadConfig` will cause the previous cache to be ignored
152
- loaded
153
- );
154
- if (err !== null) throw new Error(err);
155
- return config2;
156
- });
157
- cache = { config, hash };
196
+ async function loadConfig(configPath, outDir, build = false) {
197
+ if (build) await compileConfig(configPath, outDir);
198
+ const url = (0, import_node_url.pathToFileURL)(path2.resolve(outDir, "source.config.mjs"));
199
+ url.searchParams.set("hash", Date.now().toString());
200
+ const config = import(url.href).then(
201
+ (loaded) => buildConfig(loaded)
202
+ );
158
203
  return await config;
159
204
  }
160
- async function getConfigHash(configPath) {
161
- const stats = await fs.stat(configPath).catch(() => void 0);
162
- if (stats) {
163
- return stats.mtime.getTime().toString();
205
+ var path2, import_node_url;
206
+ var init_load = __esm({
207
+ "src/loaders/config/load.ts"() {
208
+ "use strict";
209
+ path2 = __toESM(require("path"), 1);
210
+ import_node_url = require("url");
211
+ init_build();
164
212
  }
165
- throw new Error("Cannot find config file");
166
- }
213
+ });
214
+
215
+ // src/next/index.ts
216
+ var next_exports = {};
217
+ __export(next_exports, {
218
+ createMDX: () => createMDX,
219
+ postInstall: () => postInstall
220
+ });
221
+ module.exports = __toCommonJS(next_exports);
167
222
 
168
- // src/map/index.ts
169
- var path3 = __toESM(require("path"), 1);
170
- var fs3 = __toESM(require("fs/promises"), 1);
223
+ // src/loaders/config/index.ts
224
+ var import_node_path = __toESM(require("path"), 1);
225
+ var import_promises = __toESM(require("fs/promises"), 1);
226
+ function findConfigFile() {
227
+ return import_node_path.default.resolve("source.config.ts");
228
+ }
171
229
 
172
- // src/map/generate.ts
173
- var path2 = __toESM(require("path"), 1);
174
- var fs2 = __toESM(require("fs/promises"), 1);
175
- var import_fast_glob = __toESM(require("fast-glob"), 1);
230
+ // src/next/index.ts
231
+ var path9 = __toESM(require("path"), 1);
232
+ init_load();
176
233
 
177
- // src/utils/get-type-from-path.ts
178
- var import_node_path = require("path");
179
- var docTypes = [".mdx", ".md"];
180
- var metaTypes = [".json", ".yaml"];
181
- function getTypeFromPath(path6) {
182
- const ext = (0, import_node_path.extname)(path6);
183
- if (docTypes.includes(ext)) return "doc";
184
- if (metaTypes.includes(ext)) return "meta";
234
+ // src/next/file-cache.ts
235
+ var import_lru_cache = require("lru-cache");
236
+ var import_promises2 = __toESM(require("fs/promises"), 1);
237
+ var import_node_path2 = __toESM(require("path"), 1);
238
+ var map = new import_lru_cache.LRUCache({
239
+ max: 100
240
+ });
241
+ function toFullPath(file) {
242
+ if (import_node_path2.default.isAbsolute(file)) {
243
+ return import_node_path2.default.relative(process.cwd(), file);
244
+ }
245
+ return file;
246
+ }
247
+ async function readFileWithCache(file) {
248
+ const fullPath = toFullPath(file);
249
+ const cached = map.get(fullPath);
250
+ if (cached) return cached;
251
+ const read = import_promises2.default.readFile(fullPath).then((s) => s.toString());
252
+ map.set(fullPath, read);
253
+ return read;
254
+ }
255
+ function removeFileCache(file) {
256
+ map.delete(toFullPath(file));
185
257
  }
186
258
 
187
- // src/utils/schema.ts
188
- var import_zod = require("zod");
259
+ // src/utils/validation.ts
189
260
  var import_picocolors = __toESM(require("picocolors"), 1);
190
- var metaSchema = import_zod.z.object({
191
- title: import_zod.z.string().optional(),
192
- pages: import_zod.z.array(import_zod.z.string()).optional(),
193
- description: import_zod.z.string().optional(),
194
- root: import_zod.z.boolean().optional(),
195
- defaultOpen: import_zod.z.boolean().optional(),
196
- icon: import_zod.z.string().optional()
197
- });
198
- var frontmatterSchema = import_zod.z.object({
199
- title: import_zod.z.string(),
200
- description: import_zod.z.string().optional(),
201
- icon: import_zod.z.string().optional(),
202
- full: import_zod.z.boolean().optional(),
203
- // Fumadocs OpenAPI generated
204
- _openapi: import_zod.z.object({}).passthrough().optional()
205
- });
206
261
  var ValidationError = class extends Error {
207
262
  constructor(message, issues) {
208
- super(message);
263
+ super(
264
+ `${message}:
265
+ ${issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`
266
+ );
267
+ this.title = message;
209
268
  this.issues = issues;
210
269
  }
211
- print() {
212
- console.error(
213
- [
214
- `[MDX] ${this.message}:`,
215
- ...this.issues.map(
216
- (issue) => import_picocolors.default.redBright(
217
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
218
- )
270
+ toStringFormatted() {
271
+ return [
272
+ import_picocolors.default.bold(`[MDX] ${this.title}:`),
273
+ ...this.issues.map(
274
+ (issue) => import_picocolors.default.redBright(
275
+ `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
219
276
  )
220
- ].join("\n")
221
- );
222
- }
223
- toString() {
224
- return `${this.message}:
225
- ${this.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`;
277
+ )
278
+ ].join("\n");
226
279
  }
227
280
  };
228
281
  async function validate(schema, data, context, errorMessage) {
@@ -241,45 +294,173 @@ async function validate(schema, data, context, errorMessage) {
241
294
  return data;
242
295
  }
243
296
 
244
- // src/map/file-cache.ts
245
- var import_lru_cache = require("lru-cache");
246
- var map = new import_lru_cache.LRUCache({
247
- max: 200
248
- });
249
- var fileCache = {
250
- read(namespace, path6) {
251
- return map.get(`${namespace}.${path6}`);
252
- },
253
- write(namespace, path6, data) {
254
- map.set(`${namespace}.${path6}`, data);
255
- },
256
- removeCache(path6) {
257
- for (const key of map.keys()) {
258
- const keyPath = key.slice(key.indexOf(".") + 1);
259
- if (keyPath === path6) map.delete(key);
297
+ // src/plugins/next.ts
298
+ var path7 = __toESM(require("path"), 1);
299
+ var import_node_crypto = require("crypto");
300
+ var import_js_yaml2 = require("js-yaml");
301
+
302
+ // src/utils/git-timestamp.ts
303
+ var import_node_path3 = __toESM(require("path"), 1);
304
+ var import_tinyexec = require("tinyexec");
305
+ var cache = /* @__PURE__ */ new Map();
306
+ async function getGitTimestamp(file) {
307
+ const cached = cache.get(file);
308
+ if (cached) return cached;
309
+ try {
310
+ const out = await (0, import_tinyexec.x)(
311
+ "git",
312
+ ["log", "-1", '--pretty="%ai"', import_node_path3.default.relative(process.cwd(), file)],
313
+ {
314
+ throwOnError: true
315
+ }
316
+ );
317
+ const time = new Date(out.stdout);
318
+ cache.set(file, time);
319
+ return time;
320
+ } catch {
321
+ return;
322
+ }
323
+ }
324
+
325
+ // src/utils/fuma-matter.ts
326
+ var import_js_yaml = require("js-yaml");
327
+ var regex = /^---\r?\n(.+?)\r?\n---\r?\n/s;
328
+ function fumaMatter(input) {
329
+ const output = { matter: "", data: {}, content: input };
330
+ const match = regex.exec(input);
331
+ if (!match) {
332
+ return output;
333
+ }
334
+ output.matter = match[0];
335
+ output.content = input.slice(match[0].length);
336
+ const loaded = (0, import_js_yaml.load)(match[1]);
337
+ output.data = loaded ?? {};
338
+ return output;
339
+ }
340
+
341
+ // src/utils/import-formatter.ts
342
+ var import_node_path4 = __toESM(require("path"), 1);
343
+ function getImportCode(info) {
344
+ const specifier = JSON.stringify(info.specifier);
345
+ if (info.type === "default") return `import ${info.name} from ${specifier}`;
346
+ if (info.type === "namespace")
347
+ return `import * as ${info.name} from ${specifier}`;
348
+ if (info.type === "named") {
349
+ const names = info.names.map(
350
+ (name) => Array.isArray(name) ? `${name[0]} as ${name[1]}` : name
351
+ );
352
+ return `import { ${names.join(", ")} } from ${specifier}`;
353
+ }
354
+ return `import ${specifier}`;
355
+ }
356
+ function toImportPath(file, config) {
357
+ const ext = import_node_path4.default.extname(file);
358
+ let filename;
359
+ if (ext === ".ts" && config.jsExtension) {
360
+ filename = file.substring(0, file.length - ext.length) + ".js";
361
+ } else if (ext === ".ts") {
362
+ filename = file.substring(0, file.length - ext.length);
363
+ } else {
364
+ filename = file;
365
+ }
366
+ let importPath;
367
+ if ("relativeTo" in config) {
368
+ importPath = import_node_path4.default.relative(config.relativeTo, filename);
369
+ if (!import_node_path4.default.isAbsolute(importPath) && !importPath.startsWith(".")) {
370
+ importPath = `./${importPath}`;
260
371
  }
372
+ } else {
373
+ importPath = import_node_path4.default.resolve(filename);
261
374
  }
375
+ return importPath.replaceAll(import_node_path4.default.sep, "/");
376
+ }
377
+
378
+ // src/utils/collections.ts
379
+ var import_picomatch = __toESM(require("picomatch"), 1);
380
+ var import_tinyglobby = require("tinyglobby");
381
+ var import_node_path5 = __toESM(require("path"), 1);
382
+ var SupportedFormats = {
383
+ doc: ["mdx", "md"],
384
+ meta: ["json", "yaml"]
262
385
  };
386
+ function getGlobPatterns(collection) {
387
+ if (collection.files) return collection.files;
388
+ return [`**/*.{${SupportedFormats[collection.type].join(",")}}`];
389
+ }
390
+ function isFileSupported(filePath, collection) {
391
+ return SupportedFormats[collection.type].some(
392
+ (format) => filePath.endsWith(`.${format}`)
393
+ );
394
+ }
395
+ async function getCollectionFiles(collection) {
396
+ const files = /* @__PURE__ */ new Map();
397
+ const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
398
+ const patterns = getGlobPatterns(collection);
399
+ await Promise.all(
400
+ dirs.map(async (dir) => {
401
+ const result = await (0, import_tinyglobby.glob)(patterns, {
402
+ cwd: import_node_path5.default.resolve(dir)
403
+ });
404
+ for (const item of result) {
405
+ if (!isFileSupported(item, collection)) continue;
406
+ const fullPath = import_node_path5.default.join(dir, item);
407
+ files.set(fullPath, {
408
+ path: item,
409
+ fullPath
410
+ });
411
+ }
412
+ })
413
+ );
414
+ return Array.from(files.values());
415
+ }
263
416
 
264
- // src/map/generate.ts
265
- var import_gray_matter = __toESM(require("gray-matter"), 1);
266
- async function readFileWithCache(file) {
267
- const cached = fileCache.read("read-file", file);
268
- if (cached) return cached;
269
- return (await fs2.readFile(file)).toString();
417
+ // src/plugins/next.ts
418
+ function next() {
419
+ let config;
420
+ let shouldEmitOnChange = false;
421
+ return {
422
+ name: "next",
423
+ config(v) {
424
+ config = v;
425
+ shouldEmitOnChange = false;
426
+ for (const collection of config.collections.values()) {
427
+ if (collection.type === "doc" && collection.async || collection.type === "docs" && collection.docs.async) {
428
+ shouldEmitOnChange = true;
429
+ }
430
+ }
431
+ },
432
+ configureServer(server) {
433
+ if (!server.watcher) return;
434
+ server.watcher.on("all", async () => {
435
+ if (!shouldEmitOnChange) return;
436
+ await this.core.emitAndWrite({
437
+ filterPlugin: (plugin) => plugin.name === "next"
438
+ });
439
+ });
440
+ },
441
+ async emit() {
442
+ return [
443
+ {
444
+ path: "index.ts",
445
+ content: await indexFile(this.configPath, config, {
446
+ relativeTo: this.outDir
447
+ })
448
+ }
449
+ ];
450
+ }
451
+ };
270
452
  }
271
- async function generateJS(configPath, config, outputPath, configHash) {
272
- const outDir2 = path2.dirname(outputPath);
453
+ async function indexFile(configPath, config, importPath, configHash = false) {
273
454
  let asyncInit = false;
274
455
  const lines = [
275
456
  getImportCode({
276
457
  type: "named",
277
458
  names: ["_runtime"],
278
- specifier: "fumadocs-mdx"
459
+ specifier: "fumadocs-mdx/runtime/next"
279
460
  }),
280
461
  getImportCode({
281
462
  type: "namespace",
282
- specifier: toImportPath(configPath, outDir2),
463
+ specifier: toImportPath(configPath, importPath),
283
464
  name: "_source"
284
465
  })
285
466
  ];
@@ -287,11 +468,15 @@ async function generateJS(configPath, config, outputPath, configHash) {
287
468
  async function getDocEntries(collectionName, files) {
288
469
  const items = files.map(async (file, i) => {
289
470
  const importId = `${collectionName}_${i}`;
471
+ const params = [`collection=${collectionName}`];
472
+ if (configHash) {
473
+ params.push(`hash=${configHash}`);
474
+ }
290
475
  lines.unshift(
291
476
  getImportCode({
292
477
  type: "namespace",
293
478
  name: importId,
294
- specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${collectionName}&hash=${configHash}`
479
+ specifier: `${toImportPath(file.fullPath, importPath)}?${params.join("&")}`
295
480
  })
296
481
  );
297
482
  return `{ info: ${JSON.stringify(file)}, data: ${importId} }`;
@@ -300,17 +485,17 @@ async function generateJS(configPath, config, outputPath, configHash) {
300
485
  }
301
486
  async function getMetaEntries(collection, files) {
302
487
  const items = files.map(async (file) => {
303
- const source = await readFileWithCache(file.absolutePath).catch(() => "");
304
- let data = source.length === 0 ? {} : JSON.parse(source);
488
+ const source = await readFileWithCache(file.fullPath).catch(() => "");
489
+ let data = source.length === 0 ? {} : parseMetaEntry(file.fullPath, source);
305
490
  if (collection?.schema) {
306
491
  data = await validate(
307
492
  collection.schema,
308
493
  data,
309
494
  {
310
495
  source,
311
- path: file.absolutePath
496
+ path: file.fullPath
312
497
  },
313
- `invalid data in ${file.absolutePath}`
498
+ `invalid data in ${file.fullPath}`
314
499
  );
315
500
  }
316
501
  return JSON.stringify({
@@ -328,28 +513,40 @@ async function generateJS(configPath, config, outputPath, configHash) {
328
513
  specifier: "fumadocs-mdx/runtime/async",
329
514
  names: ["_runtimeAsync", "buildConfig"]
330
515
  }),
331
- "const [err, _sourceConfig] = buildConfig(_source)",
332
- "if (!_sourceConfig) throw new Error(err)"
516
+ "const _sourceConfig = buildConfig(_source)",
517
+ getImportCode({
518
+ type: "default",
519
+ name: "path",
520
+ specifier: "node:path"
521
+ })
333
522
  );
334
523
  asyncInit = true;
335
524
  }
336
525
  const entries2 = files.map(async (file) => {
337
- const parsed = (0, import_gray_matter.default)(
338
- await readFileWithCache(file.absolutePath).catch(() => "")
339
- );
526
+ const content = await readFileWithCache(file.fullPath).catch(() => "");
527
+ const parsed = fumaMatter(content);
528
+ let data = parsed.data;
340
529
  if (collection.schema) {
341
- parsed.data = await validate(
530
+ data = await validate(
342
531
  collection.schema,
343
532
  parsed.data,
344
- { path: file.absolutePath, source: parsed.content },
345
- `invalid frontmatter in ${file.absolutePath}`
533
+ { path: file.fullPath, source: parsed.content },
534
+ `invalid frontmatter in ${file.fullPath}`
346
535
  );
347
536
  }
348
- return JSON.stringify({
349
- info: file,
350
- data: parsed.data,
351
- content: parsed.content
352
- });
537
+ let lastModified;
538
+ if (config.global?.lastModifiedTime === "git") {
539
+ lastModified = await getGitTimestamp(file.fullPath);
540
+ }
541
+ const hash = (0, import_node_crypto.createHash)("md5").update(content).digest("hex");
542
+ const infoStr = [];
543
+ for (const [k, v] of Object.entries({ ...file, hash })) {
544
+ infoStr.push(`${k}: ${JSON.stringify(v)}`);
545
+ }
546
+ infoStr.push(
547
+ `absolutePath: path.resolve(${JSON.stringify(file.fullPath)})`
548
+ );
549
+ return `{ info: { ${infoStr.join(", ")} }, lastModified: ${JSON.stringify(lastModified)}, data: ${JSON.stringify(data)} }`;
353
550
  });
354
551
  return Promise.all(entries2);
355
552
  }
@@ -382,148 +579,133 @@ async function generateJS(configPath, config, outputPath, configHash) {
382
579
  ...resolvedDeclares
383
580
  ].join("\n");
384
581
  }
385
- async function getCollectionFiles(collection) {
386
- const files = /* @__PURE__ */ new Map();
387
- const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
388
- await Promise.all(
389
- dirs.map(async (dir) => {
390
- const result = await (0, import_fast_glob.default)(collection.files ?? "**/*", {
391
- cwd: path2.resolve(dir),
392
- absolute: true
393
- });
394
- for (const item of result) {
395
- if (getTypeFromPath(item) !== collection.type) continue;
396
- files.set(item, {
397
- path: path2.relative(dir, item),
398
- absolutePath: item
399
- });
400
- }
401
- })
402
- );
403
- return Array.from(files.values());
404
- }
405
- function getImportCode(info) {
406
- const specifier = JSON.stringify(info.specifier);
407
- if (info.type === "default") return `import ${info.name} from ${specifier}`;
408
- if (info.type === "namespace")
409
- return `import * as ${info.name} from ${specifier}`;
410
- if (info.type === "named") {
411
- const names = info.names.map(
412
- (name) => Array.isArray(name) ? `${name[0]} as ${name[1]}` : name
413
- );
414
- return `import { ${names.join(", ")} } from ${specifier}`;
415
- }
416
- return `import ${specifier}`;
417
- }
418
- function toImportPath(file, dir) {
419
- const ext = path2.extname(file);
420
- let importPath = path2.relative(
421
- dir,
422
- ext === ".ts" ? file.substring(0, file.length - ext.length) : file
423
- );
424
- if (!path2.isAbsolute(importPath) && !importPath.startsWith(".")) {
425
- importPath = `./${importPath}`;
582
+ function parseMetaEntry(file, content) {
583
+ const extname2 = path7.extname(file);
584
+ try {
585
+ if (extname2 === ".json") return JSON.parse(content);
586
+ if (extname2 === ".yaml") return (0, import_js_yaml2.load)(content);
587
+ } catch (e) {
588
+ throw new Error(`Failed to parse meta file: ${file}.`, {
589
+ cause: e
590
+ });
426
591
  }
427
- return importPath.replaceAll(path2.sep, "/");
592
+ throw new Error(`Unknown meta file format: ${extname2}, in ${file}.`);
428
593
  }
429
594
 
430
- // src/map/index.ts
431
- async function start(dev, configPath, outDir2) {
432
- void fs3.rm(path3.resolve(outDir2, `index.js`), { force: true });
433
- void fs3.rm(path3.resolve(outDir2, `index.d.ts`), { force: true });
434
- await fs3.mkdir(outDir2, { recursive: true });
435
- let configHash = await getConfigHash(configPath);
436
- let config = await loadConfig(configPath, configHash, true);
437
- const outPath = path3.resolve(outDir2, `index.ts`);
438
- async function updateMapFile() {
439
- console.time(`[MDX] update map file`);
440
- try {
441
- await fs3.writeFile(
442
- outPath,
443
- await generateJS(configPath, config, outPath, configHash)
444
- );
445
- } catch (err) {
446
- if (err instanceof ValidationError) {
447
- err.print();
448
- } else {
449
- console.error(err);
595
+ // src/core.ts
596
+ var import_node_path6 = __toESM(require("path"), 1);
597
+ var import_promises3 = __toESM(require("fs/promises"), 1);
598
+ function createCore(options, defaultPlugins = []) {
599
+ let config;
600
+ let plugins2;
601
+ return {
602
+ _options: options,
603
+ getPluginContext() {
604
+ return {
605
+ core: this,
606
+ ...options
607
+ };
608
+ },
609
+ /**
610
+ * Convenient cache store, reset when config changes
611
+ */
612
+ cache: /* @__PURE__ */ new Map(),
613
+ async init({ config: newConfig }) {
614
+ config = await newConfig;
615
+ this.cache.clear();
616
+ plugins2 = [];
617
+ for await (const option of [
618
+ ...defaultPlugins,
619
+ ...config.global.plugins ?? []
620
+ ]) {
621
+ if (!option) continue;
622
+ if (Array.isArray(option)) plugins2.push(...option);
623
+ else plugins2.push(option);
450
624
  }
451
- }
452
- console.timeEnd(`[MDX] update map file`);
453
- }
454
- await updateMapFile();
455
- if (dev) {
456
- const { watcher: watcher2 } = await Promise.resolve().then(() => (init_watcher(), watcher_exports));
457
- const instance = watcher2(configPath, config);
458
- instance.on("ready", () => {
459
- console.log("[MDX] started dev server");
460
- });
461
- instance.on("all", (event, file) => {
462
- if (typeof file !== "string") return;
463
- const absolutePath = path3.resolve(file);
464
- const onUpdate = async () => {
465
- const isConfigFile = absolutePath === configPath;
466
- if (isConfigFile) {
467
- configHash = await getConfigHash(configPath);
468
- config = await loadConfig(configPath, configHash, true);
625
+ for (const plugin of plugins2) {
626
+ const out = await plugin.config?.call(this.getPluginContext(), config);
627
+ if (out) config = out;
628
+ }
629
+ return this;
630
+ },
631
+ getConfig() {
632
+ return config;
633
+ },
634
+ creatConfigLoader() {
635
+ return {
636
+ getConfig() {
637
+ return config;
469
638
  }
470
- if (event === "change") fileCache.removeCache(absolutePath);
471
- await updateMapFile();
472
639
  };
473
- void onUpdate();
474
- });
475
- process.on("exit", () => {
476
- console.log("[MDX] closing dev server");
477
- void instance.close();
478
- });
479
- }
640
+ },
641
+ async initServer(server) {
642
+ for (const plugin of plugins2) {
643
+ await plugin.configureServer?.call(this.getPluginContext(), server);
644
+ }
645
+ },
646
+ async emitAndWrite({
647
+ filterPlugin = () => true
648
+ } = {}) {
649
+ const start = performance.now();
650
+ const out = await Promise.all(
651
+ plugins2.map((plugin) => {
652
+ if (!filterPlugin(plugin) || !plugin.emit) return [];
653
+ return plugin.emit.call(this.getPluginContext());
654
+ })
655
+ );
656
+ await Promise.all(
657
+ out.flat().map(async (entry) => {
658
+ const file = import_node_path6.default.join(options.outDir, entry.path);
659
+ await import_promises3.default.mkdir(import_node_path6.default.dirname(file), { recursive: true });
660
+ await import_promises3.default.writeFile(file, entry.content);
661
+ })
662
+ );
663
+ console.log(`[MDX] generated files in ${performance.now() - start}ms`);
664
+ }
665
+ };
480
666
  }
481
667
 
482
- // src/next/create.ts
483
- var outDir = import_node_path2.default.resolve(".source");
668
+ // src/next/index.ts
484
669
  var defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
485
- function createMDX({
486
- configPath = findConfigFile()
487
- } = {}) {
488
- const isDev = process.argv.includes("dev");
489
- const isBuild = process.argv.includes("build");
490
- if ((isDev || isBuild) && process.env._FUMADOCS_MDX !== "1") {
670
+ function createMDX(createOptions = {}) {
671
+ const options = applyDefaults(createOptions);
672
+ const isDev = process.env.NODE_ENV === "development";
673
+ if (process.env._FUMADOCS_MDX !== "1") {
491
674
  process.env._FUMADOCS_MDX = "1";
492
- void start(isDev, configPath, outDir);
675
+ void init(isDev, options);
493
676
  }
494
677
  return (nextConfig = {}) => {
495
678
  const mdxLoaderOptions = {
496
- _ctx: {
497
- configPath
679
+ ...options,
680
+ isDev
681
+ };
682
+ const turbopack = {
683
+ ...nextConfig.turbopack,
684
+ rules: {
685
+ ...nextConfig.turbopack?.rules,
686
+ "*.{md,mdx}": {
687
+ loaders: [
688
+ {
689
+ loader: "fumadocs-mdx/loader-mdx",
690
+ options: mdxLoaderOptions
691
+ }
692
+ ],
693
+ as: "*.js"
694
+ }
498
695
  }
499
696
  };
500
697
  return {
501
698
  ...nextConfig,
502
- turbopack: {
503
- ...nextConfig?.turbopack,
504
- rules: {
505
- ...nextConfig?.turbopack?.rules,
506
- // @ts-expect-error -- safe
507
- "*.{md,mdx}": {
508
- loaders: [
509
- {
510
- loader: "fumadocs-mdx/loader-mdx",
511
- options: mdxLoaderOptions
512
- }
513
- ],
514
- as: "*.js"
515
- }
516
- }
517
- },
699
+ turbopack,
518
700
  pageExtensions: nextConfig.pageExtensions ?? defaultPageExtensions,
519
- webpack: (config, options) => {
701
+ webpack: (config, options2) => {
520
702
  config.resolve ||= {};
521
703
  config.module ||= {};
522
704
  config.module.rules ||= [];
523
705
  config.module.rules.push({
524
706
  test: /\.mdx?$/,
525
707
  use: [
526
- options.defaultLoaders.babel,
708
+ options2.defaultLoaders.babel,
527
709
  {
528
710
  loader: "fumadocs-mdx/loader-mdx",
529
711
  options: mdxLoaderOptions
@@ -531,34 +713,105 @@ function createMDX({
531
713
  ]
532
714
  });
533
715
  config.plugins ||= [];
534
- return nextConfig.webpack?.(config, options) ?? config;
716
+ return nextConfig.webpack?.(config, options2) ?? config;
535
717
  }
536
718
  };
537
719
  };
538
720
  }
539
-
540
- // src/postinstall.ts
541
- var path5 = __toESM(require("path"), 1);
542
- var fs4 = __toESM(require("fs"), 1);
543
- async function postInstall(configPath = findConfigFile()) {
544
- const jsOut = path5.resolve(".source/index.ts");
545
- const hash = await getConfigHash(configPath);
546
- const config = await loadConfig(configPath, hash, true);
547
- fs4.mkdirSync(path5.dirname(jsOut), { recursive: true });
548
- fs4.writeFileSync(
549
- jsOut,
550
- await generateJS(
551
- configPath,
552
- config,
553
- path5.resolve(".source/index.ts"),
554
- hash
555
- )
721
+ async function init(dev, options) {
722
+ const core = createNextCore(options);
723
+ async function initOrReload() {
724
+ await core.init({
725
+ config: loadConfig(options.configPath, options.outDir, true)
726
+ });
727
+ await core.emitAndWrite();
728
+ }
729
+ async function devServer() {
730
+ const { FSWatcher } = await import("chokidar");
731
+ const watcher = new FSWatcher({
732
+ ignoreInitial: true,
733
+ persistent: true,
734
+ ignored: [options.outDir]
735
+ });
736
+ watcher.add(options.configPath);
737
+ for (const collection of core.getConfig().collections.values()) {
738
+ if (collection.type === "docs") {
739
+ watcher.add(collection.docs.dir);
740
+ watcher.add(collection.meta.dir);
741
+ } else {
742
+ watcher.add(collection.dir);
743
+ }
744
+ }
745
+ watcher.on("ready", () => {
746
+ console.log("[MDX] started dev server");
747
+ });
748
+ watcher.on("all", async (event, file) => {
749
+ const absolutePath = path9.resolve(file);
750
+ if (event === "change") removeFileCache(absolutePath);
751
+ if (absolutePath === path9.resolve(options.configPath)) {
752
+ watcher.removeAllListeners();
753
+ await watcher.close();
754
+ await initOrReload();
755
+ console.log("[MDX] restarting dev server");
756
+ await devServer();
757
+ }
758
+ });
759
+ process.on("exit", () => {
760
+ if (watcher.closed) return;
761
+ console.log("[MDX] closing dev server");
762
+ void watcher.close();
763
+ });
764
+ await core.initServer({ watcher });
765
+ }
766
+ await initOrReload();
767
+ if (dev) {
768
+ await devServer();
769
+ }
770
+ }
771
+ async function postInstall(configPath = findConfigFile(), outDir = ".source") {
772
+ const core = await createNextCore({
773
+ outDir,
774
+ configPath
775
+ }).init({
776
+ config: loadConfig(configPath, outDir, true)
777
+ });
778
+ await core.emitAndWrite();
779
+ }
780
+ function applyDefaults(options) {
781
+ return {
782
+ outDir: options.outDir ?? ".source",
783
+ configPath: options.configPath ?? findConfigFile()
784
+ };
785
+ }
786
+ function createNextCore({
787
+ outDir,
788
+ configPath
789
+ }) {
790
+ const core = createCore(
791
+ {
792
+ environment: "next",
793
+ outDir,
794
+ configPath
795
+ },
796
+ [next()]
556
797
  );
557
- console.log("[MDX] types generated");
798
+ return {
799
+ ...core,
800
+ async emitAndWrite(...args) {
801
+ try {
802
+ await core.emitAndWrite(...args);
803
+ } catch (err) {
804
+ if (err instanceof ValidationError) {
805
+ console.error(err.toStringFormatted());
806
+ } else {
807
+ console.error(err);
808
+ }
809
+ }
810
+ }
811
+ };
558
812
  }
559
813
  // Annotate the CommonJS export names for ESM import in node:
560
814
  0 && (module.exports = {
561
815
  createMDX,
562
- postInstall,
563
- start
816
+ postInstall
564
817
  });