@ -1,6 +1,6 @@
/ * *
* marked - a markdown parser
* Copyright ( c ) 2011 - 201 3 , Christopher Jeffrey . ( MIT Licensed )
* marked - a markdown parser - v0 . 3.3
* Copyright ( c ) 2011 - 201 4 , 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 : /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\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' , /<!--[\s\S]*?-->/ )
@ -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 += '<a href="'
+ href
+ '">'
+ text
+ '</a>' ;
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 += '<a href="'
+ href
+ '">'
+ text
+ '</a>' ;
out += this . renderer . link ( href , null , text ) ;
continue ;
}
// tag
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 ) ;
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 += '<strong>'
+ this . output ( cap [ 2 ] || cap [ 1 ] )
+ '</strong>' ;
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 += '<em>'
+ this . output ( cap [ 2 ] || cap [ 1 ] )
+ '</em>' ;
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 += '<code>'
+ escape ( cap [ 2 ] , true )
+ '</code>' ;
out += this . renderer . codespan ( escape ( cap [ 2 ] , true ) ) ;
continue ;
}
// br
if ( cap = this . rules . br . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += '<br>' ;
out += this . renderer . br ( ) ;
continue ;
}
// del (gfm)
if ( cap = this . rules . del . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += '<del>'
+ this . output ( cap [ 1 ] )
+ '</del>' ;
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 '<a href="'
+ escape ( link . href )
+ '"'
+ ( link . title
? ' title="'
+ escape ( link . title )
+ '"'
: '' )
+ '>'
+ this . output ( cap [ 1 ] )
+ '</a>' ;
} else {
return '<img src="'
+ escape ( link . href )
+ '" alt="'
+ escape ( cap [ 1 ] )
+ '"'
+ ( link . title
? ' title="'
+ escape ( link . title )
+ '"'
: '' )
+ '>' ;
}
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 '<pre><code>'
+ ( escaped ? code : escape ( code , true ) )
+ '\n</code></pre>' ;
}
return '<pre><code class="'
+ this . options . langPrefix
+ escape ( lang , true )
+ '">'
+ ( escaped ? code : escape ( code , true ) )
+ '\n</code></pre>\n' ;
} ;
Renderer . prototype . blockquote = function ( quote ) {
return '<blockquote>\n' + quote + '</blockquote>\n' ;
} ;
Renderer . prototype . html = function ( html ) {
return html ;
} ;
Renderer . prototype . heading = function ( text , level , raw ) {
return '<h'
+ level
+ ' id="'
+ this . options . headerPrefix
+ raw . toLowerCase ( ) . replace ( /[^\w]+/g , '-' )
+ '">'
+ text
+ '</h'
+ level
+ '>\n' ;
} ;
Renderer . prototype . hr = function ( ) {
return this . options . xhtml ? '<hr/>\n' : '<hr>\n' ;
} ;
Renderer . prototype . list = function ( body , ordered ) {
var type = ordered ? 'ol' : 'ul' ;
return '<' + type + '>\n' + body + '</' + type + '>\n' ;
} ;
Renderer . prototype . listitem = function ( text ) {
return '<li>' + text + '</li>\n' ;
} ;
Renderer . prototype . paragraph = function ( text ) {
return '<p>' + text + '</p>\n' ;
} ;
Renderer . prototype . table = function ( header , body ) {
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n' ;
} ;
Renderer . prototype . tablerow = function ( content ) {
return '<tr>\n' + content + '</tr>\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 + '</' + type + '>\n' ;
} ;
// span level renderer
Renderer . prototype . strong = function ( text ) {
return '<strong>' + text + '</strong>' ;
} ;
Renderer . prototype . em = function ( text ) {
return '<em>' + text + '</em>' ;
} ;
Renderer . prototype . codespan = function ( text ) {
return '<code>' + text + '</code>' ;
} ;
Renderer . prototype . br = function ( ) {
return this . options . xhtml ? '<br/>' : '<br>' ;
} ;
Renderer . prototype . del = function ( text ) {
return '<del>' + text + '</del>' ;
} ;
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 = '<a href="' + href + '"' ;
if ( title ) {
out += ' title="' + title + '"' ;
}
out += '>' + text + '</a>' ;
return out ;
} ;
Renderer . prototype . image = function ( href , title , text ) {
var out = '<img src="' + href + '" alt="' + text + '"' ;
if ( title ) {
out += ' title="' + title + '"' ;
}
out += this . options . xhtml ? '/>' : '>' ;
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 '<hr>\n' ;
return this . renderer . hr ( ) ;
}
case 'heading' : {
return '<h'
+ this . token . depth
+ ' id="'
+ this . token . text . toLowerCase ( ) . replace ( /[^\w]+/g , '-' )
+ '">'
+ this . inline . output ( this . token . text )
+ '</h'
+ this . token . depth
+ '>\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 '<pre><code'
+ ( this . token . lang
? ' class="'
+ this . options . langPrefix
+ this . token . lang
+ '"'
: '' )
+ '>'
+ this . token . text
+ '</code></pre>\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 += '<thead>\n<tr>\n ';
cell = '' ;
for ( i = 0 ; i < this . token . header . length ; i ++ ) {
heading = this . inline . output ( this . token . header [ i ] ) ;
body += '<th' ;
if ( this . token . align [ i ] ) {
body += ' style="text-align:' + this . token . align [ i ] + '"' ;
}
body += '>' + heading + '</th>\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 += '</tr>\n</thead>\n' ;
header += this . renderer . tablerow ( cell ) ;
// body
body += '<tbody>\n'
for ( i = 0 ; i < this . token . cells . length ; i ++ ) {
row = this . token . cells [ i ] ;
body += '<tr>\n' ;
cell = '' ;
for ( j = 0 ; j < row . length ; j ++ ) {
cell = this . inline . output ( row [ j ] ) ;
body += '<td' ;
if ( this . token . align [ j ] ) {
body += ' style="text-align:' + this . token . align [ j ] + '"' ;
}
body += '>' + cell + '</td>\n' ;
cell += this . renderer . tablecell (
this . inline . output ( row [ j ] ) ,
{ header : false , align : this . token . align [ j ] }
) ;
}
body += '</tr>\n' ;
}
body += '</tbody>\n' ;
return '<table>\n'
+ body
+ '</table>\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 '<blockquote>\n'
+ body
+ '</blockquote>\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
+ '</'
+ type
+ '>\n' ;
return this . renderer . list ( body , ordered ) ;
}
case 'list_item_start' : {
var body = '' ;
@ -954,9 +1054,7 @@ Parser.prototype.tok = function() {
: this . tok ( ) ;
}
return '<li>'
+ body
+ '</li>\n' ;
return this . renderer . listitem ( body ) ;
}
case 'loose_item_start' : {
var body = '' ;
@ -965,24 +1063,19 @@ Parser.prototype.tok = function() {
body += this . tok ( ) ;
}
return '<li>'
+ body
+ '</li>\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 '<p>'
+ this . inline . output ( this . token . text )
+ '</p>\n' ;
return this . renderer . paragraph ( this . inline . output ( this . token . text ) ) ;
}
case 'text' : {
return '<p>'
+ this . parseText ( )
+ '</p>\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 ; } ) ;