@wireapp/cryptobox
Version:
High-level API with persistent storage for Proteus.
110 lines (87 loc) • 2.79 kB
JavaScript
var lexemeRe = /([_*`\\]|[^_*`\\]+)/g
var mdTagRe = /[_*`]/
function Markdown (options) {
this.renderer = options.renderer
}
function isMdTag (lexeme) {
return mdTagRe.test(lexeme)
}
Markdown.prototype.parse = function (text) {
var lexemes = text.match(lexemeRe)
var render = this.renderer
var formattedText = ''
var currentScope
var scopesStack = []
var activeScopes = {}
var buffer
var lexeme
var cursor = 0
function drainTillLexeme (lexeme) {
var buffer = ''
while (currentScope && currentScope.tag !== lexeme) {
buffer = currentScope.tag + currentScope.text + buffer
activeScopes[currentScope.tag] = false
currentScope = scopesStack.pop()
}
return buffer
}
while (lexeme = lexemes[cursor]) { // eslint-disable-line
buffer = ''
cursor++
if (isMdTag(lexeme)) {
if (activeScopes[lexeme]) {
// we've found matching closing tag
// if we have some other unclosed tags in-between - treat them as a plain text
buffer = drainTillLexeme(lexeme)
// now currentScope holds the scope for the tag (`lexeme`) we are trying to close
buffer = render[currentScope.tag](currentScope.text + buffer)
activeScopes[lexeme] = false
currentScope = scopesStack.pop()
} else {
var initialText = ''
if (lexeme === '`') {
// `code` according to spec has the highest priority
// and does not allow nesting
// looking if we can find the closing delimiter
// NOTE: we have already incremented cursor, so we do not need to add 1
var newCursor = lexemes.indexOf(lexeme, cursor)
if (newCursor !== -1) {
formattedText += drainTillLexeme() // if we already have activeScopes, treat them as plain text
initialText = lexemes.slice(cursor, newCursor).join('')
cursor = newCursor // set cursor to the closing backticks
}
}
if (currentScope) {
scopesStack.push(currentScope)
}
activeScopes[lexeme] = true
currentScope = {
tag: lexeme,
text: initialText
}
}
} else {
buffer = lexeme
if (lexeme === '\\') { // process escaping
var nextLexeme = lexemes[cursor]
if (isMdTag(nextLexeme) || nextLexeme === '\\') {
// ignore next md tag, because it is escaped
buffer = nextLexeme
cursor++
}
}
}
if (buffer) {
if (currentScope) {
currentScope.text += buffer
} else {
formattedText += buffer
}
buffer = ''
}
}
// get the rest of the unclosed tags
formattedText += drainTillLexeme()
return formattedText
}
module.exports = Markdown