diff --git a/src/index.js b/src/index.js
index 5bce355..4cfebb8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -6,6 +6,11 @@ const TAGS = {
'-': ['
']
};
+/**
+ * Optional, skips entity encoding
+ */
+let highlight = false
+
/** Outdent a string based on the first indented line's leading whitespace
* @private
*/
@@ -21,96 +26,95 @@ function encodeAttr(str) {
}
/** Parse Markdown into an HTML String. */
-export default function snarkdown(md, options = {}) {
- const highlight = options.highlight;
+function parse(md, prevLinks) {
+ let tokenizer = /((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^```(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:\!\[([^\]]*?)\]\(([^\)]+?)\))|(\[)|(\](?:\(([^\)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(\-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,3})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( \n\n*|\n{2,}|__|\*\*|[_*])/gm,
+ context = [],
+ out = '',
+ links = prevLinks || {},
+ last = 0,
+ chunk, prev, token, inner, t;
- return parse(md);
+ function tag(token) {
+ var desc = TAGS[token.replace(/\*/g,'_')[1] || ''],
+ end = context[context.length-1]==token;
+ if (!desc) return token;
+ if (!desc[1]) return desc[0];
+ context[end?'pop':'push'](token);
+ return desc[end|0];
+ }
- function parse(md, prevLinks) {
- let tokenizer = /((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^```(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:\!\[([^\]]*?)\]\(([^\)]+?)\))|(\[)|(\](?:\(([^\)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(\-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,3})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( \n\n*|\n{2,}|__|\*\*|[_*])/gm,
- context = [],
- out = '',
- links = prevLinks || {},
- last = 0,
- chunk, prev, token, inner, t;
+ function flush() {
+ let str = '';
+ while (context.length) str += tag(context[context.length-1]);
+ return str;
+ }
- function tag(token) {
- var desc = TAGS[token.replace(/\*/g,'_')[1] || ''],
- end = context[context.length-1]==token;
- if (!desc) return token;
- if (!desc[1]) return desc[0];
- context[end?'pop':'push'](token);
- return desc[end|0];
- }
+ md = md.replace(/^\[(.+?)\]:\s*(.+)$/gm, (s, name, url) => {
+ links[name.toLowerCase()] = url;
+ return '';
+ }).replace(/^\n+|\n+$/g, '');
- function flush() {
- let str = '';
- while (context.length) str += tag(context[context.length-1]);
- return str;
+ while ( (token=tokenizer.exec(md)) ) {
+ prev = md.substring(last, token.index);
+ last = tokenizer.lastIndex;
+ chunk = token[0];
+ if (prev.match(/[^\\](\\\\)*\\$/)) {
+ // escaped
}
-
- md = md.replace(/^\[(.+?)\]:\s*(.+)$/gm, (s, name, url) => {
- links[name.toLowerCase()] = url;
- return '';
- }).replace(/^\n+|\n+$/g, '');
-
- while ( (token=tokenizer.exec(md)) ) {
- prev = md.substring(last, token.index);
- last = tokenizer.lastIndex;
- chunk = token[0];
- if (prev.match(/[^\\](\\\\)*\\$/)) {
- // escaped
- }
- // Code/Indent blocks:
- else if (token[3] || token[4]) {
- const lang = token[4]?'poetry':token[2].toLowerCase();
- chunk = ''+outdent(
- highlight ? highlight(token[3] || token[4], lang) : encodeAttr(token[3] || token[4])
- ).replace(/^\n+|\n+$/g, '')+'
';
- }
- // > Quotes, -* lists:
- else if (token[6]) {
- t = token[6];
- if (t.match(/\./)) {
- token[5] = token[5].replace(/^\d+/gm, '');
- }
- inner = parse(outdent(token[5].replace(/^\s*[>*+.-]/gm, '')));
- if (t==='>') t = 'blockquote';
- else {
- t = t.match(/\./) ? 'ol' : 'ul';
- inner = inner.replace(/^(.*)(\n|$)/gm, '$1');
- }
- chunk = '<'+t+'>' + inner + ''+t+'>';
- }
- // Images:
- else if (token[8]) {
- chunk = ``;
- }
- // Links:
- else if (token[10]) {
- out = out.replace('', ``);
- chunk = flush() + '';
- }
- else if (token[9]) {
- chunk = '';
- }
- // Headings:
- else if (token[12] || token[14]) {
- t = 'h' + (token[14] ? token[14].length : (token[13][0]==='='?1:2));
- chunk = '<'+t+'>' + parse(token[12] || token[15], links) + ''+t+'>';
- }
- // `code`:
- else if (token[16]) {
- chunk = ''+encodeAttr(token[16])+'
';
+ // Code/Indent blocks:
+ else if (token[3] || token[4]) {
+ chunk = ''+outdent(
+ highlight ? highlight(token[3] || token[4], (token[4]?'poetry':token[2].toLowerCase())) : encodeAttr(token[3] || token[4])
+ ).replace(/^\n+|\n+$/g, '')+'
';
+ }
+ // > Quotes, -* lists:
+ else if (token[6]) {
+ t = token[6];
+ if (t.match(/\./)) {
+ token[5] = token[5].replace(/^\d+/gm, '');
}
- // Inline formatting: *em*, **strong** & friends
- else if (token[17] || token[1]) {
- chunk = tag(token[17] || '--');
+ inner = parse(outdent(token[5].replace(/^\s*[>*+.-]/gm, '')));
+ if (t==='>') t = 'blockquote';
+ else {
+ t = t.match(/\./) ? 'ol' : 'ul';
+ inner = inner.replace(/^(.*)(\n|$)/gm, '$1');
}
- out += prev;
- out += chunk;
+ chunk = '<'+t+'>' + inner + ''+t+'>';
}
-
- return (out + md.substring(last) + flush()).trim();
+ // Images:
+ else if (token[8]) {
+ chunk = ``;
+ }
+ // Links:
+ else if (token[10]) {
+ out = out.replace('', ``);
+ chunk = flush() + '';
+ }
+ else if (token[9]) {
+ chunk = '';
+ }
+ // Headings:
+ else if (token[12] || token[14]) {
+ t = 'h' + (token[14] ? token[14].length : (token[13][0]==='='?1:2));
+ chunk = '<'+t+'>' + parse(token[12] || token[15], links) + ''+t+'>';
+ }
+ // `code`:
+ else if (token[16]) {
+ chunk = ''+encodeAttr(token[16])+'
';
+ }
+ // Inline formatting: *em*, **strong** & friends
+ else if (token[17] || token[1]) {
+ chunk = tag(token[17] || '--');
+ }
+ out += prev;
+ out += chunk;
}
+
+ return (out + md.substring(last) + flush()).trim();
+}
+
+export default function snarkdown(md, opt) {
+ opt = opt || {};
+ highlight = opt.highlight;
+ return parse(md);
}