11import slugify from './slugify'
22
3+ // Helper function to transform emoji tokens
34function unemoji ( TokenConstructor , token ) {
45 if ( token . type === 'emoji' ) {
56 return Object . assign ( new TokenConstructor ( ) , token , { content : token . markup } )
@@ -13,13 +14,11 @@ export default function extendHeading(
1314 toc = false ,
1415 tocStart = 1 ,
1516 tocEnd = 3 ,
16- noHeadingAnchorLinks = false ,
17+ noHeadingAnchorLinks = false
1718) {
1819 let Token
1920 md . core . ruler . push ( 'headingLinks' , function ( state ) {
20- // save the Token constructor because we'll be building a few instances at render
21- // time; that's sort of outside the intended markdown-it parsing sequence, but
22- // since we have tight control over what we're creating (a link), we're safe
21+ // Save the Token constructor for later use when building new token instances.
2322 if ( ! Token ) {
2423 Token = state . Token
2524 }
@@ -28,13 +27,16 @@ export default function extendHeading(
2827 md . renderer . rules . heading_open = ( tokens , idx , options , env , self ) => {
2928 const token = tokens [ idx ]
3029
31- // get the token number
30+ // Get the numeric heading level (e.g., 1 for h1, 2 for h2, etc.)
3231 const tokenNumber = parseInt ( token . tag [ 1 ] )
3332
33+ // Get the children tokens (which represent the inline content)
3434 const children = tokens [ idx + 1 ] . children
3535
36+ // Build a plain text label by concatenating all child token content.
3637 const label = children . reduce ( ( acc , t ) => acc + t . content , '' )
3738
39+ // Build the CSS classes for the heading
3840 const classes = [ ]
3941 classes . push ( 'q-markdown--heading' )
4042 classes . push ( `q-markdown--heading-${ token . tag } ` )
@@ -45,6 +47,7 @@ export default function extendHeading(
4547 classes . push ( 'q-markdown--title-light' )
4648 }
4749
50+ // If heading anchor links are enabled, add the specific class.
4851 if (
4952 noHeadingAnchorLinks !== true &&
5053 tocStart &&
@@ -56,19 +59,23 @@ export default function extendHeading(
5659 classes . push ( 'q-markdown--heading--anchor-link' )
5760 }
5861
62+ // Transform emoji tokens and render the inline content.
5963 const unemojiWithToken = unemoji . bind ( null , Token )
6064 const renderedLabel = md . renderer . renderInline ( children . map ( unemojiWithToken ) , options , env )
6165
66+ // Create a slug from the rendered label for the heading id.
6267 const id = slugify (
6368 renderedLabel
64- . replace ( / [ < > ] / g, '' ) // In case the heading contains `<stuff>`
65- . toLowerCase ( ) , // should be lowercase
69+ . replace ( / [ < > ] / g, '' ) // Remove any '<' or '>' characters.
70+ . toLowerCase ( ) // Convert to lowercase.
6671 )
6772
73+ // Set attributes for the heading token.
6874 token . attrSet ( 'id' , id )
6975 token . attrSet ( 'name' , id )
7076 token . attrSet ( 'class' , classes . join ( ' ' ) )
7177
78+ // If a table of contents is enabled, add this heading to the TOC data.
7279 if ( toc ) {
7380 if (
7481 tocStart &&
@@ -81,34 +88,28 @@ export default function extendHeading(
8188 }
8289 }
8390
91+ // If anchor links are enabled and the heading level is within the TOC range,
92+ // wrap the inline children with anchor link tokens to preserve formatting.
8493 if ( noHeadingAnchorLinks !== true && tokenNumber <= tocEnd ) {
85- // add 3 new token objects link_open, text, link_close
94+ // Create the opening link token with the necessary attributes.
8695 const linkOpen = new Token ( 'link_open' , 'a' , 1 )
87- const text = new Token ( 'html_inline' , '' , 0 )
88- if ( options . enableHeadingLinkIcons ) {
89- text . content = options . linkIcon
90- }
91- text . content = label
92-
93- const linkClose = new Token ( 'link_close' , 'a' , - 1 )
94-
95- // add some link attributes
96- // linkOpen.attrSet('id', id)
97- // linkOpen.attrSet('class', '')
9896 linkOpen . attrSet ( 'href' , '#' + id )
9997 linkOpen . attrSet ( 'aria-hidden' , 'true' )
10098
101- // remove previous children
102- while ( children . length > 0 ) children . pop ( )
99+ // Create the closing link token.
100+ const linkClose = new Token ( 'link_close' , 'a' , - 1 )
101+
102+ // Preserve the original inline tokens (to keep formatting like **bold**).
103+ const originalChildren = children . slice ( )
103104
104- // add new token objects as children of heading
105- children . unshift ( linkClose )
106- children . unshift ( text )
107- children . unshift ( linkOpen )
105+ // Replace children with the new tokens wrapping the original content.
106+ tokens [ idx + 1 ] . children = [ linkOpen , ...originalChildren , linkClose ]
108107
108+ // Render the modified token.
109109 return md . renderer . renderToken ( tokens , idx , options , env , self )
110110 }
111111
112+ // Render the token as usual if no modifications were made.
112113 return self . renderToken ( tokens , idx , options )
113114 }
114115}
0 commit comments