11import Slugger from 'github-slugger' ;
2- import type { Root } from 'mdast' ;
2+ import type { Root , Nodes } from 'mdast' ;
33import { remark } from 'remark' ;
44import remarkGfm from 'remark-gfm' ;
55import type { PluggableList , Transformer } from 'unified' ;
66import { visit } from 'unist-util-visit' ;
77import { flattenNode } from './remark-utils' ;
8+ import type {
9+ MdxJsxAttribute ,
10+ MdxJsxExpressionAttribute ,
11+ } from 'mdast-util-mdx-jsx' ;
812
913interface 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
3647declare module 'mdast' {
@@ -50,8 +61,26 @@ const slugger = new Slugger();
5061 * Attach structured data to VFile, you can access via `vfile.data.structuredData`.
5162 */
5263export 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