export function escapeHtml(text: string): string {
return text
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
}
function inlineToHtml(text: string): string {
let html = escapeHtml(text)
html = html.replace(/`([^`\n]+)`/g, '$1')
html = html.replace(/\*\*([^*\n]+)\*\*/g, '$1')
return html
}
/** Convert `> …` line groups into `
` (Telegram renders it with the accent-colored left bar). */ function blocksToHtml(text: string): string { const lines = text.split('\n') const out: string[] = [] let quote: string[] = [] const flush = (): void => { if (quote.length === 0) return out.push(`${inlineToHtml(quote.join('\n'))}`) quote = [] } for (const line of lines) { if (line.startsWith('> ')) quote.push(line.slice(2)) else if (line === '>') quote.push('') else { flush() out.push(inlineToHtml(line)) } } flush() return out.join('\n') } export function markdownToHtml(text: string): string { const parts = text.split(/```[\w-]*/) if (parts.length % 2 === 0) return inlineToHtml(text) let html = '' for (let i = 0; i < parts.length; i++) { if (i % 2 === 1) { const code = parts[i]!.replace(/^\n/, '').replace(/\n$/, '') html += `${escapeHtml(code)}` } else { html += blocksToHtml(parts[i]!) } } return html } export function splitMessage(text: string, maxLength: number): string[] { if (maxLength < 1) throw new Error('maxLength must be >= 1') if (text.length <= maxLength) return [text] const chunks: string[] = [] let rest = text while (rest.length > maxLength) { const window = rest.slice(0, maxLength) const newline = window.lastIndexOf('\n') const ideographic = window.lastIndexOf('。') const sentence = window.lastIndexOf('. ') const breakAt = Math.max(newline, ideographic, sentence) const cut = breakAt > 0 ? (breakAt === sentence ? breakAt + 2 : breakAt + 1) : maxLength chunks.push(rest.slice(0, cut)) rest = rest.slice(cut) } chunks.push(rest) return chunks }