Skip to content

Commit ec85a6c

Browse files
committed
Core: support more options on remarkStructure
1 parent d7e261c commit ec85a6c

File tree

2 files changed

+51
-13
lines changed

2 files changed

+51
-13
lines changed

.changeset/orange-phones-sink.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'fumadocs-core': patch
3+
---
4+
5+
support more options on `remarkStructure`

packages/core/src/mdx-plugins/remark-structure.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import Slugger from 'github-slugger';
2-
import type { Root } from 'mdast';
2+
import type { Root, Nodes } from 'mdast';
33
import { remark } from 'remark';
44
import remarkGfm from 'remark-gfm';
55
import type { PluggableList, Transformer } from 'unified';
66
import { visit } from 'unist-util-visit';
77
import { flattenNode } from './remark-utils';
8+
import type {
9+
MdxJsxAttribute,
10+
MdxJsxExpressionAttribute,
11+
} from 'mdast-util-mdx-jsx';
812

913
interface Heading {
1014
id: string;
@@ -28,9 +32,16 @@ export interface StructureOptions {
2832
/**
2933
* Types to be scanned as content.
3034
*
31-
* @defaultValue ['paragraph', 'blockquote', 'tableCell']
35+
* @defaultValue ['heading', 'paragraph', 'blockquote', 'tableCell', 'mdxJsxFlowElement']
3236
*/
33-
types?: string[];
37+
types?: string[] | ((node: Nodes) => boolean);
38+
39+
allowedMdxAttributes?:
40+
| string[]
41+
| ((
42+
node: Nodes,
43+
attribute: MdxJsxAttribute | MdxJsxExpressionAttribute,
44+
) => boolean);
3445
}
3546

3647
declare module 'mdast' {
@@ -50,8 +61,26 @@ const slugger = new Slugger();
5061
* Attach structured data to VFile, you can access via `vfile.data.structuredData`.
5162
*/
5263
export function remarkStructure({
53-
types = ['paragraph', 'blockquote', 'heading', 'tableCell'],
64+
types = [
65+
'heading',
66+
'paragraph',
67+
'blockquote',
68+
'tableCell',
69+
'mdxJsxFlowElement',
70+
],
71+
allowedMdxAttributes = () => true,
5472
}: StructureOptions = {}): Transformer<Root, Root> {
73+
if (Array.isArray(allowedMdxAttributes)) {
74+
const arr = allowedMdxAttributes;
75+
allowedMdxAttributes = (_node, attribute) =>
76+
attribute.type === 'mdxJsxAttribute' && arr.includes(attribute.name);
77+
}
78+
79+
if (Array.isArray(types)) {
80+
const arr = types;
81+
types = (node) => arr.includes(node.type);
82+
}
83+
5584
return (node, file) => {
5685
slugger.reset();
5786
const data: StructuredData = { contents: [], headings: [] };
@@ -73,6 +102,7 @@ export function remarkStructure({
73102

74103
visit(node, (element) => {
75104
if (element.type === 'root') return;
105+
if (!types(element)) return;
76106

77107
if (element.type === 'heading') {
78108
element.data ||= {};
@@ -113,6 +143,11 @@ export function remarkStructure({
113143
? attribute.value
114144
: attribute.value?.value;
115145
if (!valueStr) return [];
146+
if (
147+
allowedMdxAttributes &&
148+
!allowedMdxAttributes(element, attribute)
149+
)
150+
return [];
116151

117152
return {
118153
heading: lastHeading,
@@ -127,17 +162,15 @@ export function remarkStructure({
127162
return;
128163
}
129164

130-
if (types.includes(element.type)) {
131-
const content = flattenNode(element).trim();
132-
if (content.length === 0) return;
165+
const content = flattenNode(element).trim();
166+
if (content.length === 0) return;
133167

134-
data.contents.push({
135-
heading: lastHeading,
136-
content,
137-
});
168+
data.contents.push({
169+
heading: lastHeading,
170+
content,
171+
});
138172

139-
return 'skip';
140-
}
173+
return 'skip';
141174
});
142175

143176
file.data.structuredData = data;

0 commit comments

Comments
 (0)