Created
April 14, 2019 18:29
-
-
Save offbynull/2009cfc1e76dfc6f6260a340282fcfe8 to your computer and use it in GitHub Desktop.
Custom markup in markdown-it
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var MarkdownIt = require("markdown-it"); | |
var md = new MarkdownIt('commonmark'); | |
// Add custom INLINE rule that pulls in anything wrapped in a ::: <TEXT> ::: and wrap in a span tag | |
function custom_inline(state, silent) { | |
let pos = state.pos; | |
let matchStart = pos; | |
let marker = ''; | |
while (true) { | |
let ch = state.src.charCodeAt(pos); | |
if (ch !== 0x3A/* : */) { | |
break; | |
} | |
marker += String.fromCharCode(ch); | |
pos++; | |
} | |
if (marker.length < 3) { | |
return false; | |
} | |
let contentStart = pos; | |
let contentEnd = state.src.indexOf(marker, pos + marker.length); | |
if (contentEnd === -1) { | |
return false; | |
} | |
let matchEnd = contentEnd + marker.length; | |
if (!silent) { | |
let token; | |
token = state.push('custom_inline', '', 0); | |
// token.attrs = [ [ 'key1', val1 ], [ 'key2', val2] ]; | |
token.markup = marker; | |
token.content = state.src.slice(contentStart, contentEnd).trim(); | |
} | |
state.pos = matchEnd; | |
return true; | |
} | |
md.inline.ruler.before('backticks', 'custom_inline', custom_inline); | |
md.renderer.rules.custom_inline = function (tokens, idx, options, env, self) { | |
return '<span>' + md.utils.escapeHtml(tokens[idx].content) + '</span>'; | |
}; | |
// Add custom BLOCK rule that pulls in anything sandwiched between a startings and ending ::: lines and wraps in a div tag | |
function getLine(state, lineNum) { | |
return state.src.slice(state.bMarks[lineNum], state.eMarks[lineNum]); | |
} | |
function custom(state, startLine, endLine, silent) { | |
let line; | |
let content = []; | |
// no whitespace allowed before beginning | |
if (state.sCount[startLine] - state.blkIndent > 0) { | |
return false; | |
} | |
// read start marker | |
line = getLine(state, startLine); | |
let marker = ''; | |
for (let i = 0; i < line.length; i++) { | |
const ch = line.charCodeAt(i); | |
if (ch !== 0x3A/* : */) { | |
break; | |
} | |
marker += String.fromCharCode(ch); | |
} | |
// if no marker found, skip | |
if (marker.length < 3) { | |
return false; | |
} | |
// first line must be just the marker | |
if (line.indexOf(marker) !== 0 || line.trim() !== marker) { | |
return false; | |
} | |
// keep reading until end marker | |
let properlyEnded = false; | |
let nextLine = startLine; | |
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { | |
line = getLine(state, nextLine); | |
if (line.indexOf(marker) === 0 && line.trim() === marker) { | |
properlyEnded = true; | |
break; | |
} | |
content.push(line); | |
} | |
if (!properlyEnded) { | |
return false; | |
} | |
state.line = nextLine + 1; | |
if (silent) { | |
return true; | |
} | |
let token; | |
token = state.push('custom', '', 0); | |
token.content = content.join('\n'); | |
token.markup = marker; | |
token.map = [ startLine, state.line ]; | |
return true; | |
} | |
md.block.ruler.before('fence', 'custom', custom); | |
md.renderer.rules.custom = function (tokens, idx, options, env, self) { | |
return '<div>' + md.utils.escapeHtml(tokens[idx].content) + '</div>'; | |
}; | |
var result = md.render('# hello!\npooper :::hello1::: ```end```\n\n:::\nhello2\ntest\n\n\ntesttest\n:::\n\n'); | |
console.log(result); | |
// OUTPUT | |
// ------ | |
// <h1>hello!</h1> | |
// <p>pooper <span>hello1</span> <code>end</code></p> | |
// <div>hello2 | |
// test | |
// | |
// | |
// testtest</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment