@@ -713,7 +713,7 @@ export function renderTelegramHtmlText(
|
713 | 713 | ): string { |
714 | 714 | const textMode = options.textMode ?? "markdown"; |
715 | 715 | if (textMode === "html") { |
716 | | -return escapeUnsupportedTelegramHtml(text); |
| 716 | +return escapeUnsupportedTelegramHtmlWithTableFallback(text); |
717 | 717 | } |
718 | 718 | // markdownToTelegramHtml already wraps file references by default |
719 | 719 | return markdownToTelegramHtml(text, { tableMode: options.tableMode }); |
@@ -727,6 +727,44 @@ export function sanitizeTelegramRichHtml(html: string): string {
|
727 | 727 | ); |
728 | 728 | } |
729 | 729 | |
| 730 | +function escapeUnsupportedTelegramHtmlWithTableFallback(html: string): string { |
| 731 | +return escapeUnsupportedTelegramHtml( |
| 732 | +normalizeTelegramLegacyHtmlTables(html), |
| 733 | +TELEGRAM_LEGACY_HTML_TAG_SUPPORT, |
| 734 | +); |
| 735 | +} |
| 736 | + |
| 737 | +function isInsideTelegramHtmlCodeContext(html: string, offset: number): boolean { |
| 738 | +let codeDepth = 0; |
| 739 | +let preDepth = 0; |
| 740 | +HTML_TAG_PATTERN.lastIndex = 0; |
| 741 | +let match: RegExpExecArray | null; |
| 742 | +while ((match = HTML_TAG_PATTERN.exec(html)) !== null && match.index < offset) { |
| 743 | +const tagName = normalizeLowercaseStringOrEmpty(match[2]); |
| 744 | +if (tagName !== "code" && tagName !== "pre") { |
| 745 | +continue; |
| 746 | +} |
| 747 | +const isClosing = match[1] === "</"; |
| 748 | +if (tagName === "code") { |
| 749 | +codeDepth = isClosing ? Math.max(0, codeDepth - 1) : codeDepth + 1; |
| 750 | +} else { |
| 751 | +preDepth = isClosing ? Math.max(0, preDepth - 1) : preDepth + 1; |
| 752 | +} |
| 753 | +} |
| 754 | +return codeDepth > 0 || preDepth > 0; |
| 755 | +} |
| 756 | + |
| 757 | +function normalizeTelegramLegacyHtmlTables(html: string): string { |
| 758 | +TELEGRAM_RICH_HTML_TABLE_PATTERN.lastIndex = 0; |
| 759 | +return html.replace(TELEGRAM_RICH_HTML_TABLE_PATTERN, (tableHtml, offset: number) => { |
| 760 | +if (isInsideTelegramHtmlCodeContext(html, offset)) { |
| 761 | +return tableHtml; |
| 762 | +} |
| 763 | +const rows = parseTelegramRichHtmlTableRows(tableHtml); |
| 764 | +return rows.length ? renderTelegramRichHtmlRawTableFallback(tableHtml, rows) : tableHtml; |
| 765 | +}); |
| 766 | +} |
| 767 | + |
730 | 768 | export function limitTelegramRichHtmlNesting(html: string, maxDepth: number): string { |
731 | 769 | const normalizedMaxDepth = Math.max(1, Math.floor(maxDepth)); |
732 | 770 | const stack: Array<{ name: string; kept: boolean }> = []; |
|