@@ -4,9 +4,45 @@ import { sendMessage } from './api.js'
44import { guessMediaType , uploadFile } from './media.js'
55import { MessageItemType , MessageState , MessageType } from './types.js'
66
7+ function stripCodeBlocks ( text : string ) : string {
8+ // Non-regex approach to avoid ReDoS on inputs with many ``` sequences.
9+ let result = ''
10+ let i = 0
11+ while ( i < text . length ) {
12+ if ( text . startsWith ( '```' , i ) ) {
13+ // Skip the opening fence (including optional language tag on same line)
14+ let j = i + 3
15+ // skip to end of first line (the fence line itself)
16+ while ( j < text . length && text [ j ] !== '\n' ) j ++
17+ if ( j < text . length ) j ++ // skip the \n
18+ // Collect content until closing ```
19+ const contentStart = j
20+ while ( j < text . length ) {
21+ if ( text . startsWith ( '```' , j ) ) {
22+ result += text . slice ( contentStart , j )
23+ // skip closing fence and its trailing newline
24+ j += 3
25+ while ( j < text . length && text [ j ] !== '\n' ) j ++
26+ if ( j < text . length ) j ++ // skip \n
27+ break
28+ }
29+ j ++
30+ }
31+ // If no closing fence found, include rest as-is
32+ if ( j >= text . length && ! text . startsWith ( '```' , j - 3 ) ) {
33+ result += text . slice ( i )
34+ }
35+ i = j
36+ } else {
37+ result += text [ i ]
38+ i ++
39+ }
40+ }
41+ return result
42+ }
43+
744export function markdownToPlainText ( text : string ) : string {
8- return text
9- . replace ( / ` ` ` [ \s \S ] * ?\n ( [ \s \S ] * ?) ` ` ` / g, '$1' )
45+ return stripCodeBlocks ( text )
1046 . replace ( / ` ( [ ^ ` ] + ) ` / g, '$1' )
1147 . replace ( / \* \* \* ( .+ ?) \* \* \* / g, '$1' )
1248 . replace ( / \* \* ( .+ ?) \* \* / g, '$1' )
0 commit comments