@@ -20,6 +20,56 @@ export interface CompiledPage {
2020 body : FC < { components ?: MDXComponents } > ;
2121}
2222
23+ // Function to clean TOC items and convert them to plain text
24+ function cleanTocItems ( toc : TableOfContents ) : TableOfContents {
25+ return toc . map ( item => ( {
26+ ...item ,
27+ title : cleanTocTitle ( item . title )
28+ } ) ) ;
29+ }
30+
31+ // Function to convert TOC title to plain text
32+ function cleanTocTitle ( title : any ) : string {
33+ if ( typeof title === 'string' ) {
34+ // Remove HTML tags and decode entities
35+ return title
36+ . replace ( / < [ ^ > ] * > / g, '' ) // Remove HTML tags
37+ . replace ( / & l t ; / g, '<' )
38+ . replace ( / & g t ; / g, '>' )
39+ . replace ( / & a m p ; / g, '&' )
40+ . replace ( / & q u o t ; / g, '"' )
41+ . replace ( / & # 3 9 ; / g, "'" )
42+ . trim ( ) ;
43+ }
44+
45+ if ( title && typeof title === 'object' ) {
46+ // Handle React nodes - extract text content
47+ if ( title . props && title . props . children ) {
48+ return cleanTocTitle ( title . props . children ) ;
49+ }
50+
51+ if ( Array . isArray ( title ) ) {
52+ return title . map ( cleanTocTitle ) . filter ( Boolean ) . join ( '' ) ;
53+ }
54+
55+ // If it's a React element with type and props
56+ if ( title . type === 'a' && title . props && title . props . children ) {
57+ return cleanTocTitle ( title . props . children ) ;
58+ }
59+
60+ // Handle other React node types
61+ if ( title . toString && typeof title . toString === 'function' ) {
62+ return cleanTocTitle ( title . toString ( ) ) ;
63+ }
64+ }
65+
66+ if ( Array . isArray ( title ) ) {
67+ return title . map ( cleanTocTitle ) . filter ( Boolean ) . join ( '' ) ;
68+ }
69+
70+ return String ( title || '' ) . trim ( ) ;
71+ }
72+
2373// Create a cached compile function using React cache
2474const cachedCompile = reactCache ( async ( filePath : string , source : string ) : Promise < CompiledPage > => {
2575 // console.time(`compile md: ${filePath}`);
@@ -31,7 +81,7 @@ const cachedCompile = reactCache(async (filePath: string, source: string): Promi
3181 } )
3282 . then ( ( compiled ) => ( {
3383 body : compiled . body ,
34- toc : compiled . toc ,
84+ toc : cleanTocItems ( compiled . toc ) , // Clean TOC items to ensure plain text titles
3585 ...compiled . frontmatter ,
3686 } ) )
3787 . catch ( ( error ) => {
@@ -130,11 +180,51 @@ function parseSourceBeforeCompile(filePath: string, source: string): string {
130180 '<div class="note">$1</div>' ,
131181 ) ;
132182
133- // Replace "style="xx" as mdx format
183+ // Fix type annotations that get interpreted as HTML tags
184+ // Replace array<type> with array<type> to prevent HTML parsing
134185 parsedSource = parsedSource . replace (
135- / s t y l e = " ( [ ^ " ] + ) " / g,
136- ( match , p1 ) => {
137- return `style={{ ${ p1 } }}` ;
186+ / a r r a y < ( [ ^ > ] + ) > / g,
187+ 'array<$1>' ,
188+ ) ;
189+
190+ // Fix standalone type annotations at start of lines or after colons/spaces
191+ // This handles cases like "- `id`: int" -> "- `id`: `int`"
192+ parsedSource = parsedSource . replace (
193+ / ( \s + - ` [ ^ ` ] + ` ) : \s + ( i n t | s t r i n g | b o o l | f l o a t | d o u b l e | o b j e c t | a r r a y ) ( \s | $ ) / g,
194+ '$1: `$2`$3' ,
195+ ) ;
196+
197+ // Fix type annotations in parameter lists
198+ // This handles cases like "- **tags**: array<int> (optional)"
199+ parsedSource = parsedSource . replace (
200+ / ( \* \* [ ^ * ] + \* \* ) : \s + ( a r r a y & l t ; [ ^ & ] + & g t ; | i n t | s t r i n g | b o o l | f l o a t | d o u b l e | o b j e c t | a r r a y ) ( \s ) / g,
201+ '$1: `$2`$3' ,
202+ ) ;
203+
204+ // Replace "style="xx" as mdx format
205+ // Convert CSS style attributes to JSX format
206+ parsedSource = parsedSource . replace (
207+ / s t y l e \s * = \s * " ( [ ^ " ] + ) " / g,
208+ ( match : string , styleValue : string ) : string => {
209+ // Parse CSS properties and convert to JSX object
210+ const styles = styleValue
211+ . split ( ';' )
212+ . filter ( ( prop : string ) => prop . trim ( ) )
213+ . map ( ( prop : string ) => {
214+ const [ property , ...valueParts ] = prop . split ( ':' ) ;
215+ const value = valueParts . join ( ':' ) . trim ( ) ; // Handle values with colons
216+ const trimmedProperty = property . trim ( ) ;
217+
218+ if ( ! trimmedProperty || ! value ) return '' ;
219+
220+ // Convert kebab-case to camelCase
221+ const camelProperty = trimmedProperty . replace ( / - ( [ a - z ] ) / g, ( _ , letter : string ) => letter . toUpperCase ( ) ) ;
222+ return `${ camelProperty } : "${ value } "` ;
223+ } )
224+ . filter ( ( prop : string ) => prop )
225+ . join ( ', ' ) ;
226+
227+ return `style={{ ${ styles } }}` ;
138228 }
139229 ) ;
140230
@@ -144,9 +234,10 @@ function parseSourceBeforeCompile(filePath: string, source: string): string {
144234 '\\{\\{$1\\}\\}' ,
145235 ) ;
146236
237+
147238 return parsedSource ;
148239}
149240
150241export async function compile ( filePath : string , source : string ) {
151242 return cachedCompile ( filePath , source ) ;
152- }
243+ }
0 commit comments