fumadocs-core 16.5.2 → 16.5.3

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,5 +1,5 @@
1
1
  import { BlockContent, Text } from "mdast";
2
- import { MdxJsxAttribute, MdxJsxFlowElement } from "mdast-util-mdx-jsx";
2
+ import { MdxJsxAttribute, MdxJsxFlowElement } from "mdast-util-mdx";
3
3
 
4
4
  //#region src/mdx-plugins/codeblock-utils.d.ts
5
5
  interface CodeBlockTabsOptions {
@@ -3,7 +3,7 @@ import { r as transformerIcon, t as CodeBlockIcon } from "../transformer-icon-D7
3
3
  import { transformerTab } from "./rehype-code.core.js";
4
4
  import { RehypeCodeOptions, rehypeCode, rehypeCodeDefaultOptions } from "./rehype-code.js";
5
5
  import { RemarkImageOptions, remarkImage } from "./remark-image.js";
6
- import { StructureOptions, StructuredData, remarkStructure, remarkStructureDefaultOptions, structure } from "./remark-structure.js";
6
+ import { StructureOptions, StructuredData, defaultStringify, remarkStructure, remarkStructureDefaultOptions, structure } from "./remark-structure.js";
7
7
  import { RemarkHeadingOptions, remarkHeading } from "./remark-heading.js";
8
8
  import { RemarkAdmonitionOptions, remarkAdmonition } from "./remark-admonition.js";
9
9
  import { RemarkDirectiveAdmonitionOptions, remarkDirectiveAdmonition } from "./remark-directive-admonition.js";
@@ -15,4 +15,4 @@ import { CodeBlockAttributes, CodeBlockTabsOptions, generateCodeBlockTabs, parse
15
15
  import { RemarkMdxFilesOptions, remarkMdxFiles } from "./remark-mdx-files.js";
16
16
  import { RemarkMdxMermaidOptions, remarkMdxMermaid } from "./remark-mdx-mermaid.js";
17
17
  import { FeedbackBlockProps, RemarkFeedbackBlockOptions, remarkFeedbackBlock } from "./remark-feedback-block.js";
18
- export { CodeBlockAttributes, CodeBlockIcon, CodeBlockTabsOptions, FeedbackBlockProps, RehypeCodeOptions, RehypeTocOptions, RemarkAdmonitionOptions, RemarkCodeTabOptions, RemarkDirectiveAdmonitionOptions, RemarkFeedbackBlockOptions, RemarkGfmOptions, RemarkHeadingOptions, RemarkImageOptions, type RemarkMdxFilesOptions, RemarkMdxMermaidOptions, RemarkNpmOptions, RemarkStepsOptions, StructureOptions, StructuredData, generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkDirectiveAdmonition, remarkFeedbackBlock, remarkGfm, remarkHeading, remarkImage, remarkMdxFiles, remarkMdxMermaid, remarkNpm, remarkSteps, remarkStructure, remarkStructureDefaultOptions, structure, transformerIcon, transformerTab };
18
+ export { CodeBlockAttributes, CodeBlockIcon, CodeBlockTabsOptions, FeedbackBlockProps, RehypeCodeOptions, RehypeTocOptions, RemarkAdmonitionOptions, RemarkCodeTabOptions, RemarkDirectiveAdmonitionOptions, RemarkFeedbackBlockOptions, RemarkGfmOptions, RemarkHeadingOptions, RemarkImageOptions, type RemarkMdxFilesOptions, RemarkMdxMermaidOptions, RemarkNpmOptions, RemarkStepsOptions, StructureOptions, StructuredData, defaultStringify, generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkDirectiveAdmonition, remarkFeedbackBlock, remarkGfm, remarkHeading, remarkImage, remarkMdxFiles, remarkMdxMermaid, remarkNpm, remarkSteps, remarkStructure, remarkStructureDefaultOptions, structure, transformerIcon, transformerTab };
@@ -6,7 +6,7 @@ import { t as transformerIcon } from "../transformer-icon-BYedaeE8.js";
6
6
  import { transformerTab } from "./rehype-code.core.js";
7
7
  import { rehypeCode, rehypeCodeDefaultOptions } from "./rehype-code.js";
8
8
  import { remarkImage } from "./remark-image.js";
9
- import { remarkStructure, remarkStructureDefaultOptions, structure } from "./remark-structure.js";
9
+ import { defaultStringify, remarkStructure, remarkStructureDefaultOptions, structure } from "./remark-structure.js";
10
10
  import { remarkAdmonition } from "./remark-admonition.js";
11
11
  import { remarkDirectiveAdmonition } from "./remark-directive-admonition.js";
12
12
  import { rehypeToc } from "./rehype-toc.js";
@@ -17,4 +17,4 @@ import { remarkMdxFiles } from "./remark-mdx-files.js";
17
17
  import { remarkMdxMermaid } from "./remark-mdx-mermaid.js";
18
18
  import { remarkFeedbackBlock } from "./remark-feedback-block.js";
19
19
 
20
- export { generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkDirectiveAdmonition, remarkFeedbackBlock, remarkGfm, remarkHeading, remarkImage, remarkMdxFiles, remarkMdxMermaid, remarkNpm, remarkSteps, remarkStructure, remarkStructureDefaultOptions, structure, transformerIcon, transformerTab };
20
+ export { defaultStringify, generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkDirectiveAdmonition, remarkFeedbackBlock, remarkGfm, remarkHeading, remarkImage, remarkMdxFiles, remarkMdxMermaid, remarkNpm, remarkSteps, remarkStructure, remarkStructureDefaultOptions, structure, transformerIcon, transformerTab };
@@ -1,6 +1,6 @@
1
1
  import { Processor, Transformer } from "unified";
2
2
  import { Code, Root } from "mdast";
3
- import { MdxJsxFlowElement } from "mdast-util-mdx-jsx";
3
+ import { MdxJsxFlowElement } from "mdast-util-mdx";
4
4
 
5
5
  //#region src/mdx-plugins/remark-code-tab.d.ts
6
6
  type TabType = keyof typeof Types;
@@ -1,6 +1,6 @@
1
1
  import { Transformer } from "unified";
2
2
  import { Root } from "mdast";
3
- import { MdxJsxFlowElement } from "mdast-util-mdx-jsx";
3
+ import { MdxJsxFlowElement } from "mdast-util-mdx";
4
4
 
5
5
  //#region src/mdx-plugins/remark-mdx-files.d.ts
6
6
  interface FileNode {
@@ -1,6 +1,7 @@
1
- import { PluggableList, Transformer } from "unified";
1
+ import { Options } from "mdast-util-to-markdown";
2
+ import { PluggableList, Processor, Transformer } from "unified";
2
3
  import { Nodes, Root } from "mdast";
3
- import { MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxFlowElement } from "mdast-util-mdx-jsx";
4
+ import { MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxFlowElement, MdxJsxTextElement } from "mdast-util-mdx";
4
5
 
5
6
  //#region src/mdx-plugins/remark-structure.d.ts
6
7
  interface Heading$1 {
@@ -20,27 +21,33 @@ interface StructuredData {
20
21
  }
21
22
  interface StructureOptions {
22
23
  /**
23
- * Types to be scanned as content.
24
+ * MDAST **block** types to be scanned as content.
25
+ *
26
+ * If a node's type is represented in this array, it will be stringified and its children will not be scanned separatedly.
24
27
  *
25
28
  * @defaultValue ['heading', 'paragraph', 'blockquote', 'tableCell', 'mdxJsxFlowElement']
26
29
  */
27
30
  types?: string[] | ((node: Nodes) => boolean);
28
31
  /**
29
- * A list of indexable MDX attributes, either:
32
+ * stringify a given node & its children, you can use something like `mdast-util-to-markdown`.
33
+ */
34
+ stringify?: (this: Processor, node: Nodes) => string;
35
+ /**
36
+ * By default, it will not index MDX attributes. You can define a list of MDX attributes to index, either:
30
37
  *
31
38
  * - an array of attribute names.
32
39
  * - a function that determines if attribute should be indexed.
33
40
  */
34
- allowedMdxAttributes?: string[] | ((node: MdxJsxFlowElement, attribute: MdxJsxAttribute | MdxJsxExpressionAttribute) => boolean);
41
+ allowedMdxAttributes?: string[] | ((node: MdxJsxFlowElement | MdxJsxTextElement, attribute: MdxJsxAttribute | MdxJsxExpressionAttribute) => boolean);
35
42
  /**
36
- * export as `structuredData` or specified variable name.
43
+ * export as `structuredData` (if true) or specified variable name.
37
44
  */
38
45
  exportAs?: string | boolean;
39
46
  }
40
47
  declare module 'mdast' {
41
48
  interface Data {
42
49
  /**
43
- * [Fumadocs] Get content of unserializable element, `remarkStructure` uses it to generate search index.
50
+ * [Fumadocs] Stringified form of node, `remarkStructure` uses it to generate search index.
44
51
  */
45
52
  _string?: string[];
46
53
  }
@@ -55,7 +62,7 @@ declare module 'vfile' {
55
62
  }
56
63
  declare const remarkStructureDefaultOptions: {
57
64
  types: string[];
58
- allowedMdxAttributes: (node: MdxJsxFlowElement) => boolean;
65
+ allowedMdxAttributes(node: MdxJsxFlowElement | MdxJsxTextElement): boolean;
59
66
  exportAs: false;
60
67
  };
61
68
  /**
@@ -63,8 +70,9 @@ declare const remarkStructureDefaultOptions: {
63
70
  *
64
71
  * By default, the output is stored into VFile (`vfile.data.structuredData`), you can specify `exportAs` to export it.
65
72
  */
66
- declare function remarkStructure({
73
+ declare function remarkStructure(this: Processor, {
67
74
  types,
75
+ stringify,
68
76
  allowedMdxAttributes,
69
77
  exportAs
70
78
  }?: StructureOptions): Transformer<Root, Root>;
@@ -72,5 +80,8 @@ declare function remarkStructure({
72
80
  * Extract data from markdown/mdx content
73
81
  */
74
82
  declare function structure(content: string, remarkPlugins?: PluggableList, options?: StructureOptions): StructuredData;
83
+ declare function defaultStringify(config?: Options & {
84
+ filterMdxAttributes?: (node: MdxJsxFlowElement | MdxJsxTextElement, attribute: MdxJsxAttribute | MdxJsxExpressionAttribute) => boolean;
85
+ }): (this: Processor, node: Nodes) => string;
75
86
  //#endregion
76
- export { StructureOptions, StructuredData, remarkStructure, remarkStructureDefaultOptions, structure };
87
+ export { StructureOptions, StructuredData, defaultStringify, remarkStructure, remarkStructureDefaultOptions, structure };
@@ -1,8 +1,9 @@
1
1
  import { n as toMdxExport, t as flattenNode } from "../mdast-utils-gJMY143g.js";
2
+ import { remarkHeading } from "./remark-heading.js";
2
3
  import { remark } from "remark";
3
4
  import remarkGfm from "remark-gfm";
4
- import Slugger from "github-slugger";
5
5
  import { visit } from "unist-util-visit";
6
+ import { toMarkdown } from "mdast-util-to-markdown";
6
7
 
7
8
  //#region src/mdx-plugins/remark-structure.ts
8
9
  const remarkStructureDefaultOptions = {
@@ -13,9 +14,12 @@ const remarkStructureDefaultOptions = {
13
14
  "tableCell",
14
15
  "mdxJsxFlowElement"
15
16
  ],
16
- allowedMdxAttributes: (node) => {
17
- if (!node.name) return false;
18
- return ["TypeTable", "Callout"].includes(node.name);
17
+ allowedMdxAttributes(node) {
18
+ switch (node.name) {
19
+ case "TypeTable":
20
+ case "Callout": return true;
21
+ default: return false;
22
+ }
19
23
  },
20
24
  exportAs: false
21
25
  };
@@ -24,8 +28,7 @@ const remarkStructureDefaultOptions = {
24
28
  *
25
29
  * By default, the output is stored into VFile (`vfile.data.structuredData`), you can specify `exportAs` to export it.
26
30
  */
27
- function remarkStructure({ types = remarkStructureDefaultOptions.types, allowedMdxAttributes = remarkStructureDefaultOptions.allowedMdxAttributes, exportAs = remarkStructureDefaultOptions.exportAs } = {}) {
28
- const slugger = new Slugger();
31
+ function remarkStructure({ types = remarkStructureDefaultOptions.types, stringify, allowedMdxAttributes = remarkStructureDefaultOptions.allowedMdxAttributes, exportAs = remarkStructureDefaultOptions.exportAs } = {}) {
29
32
  if (Array.isArray(allowedMdxAttributes)) {
30
33
  const arr = allowedMdxAttributes;
31
34
  allowedMdxAttributes = (_node, attribute) => attribute.type === "mdxJsxAttribute" && arr.includes(attribute.name);
@@ -34,8 +37,8 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, allowedM
34
37
  const arr = types;
35
38
  types = (node) => arr.includes(node.type);
36
39
  }
40
+ stringify ??= defaultStringify({ filterMdxAttributes: allowedMdxAttributes });
37
41
  return (tree, file) => {
38
- slugger.reset();
39
42
  const data = {
40
43
  contents: [],
41
44
  headings: []
@@ -53,12 +56,14 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, allowedM
53
56
  if (element.type === "heading") {
54
57
  element.data ||= {};
55
58
  element.data.hProperties ||= {};
56
- const properties = element.data.hProperties;
57
- const content = flattenNode(element).trim();
58
- const id = properties.id ?? slugger.slug(content);
59
+ const id = element.data.hProperties.id;
60
+ if (typeof id !== "string") {
61
+ console.warn("[remark-structure] hProperties.id is missing in heading node, it is required to generate heading data. You can add remark-heading prior to remark-structure to generate heading IDs.");
62
+ return "skip";
63
+ }
59
64
  data.headings.push({
60
65
  id,
61
- content
66
+ content: flattenNode(element).trim()
62
67
  });
63
68
  lastHeading = id;
64
69
  return "skip";
@@ -70,21 +75,8 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, allowedM
70
75
  });
71
76
  return "skip";
72
77
  }
73
- if (element.type === "mdxJsxFlowElement" && element.name) {
74
- data.contents.push(...element.attributes.flatMap((attribute) => {
75
- const value = typeof attribute.value === "string" ? attribute.value : attribute.value?.value;
76
- if (!value || value.length === 0) return [];
77
- if (allowedMdxAttributes && !allowedMdxAttributes(element, attribute)) return [];
78
- return {
79
- heading: lastHeading,
80
- content: attribute.type === "mdxJsxAttribute" ? `${attribute.name}: ${value}` : value
81
- };
82
- }));
83
- return;
84
- }
85
- const content = flattenNode(element).trim();
86
- if (content.length === 0) return;
87
- data.contents.push({
78
+ const content = stringify.call(this, element).trim();
79
+ if (content.length > 0) data.contents.push({
88
80
  heading: lastHeading,
89
81
  content
90
82
  });
@@ -98,8 +90,47 @@ function remarkStructure({ types = remarkStructureDefaultOptions.types, allowedM
98
90
  * Extract data from markdown/mdx content
99
91
  */
100
92
  function structure(content, remarkPlugins = [], options = {}) {
101
- return remark().use(remarkGfm).use(remarkPlugins).use(remarkStructure, options).processSync(content).data.structuredData;
93
+ return remark().use(remarkGfm).use(remarkPlugins).use(remarkHeading).use(remarkStructure, options).processSync(content).data.structuredData;
94
+ }
95
+ function defaultStringify(config = {}) {
96
+ const { filterMdxAttributes } = config;
97
+ function modHandler(handler) {
98
+ return function(node, ...rest) {
99
+ if (node.data?._string) return node.data._string.join("\n");
100
+ switch (node.type) {
101
+ case "mdxJsxFlowElement":
102
+ case "mdxJsxTextElement": if (filterMdxAttributes) {
103
+ const temp = node.attributes;
104
+ node.attributes = node.attributes.filter((attr) => filterMdxAttributes(node, attr));
105
+ const s = handler(node, ...rest);
106
+ node.attributes = temp;
107
+ return s;
108
+ }
109
+ default: return handler(node, ...rest);
110
+ }
111
+ };
112
+ }
113
+ const handlers = {
114
+ ...config.handlers,
115
+ _custom(node, _, state, info) {
116
+ const handlers = state.handlers;
117
+ for (const k in handlers) handlers[k] = modHandler(handlers[k]);
118
+ return state.handle(node.root, void 0, state, info);
119
+ }
120
+ };
121
+ return function(root) {
122
+ const defaultExtensions = this.data("toMarkdownExtensions") ?? [];
123
+ return toMarkdown({
124
+ type: "_custom",
125
+ root
126
+ }, {
127
+ ...this.data("settings"),
128
+ ...config,
129
+ extensions: config.extensions ? [...defaultExtensions, ...config.extensions] : defaultExtensions,
130
+ handlers
131
+ });
132
+ };
102
133
  }
103
134
 
104
135
  //#endregion
105
- export { remarkStructure, remarkStructureDefaultOptions, structure };
136
+ export { defaultStringify, remarkStructure, remarkStructureDefaultOptions, structure };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.5.2",
3
+ "version": "16.5.3",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",
@@ -125,6 +125,8 @@
125
125
  "hast-util-to-estree": "^3.1.3",
126
126
  "hast-util-to-jsx-runtime": "^2.3.6",
127
127
  "image-size": "^2.0.2",
128
+ "mdast-util-mdx": "^3.0.0",
129
+ "mdast-util-to-markdown": "^2.1.2",
128
130
  "negotiator": "^1.0.0",
129
131
  "npm-to-yarn": "^3.0.1",
130
132
  "path-to-regexp": "^8.3.0",
@@ -153,8 +155,6 @@
153
155
  "@types/react-dom": "^19.2.3",
154
156
  "algoliasearch": "5.48.0",
155
157
  "lucide-react": "^0.563.0",
156
- "mdast-util-mdx-jsx": "^3.2.0",
157
- "mdast-util-mdxjs-esm": "^2.0.1",
158
158
  "next": "16.1.6",
159
159
  "react-router": "^7.13.0",
160
160
  "remark-directive": "^4.0.0",
@@ -179,7 +179,6 @@
179
179
  "@types/react": "*",
180
180
  "algoliasearch": "5.x.x",
181
181
  "lucide-react": "*",
182
- "mdast-util-mdx-jsx": "*",
183
182
  "next": "16.x.x",
184
183
  "react": "^19.2.0",
185
184
  "react-dom": "^19.2.0",
@@ -188,9 +187,6 @@
188
187
  "zod": "4.x.x"
189
188
  },
190
189
  "peerDependenciesMeta": {
191
- "mdast-util-mdx-jsx": {
192
- "optional": true
193
- },
194
190
  "@mdx-js/mdx": {
195
191
  "optional": true
196
192
  },