1
1
import slugify from './slugify'
2
2
3
+ // Helper function to transform emoji tokens
3
4
function unemoji ( TokenConstructor , token ) {
4
5
if ( token . type === 'emoji' ) {
5
6
return Object . assign ( new TokenConstructor ( ) , token , { content : token . markup } )
@@ -13,13 +14,11 @@ export default function extendHeading(
13
14
toc = false ,
14
15
tocStart = 1 ,
15
16
tocEnd = 3 ,
16
- noHeadingAnchorLinks = false ,
17
+ noHeadingAnchorLinks = false
17
18
) {
18
19
let Token
19
20
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.
23
22
if ( ! Token ) {
24
23
Token = state . Token
25
24
}
@@ -28,13 +27,16 @@ export default function extendHeading(
28
27
md . renderer . rules . heading_open = ( tokens , idx , options , env , self ) => {
29
28
const token = tokens [ idx ]
30
29
31
- // get the token number
30
+ // Get the numeric heading level (e.g., 1 for h1, 2 for h2, etc.)
32
31
const tokenNumber = parseInt ( token . tag [ 1 ] )
33
32
33
+ // Get the children tokens (which represent the inline content)
34
34
const children = tokens [ idx + 1 ] . children
35
35
36
+ // Build a plain text label by concatenating all child token content.
36
37
const label = children . reduce ( ( acc , t ) => acc + t . content , '' )
37
38
39
+ // Build the CSS classes for the heading
38
40
const classes = [ ]
39
41
classes . push ( 'q-markdown--heading' )
40
42
classes . push ( `q-markdown--heading-${ token . tag } ` )
@@ -45,6 +47,7 @@ export default function extendHeading(
45
47
classes . push ( 'q-markdown--title-light' )
46
48
}
47
49
50
+ // If heading anchor links are enabled, add the specific class.
48
51
if (
49
52
noHeadingAnchorLinks !== true &&
50
53
tocStart &&
@@ -56,19 +59,23 @@ export default function extendHeading(
56
59
classes . push ( 'q-markdown--heading--anchor-link' )
57
60
}
58
61
62
+ // Transform emoji tokens and render the inline content.
59
63
const unemojiWithToken = unemoji . bind ( null , Token )
60
64
const renderedLabel = md . renderer . renderInline ( children . map ( unemojiWithToken ) , options , env )
61
65
66
+ // Create a slug from the rendered label for the heading id.
62
67
const id = slugify (
63
68
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.
66
71
)
67
72
73
+ // Set attributes for the heading token.
68
74
token . attrSet ( 'id' , id )
69
75
token . attrSet ( 'name' , id )
70
76
token . attrSet ( 'class' , classes . join ( ' ' ) )
71
77
78
+ // If a table of contents is enabled, add this heading to the TOC data.
72
79
if ( toc ) {
73
80
if (
74
81
tocStart &&
@@ -81,34 +88,28 @@ export default function extendHeading(
81
88
}
82
89
}
83
90
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.
84
93
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.
86
95
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', '')
98
96
linkOpen . attrSet ( 'href' , '#' + id )
99
97
linkOpen . attrSet ( 'aria-hidden' , 'true' )
100
98
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 ( )
103
104
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 ]
108
107
108
+ // Render the modified token.
109
109
return md . renderer . renderToken ( tokens , idx , options , env , self )
110
110
}
111
111
112
+ // Render the token as usual if no modifications were made.
112
113
return self . renderToken ( tokens , idx , options )
113
114
}
114
115
}
0 commit comments