marked-mfm/src/index.js

90 lines
2.7 KiB
JavaScript

export default {
extensions: [
{
name: 'mfm',
level: 'inline',
start (src) { return src.match(/\$\[/)?.index },
tokenizer (src, tokens) {
// regex doesn't do well finding MFM tags: it's always either too lazy
// or too greedy.
let level = 0
let walk = 0
while (level > 0 || walk === 0) {
if (walk >= src.length) {
return null
}
if (src[walk] + src[walk + 1] === '$[') {
level++
walk++
} else if (src[walk] === ']') {
level--
}
walk++
}
// original regex, now definitely on the correct tag
const rule = /^\$\[(?<tag>[\w\d]+)(?:\.(?<options>\S+))? (?<text>[\S\s]+)\]/
const match = rule.exec(src.slice(0, walk))
if (match) {
const token = {
type: 'mfm',
raw: match[0],
tag: match.groups.tag,
options: match.groups.options,
text: match.groups.text,
tokens: [],
}
this.lexer.inline(token.text, token.tokens)
return token
}
},
renderer (token) {
const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'font', 'blur', 'rainbow', 'rotate', 'sparkle']
if (MFM_TAGS.includes(token.tag)) {
let options = []
if (token.options) {
options = token.options.split(',').map((opt) => (opt.split('=').length === 2 ? `data-${opt.split('=')[0]}="${opt.split('=')[1]}"` : `data-${opt}`))
}
return `<span class="mfm _mfm_${token.tag}_" ${options.join(' ')}>${this.parser.parseInline(token.tokens)}</span>`
}
return `$[${token.tag} ${this.parser.parseInline(token.tokens)}]`
},
},
{
name: 'escapedMfm',
level: 'inline',
start (src) { return src.match(/\\\$\[/) },
tokenizer (src, tokens) {
if (/^\\\$\[/.exec(src)) {
return { type: 'escapedMfm', raw: '\\$[' }
}
},
renderer (token) {
return '$['
},
},
{
name: 'center',
level: 'block',
start (src) { return src.match(/<center>/) },
tokenizer (src, tokens) {
const rule = /^<center>([\S\s]*)<\/center>/
const match = rule.exec(src)
if (match) {
const token = {
type: 'center',
raw: match[0],
text: match[1],
tokens: [],
}
this.lexer.inline(token.text, token.tokens)
return token
}
},
renderer (token) {
return `<center>${this.parser.parseInline(token.tokens)}</center>\n`
},
},
],
}