fumadocs-mdx 11.3.1 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,11 @@
1
- import {
2
- remarkInclude
3
- } from "./chunk-PY2KKTR2.js";
4
1
  import {
5
2
  getConfigHash,
6
3
  loadConfigCached
7
- } from "./chunk-2ZPSMAUV.js";
4
+ } from "./chunk-IU4D6M3A.js";
5
+ import {
6
+ remarkInclude
7
+ } from "./chunk-PY2KKTR2.js";
8
+ import "./chunk-2DJQ3DOD.js";
8
9
 
9
10
  // src/loader-mdx.ts
10
11
  import * as path2 from "node:path";
@@ -52,11 +53,11 @@ function buildMDX(group, configHash, source, options = {}) {
52
53
 
53
54
  // src/utils/format-error.ts
54
55
  function formatError(message, error) {
55
- const lines = [];
56
+ const lines2 = [];
56
57
  function walk(key, { _errors, ...rest }, padStart = 0) {
57
58
  if (key !== void 0 || _errors.length > 0) {
58
59
  const text = key ? `${key}: ${_errors.join("\n ")}` : _errors.join("\n");
59
- lines.push(
60
+ lines2.push(
60
61
  text.split("\n").map((line) => `${" ".repeat(padStart)}${line}`).join("\n")
61
62
  );
62
63
  }
@@ -65,7 +66,7 @@ function formatError(message, error) {
65
66
  }
66
67
  }
67
68
  walk(void 0, error.format());
68
- return [message, ...lines].join("\n");
69
+ return [message, ...lines2].join("\n");
69
70
  }
70
71
 
71
72
  // src/utils/git-timestamp.ts
@@ -122,7 +123,6 @@ async function loader(source, callback) {
122
123
  collection = void 0;
123
124
  }
124
125
  const mdxOptions = collection?.mdxOptions ?? await config.getDefaultMDXOptions();
125
- let frontmatter = matter.data;
126
126
  if (collection?.schema) {
127
127
  let schema = collection.schema;
128
128
  if (typeof schema === "function") {
@@ -140,7 +140,7 @@ async function loader(source, callback) {
140
140
  path: filePath
141
141
  });
142
142
  }
143
- const result = await schema.safeParseAsync(frontmatter);
143
+ const result = await schema.safeParseAsync(matter.data);
144
144
  if (result.error) {
145
145
  callback(
146
146
  new Error(
@@ -149,21 +149,24 @@ async function loader(source, callback) {
149
149
  );
150
150
  return;
151
151
  }
152
- frontmatter = result.data;
152
+ matter.data = result.data;
153
153
  }
154
154
  let timestamp;
155
155
  if (config.global?.lastModifiedTime === "git")
156
156
  timestamp = (await getGitTimestamp(filePath))?.getTime();
157
157
  try {
158
+ const lineOffset = "\n".repeat(
159
+ this.mode === "development" ? lines(source) - lines(matter.content) : 0
160
+ );
158
161
  const file = await buildMDX(
159
162
  collectionId ?? "global",
160
163
  configHash,
161
- matter.content,
164
+ lineOffset + matter.content,
162
165
  {
163
166
  development: this.mode === "development",
164
167
  ...mdxOptions,
165
168
  filePath,
166
- frontmatter,
169
+ frontmatter: matter.data,
167
170
  data: {
168
171
  lastModified: timestamp
169
172
  },
@@ -178,6 +181,13 @@ async function loader(source, callback) {
178
181
  callback(error);
179
182
  }
180
183
  }
184
+ function lines(s) {
185
+ let num = 0;
186
+ for (const c of s) {
187
+ if (c === "\n") num++;
188
+ }
189
+ return num;
190
+ }
181
191
  export {
182
192
  loader as default
183
193
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDefaultMDXOptions
3
- } from "./chunk-6LEQ23AC.js";
3
+ } from "./chunk-IOENRFUX.js";
4
4
  export {
5
5
  getDefaultMDXOptions
6
6
  };
@@ -100,6 +100,7 @@ function getDefaultMDXOptions({
100
100
  remarkImageOptions,
101
101
  remarkHeadingOptions,
102
102
  remarkStructureOptions,
103
+ remarkCodeTabOptions,
103
104
  ...mdxOptions
104
105
  }) {
105
106
  const mdxExports = [
@@ -110,18 +111,20 @@ function getDefaultMDXOptions({
110
111
  ];
111
112
  const remarkPlugins = pluginOption(
112
113
  (v) => [
113
- import_mdx_plugins.remarkGfm,
114
+ plugins.remarkGfm,
114
115
  [
115
- import_mdx_plugins.remarkHeading,
116
+ plugins.remarkHeading,
116
117
  {
117
118
  generateToc: false,
118
119
  ...remarkHeadingOptions
119
120
  }
120
121
  ],
121
- remarkImageOptions !== false && [import_mdx_plugins.remarkImage, remarkImageOptions],
122
+ remarkImageOptions !== false && [plugins.remarkImage, remarkImageOptions],
123
+ // Fumadocs 14 compatibility
124
+ "remarkCodeTab" in plugins && remarkCodeTabOptions !== false && plugins.remarkCodeTab,
122
125
  ...v,
123
126
  remarkStructureOptions !== false && [
124
- import_mdx_plugins.remarkStructure,
127
+ plugins.remarkStructure,
125
128
  remarkStructureOptions
126
129
  ],
127
130
  [remarkMdxExport, { values: mdxExports }]
@@ -130,9 +133,9 @@ function getDefaultMDXOptions({
130
133
  );
131
134
  const rehypePlugins = pluginOption(
132
135
  (v) => [
133
- rehypeCodeOptions !== false && [import_mdx_plugins.rehypeCode, rehypeCodeOptions],
136
+ rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
134
137
  ...v,
135
- [import_mdx_plugins.rehypeToc]
138
+ [plugins.rehypeToc]
136
139
  ],
137
140
  mdxOptions.rehypePlugins
138
141
  );
@@ -142,11 +145,11 @@ function getDefaultMDXOptions({
142
145
  rehypePlugins
143
146
  };
144
147
  }
145
- var import_mdx_plugins;
148
+ var plugins;
146
149
  var init_mdx_options = __esm({
147
150
  "src/utils/mdx-options.ts"() {
148
151
  "use strict";
149
- import_mdx_plugins = require("fumadocs-core/mdx-plugins");
152
+ plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
150
153
  init_remark_exports();
151
154
  }
152
155
  });
@@ -187,40 +190,11 @@ module.exports = __toCommonJS(next_exports);
187
190
  // src/next/create.ts
188
191
  var import_node_path2 = __toESM(require("path"), 1);
189
192
 
190
- // src/config/load.ts
193
+ // src/utils/load-config.ts
191
194
  var path = __toESM(require("path"), 1);
192
195
  var import_node_url = require("url");
193
- function findConfigFile() {
194
- return path.resolve("source.config.ts");
195
- }
196
- async function loadConfig(configPath) {
197
- const { build } = await import("esbuild");
198
- const url = (0, import_node_url.pathToFileURL)(path.resolve(".source/source.config.mjs"));
199
- const transformed = await build({
200
- entryPoints: [{ in: configPath, out: "source.config" }],
201
- bundle: true,
202
- outdir: ".source",
203
- target: "node18",
204
- write: true,
205
- platform: "node",
206
- format: "esm",
207
- packages: "external",
208
- outExtension: {
209
- ".js": ".mjs"
210
- },
211
- allowOverwrite: true
212
- });
213
- if (transformed.errors.length > 0) {
214
- throw new Error("failed to compile configuration file");
215
- }
216
- const loaded = await import(`${url.href}?hash=${Date.now().toString()}`);
217
- const [err, config] = buildConfig(
218
- // every call to `loadConfig` will cause the previous cache to be ignored
219
- loaded
220
- );
221
- if (err !== null) throw new Error(err);
222
- return config;
223
- }
196
+
197
+ // src/config/build.ts
224
198
  function buildConfig(config) {
225
199
  const collections = /* @__PURE__ */ new Map();
226
200
  let globalConfig;
@@ -268,13 +242,46 @@ function buildConfig(config) {
268
242
  ];
269
243
  }
270
244
 
245
+ // src/utils/load-config.ts
246
+ function findConfigFile() {
247
+ return path.resolve("source.config.ts");
248
+ }
249
+ async function loadConfig(configPath) {
250
+ const { build } = await import("esbuild");
251
+ const url = (0, import_node_url.pathToFileURL)(path.resolve(".source/source.config.mjs"));
252
+ const transformed = await build({
253
+ entryPoints: [{ in: configPath, out: "source.config" }],
254
+ bundle: true,
255
+ outdir: ".source",
256
+ target: "node18",
257
+ write: true,
258
+ platform: "node",
259
+ format: "esm",
260
+ packages: "external",
261
+ outExtension: {
262
+ ".js": ".mjs"
263
+ },
264
+ allowOverwrite: true
265
+ });
266
+ if (transformed.errors.length > 0) {
267
+ throw new Error("failed to compile configuration file");
268
+ }
269
+ const loaded = await import(`${url.href}?hash=${Date.now().toString()}`);
270
+ const [err, config] = buildConfig(
271
+ // every call to `loadConfig` will cause the previous cache to be ignored
272
+ loaded
273
+ );
274
+ if (err !== null) throw new Error(err);
275
+ return config;
276
+ }
277
+
271
278
  // src/map/index.ts
272
279
  var path3 = __toESM(require("path"), 1);
273
280
  var fs2 = __toESM(require("fs"), 1);
274
281
  var import_promises = require("fs/promises");
275
282
  var import_gray_matter = __toESM(require("gray-matter"), 1);
276
283
 
277
- // src/config/cached.ts
284
+ // src/utils/config-cache.ts
278
285
  var import_node_crypto = require("crypto");
279
286
  var fs = __toESM(require("fs"), 1);
280
287
  var cache = /* @__PURE__ */ new Map();
@@ -316,48 +323,62 @@ async function generateJS(configPath, config, outputPath, configHash, getFrontma
316
323
  const imports = [
317
324
  {
318
325
  type: "named",
319
- names: ["toRuntime", "toRuntimeAsync"],
326
+ names: ["toRuntime"],
320
327
  specifier: "fumadocs-mdx"
321
328
  }
322
329
  ];
323
- const importedCollections = /* @__PURE__ */ new Set();
324
- async function generateEntry(file, collectionName, collection, importId) {
325
- if (collection.type === "doc" && collection.async) {
326
- const importPath = `${toImportPath(file.absolutePath, outDir2)}?hash=${configHash}&collection=${collectionName}`;
327
- const frontmatter = await getFrontmatter(file.absolutePath);
328
- return `toRuntimeAsync(${JSON.stringify(frontmatter)}, () => import(${JSON.stringify(importPath)}), ${JSON.stringify(file)})`;
329
- }
330
- imports.push({
331
- type: "namespace",
332
- name: importId,
333
- specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${collectionName}&hash=${configHash}`
334
- });
335
- return `toRuntime("${collection.type}", ${importId}, ${JSON.stringify(file)})`;
336
- }
330
+ let asyncInit = false;
331
+ const lines = [];
337
332
  config._runtime.files.clear();
338
333
  const entries = Array.from(config.collections.entries());
339
334
  const declares = entries.map(async ([k, collection]) => {
340
335
  const files = await getCollectionFiles(collection);
336
+ if (collection.type === "doc" && collection.async) {
337
+ if (!asyncInit) {
338
+ imports.push(
339
+ {
340
+ type: "namespace",
341
+ specifier: toImportPath(configPath, outDir2),
342
+ name: "_source"
343
+ },
344
+ {
345
+ type: "named",
346
+ specifier: "fumadocs-mdx/runtime/async",
347
+ names: ["asyncFiles", "buildConfig"]
348
+ }
349
+ );
350
+ lines.unshift(
351
+ "const [err, _sourceConfig] = buildConfig(_source)",
352
+ "if (err) throw new Error(err)"
353
+ );
354
+ asyncInit = true;
355
+ }
356
+ const entries2 = files.map(async (file) => {
357
+ const frontmatter = await getFrontmatter(file.absolutePath);
358
+ return JSON.stringify({
359
+ frontmatter,
360
+ file
361
+ });
362
+ });
363
+ return `export const ${k} = asyncFiles([${(await Promise.all(entries2)).join(", ")}], "${k}", _sourceConfig)`;
364
+ }
341
365
  const items = files.map(async (file, i) => {
342
366
  config._runtime.files.set(file.absolutePath, k);
343
- return generateEntry(file, k, collection, `${k}_${i}`);
367
+ const importId = `${k}_${i}`;
368
+ imports.push({
369
+ type: "namespace",
370
+ name: importId,
371
+ specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${k}&hash=${configHash}`
372
+ });
373
+ return `toRuntime("${collection.type}", ${importId}, ${JSON.stringify(file)})`;
344
374
  });
345
375
  const resolvedItems = await Promise.all(items);
346
- if (collection.transform) {
347
- if (config.global) importedCollections.add("default");
348
- importedCollections.add(k);
349
- }
350
- return collection.transform ? `export const ${k} = await Promise.all([${resolvedItems.join(", ")}].map(v => c_${k}.transform(v, ${config.global ? "c_default" : "undefined"})));` : `export const ${k} = [${resolvedItems.join(", ")}];`;
376
+ return `export const ${k} = [${resolvedItems.join(", ")}];`;
351
377
  });
352
378
  const resolvedDeclares = await Promise.all(declares);
353
- if (importedCollections.size > 0) {
354
- imports.push({
355
- type: "named",
356
- names: Array.from(importedCollections.values()).sort().map((v) => [v, `c_${v}`]),
357
- specifier: toImportPath(configPath, outDir2)
358
- });
359
- }
360
- return [...imports.map(getImportCode), ...resolvedDeclares].join("\n");
379
+ return [...imports.map(getImportCode), ...lines, ...resolvedDeclares].join(
380
+ "\n"
381
+ );
361
382
  }
362
383
  async function getCollectionFiles(collection) {
363
384
  const files = /* @__PURE__ */ new Map();
@@ -422,14 +443,41 @@ async function start(dev, configPath, outDir2) {
422
443
  const typeOut = path3.resolve(outDir2, `index.d.ts`);
423
444
  const frontmatterCache = /* @__PURE__ */ new Map();
424
445
  let hookUpdate = false;
425
- const readFrontmatter = async (file) => {
446
+ async function readFrontmatter(file) {
447
+ hookUpdate = true;
426
448
  const cached = frontmatterCache.get(file);
427
449
  if (cached) return cached;
428
- hookUpdate = true;
429
- return (0, import_gray_matter.default)({
430
- content: await (0, import_promises.readFile)(file).then((res) => res.toString())
431
- }).data;
432
- };
450
+ const readStream = fs2.createReadStream(file, {
451
+ highWaterMark: 250
452
+ });
453
+ return new Promise((res, rej) => {
454
+ let idx = 0;
455
+ let str = "";
456
+ readStream.on("data", (_chunk) => {
457
+ const chunk = _chunk.toString();
458
+ if (idx === 0 && !chunk.startsWith("---")) {
459
+ res({});
460
+ readStream.close();
461
+ return;
462
+ }
463
+ str += chunk;
464
+ idx++;
465
+ if (str.includes("\n---")) {
466
+ res(
467
+ (0, import_gray_matter.default)({
468
+ content: str
469
+ }).data
470
+ );
471
+ readStream.close();
472
+ }
473
+ });
474
+ readStream.on("end", () => res({}));
475
+ readStream.on("error", (e) => rej(e));
476
+ }).then((res) => {
477
+ frontmatterCache.set(file, res);
478
+ return res;
479
+ });
480
+ }
433
481
  fs2.mkdirSync(outDir2, { recursive: true });
434
482
  fs2.writeFileSync(
435
483
  jsOut,
@@ -3,7 +3,8 @@ import {
3
3
  getConfigHash,
4
4
  loadConfig,
5
5
  loadConfigCached
6
- } from "../chunk-2ZPSMAUV.js";
6
+ } from "../chunk-IU4D6M3A.js";
7
+ import "../chunk-2DJQ3DOD.js";
7
8
 
8
9
  // src/next/create.ts
9
10
  import path3 from "node:path";
@@ -11,7 +12,7 @@ import path3 from "node:path";
11
12
  // src/map/index.ts
12
13
  import * as path2 from "node:path";
13
14
  import * as fs from "node:fs";
14
- import { readFile, writeFile } from "node:fs/promises";
15
+ import { writeFile } from "node:fs/promises";
15
16
  import grayMatter from "gray-matter";
16
17
 
17
18
  // src/map/generate.ts
@@ -34,48 +35,62 @@ async function generateJS(configPath, config, outputPath, configHash, getFrontma
34
35
  const imports = [
35
36
  {
36
37
  type: "named",
37
- names: ["toRuntime", "toRuntimeAsync"],
38
+ names: ["toRuntime"],
38
39
  specifier: "fumadocs-mdx"
39
40
  }
40
41
  ];
41
- const importedCollections = /* @__PURE__ */ new Set();
42
- async function generateEntry(file, collectionName, collection, importId) {
43
- if (collection.type === "doc" && collection.async) {
44
- const importPath = `${toImportPath(file.absolutePath, outDir2)}?hash=${configHash}&collection=${collectionName}`;
45
- const frontmatter = await getFrontmatter(file.absolutePath);
46
- return `toRuntimeAsync(${JSON.stringify(frontmatter)}, () => import(${JSON.stringify(importPath)}), ${JSON.stringify(file)})`;
47
- }
48
- imports.push({
49
- type: "namespace",
50
- name: importId,
51
- specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${collectionName}&hash=${configHash}`
52
- });
53
- return `toRuntime("${collection.type}", ${importId}, ${JSON.stringify(file)})`;
54
- }
42
+ let asyncInit = false;
43
+ const lines = [];
55
44
  config._runtime.files.clear();
56
45
  const entries = Array.from(config.collections.entries());
57
46
  const declares = entries.map(async ([k, collection]) => {
58
47
  const files = await getCollectionFiles(collection);
48
+ if (collection.type === "doc" && collection.async) {
49
+ if (!asyncInit) {
50
+ imports.push(
51
+ {
52
+ type: "namespace",
53
+ specifier: toImportPath(configPath, outDir2),
54
+ name: "_source"
55
+ },
56
+ {
57
+ type: "named",
58
+ specifier: "fumadocs-mdx/runtime/async",
59
+ names: ["asyncFiles", "buildConfig"]
60
+ }
61
+ );
62
+ lines.unshift(
63
+ "const [err, _sourceConfig] = buildConfig(_source)",
64
+ "if (err) throw new Error(err)"
65
+ );
66
+ asyncInit = true;
67
+ }
68
+ const entries2 = files.map(async (file) => {
69
+ const frontmatter = await getFrontmatter(file.absolutePath);
70
+ return JSON.stringify({
71
+ frontmatter,
72
+ file
73
+ });
74
+ });
75
+ return `export const ${k} = asyncFiles([${(await Promise.all(entries2)).join(", ")}], "${k}", _sourceConfig)`;
76
+ }
59
77
  const items = files.map(async (file, i) => {
60
78
  config._runtime.files.set(file.absolutePath, k);
61
- return generateEntry(file, k, collection, `${k}_${i}`);
79
+ const importId = `${k}_${i}`;
80
+ imports.push({
81
+ type: "namespace",
82
+ name: importId,
83
+ specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${k}&hash=${configHash}`
84
+ });
85
+ return `toRuntime("${collection.type}", ${importId}, ${JSON.stringify(file)})`;
62
86
  });
63
87
  const resolvedItems = await Promise.all(items);
64
- if (collection.transform) {
65
- if (config.global) importedCollections.add("default");
66
- importedCollections.add(k);
67
- }
68
- return collection.transform ? `export const ${k} = await Promise.all([${resolvedItems.join(", ")}].map(v => c_${k}.transform(v, ${config.global ? "c_default" : "undefined"})));` : `export const ${k} = [${resolvedItems.join(", ")}];`;
88
+ return `export const ${k} = [${resolvedItems.join(", ")}];`;
69
89
  });
70
90
  const resolvedDeclares = await Promise.all(declares);
71
- if (importedCollections.size > 0) {
72
- imports.push({
73
- type: "named",
74
- names: Array.from(importedCollections.values()).sort().map((v) => [v, `c_${v}`]),
75
- specifier: toImportPath(configPath, outDir2)
76
- });
77
- }
78
- return [...imports.map(getImportCode), ...resolvedDeclares].join("\n");
91
+ return [...imports.map(getImportCode), ...lines, ...resolvedDeclares].join(
92
+ "\n"
93
+ );
79
94
  }
80
95
  async function getCollectionFiles(collection) {
81
96
  const files = /* @__PURE__ */ new Map();
@@ -140,14 +155,41 @@ async function start(dev, configPath, outDir2) {
140
155
  const typeOut = path2.resolve(outDir2, `index.d.ts`);
141
156
  const frontmatterCache = /* @__PURE__ */ new Map();
142
157
  let hookUpdate = false;
143
- const readFrontmatter = async (file) => {
158
+ async function readFrontmatter(file) {
159
+ hookUpdate = true;
144
160
  const cached = frontmatterCache.get(file);
145
161
  if (cached) return cached;
146
- hookUpdate = true;
147
- return grayMatter({
148
- content: await readFile(file).then((res) => res.toString())
149
- }).data;
150
- };
162
+ const readStream = fs.createReadStream(file, {
163
+ highWaterMark: 250
164
+ });
165
+ return new Promise((res, rej) => {
166
+ let idx = 0;
167
+ let str = "";
168
+ readStream.on("data", (_chunk) => {
169
+ const chunk = _chunk.toString();
170
+ if (idx === 0 && !chunk.startsWith("---")) {
171
+ res({});
172
+ readStream.close();
173
+ return;
174
+ }
175
+ str += chunk;
176
+ idx++;
177
+ if (str.includes("\n---")) {
178
+ res(
179
+ grayMatter({
180
+ content: str
181
+ }).data
182
+ );
183
+ readStream.close();
184
+ }
185
+ });
186
+ readStream.on("end", () => res({}));
187
+ readStream.on("error", (e) => rej(e));
188
+ }).then((res) => {
189
+ frontmatterCache.set(file, res);
190
+ return res;
191
+ });
192
+ }
151
193
  fs.mkdirSync(outDir2, { recursive: true });
152
194
  fs.writeFileSync(
153
195
  jsOut,