const ESCAPE_REGEX = /[.*+?^${}()|[\]\\]/g; const HTML_ESCAPE_MAP: Record = { '&': '&', '"': '"', '<': '<', '>': '>', }; const HTML_ESCAPE_REGEX = /[&"<>]/g; interface EmojiEntry { shortcode?: string; url?: string; staticUrl?: string; } function escapeRegex(str: string): string { return str.replace(ESCAPE_REGEX, '\\$&'); } function escapeHTML(str: string): string { return str.replace(HTML_ESCAPE_REGEX, (char) => HTML_ESCAPE_MAP[char]); } function emojifyText(text: string, emojis: EmojiEntry[] = []): string { if (!text) return ''; if (!emojis.length) return text; if (!text.includes(':')) return text; // Deduplicate emojis by shortcode and filter out invalid entries const emojiMap = new Map(); for (let i = 0; i < emojis.length; i++) { const emoji = emojis[i]; if (emoji?.shortcode && emoji?.url) { emojiMap.set(emoji.shortcode, emoji); } } if (emojiMap.size === 0) return text; const shortcodes = Array.from(emojiMap.keys()); const pattern = shortcodes.map((sc) => `:${escapeRegex(sc)}:`).join('|'); const regex = new RegExp(pattern, 'g'); return text.replace(regex, (match) => { const shortcode = match.slice(1, -1); const emoji = emojiMap.get(shortcode); if (!emoji) return match; const { staticUrl, url } = emoji; const escapedShortcode = escapeHTML(match); const sourceTag = staticUrl ? `` : ''; return `${sourceTag}${escapedShortcode}`; }); } export default emojifyText;