src/lib/markdown.js
import Util from './util.js'
/**
* Convert the HTML DOM Node to Markdown text.
* @type {MdConverter[]}
* @see https://github.com/domchristie/to-markdown/blob/master/lib/md-converters.js
*/
const MarkdownConverters = [
// Paragraph
{
filter: 'p',
replacement: (node, content) => {
return '\n\n' + content + '\n\n'
}
},
// Line break
{
filter: 'br',
replacement: () => {
return ' \n'
}
},
// Header
{
filter: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ],
replacement: (node, content, modes) => {
const level = node.nodeName.charAt(1)
let prefix = ''
for (let i = 0; i < level; ++i) {
prefix += '#'
}
// Inter link (Markdown Extra)
if (node.id && !(modes.noMELink)) {
return '\n\n' + prefix + ' ' + content + ' {#' + node.id + '}\n\n'
}
return '\n\n' + prefix + ' ' + content + '\n\n'
}
},
// Line
{
filter: 'hr',
replacement: () => {
return '\n\n* * *\n\n'
}
},
// Italic
{
filter: ['em', 'i'],
replacement: (node, content) => {
return '_' + content + '_'
}
},
// Strong
{
filter: [ 'strong', 'b' ],
replacement: (node, content) => {
return '**' + content + '**'
}
},
// Inline code
{
filter: (node) => {
const hasSiblings = node.previousSibling || node.nextSibling
const isCodeBlock = (node.parentNode.nodeName === 'PRE' && !(hasSiblings))
return (node.nodeName === 'CODE' && !(isCodeBlock))
},
replacement: (node, content) => {
return '`' + content + '`'
}
},
// Link
{
filter: (node) => {
return (node.nodeName === 'A' && node.getAttribute('href'))
},
replacement: (node, content) => {
const titlePart = node.title ? ' "' + node.title + '"' : ''
return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'
}
},
// Image
{
filter: 'img',
replacement: (node) => {
const alt = node.alt || ''
const src = node.getAttribute('src') || ''
const title = node.title || ''
const titlePart = title ? ' "' + title + '"' : ''
return src ? '' : ''
}
},
// Code blocks
{
filter: (node) => {
return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'
},
replacement: (node) => {
return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n'
}
},
// Block quote
{
filter: 'blockquote',
replacement: (node, content) => {
let result = Util.trim(content)
result = result.replace(/\n{3,}/g, '\n\n')
result = result.replace(/^/gm, '> ')
return '\n\n' + result + '\n\n'
}
},
// List item
{
filter: 'li',
replacement: (node, content) => {
const text = content.replace(/^\s+/, '').replace(/\n/gm, '\n ')
const parent = node.parentNode
const index = Util.arrayIndexOf(parent.children, node) + 1
const ol = /ol/i
const prefix = ol.test(parent.nodeName) ? index + '. ' : '* '
return prefix + text
}
},
// List
{
filter: [ 'ul', 'ol' ],
replacement: (node) => {
const strings = []
for (let i = 0, max = node.childNodes.length; i < max; ++i) {
if (node.childNodes[i]._replacement) {
strings.push(node.childNodes[i]._replacement)
}
}
const li = /li/i
if (li.test(node.parentNode.nodeName)) {
return '\n' + strings.join('\n')
}
return '\n\n' + strings.join('\n') + '\n\n'
}
},
// Block element
{
filter: (node) => {
return Util.isBlockElement(node)
},
replacement: (node, content) => {
return '\n\n' + Util.outerHTML(node, content) + '\n\n'
}
},
// Anything else!
{
filter: () => {
return true
},
replacement: (node, content) => {
return Util.outerHTML(node, content)
}
}
]
export default MarkdownConverters