Skip to content

Commit 61e5f9b

Browse files
committed
fix: protect URLs from Markdown parsing
1 parent 1176962 commit 61e5f9b

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

src/util/parseHtmlAsFormattedText.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ function parseMarkdown(html: string) {
113113
'<img alt="$1" data-document-id="$2">',
114114
);
115115

116+
// Protect raw URLs from markdown processing (e.g., '__' inside paths)
117+
// Temporarily replace detected URLs with placeholders, apply markdown, then restore.
118+
const urlPlaceholders: string[] = [];
119+
const PLACEHOLDER_PREFIX = '[[TT_URL_';
120+
const PLACEHOLDER_SUFFIX = ']]';
121+
const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
122+
const reRawLink = new RegExp(RE_LINK_TEMPLATE, 'g');
123+
parsedHtml = parsedHtml.replace(reRawLink, (match) => {
124+
const i = urlPlaceholders.push(match) - 1;
125+
return `${PLACEHOLDER_PREFIX}${i}${PLACEHOLDER_SUFFIX}`;
126+
});
127+
116128
// Other simple markdown
117129
parsedHtml = parsedHtml.replace(
118130
/(?!<(code|pre)[^<]*|<\/)[*]{2}([^*\n]+)[*]{2}(?![^<]*<\/(code|pre)>)/g,
@@ -131,6 +143,15 @@ function parseMarkdown(html: string) {
131143
`<span data-entity-type="${ApiMessageEntityTypes.Spoiler}">$2</span>`,
132144
);
133145

146+
// Restore protected URLs
147+
if (urlPlaceholders.length) {
148+
const restoreRe = new RegExp(`${escapeRegExp(PLACEHOLDER_PREFIX)}(\\d+)${escapeRegExp(PLACEHOLDER_SUFFIX)}`, 'g');
149+
parsedHtml = parsedHtml.replace(restoreRe, (full, idx) => {
150+
const i = Number(idx);
151+
return Number.isFinite(i) && urlPlaceholders[i] !== undefined ? urlPlaceholders[i] : full;
152+
});
153+
}
154+
134155
return parsedHtml;
135156
}
136157

0 commit comments

Comments
 (0)