Spaces:
Running
Running
;(function() { "use strict"; | |
var | |
/** | |
* The parsed output string, in HTML format. | |
* @type {String} | |
*/ | |
output = "", | |
BLOCK = "block", | |
INLINE = "inline", | |
/** | |
* Used to attach MarkdownToHtml object to `window` in browser | |
* context, or as an AMD module where appropriate. | |
* @type {Object} | |
*/ | |
exports, | |
/** | |
* An array of parse rule descriptor objects. Each object has two keys; | |
* pattern (the RegExp to match), and replace (the replacement string or | |
* function to execute). | |
* @type {Array} | |
*/ | |
parseMap = [ | |
{ | |
// <h1> | |
// A line starting with 1-6 hashes. | |
pattern: /(#{1,6})([^\n]+)/g, | |
replace: "<h$L1>$2</h$L1>", | |
type: BLOCK, | |
}, | |
{ | |
// <p> | |
// Any line surrounded by newlines that doesn't start with | |
// an HTML tag, asterisk or numeric value with dot following. | |
pattern: /\n(?!<\/?\w+>|\s?\*|\s?[0-9]+|>|\>|-{5,})([^\n]+)/g, | |
replace: "<p>$1</p>", | |
type: BLOCK, | |
}, | |
{ | |
// <blockquote> | |
// A greater-than character preceding any characters. | |
pattern: /\n(?:>|\>)\W*(.*)/g, | |
replace: "<blockquote><p>$1</p></blockquote>", | |
type: BLOCK, | |
}, | |
{ | |
// <ul> | |
// | |
pattern: /\n\s?\*\s*(.*)/g, | |
replace: "<ul>\n\t<li>$1</li>\n</ul>", | |
type: BLOCK, | |
}, | |
{ | |
// <ol> | |
// | |
pattern: /\n\s?[0-9]+\.\s*(.*)/g, | |
replace: "<ol>\n\t<li>$1</li>\n</ol>", | |
type: BLOCK, | |
}, | |
{ | |
// <strong> | |
// Either two asterisks or two underscores, followed by any | |
// characters, followed by the same two starting characters. | |
pattern: /(\*\*|__)(.*?)\1/g, | |
replace: "<strong>$2</strong>", | |
type: INLINE, | |
}, | |
{ | |
// <em> | |
// Either one asterisk or one underscore, followed by any | |
// characters, followed by the starting character. | |
pattern: /(\*|_)(.*?)\1/g, | |
replace: "<em>$2</em>", | |
type: INLINE, | |
}, | |
{ | |
// <a> | |
// Not starting with an exclamation mark, square brackets | |
// surrounding any characters, followed by parenthesis surrounding | |
// any characters. | |
pattern: /([^!])\[([^\[]+)\]\(([^\)]+)\)/g, | |
replace: "$1<a href=\"$3\">$2</a>", | |
type: INLINE, | |
}, | |
{ | |
// <img> | |
// Starting with an exclamation mark, then followed by square | |
// brackets surrounding any characters, followed by parenthesis | |
// surrounding any characters. | |
pattern: /!\[([^\[]+)\]\(([^\)]+)\)/g, | |
replace: "<img src=\"$2\" alt=\"$1\" />", | |
type: INLINE, | |
}, | |
{ | |
// <del> | |
// Double tilde characters surrounding any characters. | |
pattern: /\~\~(.*?)\~\~/g, | |
replace: "<del>$1</del>", | |
type: INLINE, | |
}, | |
{ | |
// <code> | |
// | |
pattern: /`(.*?)`/g, | |
replace: "<code>$1</code>", | |
type: INLINE, | |
}, | |
{ | |
// <hr> | |
// | |
pattern: /\n-{5,}\n/g, | |
replace: "<hr />", | |
type: BLOCK, | |
}, | |
], | |
$$; | |
/** | |
* Self-executing function to handle exporting the parse function for | |
* external use. | |
*/ | |
(function go() { | |
// Export AMD module if possible. | |
if(typeof module !== "undefined" | |
&& typeof module.exports !== "undefined") { | |
exports = module.exports; | |
} | |
// Otherwise check for browser context. | |
else if(typeof window !== "undefined") { | |
window.MarkdownToHtml = {}; | |
exports = window.MarkdownToHtml; | |
} | |
exports.parse = parse; | |
})(); | |
/** | |
* Parses a provided Markdown string into valid HTML. | |
* | |
* @param {string} string Markdown input for transformation | |
* @return {string} Transformed HTML output | |
*/ | |
function parse(string) { | |
// Pad with newlines for compatibility. | |
output = "\n" + string + "\n"; | |
parseMap.forEach(function(p) { | |
// Replace all matches of provided RegExp pattern with either the | |
// replacement string or callback function. | |
output = output.replace(p.pattern, function() { | |
// console.log(this, arguments); | |
return replace.call(this, arguments, p.replace, p.type); | |
}); | |
}); | |
// Perform any post-processing required. | |
output = clean(output); | |
// Trim for any spaces or newlines. | |
output = output.trim(); | |
// Tidy up newlines to condense where more than 1 occurs back to back. | |
output = output.replace(/[\n]{1,}/g, "\n"); | |
return output; | |
} | |
function replace(matchList, replacement, type) { | |
var | |
i, | |
$$; | |
for(i in matchList) { | |
if(!matchList.hasOwnProperty(i)) { | |
continue; | |
} | |
// Replace $n with the matching regexp group. | |
replacement = replacement.split("$" + i).join(matchList[i]); | |
// Replace $Ln with the matching regexp group's string length. | |
replacement = replacement.split("$L" + i).join(matchList[i].length); | |
} | |
if(type === BLOCK) { | |
replacement = replacement.trim() + "\n"; | |
} | |
return replacement; | |
} | |
function clean(string) { | |
var cleaningRuleArray = [ | |
{ | |
match: /<\/([uo]l)>\s*<\1>/g, | |
replacement: "", | |
}, | |
{ | |
match: /(<\/\w+>)<\/(blockquote)>\s*<\2>/g, | |
replacement: "$1", | |
}, | |
]; | |
cleaningRuleArray.forEach(function(rule) { | |
string = string.replace(rule.match, rule.replacement); | |
}); | |
return string; | |
} | |
})(); |