|
|
|
@ -1,6 +1,6 @@ |
|
|
|
/** |
|
|
|
/** |
|
|
|
* marked - a markdown parser |
|
|
|
* marked - a markdown parser |
|
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) |
|
|
|
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) |
|
|
|
* https://github.com/chjj/marked
|
|
|
|
* https://github.com/chjj/marked
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@ -18,9 +18,9 @@ var block = { |
|
|
|
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, |
|
|
|
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, |
|
|
|
nptable: noop, |
|
|
|
nptable: noop, |
|
|
|
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, |
|
|
|
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, |
|
|
|
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, |
|
|
|
blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, |
|
|
|
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, |
|
|
|
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, |
|
|
|
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, |
|
|
|
html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, |
|
|
|
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, |
|
|
|
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, |
|
|
|
table: noop, |
|
|
|
table: noop, |
|
|
|
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, |
|
|
|
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) |
|
|
|
block.list = replace(block.list) |
|
|
|
(/bull/g, block.bullet) |
|
|
|
(/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 = '(?!(?:' |
|
|
|
block._tag = '(?!(?:' |
|
|
|
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' |
|
|
|
+ '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' |
|
|
|
+ '|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) |
|
|
|
block.html = replace(block.html) |
|
|
|
('comment', /<!--[\s\S]*?-->/) |
|
|
|
('comment', /<!--[\s\S]*?-->/) |
|
|
|
@ -141,7 +146,7 @@ Lexer.prototype.lex = function(src) { |
|
|
|
* Lexing |
|
|
|
* Lexing |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
Lexer.prototype.token = function(src, top) { |
|
|
|
Lexer.prototype.token = function(src, top, bq) { |
|
|
|
var src = src.replace(/^ +$/gm, '') |
|
|
|
var src = src.replace(/^ +$/gm, '') |
|
|
|
, next |
|
|
|
, next |
|
|
|
, loose |
|
|
|
, loose |
|
|
|
@ -264,7 +269,7 @@ Lexer.prototype.token = function(src, top) { |
|
|
|
// Pass `top` to keep the current
|
|
|
|
// Pass `top` to keep the current
|
|
|
|
// "toplevel" state. This is exactly
|
|
|
|
// "toplevel" state. This is exactly
|
|
|
|
// how markdown.pl works.
|
|
|
|
// how markdown.pl works.
|
|
|
|
this.token(cap, top); |
|
|
|
this.token(cap, top, true); |
|
|
|
|
|
|
|
|
|
|
|
this.tokens.push({ |
|
|
|
this.tokens.push({ |
|
|
|
type: 'blockquote_end' |
|
|
|
type: 'blockquote_end' |
|
|
|
@ -333,7 +338,7 @@ Lexer.prototype.token = function(src, top) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Recurse.
|
|
|
|
// Recurse.
|
|
|
|
this.token(item, false); |
|
|
|
this.token(item, false, bq); |
|
|
|
|
|
|
|
|
|
|
|
this.tokens.push({ |
|
|
|
this.tokens.push({ |
|
|
|
type: 'list_item_end' |
|
|
|
type: 'list_item_end' |
|
|
|
@ -361,7 +366,7 @@ Lexer.prototype.token = function(src, top) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// def
|
|
|
|
// def
|
|
|
|
if (top && (cap = this.rules.def.exec(src))) { |
|
|
|
if ((!bq && top) && (cap = this.rules.def.exec(src))) { |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
this.tokens.links[cap[1].toLowerCase()] = { |
|
|
|
this.tokens.links[cap[1].toLowerCase()] = { |
|
|
|
href: cap[2], |
|
|
|
href: cap[2], |
|
|
|
@ -515,6 +520,7 @@ function InlineLexer(links, options) { |
|
|
|
this.links = links; |
|
|
|
this.links = links; |
|
|
|
this.rules = inline.normal; |
|
|
|
this.rules = inline.normal; |
|
|
|
this.renderer = this.options.renderer || new Renderer; |
|
|
|
this.renderer = this.options.renderer || new Renderer; |
|
|
|
|
|
|
|
this.renderer.options = this.options; |
|
|
|
|
|
|
|
|
|
|
|
if (!this.links) { |
|
|
|
if (!this.links) { |
|
|
|
throw new |
|
|
|
throw new |
|
|
|
@ -583,7 +589,7 @@ InlineLexer.prototype.output = function(src) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// url (gfm)
|
|
|
|
// url (gfm)
|
|
|
|
if (cap = this.rules.url.exec(src)) { |
|
|
|
if (!this.inLink && (cap = this.rules.url.exec(src))) { |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
text = escape(cap[1]); |
|
|
|
text = escape(cap[1]); |
|
|
|
href = text; |
|
|
|
href = text; |
|
|
|
@ -593,6 +599,11 @@ InlineLexer.prototype.output = function(src) { |
|
|
|
|
|
|
|
|
|
|
|
// tag
|
|
|
|
// tag
|
|
|
|
if (cap = this.rules.tag.exec(src)) { |
|
|
|
if (cap = this.rules.tag.exec(src)) { |
|
|
|
|
|
|
|
if (!this.inLink && /^<a /i.test(cap[0])) { |
|
|
|
|
|
|
|
this.inLink = true; |
|
|
|
|
|
|
|
} else if (this.inLink && /^<\/a>/i.test(cap[0])) { |
|
|
|
|
|
|
|
this.inLink = false; |
|
|
|
|
|
|
|
} |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
out += this.options.sanitize |
|
|
|
out += this.options.sanitize |
|
|
|
? escape(cap[0]) |
|
|
|
? escape(cap[0]) |
|
|
|
@ -603,10 +614,12 @@ InlineLexer.prototype.output = function(src) { |
|
|
|
// link
|
|
|
|
// link
|
|
|
|
if (cap = this.rules.link.exec(src)) { |
|
|
|
if (cap = this.rules.link.exec(src)) { |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
src = src.substring(cap[0].length); |
|
|
|
|
|
|
|
this.inLink = true; |
|
|
|
out += this.outputLink(cap, { |
|
|
|
out += this.outputLink(cap, { |
|
|
|
href: cap[2], |
|
|
|
href: cap[2], |
|
|
|
title: cap[3] |
|
|
|
title: cap[3] |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
this.inLink = false; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -621,7 +634,9 @@ InlineLexer.prototype.output = function(src) { |
|
|
|
src = cap[0].substring(1) + src; |
|
|
|
src = cap[0].substring(1) + src; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.inLink = true; |
|
|
|
out += this.outputLink(cap, link); |
|
|
|
out += this.outputLink(cap, link); |
|
|
|
|
|
|
|
this.inLink = false; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -735,13 +750,13 @@ InlineLexer.prototype.mangle = function(text) { |
|
|
|
* Renderer |
|
|
|
* Renderer |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
function Renderer() {} |
|
|
|
function Renderer(options) { |
|
|
|
|
|
|
|
this.options = options || {}; |
|
|
|
Renderer.prototype.code = function(code, lang, escaped, options) { |
|
|
|
} |
|
|
|
options = options || {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (options.highlight) { |
|
|
|
Renderer.prototype.code = function(code, lang, escaped) { |
|
|
|
var out = options.highlight(code, lang); |
|
|
|
if (this.options.highlight) { |
|
|
|
|
|
|
|
var out = this.options.highlight(code, lang); |
|
|
|
if (out != null && out !== code) { |
|
|
|
if (out != null && out !== code) { |
|
|
|
escaped = true; |
|
|
|
escaped = true; |
|
|
|
code = out; |
|
|
|
code = out; |
|
|
|
@ -755,10 +770,10 @@ Renderer.prototype.code = function(code, lang, escaped, options) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return '<pre><code class="' |
|
|
|
return '<pre><code class="' |
|
|
|
+ options.langPrefix |
|
|
|
+ this.options.langPrefix |
|
|
|
+ lang |
|
|
|
+ escape(lang, true) |
|
|
|
+ '">' |
|
|
|
+ '">' |
|
|
|
+ (escaped ? code : escape(code)) |
|
|
|
+ (escaped ? code : escape(code, true)) |
|
|
|
+ '\n</code></pre>\n'; |
|
|
|
+ '\n</code></pre>\n'; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -770,11 +785,11 @@ Renderer.prototype.html = function(html) { |
|
|
|
return html; |
|
|
|
return html; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.heading = function(text, level, raw, options) { |
|
|
|
Renderer.prototype.heading = function(text, level, raw) { |
|
|
|
return '<h' |
|
|
|
return '<h' |
|
|
|
+ level |
|
|
|
+ level |
|
|
|
+ ' id="' |
|
|
|
+ ' id="' |
|
|
|
+ options.headerPrefix |
|
|
|
+ this.options.headerPrefix |
|
|
|
+ raw.toLowerCase().replace(/[^\w]+/g, '-') |
|
|
|
+ raw.toLowerCase().replace(/[^\w]+/g, '-') |
|
|
|
+ '">' |
|
|
|
+ '">' |
|
|
|
+ text |
|
|
|
+ text |
|
|
|
@ -784,7 +799,7 @@ Renderer.prototype.heading = function(text, level, raw, options) { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.hr = function() { |
|
|
|
Renderer.prototype.hr = function() { |
|
|
|
return '<hr>\n'; |
|
|
|
return this.options.xhtml ? '<hr/>\n' : '<hr>\n'; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.list = function(body, ordered) { |
|
|
|
Renderer.prototype.list = function(body, ordered) { |
|
|
|
@ -837,7 +852,7 @@ Renderer.prototype.codespan = function(text) { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.br = function() { |
|
|
|
Renderer.prototype.br = function() { |
|
|
|
return '<br>'; |
|
|
|
return this.options.xhtml ? '<br/>' : '<br>'; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.del = function(text) { |
|
|
|
Renderer.prototype.del = function(text) { |
|
|
|
@ -845,6 +860,18 @@ Renderer.prototype.del = function(text) { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Renderer.prototype.link = function(href, title, 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) { |
|
|
|
|
|
|
|
return ''; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
var out = '<a href="' + href + '"'; |
|
|
|
var out = '<a href="' + href + '"'; |
|
|
|
if (title) { |
|
|
|
if (title) { |
|
|
|
out += ' title="' + title + '"'; |
|
|
|
out += ' title="' + title + '"'; |
|
|
|
@ -858,7 +885,7 @@ Renderer.prototype.image = function(href, title, text) { |
|
|
|
if (title) { |
|
|
|
if (title) { |
|
|
|
out += ' title="' + title + '"'; |
|
|
|
out += ' title="' + title + '"'; |
|
|
|
} |
|
|
|
} |
|
|
|
out += '>'; |
|
|
|
out += this.options.xhtml ? '/>' : '>'; |
|
|
|
return out; |
|
|
|
return out; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -872,6 +899,7 @@ function Parser(options) { |
|
|
|
this.options = options || marked.defaults; |
|
|
|
this.options = options || marked.defaults; |
|
|
|
this.options.renderer = this.options.renderer || new Renderer; |
|
|
|
this.options.renderer = this.options.renderer || new Renderer; |
|
|
|
this.renderer = this.options.renderer; |
|
|
|
this.renderer = this.options.renderer; |
|
|
|
|
|
|
|
this.renderer.options = this.options; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -945,15 +973,12 @@ Parser.prototype.tok = function() { |
|
|
|
return this.renderer.heading( |
|
|
|
return this.renderer.heading( |
|
|
|
this.inline.output(this.token.text), |
|
|
|
this.inline.output(this.token.text), |
|
|
|
this.token.depth, |
|
|
|
this.token.depth, |
|
|
|
this.token.text, |
|
|
|
this.token.text); |
|
|
|
this.options |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
case 'code': { |
|
|
|
case 'code': { |
|
|
|
return this.renderer.code(this.token.text, |
|
|
|
return this.renderer.code(this.token.text, |
|
|
|
this.token.lang, |
|
|
|
this.token.lang, |
|
|
|
this.token.escaped, |
|
|
|
this.token.escaped); |
|
|
|
this.options); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
case 'table': { |
|
|
|
case 'table': { |
|
|
|
var header = '' |
|
|
|
var header = '' |
|
|
|
@ -1057,6 +1082,19 @@ function escape(html, encode) { |
|
|
|
.replace(/'/g, '''); |
|
|
|
.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) { |
|
|
|
function replace(regex, opt) { |
|
|
|
regex = regex.source; |
|
|
|
regex = regex.source; |
|
|
|
opt = opt || ''; |
|
|
|
opt = opt || ''; |
|
|
|
@ -1116,8 +1154,13 @@ function marked(src, opt, callback) { |
|
|
|
|
|
|
|
|
|
|
|
pending = tokens.length; |
|
|
|
pending = tokens.length; |
|
|
|
|
|
|
|
|
|
|
|
var done = function() { |
|
|
|
var done = function(err) { |
|
|
|
var out, err; |
|
|
|
if (err) { |
|
|
|
|
|
|
|
opt.highlight = highlight; |
|
|
|
|
|
|
|
return callback(err); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var out; |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
out = Parser.parse(tokens, opt); |
|
|
|
out = Parser.parse(tokens, opt); |
|
|
|
@ -1146,6 +1189,7 @@ function marked(src, opt, callback) { |
|
|
|
return --pending || done(); |
|
|
|
return --pending || done(); |
|
|
|
} |
|
|
|
} |
|
|
|
return highlight(token.text, token.lang, function(err, code) { |
|
|
|
return highlight(token.text, token.lang, function(err, code) { |
|
|
|
|
|
|
|
if (err) return done(err); |
|
|
|
if (code == null || code === token.text) { |
|
|
|
if (code == null || code === token.text) { |
|
|
|
return --pending || done(); |
|
|
|
return --pending || done(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -1194,7 +1238,8 @@ marked.defaults = { |
|
|
|
langPrefix: 'lang-', |
|
|
|
langPrefix: 'lang-', |
|
|
|
smartypants: false, |
|
|
|
smartypants: false, |
|
|
|
headerPrefix: '', |
|
|
|
headerPrefix: '', |
|
|
|
renderer: new Renderer |
|
|
|
renderer: new Renderer, |
|
|
|
|
|
|
|
xhtml: false |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -1214,7 +1259,7 @@ marked.inlineLexer = InlineLexer.output; |
|
|
|
|
|
|
|
|
|
|
|
marked.parse = marked; |
|
|
|
marked.parse = marked; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof exports === 'object') { |
|
|
|
if (typeof module !== 'undefined' && typeof exports === 'object') { |
|
|
|
module.exports = marked; |
|
|
|
module.exports = marked; |
|
|
|
} else if (typeof define === 'function' && define.amd) { |
|
|
|
} else if (typeof define === 'function' && define.amd) { |
|
|
|
define(function() { return marked; }); |
|
|
|
define(function() { return marked; }); |
|
|
|
|