import markdownit from 'markdown-it'
import emoji from 'markdown-it-emoji'
import math from '@rokt33r/markdown-it-math'
import _ from 'lodash'
const katex = window.katex
function createGutter (str) {
let lc = (str.match(/\n/g) || []).length
let lines = []
for (let i = 1; i <= lc; i++) {
lines.push('' + i + '')
}
return '' + lines.join('') + ''
}
var md = markdownit({
typographer: true,
linkify: true,
html: true,
xhtmlOut: true,
highlight: function (str, lang) {
if (lang === 'flowchart') {
return `
${str}`
}
if (lang === 'sequence') {
return `${str}`
}
return '' +
createGutter(str) +
'' +
str +
''
}
})
md.use(emoji, {
shortcuts: {}
})
md.use(math, {
inlineRenderer: function (str) {
let output = ''
try {
output = katex.renderToString(str.trim())
} catch (err) {
output = `${err.message}`
}
return output
},
blockRenderer: function (str) {
let output = ''
try {
output = katex.renderToString(str.trim(), {displayMode: true})
} catch (err) {
output = `${err.message}
`
}
return output
}
})
md.use(require('markdown-it-footnote'))
// Override task item
md.block.ruler.at('paragraph', function (state, startLine/*, endLine*/) {
let content, terminate, i, l, token
let nextLine = startLine + 1
let terminatorRules = state.md.block.ruler.getRules('paragraph')
let endLine = state.lineMax
// jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
// this would be a code block normally, but after paragraph
// it's considered a lazy continuation regardless of what's there
if (state.sCount[nextLine] - state.blkIndent > 3) { continue }
// quirk for blockquotes, this line should already be checked by that rule
if (state.sCount[nextLine] < 0) { continue }
// Some tags can terminate paragraph without empty line.
terminate = false
for (i = 0, l = terminatorRules.length; i < l; i++) {
if (terminatorRules[i](state, nextLine, endLine, true)) {
terminate = true
break
}
}
if (terminate) { break }
}
content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()
state.line = nextLine
token = state.push('paragraph_open', 'p', 1)
token.map = [ startLine, state.line ]
if (state.parentType === 'list') {
let match = content.match(/^\[( |x)\] ?(.+)/i)
if (match) {
content = ``
}
}
token = state.push('inline', '', 0)
token.content = content
token.map = [ startLine, state.line ]
token.children = []
token = state.push('paragraph_close', 'p', -1)
return true
})
// Add line number attribute for scrolling
let originalRender = md.renderer.render
md.renderer.render = function render (tokens, options, env) {
tokens.forEach((token) => {
switch (token.type) {
case 'heading_open':
case 'paragraph_open':
case 'blockquote_open':
case 'table_open':
token.attrPush(['data-line', token.map[0]])
}
})
let result = originalRender.call(md.renderer, tokens, options, env)
return result
}
window.md = md
function strip (input) {
var output = input
try {
output = output
.replace(/^([\s\t]*)([\*\-\+]|\d\.)\s+/gm, '$1')
.replace(/\n={2,}/g, '\n')
.replace(/~~/g, '')
.replace(/`{3}.*\n/g, '')
.replace(/<(.*?)>/g, '$1')
.replace(/^[=\-]{2,}\s*$/g, '')
.replace(/\[\^.+?\](: .*?$)?/g, '')
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
.replace(/>/g, '')
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
.replace(/([\*_]{1,3})(\S.*?\S)\1/g, '$2')
.replace(/(`{3,})(.*?)\1/gm, '$2')
.replace(/^-{3,}\s*$/g, '')
.replace(/`(.+?)`/g, '$1')
.replace(/\n{2,}/g, '\n\n')
} catch (e) {
console.error(e)
return input
}
return output
}
const markdown = {
render: function markdown (content) {
if (!_.isString(content)) content = ''
return md.render(content)
},
strip
}
export default markdown