@@ -10,6 +10,7 @@ export interface ContentParseOptions {
10
10
markdown ?: boolean
11
11
replaceUnicodeEmoji ?: boolean
12
12
astTransforms ?: Transform [ ]
13
+ convertMentionLink ?: boolean
13
14
}
14
15
15
16
const sanitizerBasicClasses = filterClasses ( / ^ ( h - \S * | p - \S * | u - \S * | d t - \S * | e - \S * | m e n t i o n | h a s h t a g | e l l i p s i s | i n v i s i b l e ) $ / u)
@@ -53,6 +54,7 @@ export function parseMastodonHTML(
53
54
const {
54
55
markdown = true ,
55
56
replaceUnicodeEmoji = true ,
57
+ convertMentionLink = false ,
56
58
} = options
57
59
58
60
if ( markdown ) {
@@ -77,6 +79,9 @@ export function parseMastodonHTML(
77
79
if ( markdown )
78
80
transforms . push ( transformMarkdown )
79
81
82
+ if ( convertMentionLink )
83
+ transforms . push ( transformMentionLink )
84
+
80
85
transforms . push ( replaceCustomEmoji ( options . emojis || { } ) )
81
86
82
87
transforms . push ( transformParagraphs )
@@ -92,6 +97,7 @@ export function convertMastodonHTML(html: string, customEmojis: Record<string, m
92
97
emojis : customEmojis ,
93
98
markdown : true ,
94
99
replaceUnicodeEmoji : false ,
100
+ convertMentionLink : true ,
95
101
} )
96
102
return render ( tree )
97
103
}
@@ -360,3 +366,19 @@ function transformParagraphs(node: Node): Node | Node[] {
360
366
return [ node , h ( 'p' ) ]
361
367
return node
362
368
}
369
+
370
+ function transformMentionLink ( node : Node ) : string | Node | ( string | Node ) [ ] | null {
371
+ if ( node . name === 'a' && node . attributes . class ?. includes ( 'mention' ) ) {
372
+ const href = node . attributes . href
373
+ if ( href ) {
374
+ const matchUser = href . match ( UserLinkRE )
375
+ if ( matchUser ) {
376
+ const [ , server , username ] = matchUser
377
+ const handle = `${ username } @${ server . replace ( / ( .+ \. ) ( .+ \. .+ ) / , '$2' ) } `
378
+ // convert to TipTap mention node
379
+ return h ( 'span' , { 'data-type' : 'mention' , 'data-id' : handle } , handle )
380
+ }
381
+ }
382
+ }
383
+ return node
384
+ }
0 commit comments