increase emoji-parsing performance

This commit is contained in:
brecert 2019-07-26 19:44:26 -04:00
parent 5db33c4e7c
commit 4393095af4

View file

@ -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)