From c347811e2931f37d0d5dfa3b66150b0a521b2b32 Mon Sep 17 00:00:00 2001 From: Wes Cossick Date: Fri, 26 Jun 2015 15:41:21 -0500 Subject: [PATCH] Update Marked to 0.3.3 --- source files/marked.js | 432 ++++++++++++++++++++++++++--------------- 1 file changed, 276 insertions(+), 156 deletions(-) diff --git a/source files/marked.js b/source files/marked.js index 2e8d6d4..6c637c8 100644 --- a/source files/marked.js +++ b/source files/marked.js @@ -1,6 +1,6 @@ /** - * marked - a markdown parser - * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) + * marked - a markdown parser - v0.3.3 + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) * https://github.com/chjj/marked */ @@ -18,9 +18,9 @@ var block = { heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, nptable: noop, lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, - blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, - list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, - html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, + blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, + list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, table: noop, paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, @@ -35,13 +35,18 @@ block.item = replace(block.item, 'gm') block.list = replace(block.list) (/bull/g, block.bullet) - ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/) + ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') + ('def', '\\n+(?=' + block.def.source + ')') + (); + +block.blockquote = replace(block.blockquote) + ('def', block.def) (); block._tag = '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' - + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b'; + + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b'; block.html = replace(block.html) ('comment', //) @@ -70,8 +75,9 @@ block.normal = merge({}, block); */ block.gfm = merge({}, block.normal, { - fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, - paragraph: /^/ + fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, + paragraph: /^/, + heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ }); block.gfm.paragraph = replace(block.paragraph) @@ -141,7 +147,7 @@ Lexer.prototype.lex = function(src) { * Lexing */ -Lexer.prototype.token = function(src, top) { +Lexer.prototype.token = function(src, top, bq) { var src = src.replace(/^ +$/gm, '') , next , loose @@ -264,7 +270,7 @@ Lexer.prototype.token = function(src, top) { // Pass `top` to keep the current // "toplevel" state. This is exactly // how markdown.pl works. - this.token(cap, top); + this.token(cap, top, true); this.tokens.push({ type: 'blockquote_end' @@ -333,7 +339,7 @@ Lexer.prototype.token = function(src, top) { }); // Recurse. - this.token(item, false); + this.token(item, false, bq); this.tokens.push({ type: 'list_item_end' @@ -354,14 +360,15 @@ Lexer.prototype.token = function(src, top) { type: this.options.sanitize ? 'paragraph' : 'html', - pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), text: cap[0] }); continue; } // def - if (top && (cap = this.rules.def.exec(src))) { + if ((!bq && top) && (cap = this.rules.def.exec(src))) { src = src.substring(cap[0].length); this.tokens.links[cap[1].toLowerCase()] = { href: cap[2], @@ -514,6 +521,8 @@ function InlineLexer(links, options) { this.options = options || marked.defaults; this.links = links; this.rules = inline.normal; + this.renderer = this.options.renderer || new Renderer; + this.renderer.options = this.options; if (!this.links) { throw new @@ -577,43 +586,44 @@ InlineLexer.prototype.output = function(src) { text = escape(cap[1]); href = text; } - out += '' - + text - + ''; + out += this.renderer.link(href, null, text); continue; } // url (gfm) - if (cap = this.rules.url.exec(src)) { + if (!this.inLink && (cap = this.rules.url.exec(src))) { src = src.substring(cap[0].length); text = escape(cap[1]); href = text; - out += '' - + text - + ''; + out += this.renderer.link(href, null, text); continue; } // tag if (cap = this.rules.tag.exec(src)) { + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; + } src = src.substring(cap[0].length); out += this.options.sanitize - ? escape(cap[0]) - : cap[0]; + ? this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape(cap[0]) + : cap[0] continue; } // link if (cap = this.rules.link.exec(src)) { src = src.substring(cap[0].length); + this.inLink = true; out += this.outputLink(cap, { href: cap[2], title: cap[3] }); + this.inLink = false; continue; } @@ -628,57 +638,51 @@ InlineLexer.prototype.output = function(src) { src = cap[0].substring(1) + src; continue; } + this.inLink = true; out += this.outputLink(cap, link); + this.inLink = false; continue; } // strong if (cap = this.rules.strong.exec(src)) { src = src.substring(cap[0].length); - out += '' - + this.output(cap[2] || cap[1]) - + ''; + out += this.renderer.strong(this.output(cap[2] || cap[1])); continue; } // em if (cap = this.rules.em.exec(src)) { src = src.substring(cap[0].length); - out += '' - + this.output(cap[2] || cap[1]) - + ''; + out += this.renderer.em(this.output(cap[2] || cap[1])); continue; } // code if (cap = this.rules.code.exec(src)) { src = src.substring(cap[0].length); - out += '' - + escape(cap[2], true) - + ''; + out += this.renderer.codespan(escape(cap[2], true)); continue; } // br if (cap = this.rules.br.exec(src)) { src = src.substring(cap[0].length); - out += '
'; + out += this.renderer.br(); continue; } // del (gfm) if (cap = this.rules.del.exec(src)) { src = src.substring(cap[0].length); - out += '' - + this.output(cap[1]) - + ''; + out += this.renderer.del(this.output(cap[1])); continue; } // text if (cap = this.rules.text.exec(src)) { src = src.substring(cap[0].length); - out += escape(this.smartypants(cap[0])); + out += this.renderer.text(escape(this.smartypants(cap[0]))); continue; } @@ -696,31 +700,12 @@ InlineLexer.prototype.output = function(src) { */ InlineLexer.prototype.outputLink = function(cap, link) { - if (cap[0].charAt(0) !== '!') { - return '
' - + this.output(cap[1]) - + ''; - } else { - return ''
-	  + escape(cap[1])
-	  + ''; - } + var href = escape(link.href) + , title = link.title ? escape(link.title) : null; + + return cap[0].charAt(0) !== '!' + ? this.renderer.link(href, title, this.output(cap[1])) + : this.renderer.image(href, title, escape(cap[1])); }; /** @@ -731,7 +716,9 @@ InlineLexer.prototype.smartypants = function(text) { if (!this.options.smartypants) return text; return text // em-dashes - .replace(/--/g, '\u2014') + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') // opening singles .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') // closing singles & apostrophes @@ -749,6 +736,7 @@ InlineLexer.prototype.smartypants = function(text) { */ InlineLexer.prototype.mangle = function(text) { + if (!this.options.mangle) return text; var out = '' , l = text.length , i = 0 @@ -765,6 +753,153 @@ InlineLexer.prototype.mangle = function(text) { return out; }; +/** + * Renderer + */ + +function Renderer(options) { + this.options = options || {}; +} + +Renderer.prototype.code = function(code, lang, escaped) { + if (this.options.highlight) { + var out = this.options.highlight(code, lang); + if (out != null && out !== code) { + escaped = true; + code = out; + } + } + + if (!lang) { + return '
'
+	  + (escaped ? code : escape(code, true))
+	  + '\n
'; + } + + return '
'
+	+ (escaped ? code : escape(code, true))
+	+ '\n
\n'; +}; + +Renderer.prototype.blockquote = function(quote) { + return '
\n' + quote + '
\n'; +}; + +Renderer.prototype.html = function(html) { + return html; +}; + +Renderer.prototype.heading = function(text, level, raw) { + return '' + + text + + '\n'; +}; + +Renderer.prototype.hr = function() { + return this.options.xhtml ? '
\n' : '
\n'; +}; + +Renderer.prototype.list = function(body, ordered) { + var type = ordered ? 'ol' : 'ul'; + return '<' + type + '>\n' + body + '\n'; +}; + +Renderer.prototype.listitem = function(text) { + return '
  • ' + text + '
  • \n'; +}; + +Renderer.prototype.paragraph = function(text) { + return '

    ' + text + '

    \n'; +}; + +Renderer.prototype.table = function(header, body) { + return '\n' + + '\n' + + header + + '\n' + + '\n' + + body + + '\n' + + '
    \n'; +}; + +Renderer.prototype.tablerow = function(content) { + return '\n' + content + '\n'; +}; + +Renderer.prototype.tablecell = function(content, flags) { + var type = flags.header ? 'th' : 'td'; + var tag = flags.align + ? '<' + type + ' style="text-align:' + flags.align + '">' + : '<' + type + '>'; + return tag + content + '\n'; +}; + +// span level renderer +Renderer.prototype.strong = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.em = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.codespan = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.br = function() { + return this.options.xhtml ? '
    ' : '
    '; +}; + +Renderer.prototype.del = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.link = function(href, title, text) { + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, '') + .toLowerCase(); + } catch (e) { + return ''; + } + if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) { + return ''; + } + } + var out = ''; + return out; +}; + +Renderer.prototype.image = function(href, title, text) { + var out = '' + text + '' : '>'; + return out; +}; + +Renderer.prototype.text = function(text) { + return text; +}; + /** * Parsing & Compiling */ @@ -773,14 +908,17 @@ function Parser(options) { this.tokens = []; this.token = null; this.options = options || marked.defaults; + this.options.renderer = this.options.renderer || new Renderer; + this.renderer = this.options.renderer; + this.renderer.options = this.options; } /** * Static Parse Method */ -Parser.parse = function(src, options) { - var parser = new Parser(options); +Parser.parse = function(src, options, renderer) { + var parser = new Parser(options, renderer); return parser.parse(src); }; @@ -789,7 +927,7 @@ Parser.parse = function(src, options) { */ Parser.prototype.parse = function(src) { - this.inline = new InlineLexer(src.links, this.options); + this.inline = new InlineLexer(src.links, this.options, this.renderer); this.tokens = src.reverse(); var out = ''; @@ -840,83 +978,53 @@ Parser.prototype.tok = function() { return ''; } case 'hr': { - return '
    \n'; + return this.renderer.hr(); } case 'heading': { - return '' - + this.inline.output(this.token.text) - + '\n'; + return this.renderer.heading( + this.inline.output(this.token.text), + this.token.depth, + this.token.text); } case 'code': { - if (this.options.highlight) { - var code = this.options.highlight(this.token.text, this.token.lang); - if (code != null && code !== this.token.text) { - this.token.escaped = true; - this.token.text = code; - } - } - - if (!this.token.escaped) { - this.token.text = escape(this.token.text, true); - } - - return '
    '
    -		+ this.token.text
    -		+ '
    \n'; + return this.renderer.code(this.token.text, + this.token.lang, + this.token.escaped); } case 'table': { - var body = '' - , heading + var header = '' + , body = '' , i , row , cell + , flags , j; // header - body += '\n\n'; + cell = ''; for (i = 0; i < this.token.header.length; i++) { - heading = this.inline.output(this.token.header[i]); - body += '\n'; + flags = { header: true, align: this.token.align[i] }; + cell += this.renderer.tablecell( + this.inline.output(this.token.header[i]), + { header: true, align: this.token.align[i] } + ); } - body += '\n\n'; + header += this.renderer.tablerow(cell); - // body - body += '\n' for (i = 0; i < this.token.cells.length; i++) { row = this.token.cells[i]; - body += '\n'; + + cell = ''; for (j = 0; j < row.length; j++) { - cell = this.inline.output(row[j]); - body += '\n'; + cell += this.renderer.tablecell( + this.inline.output(row[j]), + { header: false, align: this.token.align[j] } + ); } - body += '\n'; - } - body += '\n'; - return '\n' - + body - + '
    \n'; + body += this.renderer.tablerow(cell); + } + return this.renderer.table(header, body); } case 'blockquote_start': { var body = ''; @@ -925,25 +1033,17 @@ Parser.prototype.tok = function() { body += this.tok(); } - return '
    \n' - + body - + '
    \n'; + return this.renderer.blockquote(body); } case 'list_start': { - var type = this.token.ordered ? 'ol' : 'ul' - , body = ''; + var body = '' + , ordered = this.token.ordered; while (this.next().type !== 'list_end') { body += this.tok(); } - return '<' - + type - + '>\n' - + body - + '\n'; + return this.renderer.list(body, ordered); } case 'list_item_start': { var body = ''; @@ -954,9 +1054,7 @@ Parser.prototype.tok = function() { : this.tok(); } - return '
  • ' - + body - + '
  • \n'; + return this.renderer.listitem(body); } case 'loose_item_start': { var body = ''; @@ -965,24 +1063,19 @@ Parser.prototype.tok = function() { body += this.tok(); } - return '
  • ' - + body - + '
  • \n'; + return this.renderer.listitem(body); } case 'html': { - return !this.token.pre && !this.options.pedantic + var html = !this.token.pre && !this.options.pedantic ? this.inline.output(this.token.text) : this.token.text; + return this.renderer.html(html); } case 'paragraph': { - return '

    ' - + this.inline.output(this.token.text) - + '

    \n'; + return this.renderer.paragraph(this.inline.output(this.token.text)); } case 'text': { - return '

    ' - + this.parseText() - + '

    \n'; + return this.renderer.paragraph(this.parseText()); } } }; @@ -1000,6 +1093,19 @@ function escape(html, encode) { .replace(/'/g, '''); } +function unescape(html) { + return html.replace(/&([#\w]+);/g, function(_, n) { + n = n.toLowerCase(); + if (n === 'colon') return ':'; + if (n.charAt(0) === '#') { + return n.charAt(1) === 'x' + ? String.fromCharCode(parseInt(n.substring(2), 16)) + : String.fromCharCode(+n.substring(1)); + } + return ''; + }); +} + function replace(regex, opt) { regex = regex.source; opt = opt || ''; @@ -1032,6 +1138,7 @@ function merge(obj) { return obj; } + /** * Marked */ @@ -1058,8 +1165,13 @@ function marked(src, opt, callback) { pending = tokens.length; - var done = function() { - var out, err; + var done = function(err) { + if (err) { + opt.highlight = highlight; + return callback(err); + } + + var out; try { out = Parser.parse(tokens, opt); @@ -1088,6 +1200,7 @@ function marked(src, opt, callback) { return --pending || done(); } return highlight(token.text, token.lang, function(err, code) { + if (err) return done(err); if (code == null || code === token.text) { return --pending || done(); } @@ -1130,11 +1243,16 @@ marked.defaults = { breaks: false, pedantic: false, sanitize: false, + sanitizer: null, + mangle: true, smartLists: false, silent: false, highlight: null, langPrefix: 'lang-', - smartypants: false + smartypants: false, + headerPrefix: '', + renderer: new Renderer, + xhtml: false }; /** @@ -1144,6 +1262,8 @@ marked.defaults = { marked.Parser = Parser; marked.parser = Parser.parse; +marked.Renderer = Renderer; + marked.Lexer = Lexer; marked.lexer = Lexer.lex; @@ -1152,7 +1272,7 @@ marked.inlineLexer = InlineLexer.output; marked.parse = marked; -if (typeof exports === 'object') { +if (typeof module !== 'undefined' && typeof exports === 'object') { module.exports = marked; } else if (typeof define === 'function' && define.amd) { define(function() { return marked; });