From 4393095af4d4f0487e456ebd30d08ad6b69f0919 Mon Sep 17 00:00:00 2001 From: brecert <11599528+Brecert@users.noreply.github.com> Date: Fri, 26 Jul 2019 19:44:26 -0400 Subject: [PATCH] increase emoji-parsing performance --- .../markdown-it-plugins/replaceCustomEmoji.js | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/utils/markdown-it-plugins/replaceCustomEmoji.js b/src/utils/markdown-it-plugins/replaceCustomEmoji.js index b810514..bcf4d71 100644 --- a/src/utils/markdown-it-plugins/replaceCustomEmoji.js +++ b/src/utils/markdown-it-plugins/replaceCustomEmoji.js @@ -3,39 +3,52 @@ import config from "@/config.js"; /* 58: ':' */ /* 60: '<' */ /* 62: '>' */ +/* example: '<:cat_1:1hvDmIdozFp2vTTkEIsO-wBHPaYRkGmlP>' */ -function render_custom_emoji(tokens, idx) { - return ':3' +function skipUntil(state, pos, code) { + for (let max = state.src.length; pos < max; pos++) { + if (state.src.charCodeAt(pos) === code) { break; } + } + return pos; } -function parseUntil(state, fromPos, until) { +// old +function parseUntil(state, fromPos, until, maxLength = 16) { let max = state.posMax let found = false - + let pos = state.pos + fromPos let oldPos = state.pos - // let start = nameStart + 1 - state.pos = fromPos let end = -1 - while(state.pos++ < max) { - let marker = state.src.charCodeAt(state.pos) + + while(pos < max && pos - oldPos < maxLength) { + let marker = state.src.charCodeAt(pos) if(marker === until) { found = true; break; } + + // state.md.inline.skipToken(state); + + pos += 1 } if(found) { - end = state.pos + end = pos } - state.pos = oldPos - return end } +function render_custom_emoji(tokens, idx) { + return '' +} + + function parseEmojiName(state, nameStart) { - return parseUntil(state, nameStart, 58) + // return parseUntil(state, nameStart, 58) + + return skipUntil(state, nameStart, 58) } function replace_custom_emoji(state, silent) { @@ -53,8 +66,10 @@ function replace_custom_emoji(state, silent) { let nameStart = pos + 1 let nameEnd = parseEmojiName(state, nameStart) + // console.log(nameEnd, parseUntil(state,nameStart,58)) + // parser failed to find another ':', so it's not a valid emoji - if(nameEnd < 0 || nameEnd - nameStart <= 1) { return false; } + if(nameEnd > max || nameEnd < 0 || nameEnd - nameStart <= 1) { return false; } let emojiName = state.src.slice(nameStart, nameEnd) @@ -62,9 +77,9 @@ function replace_custom_emoji(state, silent) { // parse until '>' let idStart = pos - let idEnd = parseUntil(state, idStart, 62) + let idEnd = skipUntil(state, pos, 62); - if(idEnd < 0 || idEnd - idStart <= 1) { return false; } + if(idEnd > max || idEnd < 0 || idEnd - idStart <= 1) { return false; } let emojiID = state.src.slice(idStart, idEnd) @@ -72,20 +87,25 @@ function replace_custom_emoji(state, silent) { state.pos = idStart state.posMax = idEnd - let token = state.push('custom_emoji_open', 'img', 1); - token.attrs = [[ 'src', `${config.domain}/files/${emojiID}` ]] - - // state.md.inline.tokenize(state) + let token = state.push('custom_emoji', 'img', 0); + token.attrs = [[ 'src', `${config.domain}/files/${emojiID}` ], [ 'alt', emojiName ]] } state.pos = idEnd + 1 state.posMax = max return true } + export default function custom_emoji_plugin(md, opts) { - md.renderer.rules.custom_emoji_open = (tokens, idx) => { + md.renderer.rules.custom_emoji = (tokens, idx) => { let token = tokens[idx] - return `<${md.utils.escapeHtml(token.tag)} class="emoji" src=${md.utils.escapeHtml(token.attrs.find(([name]) => name === 'src')[1])} />` + + // todo: better escaping method, + // even if this is good and covers most cases, there may be edge cases where DOMPurify may be better + let src = md.utils.escapeHtml(token.attrs.find(([name]) => name === 'src')[1]) + let alt = md.utils.escapeHtml(token.attrs.find(([name]) => name === 'alt')[1]) + + return `<${md.utils.escapeHtml(token.tag)} class="emoji" title=${alt} alt=${alt} src=${src} />` } md.inline.ruler.push('custom_emoji', replace_custom_emoji)