@@ -32,7 +32,6 @@ type globalVarsType struct {
3232 comparePattern * regexp.Regexp
3333 fullURLPattern * regexp.Regexp
3434 emailRegex * regexp.Regexp
35- blackfridayExtRegex * regexp.Regexp
3635 emojiShortCodeRegex * regexp.Regexp
3736 issueFullPattern * regexp.Regexp
3837 filesChangedFullPattern * regexp.Regexp
@@ -74,9 +73,6 @@ var globalVars = sync.OnceValue(func() *globalVarsType {
7473 // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
7574 v .emailRegex = regexp .MustCompile ("(?:\\ s|^|\\ (|\\ [)([a-zA-Z0-9.!#$%&'*+\\ /=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\ .[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\ s|$|\\ )|\\ ]|;|,|\\ ?|!|\\ .(\\ s|$))" )
7675
77- // blackfridayExtRegex is for blackfriday extensions create IDs like fn:user-content-footnote
78- v .blackfridayExtRegex = regexp .MustCompile (`[^:]*:user-content-` )
79-
8076 // emojiShortCodeRegex find emoji by alias like :smile:
8177 v .emojiShortCodeRegex = regexp .MustCompile (`:[-+\w]+:` )
8278
@@ -94,17 +90,12 @@ var globalVars = sync.OnceValue(func() *globalVarsType {
9490 return v
9591})
9692
97- // IsFullURLBytes reports whether link fits valid format.
98- func IsFullURLBytes (link []byte ) bool {
99- return globalVars ().fullURLPattern .Match (link )
100- }
101-
10293func IsFullURLString (link string ) bool {
10394 return globalVars ().fullURLPattern .MatchString (link )
10495}
10596
10697func IsNonEmptyRelativePath (link string ) bool {
107- return link != "" && ! IsFullURLString (link ) && link [0 ] != '/' && link [ 0 ] != ' ?' && link [0 ] != '#'
98+ return link != "" && ! IsFullURLString (link ) && link [0 ] != '?' && link [0 ] != '#'
10899}
109100
110101// CustomLinkURLSchemes allows for additional schemes to be detected when parsing links within text
@@ -316,44 +307,38 @@ func isEmojiNode(node *html.Node) bool {
316307}
317308
318309func visitNode (ctx * RenderContext , procs []processor , node * html.Node ) * html.Node {
319- // Add user-content- to IDs and "#" links if they don't already have them
320- for idx , attr := range node .Attr {
321- val := strings .TrimPrefix (attr .Val , "#" )
322- notHasPrefix := ! (strings .HasPrefix (val , "user-content-" ) || globalVars ().blackfridayExtRegex .MatchString (val ))
323-
324- if attr .Key == "id" && notHasPrefix {
325- node .Attr [idx ].Val = "user-content-" + attr .Val
326- }
327-
328- if attr .Key == "href" && strings .HasPrefix (attr .Val , "#" ) && notHasPrefix {
329- node .Attr [idx ].Val = "#user-content-" + val
330- }
331- }
332-
333- switch node .Type {
334- case html .TextNode :
310+ if node .Type == html .TextNode {
335311 for _ , proc := range procs {
336312 proc (ctx , node ) // it might add siblings
337313 }
314+ return node .NextSibling
315+ }
316+ if node .Type != html .ElementNode {
317+ return node .NextSibling
318+ }
338319
339- case html .ElementNode :
340- if isEmojiNode (node ) {
341- // TextNode emoji will be converted to `<span class="emoji">`, then the next iteration will visit the "span"
342- // if we don't stop it, it will go into the TextNode again and create an infinite recursion
343- return node .NextSibling
344- } else if node .Data == "code" || node .Data == "pre" {
345- return node .NextSibling // ignore code and pre nodes
346- } else if node .Data == "img" {
347- return visitNodeImg (ctx , node )
348- } else if node .Data == "video" {
349- return visitNodeVideo (ctx , node )
350- } else if node .Data == "a" {
351- procs = emojiProcessors // Restrict text in links to emojis
352- }
353- for n := node .FirstChild ; n != nil ; {
354- n = visitNode (ctx , procs , n )
355- }
356- default :
320+ processNodeAttrID (node )
321+
322+ if isEmojiNode (node ) {
323+ // TextNode emoji will be converted to `<span class="emoji">`, then the next iteration will visit the "span"
324+ // if we don't stop it, it will go into the TextNode again and create an infinite recursion
325+ return node .NextSibling
326+ } else if node .Data == "code" || node .Data == "pre" {
327+ return node .NextSibling // ignore code and pre nodes
328+ } else if node .Data == "img" {
329+ return visitNodeImg (ctx , node )
330+ } else if node .Data == "video" {
331+ return visitNodeVideo (ctx , node )
332+ }
333+
334+ if node .Data == "a" {
335+ processNodeA (ctx , node )
336+ // only use emoji processors for the content in the "A" tag,
337+ // because the content there is not processable, for example: the content is a commit id or a full URL.
338+ procs = emojiProcessors
339+ }
340+ for n := node .FirstChild ; n != nil ; {
341+ n = visitNode (ctx , procs , n )
357342 }
358343 return node .NextSibling
359344}
0 commit comments