diff --git a/src/utils/emojify-text.js b/src/utils/emojify-text.js index 99977fc1..f6552e53 100644 --- a/src/utils/emojify-text.js +++ b/src/utils/emojify-text.js @@ -1,18 +1,55 @@ +const ESCAPE_REGEX = /[.*+?^${}()|[\]\\]/g; +const HTML_ESCAPE_MAP = { + '&': '&', + '"': '"', + '<': '<', + '>': '>', +}; +const HTML_ESCAPE_REGEX = /[&"<>]/g; + +function escapeRegex(str) { + return str.replace(ESCAPE_REGEX, '\\$&'); +} + +function escapeHTML(str) { + return str.replace(HTML_ESCAPE_REGEX, (char) => HTML_ESCAPE_MAP[char]); +} + function emojifyText(text, emojis = []) { if (!text) return ''; if (!emojis.length) return text; - if (text.indexOf(':') === -1) return text; - // Replace shortcodes in text with emoji - // emojis = [{ shortcode: 'smile', url: 'https://example.com/emoji.png' }] - emojis.forEach((emoji) => { - const { shortcode, staticUrl, url } = emoji; - text = text.replace( - new RegExp(`:${shortcode}:`, 'g'), - `:${shortcode}:`, - ); + 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}`; }); - // console.log(text, emojis); - return text; } export default emojifyText;