fumadocs-mdx 11.8.0 → 11.8.2

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.
@@ -30,15 +30,40 @@ 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/mdx-plugins/remark-exports.ts
34
- function remarkMdxExport({ values }) {
35
- return (tree, vfile) => {
36
- for (const name of values) {
37
- if (!(name in vfile.data)) return;
38
- tree.children.unshift(getMdastExport(name, vfile.data[name]));
33
+ // src/mdx-plugins/remark-postprocess.ts
34
+ function remarkPostprocess({
35
+ injectExports
36
+ }) {
37
+ return (tree, file) => {
38
+ let title;
39
+ const urls = [];
40
+ (0, import_unist_util_visit.visit)(tree, ["heading", "link"], (node) => {
41
+ if (node.type === "heading" && node.depth === 1) {
42
+ title = flattenNode(node);
43
+ }
44
+ if (node.type !== "link") return;
45
+ urls.push({
46
+ href: node.url
47
+ });
48
+ return "skip";
49
+ });
50
+ if (title) {
51
+ file.data.frontmatter ??= {};
52
+ if (!file.data.frontmatter.title) file.data.frontmatter.title = title;
53
+ }
54
+ file.data.extractedReferences = urls;
55
+ for (const name of injectExports) {
56
+ if (!(name in file.data)) continue;
57
+ tree.children.unshift(getMdastExport(name, file.data[name]));
39
58
  }
40
59
  };
41
60
  }
61
+ function flattenNode(node) {
62
+ if ("children" in node)
63
+ return node.children.map((child) => flattenNode(child)).join("");
64
+ if ("value" in node) return node.value;
65
+ return "";
66
+ }
42
67
  function getMdastExport(name, value) {
43
68
  return {
44
69
  type: "mdxjsEsm",
@@ -50,6 +75,7 @@ function getMdastExport(name, value) {
50
75
  body: [
51
76
  {
52
77
  type: "ExportNamedDeclaration",
78
+ attributes: [],
53
79
  specifiers: [],
54
80
  source: null,
55
81
  declaration: {
@@ -72,10 +98,11 @@ function getMdastExport(name, value) {
72
98
  }
73
99
  };
74
100
  }
75
- var import_estree_util_value_to_estree;
76
- var init_remark_exports = __esm({
77
- "src/mdx-plugins/remark-exports.ts"() {
101
+ var import_unist_util_visit, import_estree_util_value_to_estree;
102
+ var init_remark_postprocess = __esm({
103
+ "src/mdx-plugins/remark-postprocess.ts"() {
78
104
  "use strict";
105
+ import_unist_util_visit = require("unist-util-visit");
79
106
  import_estree_util_value_to_estree = require("estree-util-value-to-estree");
80
107
  }
81
108
  });
@@ -107,6 +134,7 @@ function getDefaultMDXOptions({
107
134
  }) {
108
135
  const mdxExports = [
109
136
  "structuredData",
137
+ "extractedReferences",
110
138
  "frontmatter",
111
139
  "lastModified",
112
140
  ...valueToExport
@@ -138,7 +166,10 @@ function getDefaultMDXOptions({
138
166
  plugins.remarkStructure,
139
167
  remarkStructureOptions
140
168
  ],
141
- [remarkMdxExport, { values: mdxExports }]
169
+ [
170
+ remarkPostprocess,
171
+ { injectExports: mdxExports }
172
+ ]
142
173
  ],
143
174
  mdxOptions.remarkPlugins
144
175
  );
@@ -162,7 +193,7 @@ var init_mdx_options = __esm({
162
193
  "src/utils/mdx-options.ts"() {
163
194
  "use strict";
164
195
  plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
165
- init_remark_exports();
196
+ init_remark_postprocess();
166
197
  }
167
198
  });
168
199
 
@@ -227,7 +258,8 @@ function buildConfig(config) {
227
258
  var import_mdx = require("@mdx-js/mdx");
228
259
 
229
260
  // src/mdx-plugins/remark-include.ts
230
- var import_unist_util_visit = require("unist-util-visit");
261
+ var import_unified = require("unified");
262
+ var import_unist_util_visit2 = require("unist-util-visit");
231
263
  var path = __toESM(require("path"), 1);
232
264
  var fs = __toESM(require("fs/promises"), 1);
233
265
 
@@ -248,9 +280,13 @@ function fumaMatter(input) {
248
280
  }
249
281
 
250
282
  // src/mdx-plugins/remark-include.ts
251
- function flattenNode(node) {
283
+ var import_remark_parse = __toESM(require("remark-parse"), 1);
284
+ var import_remark_mdx = __toESM(require("remark-mdx"), 1);
285
+ var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
286
+ var baseProcessor = (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading);
287
+ function flattenNode2(node) {
252
288
  if ("children" in node)
253
- return node.children.map((child) => flattenNode(child)).join("");
289
+ return node.children.map((child) => flattenNode2(child)).join("");
254
290
  if ("value" in node) return node.value;
255
291
  return "";
256
292
  }
@@ -263,86 +299,96 @@ function parseSpecifier(specifier) {
263
299
  };
264
300
  }
265
301
  function extractSection(root, section) {
302
+ let nodes;
266
303
  for (const node of root.children) {
267
304
  if (node.type === "mdxJsxFlowElement" && node.name === "section" && node.attributes.some(
268
305
  (attr) => attr.type === "mdxJsxAttribute" && attr.name === "id" && attr.value === section
269
306
  )) {
270
- return {
271
- type: "root",
272
- children: node.children
273
- };
307
+ nodes = node.children;
308
+ break;
274
309
  }
310
+ if (node.type === "heading" && node.data?.hProperties?.id === section) {
311
+ nodes = [node];
312
+ continue;
313
+ }
314
+ if (!nodes) continue;
315
+ if (node.type === "heading") break;
316
+ nodes.push(node);
275
317
  }
318
+ if (nodes)
319
+ return {
320
+ type: "root",
321
+ children: nodes
322
+ };
276
323
  }
277
324
  function remarkInclude() {
278
325
  const TagName = "include";
326
+ async function embedContent(file, heading, params, data) {
327
+ let content;
328
+ try {
329
+ content = (await fs.readFile(file)).toString();
330
+ } catch (e) {
331
+ throw new Error(
332
+ `failed to read file ${file}
333
+ ${e instanceof Error ? e.message : String(e)}`,
334
+ { cause: e }
335
+ );
336
+ }
337
+ const ext = path.extname(file);
338
+ data._compiler?.addDependency(file);
339
+ if (params.lang || ext !== ".md" && ext !== ".mdx") {
340
+ const lang = params.lang ?? ext.slice(1);
341
+ return {
342
+ type: "code",
343
+ lang,
344
+ meta: params.meta,
345
+ value: content,
346
+ data: {}
347
+ };
348
+ }
349
+ const processor = (data._getProcessor ?? getDefaultProcessor)(
350
+ ext === ".mdx" ? "mdx" : "md"
351
+ );
352
+ let parsed = await baseProcessor.run(
353
+ processor.parse(fumaMatter(content).content)
354
+ );
355
+ if (heading) {
356
+ const extracted = extractSection(parsed, heading);
357
+ if (!extracted)
358
+ throw new Error(
359
+ `Cannot find section ${heading} in ${file}, make sure you have encapsulated the section in a <section id="${heading}"> tag.`
360
+ );
361
+ parsed = extracted;
362
+ }
363
+ await update(parsed, path.dirname(file), data);
364
+ return parsed;
365
+ }
279
366
  async function update(tree, directory, data) {
280
367
  const queue = [];
281
- (0, import_unist_util_visit.visit)(
368
+ (0, import_unist_util_visit2.visit)(
282
369
  tree,
283
370
  ["mdxJsxFlowElement", "mdxJsxTextElement"],
284
- (node, _, parent) => {
285
- let specifier;
371
+ (_node, _, parent) => {
372
+ const node = _node;
373
+ if (node.name !== TagName) return;
286
374
  const params = {};
287
- if ((node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && node.name === TagName) {
288
- const value = flattenNode(node);
289
- if (value.length > 0) {
290
- for (const attr of node.attributes) {
291
- if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
292
- params[attr.name] = attr.value;
293
- }
294
- }
295
- specifier = value;
375
+ const specifier = flattenNode2(node);
376
+ if (specifier.length === 0) return "skip";
377
+ for (const attr of node.attributes) {
378
+ if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
379
+ params[attr.name] = attr.value;
296
380
  }
297
381
  }
298
- if (!specifier) return;
299
- const { file, section } = parseSpecifier(specifier);
300
- const targetPath = path.resolve(
382
+ const { file: relativePath, section } = parseSpecifier(specifier);
383
+ const file = path.resolve(
301
384
  "cwd" in params ? process.cwd() : directory,
302
- file
385
+ relativePath
303
386
  );
304
- const asCode = params.lang || !file.endsWith(".md") && !file.endsWith(".mdx");
305
387
  queue.push(
306
- fs.readFile(targetPath).then((buffer) => buffer.toString()).then(async (content) => {
307
- data._compiler?.addDependency(targetPath);
308
- if (asCode) {
309
- const lang = params.lang ?? path.extname(file).slice(1);
310
- Object.assign(node, {
311
- type: "code",
312
- lang,
313
- meta: params.meta,
314
- value: content,
315
- data: {}
316
- });
317
- return;
318
- }
319
- const processor = data._processor ? data._processor.getProcessor(
320
- targetPath.endsWith(".md") ? "md" : "mdx"
321
- ) : this;
322
- let parsed = processor.parse(fumaMatter(content).content);
323
- if (section) {
324
- const extracted = extractSection(parsed, section);
325
- if (!extracted)
326
- throw new Error(
327
- `Cannot find section ${section} in ${file}, make sure you have encapsulated the section in a <section id="${section}"> tag`
328
- );
329
- parsed = extracted;
330
- }
331
- await update.call(
332
- processor,
333
- parsed,
334
- path.dirname(targetPath),
335
- data
336
- );
388
+ embedContent(file, section, params, data).then((replace) => {
337
389
  Object.assign(
338
390
  parent && parent.type === "paragraph" ? parent : node,
339
- parsed
340
- );
341
- }).catch((e) => {
342
- throw new Error(
343
- `failed to read file ${targetPath}
344
- ${e instanceof Error ? e.message : String(e)}`,
345
- { cause: e }
391
+ replace
346
392
  );
347
393
  })
348
394
  );
@@ -352,9 +398,14 @@ ${e instanceof Error ? e.message : String(e)}`,
352
398
  await Promise.all(queue);
353
399
  }
354
400
  return async (tree, file) => {
355
- await update.call(this, tree, path.dirname(file.path), file.data);
401
+ await update(tree, path.dirname(file.path), file.data);
356
402
  };
357
403
  }
404
+ function getDefaultProcessor(format) {
405
+ const mdProcessor = (0, import_unified.unified)().use(import_remark_parse.default);
406
+ if (format === "md") return mdProcessor;
407
+ return mdProcessor.use(import_remark_mdx.default);
408
+ }
358
409
 
359
410
  // src/utils/build-mdx.ts
360
411
  var cache = /* @__PURE__ */ new Map();
@@ -383,9 +434,7 @@ async function buildMDX(cacheKey, source, options) {
383
434
  ...data,
384
435
  frontmatter,
385
436
  _compiler,
386
- _processor: {
387
- getProcessor
388
- }
437
+ _getProcessor: getProcessor
389
438
  }
390
439
  });
391
440
  }
@@ -13,11 +13,11 @@ import {
13
13
  } from "../chunk-GX3THK2Q.js";
14
14
  import {
15
15
  buildMDX
16
- } from "../chunk-7JFPDRW7.js";
17
- import "../chunk-IGXZS2W6.js";
16
+ } from "../chunk-QQWCBFFE.js";
17
+ import "../chunk-SVTXMVLQ.js";
18
18
  import {
19
19
  buildConfig
20
- } from "../chunk-XVL4ZQFK.js";
20
+ } from "../chunk-QVZ7JH4H.js";
21
21
  import {
22
22
  fumaMatter
23
23
  } from "../chunk-VWJKRQZR.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-mdx",
3
- "version": "11.8.0",
3
+ "version": "11.8.2",
4
4
  "description": "The built-in source for Fumadocs",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -56,6 +56,7 @@
56
56
  "bin.js"
57
57
  ],
58
58
  "dependencies": {
59
+ "unified": "^11.0.5",
59
60
  "@mdx-js/mdx": "^3.1.0",
60
61
  "@standard-schema/spec": "^1.0.0",
61
62
  "chokidar": "^4.0.3",
@@ -64,28 +65,29 @@
64
65
  "js-yaml": "^4.1.0",
65
66
  "lru-cache": "^11.1.0",
66
67
  "picocolors": "^1.1.1",
68
+ "remark-mdx": "^3.1.0",
69
+ "remark-parse": "^11.0.0",
67
70
  "tinyexec": "^1.0.1",
68
71
  "tinyglobby": "^0.2.14",
69
72
  "unist-util-visit": "^5.0.0",
70
- "zod": "^4.0.17"
73
+ "zod": "^4.1.4"
71
74
  },
72
75
  "devDependencies": {
73
76
  "@types/js-yaml": "^4.0.9",
74
77
  "@types/mdast": "^4.0.3",
75
78
  "@types/mdx": "^2.0.13",
76
79
  "@types/node": "^24.3.0",
77
- "@types/react": "^19.1.10",
80
+ "@types/react": "^19.1.12",
78
81
  "mdast-util-mdx-jsx": "^3.2.0",
79
- "next": "^15.5.0",
82
+ "next": "^15.5.2",
80
83
  "react": "^19.1.1",
81
- "rollup": "^4.46.3",
82
- "unified": "^11.0.5",
84
+ "rollup": "^4.49.0",
83
85
  "vfile": "^6.0.3",
84
86
  "vite": "^7.1.3",
85
87
  "webpack": "^5.101.3",
86
88
  "@fumadocs/mdx-remote": "1.4.0",
87
89
  "eslint-config-custom": "0.0.0",
88
- "fumadocs-core": "15.7.0",
90
+ "fumadocs-core": "15.7.6",
89
91
  "tsconfig": "0.0.0"
90
92
  },
91
93
  "peerDependencies": {
@@ -1,119 +0,0 @@
1
- import {
2
- fumaMatter
3
- } from "./chunk-VWJKRQZR.js";
4
-
5
- // src/mdx-plugins/remark-include.ts
6
- import { visit } from "unist-util-visit";
7
- import * as path from "path";
8
- import * as fs from "fs/promises";
9
- function flattenNode(node) {
10
- if ("children" in node)
11
- return node.children.map((child) => flattenNode(child)).join("");
12
- if ("value" in node) return node.value;
13
- return "";
14
- }
15
- function parseSpecifier(specifier) {
16
- const idx = specifier.lastIndexOf("#");
17
- if (idx === -1) return { file: specifier };
18
- return {
19
- file: specifier.slice(0, idx),
20
- section: specifier.slice(idx + 1)
21
- };
22
- }
23
- function extractSection(root, section) {
24
- for (const node of root.children) {
25
- if (node.type === "mdxJsxFlowElement" && node.name === "section" && node.attributes.some(
26
- (attr) => attr.type === "mdxJsxAttribute" && attr.name === "id" && attr.value === section
27
- )) {
28
- return {
29
- type: "root",
30
- children: node.children
31
- };
32
- }
33
- }
34
- }
35
- function remarkInclude() {
36
- const TagName = "include";
37
- async function update(tree, directory, data) {
38
- const queue = [];
39
- visit(
40
- tree,
41
- ["mdxJsxFlowElement", "mdxJsxTextElement"],
42
- (node, _, parent) => {
43
- let specifier;
44
- const params = {};
45
- if ((node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && node.name === TagName) {
46
- const value = flattenNode(node);
47
- if (value.length > 0) {
48
- for (const attr of node.attributes) {
49
- if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
50
- params[attr.name] = attr.value;
51
- }
52
- }
53
- specifier = value;
54
- }
55
- }
56
- if (!specifier) return;
57
- const { file, section } = parseSpecifier(specifier);
58
- const targetPath = path.resolve(
59
- "cwd" in params ? process.cwd() : directory,
60
- file
61
- );
62
- const asCode = params.lang || !file.endsWith(".md") && !file.endsWith(".mdx");
63
- queue.push(
64
- fs.readFile(targetPath).then((buffer) => buffer.toString()).then(async (content) => {
65
- data._compiler?.addDependency(targetPath);
66
- if (asCode) {
67
- const lang = params.lang ?? path.extname(file).slice(1);
68
- Object.assign(node, {
69
- type: "code",
70
- lang,
71
- meta: params.meta,
72
- value: content,
73
- data: {}
74
- });
75
- return;
76
- }
77
- const processor = data._processor ? data._processor.getProcessor(
78
- targetPath.endsWith(".md") ? "md" : "mdx"
79
- ) : this;
80
- let parsed = processor.parse(fumaMatter(content).content);
81
- if (section) {
82
- const extracted = extractSection(parsed, section);
83
- if (!extracted)
84
- throw new Error(
85
- `Cannot find section ${section} in ${file}, make sure you have encapsulated the section in a <section id="${section}"> tag`
86
- );
87
- parsed = extracted;
88
- }
89
- await update.call(
90
- processor,
91
- parsed,
92
- path.dirname(targetPath),
93
- data
94
- );
95
- Object.assign(
96
- parent && parent.type === "paragraph" ? parent : node,
97
- parsed
98
- );
99
- }).catch((e) => {
100
- throw new Error(
101
- `failed to read file ${targetPath}
102
- ${e instanceof Error ? e.message : String(e)}`,
103
- { cause: e }
104
- );
105
- })
106
- );
107
- return "skip";
108
- }
109
- );
110
- await Promise.all(queue);
111
- }
112
- return async (tree, file) => {
113
- await update.call(this, tree, path.dirname(file.path), file.data);
114
- };
115
- }
116
-
117
- export {
118
- remarkInclude
119
- };