const tagRules = {
b: '\\*\\*',
i: '_',
strike: '~~',
code: '`'
};
tagRules.keys = Object.keys(tagRules);
const toTag = (str, delim, tag) => str.replace(
new RegExp(
`${delim}(.+)${delim}`, 'gm'),`<${tag}>$1</${tag}>`)
const makeTags = str =>
tagRules.keys.reduce((accum, val, i) =>
toTag(accum, tagRules[val], val), str)
const markConfig = {
emptyLine: {
check: val => val.trim() === '',
process: () => '<br>'
},
header: {
calc: val => val.split`#`.length - 1,
check: (val, result) => result > 0,
process: (val, result) => `<h${result} style="margin-bottom:0">
${val.replace(/#/g, '')}</h${result}>`
},
hr: {
check: val => val.trim() === '***',
process: () => '<hr>'
},
li: {
check: val => val.startsWith('- '),
process: (val, result, lastMethod) => {
const open = lastMethod != 'li' ? '<ul>' : '';
return `${open}<li>${val}</li>`;
}
}
};
markConfig.keys = Object.keys(markConfig);
markConfig.tail = {
process: (val, result, lastMethod) => {
const close = lastMethod == 'li' ? '</ul>' : '';
return val + close;
}
};
const mark = str => {
const lines = str.split`\n`;
let lastMethod;
const newStr = lines.map((line, i) => {
const method = markConfig.keys.find(key => {
const { calc = () => {}, check } = markConfig[key];
return check(line, calc(line))
}) || 'tail'
const { calc = () => {} } = markConfig[method];
const newLine = markConfig[method].process(line, calc(line), lastMethod);
lastMethod = method;
return newLine;
})
return newStr.join`\n`;
}
// try it out
const md = document.body.appendChild(document.createElement('div'));
md.style.fontFamily = 'sans-serif';
md.innerHTML = `# Mini Markdown Subset
This is a subset of markdown stuff
## It includes
- headers
- **bold styles**
- _italic styles, <br> multiline fine..._
- \`code style\`
Other than ~~strikethrough~~ that is pretty much it... oh and **hr** tags
***
***
_here is some italic text with some bold text **nested** <br>within it etc..._
`;
md.innerHTML = makeTags(mark(md.innerHTML));