1/** 2 * marked - a markdown parser 3 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) 4 * https://github.com/chjj/marked 5 */ 6 7;(function() { 8 9/** 10 * Block-Level Grammar 11 */ 12 13var block = { 14 newline: /^\n+/, 15 code: /^( {4}[^\n]+\n*)+/, 16 fences: noop, 17 hr: /^( *[-*_]){3,} *(?:\n+|$)/, 18 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, 19 nptable: noop, 20 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, 21 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, 22 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, 23 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, 24 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, 25 table: noop, 26 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, 27 text: /^[^\n]+/ 28}; 29 30block.bullet = /(?:[*+-]|\d+\.)/; 31block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; 32block.item = replace(block.item, 'gm') 33 (/bull/g, block.bullet) 34 (); 35 36block.list = replace(block.list) 37 (/bull/g, block.bullet) 38 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') 39 ('def', '\\n+(?=' + block.def.source + ')') 40 (); 41 42block.blockquote = replace(block.blockquote) 43 ('def', block.def) 44 (); 45 46block._tag = '(?!(?:' 47 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' 48 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' 49 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b'; 50 51block.html = replace(block.html) 52 ('comment', /<!--[\s\S]*?-->/) 53 ('closed', /<(tag)[\s\S]+?<\/\1>/) 54 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/) 55 (/tag/g, block._tag) 56 (); 57 58block.paragraph = replace(block.paragraph) 59 ('hr', block.hr) 60 ('heading', block.heading) 61 ('lheading', block.lheading) 62 ('blockquote', block.blockquote) 63 ('tag', '<' + block._tag) 64 ('def', block.def) 65 (); 66 67/** 68 * Normal Block Grammar 69 */ 70 71block.normal = merge({}, block); 72 73/** 74 * GFM Block Grammar 75 */ 76 77block.gfm = merge({}, block.normal, { 78 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/, 79 paragraph: /^/, 80 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ 81}); 82 83block.gfm.paragraph = replace(block.paragraph) 84 ('(?!', '(?!' 85 + block.gfm.fences.source.replace('\\1', '\\2') + '|' 86 + block.list.source.replace('\\1', '\\3') + '|') 87 (); 88 89/** 90 * GFM + Tables Block Grammar 91 */ 92 93block.tables = merge({}, block.gfm, { 94 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, 95 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ 96}); 97 98/** 99 * Block Lexer 100 */ 101 102function Lexer(options) { 103 this.tokens = []; 104 this.tokens.links = {}; 105 this.options = options || marked.defaults; 106 this.rules = block.normal; 107 108 if (this.options.gfm) { 109 if (this.options.tables) { 110 this.rules = block.tables; 111 } else { 112 this.rules = block.gfm; 113 } 114 } 115} 116 117/** 118 * Expose Block Rules 119 */ 120 121Lexer.rules = block; 122 123/** 124 * Static Lex Method 125 */ 126 127Lexer.lex = function(src, options) { 128 var lexer = new Lexer(options); 129 return lexer.lex(src); 130}; 131 132/** 133 * Preprocessing 134 */ 135 136Lexer.prototype.lex = function(src) { 137 src = src 138 .replace(/\r\n|\r/g, '\n') 139 .replace(/\t/g, ' ') 140 .replace(/\u00a0/g, ' ') 141 .replace(/\u2424/g, '\n'); 142 143 return this.token(src, true); 144}; 145 146/** 147 * Lexing 148 */ 149 150Lexer.prototype.token = function(src, top, bq) { 151 var src = src.replace(/^ +$/gm, '') 152 , next 153 , loose 154 , cap 155 , bull 156 , b 157 , item 158 , space 159 , i 160 , l; 161 162 while (src) { 163 // newline 164 if (cap = this.rules.newline.exec(src)) { 165 src = src.substring(cap[0].length); 166 if (cap[0].length > 1) { 167 this.tokens.push({ 168 type: 'space' 169 }); 170 } 171 } 172 173 // code 174 if (cap = this.rules.code.exec(src)) { 175 src = src.substring(cap[0].length); 176 cap = cap[0].replace(/^ {4}/gm, ''); 177 this.tokens.push({ 178 type: 'code', 179 text: !this.options.pedantic 180 ? cap.replace(/\n+$/, '') 181 : cap 182 }); 183 continue; 184 } 185 186 // fences (gfm) 187 if (cap = this.rules.fences.exec(src)) { 188 src = src.substring(cap[0].length); 189 this.tokens.push({ 190 type: 'code', 191 lang: cap[2], 192 text: cap[3] || '' 193 }); 194 continue; 195 } 196 197 // heading 198 if (cap = this.rules.heading.exec(src)) { 199 src = src.substring(cap[0].length); 200 this.tokens.push({ 201 type: 'heading', 202 depth: cap[1].length, 203 text: cap[2] 204 }); 205 continue; 206 } 207 208 // table no leading pipe (gfm) 209 if (top && (cap = this.rules.nptable.exec(src))) { 210 src = src.substring(cap[0].length); 211 212 item = { 213 type: 'table', 214 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), 215 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), 216 cells: cap[3].replace(/\n$/, '').split('\n') 217 }; 218 219 for (i = 0; i < item.align.length; i++) { 220 if (/^ *-+: *$/.test(item.align[i])) { 221 item.align[i] = 'right'; 222 } else if (/^ *:-+: *$/.test(item.align[i])) { 223 item.align[i] = 'center'; 224 } else if (/^ *:-+ *$/.test(item.align[i])) { 225 item.align[i] = 'left'; 226 } else { 227 item.align[i] = null; 228 } 229 } 230 231 for (i = 0; i < item.cells.length; i++) { 232 item.cells[i] = item.cells[i].split(/ *\| */); 233 } 234 235 this.tokens.push(item); 236 237 continue; 238 } 239 240 // lheading 241 if (cap = this.rules.lheading.exec(src)) { 242 src = src.substring(cap[0].length); 243 this.tokens.push({ 244 type: 'heading', 245 depth: cap[2] === '=' ? 1 : 2, 246 text: cap[1] 247 }); 248 continue; 249 } 250 251 // hr 252 if (cap = this.rules.hr.exec(src)) { 253 src = src.substring(cap[0].length); 254 this.tokens.push({ 255 type: 'hr' 256 }); 257 continue; 258 } 259 260 // blockquote 261 if (cap = this.rules.blockquote.exec(src)) { 262 src = src.substring(cap[0].length); 263 264 this.tokens.push({ 265 type: 'blockquote_start' 266 }); 267 268 cap = cap[0].replace(/^ *> ?/gm, ''); 269 270 // Pass `top` to keep the current 271 // "toplevel" state. This is exactly 272 // how markdown.pl works. 273 this.token(cap, top, true); 274 275 this.tokens.push({ 276 type: 'blockquote_end' 277 }); 278 279 continue; 280 } 281 282 // list 283 if (cap = this.rules.list.exec(src)) { 284 src = src.substring(cap[0].length); 285 bull = cap[2]; 286 287 this.tokens.push({ 288 type: 'list_start', 289 ordered: bull.length > 1 290 }); 291 292 // Get each top-level item. 293 cap = cap[0].match(this.rules.item); 294 295 next = false;
296 l = cap.length; 297 i = 0; 298 299 for (; i < l; i++) { 300 item = cap[i]; 301 302 // Remove the list item's bullet 303 // so it is seen as the next token. 304 space = item.length; 305 item = item.replace(/^ *([*+-]|\d+\.) +/, ''); 306 307 // Outdent whatever the 308 // list item contains. Hacky. 309 if (~item.indexOf('\n ')) { 310 space -= item.length; 311 item = !this.options.pedantic 312 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') 313 : item.replace(/^ {1,4}/gm, ''); 314 } 315 316 // Determine whether the next list item belongs here. 317 // Backpedal if it does not belong in this list. 318 if (this.options.smartLists && i !== l - 1) { 319 b = block.bullet.exec(cap[i + 1])[0]; 320 if (bull !== b && !(bull.length > 1 && b.length > 1)) { 321 src = cap.slice(i + 1).join('\n') + src; 322 i = l - 1; 323 } 324 } 325 326 // Determine whether item is loose or not. 327 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ 328 // for discount behavior. 329 loose = next || /\n\n(?!\s*$)/.test(item); 330 if (i !== l - 1) { 331 next = item.charAt(item.length - 1) === '\n'; 332 if (!loose) loose = next; 333 } 334 335 this.tokens.push({ 336 type: loose 337 ? 'loose_item_start' 338 : 'list_item_start' 339 }); 340 341 // Recurse. 342 this.token(item, false, bq); 343 344 this.tokens.push({ 345 type: 'list_item_end' 346 }); 347 } 348 349 this.tokens.push({ 350 type: 'list_end' 351 }); 352 353 continue; 354 } 355 356 // html 357 if (cap = this.rules.html.exec(src)) { 358 src = src.substring(cap[0].length); 359 this.tokens.push({ 360 type: this.options.sanitize 361 ? 'paragraph' 362 : 'html', 363 pre: !this.options.sanitizer 364 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), 365 text: cap[0] 366 }); 367 continue; 368 } 369 370 // def 371 if ((!bq && top) && (cap = this.rules.def.exec(src))) { 372 src = src.substring(cap[0].length); 373 this.tokens.links[cap[1].toLowerCase()] = { 374 href: cap[2], 375 title: cap[3] 376 }; 377 continue; 378 } 379 380 // table (gfm) 381 if (top && (cap = this.rules.table.exec(src))) { 382 src = src.substring(cap[0].length); 383 384 item = { 385 type: 'table', 386 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), 387 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), 388 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') 389 }; 390 391 for (i = 0; i < item.align.length; i++) { 392 if (/^ *-+: *$/.test(item.align[i])) { 393 item.align[i] = 'right'; 394 } else if (/^ *:-+: *$/.test(item.align[i])) { 395 item.align[i] = 'center'; 396 } else if (/^ *:-+ *$/.test(item.align[i])) { 397 item.align[i] = 'left'; 398 } else { 399 item.align[i] = null; 400 } 401 } 402 403 for (i = 0; i < item.cells.length; i++) { 404 item.cells[i] = item.cells[i] 405 .replace(/^ *\| *| *\| *$/g, '') 406 .split(/ *\| */); 407 } 408 409 this.tokens.push(item); 410 411 continue; 412 } 413 414 // top-level paragraph 415 if (top && (cap = this.rules.paragraph.exec(src))) { 416 src = src.substring(cap[0].length); 417 this.tokens.push({ 418 type: 'paragraph', 419 text: cap[1].charAt(cap[1].length - 1) === '\n' 420 ? cap[1].slice(0, -1) 421 : cap[1] 422 }); 423 continue; 424 } 425 426 // text 427 if (cap = this.rules.text.exec(src)) { 428 // Top-level should never reach here. 429 src = src.substring(cap[0].length); 430 this.tokens.push({ 431 type: 'text', 432 text: cap[0] 433 }); 434 continue; 435 } 436 437 if (src) { 438 throw new 439 Error('Infinite loop on byte: ' + src.charCodeAt(0)); 440 } 441 } 442 443 return this.tokens; 444}; 445 446/** 447 * Inline-Level Grammar 448 */ 449 450var inline = { 451 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, 452 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, 453 url: noop, 454 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, 455 link: /^!?\[(inside)\]\(href\)/, 456 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, 457 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, 458 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, 459 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, 460 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, 461 br: /^ {2,}\n(?!\s*$)/, 462 del: noop, 463 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/ 464}; 465 466inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/; 467inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/; 468 469inline.link = replace(inline.link) 470 ('inside', inline._inside) 471 ('href', inline._href) 472 (); 473 474inline.reflink = replace(inline.reflink) 475 ('inside', inline._inside) 476 (); 477 478/** 479 * Normal Inline Grammar 480 */ 481 482inline.normal = merge({}, inline); 483 484/** 485 * Pedantic Inline Grammar 486 */ 487 488inline.pedantic = merge({}, inline.normal, { 489 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, 490 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ 491}); 492 493/** 494 * GFM Inline Grammar 495 */ 496 497inline.gfm = merge({}, inline.normal, { 498 escape: replace(inline.escape)('])', '~|])')(), 499 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, 500 del: /^~~(?=\S)([\s\S]*?\S)~~/, 501 text: replace(inline.text) 502 (']|', '~]|') 503 ('|', '|https?://|') 504 () 505}); 506 507/** 508 * GFM + Line Breaks Inline Grammar 509 */ 510 511inline.breaks = merge({}, inline.gfm, { 512 br: replace(inline.br)('{2,}', '*')(), 513 text: replace(inline.gfm.text)('{2,}', '*')() 514}); 515 516/** 517 * Inline Lexer & Compiler 518 */ 519 520function InlineLexer(links, options) { 521 this.options = options || marked.defaults; 522 this.links = links; 523 this.rules = inline.normal; 524 this.renderer = this.options.renderer || new Renderer; 525 this.renderer.options = this.options; 526 527 if (!this.links) { 528 throw new 529 Error('Tokens array requires a `links` property.'); 530 } 531 532 if (this.options.gfm) { 533 if (this.options.breaks) { 534 this.rules = inline.breaks; 535 } else { 536 this.rules = inline.gfm; 537 } 538 } else if (this.options.pedantic) { 539 this.rules = inline.pedantic; 540 } 541} 542 543/** 544 * Expose Inline Rules 545 */ 546 547InlineLexer.rules = inline; 548 549/** 550 * Static Lexing/Compiling Method 551 */ 552 553InlineLexer.output = function(src, links, options) { 554 var inline = new InlineLexer(links, options); 555 return inline.output(src); 556}; 557 558/** 559 * Lexing/Compiling 560 */ 561 562InlineLexer.prototype.output = function(src) { 563 var out = '' 564 , link 565 , text 566 , href 567 , cap; 568 569 while (src) { 570 // escape 571 if (cap = this.rules.escape.exec(src)) { 572 src = src.substring(cap[0].length); 573 out += cap[1]; 574 continue; 575 } 576 577 // autolink 578 if (cap = this.rules.autolink.exec(src)) { 579 src = src.substring(cap[0].length); 580 if (cap[2] === '@') { 581 text = cap[1].charAt(6) === ':' 582 ? this.mangle(cap[1].substring(7)) 583 : this.mangle(cap[1]); 584 href = this.mangle('mailto:') + text; 585 } else { 586 text = escape(cap[1]); 587 href = text; 588 } 589 out += this.renderer.link(href, null, text); 590 continue; 591 } 592 593 // url (gfm) 594 if (!this.inLink && (cap = this.rules.url.exec(src))) { 595 src = src.substring(cap[0].length); 596 text = escape(cap[1]); 597 href = text; 598 out += this.renderer.link(href, null, text); 599 continue; 600 } 601 602 // tag 603 if (cap = this.rules.tag.exec(src)) { 604 if (!this.inLink && /^<a /i.test(cap[0])) { 605 this.inLink = true; 606 } else if (this.inLink && /^<\/a>/i.test(cap[0])) { 607 this.inLink = false;
608 } 609 src = src.substring(cap[0].length); 610 out += this.options.sanitize 611 ? this.options.sanitizer 612 ? this.options.sanitizer(cap[0]) 613 : escape(cap[0]) 614 : cap[0] 615 continue; 616 } 617 618 // link 619 if (cap = this.rules.link.exec(src)) { 620 src = src.substring(cap[0].length); 621 this.inLink = true; 622 out += this.outputLink(cap, { 623 href: cap[2], 624 title: cap[3] 625 }); 626 this.inLink = false; 627 continue; 628 } 629 630 // reflink, nolink 631 if ((cap = this.rules.reflink.exec(src)) 632 || (cap = this.rules.nolink.exec(src))) { 633 src = src.substring(cap[0].length); 634 link = (cap[2] || cap[1]).replace(/\s+/g, ' '); 635 link = this.links[link.toLowerCase()]; 636 if (!link || !link.href) { 637 out += cap[0].charAt(0); 638 src = cap[0].substring(1) + src; 639 continue; 640 } 641 this.inLink = true; 642 out += this.outputLink(cap, link); 643 this.inLink = false; 644 continue; 645 } 646 647 // strong 648 if (cap = this.rules.strong.exec(src)) { 649 src = src.substring(cap[0].length); 650 out += this.renderer.strong(this.output(cap[2] || cap[1])); 651 continue; 652 } 653 654 // em 655 if (cap = this.rules.em.exec(src)) { 656 src = src.substring(cap[0].length); 657 out += this.renderer.em(this.output(cap[2] || cap[1])); 658 continue; 659 } 660 661 // code 662 if (cap = this.rules.code.exec(src)) { 663 src = src.substring(cap[0].length); 664 out += this.renderer.codespan(escape(cap[2], true)); 665 continue; 666 } 667 668 // br 669 if (cap = this.rules.br.exec(src)) { 670 src = src.substring(cap[0].length); 671 out += this.renderer.br(); 672 continue; 673 } 674 675 // del (gfm) 676 if (cap = this.rules.del.exec(src)) { 677 src = src.substring(cap[0].length); 678 out += this.renderer.del(this.output(cap[1])); 679 continue; 680 } 681 682 // text 683 if (cap = this.rules.text.exec(src)) { 684 src = src.substring(cap[0].length); 685 out += this.renderer.text(escape(this.smartypants(cap[0]))); 686 continue; 687 } 688 689 if (src) { 690 throw new 691 Error('Infinite loop on byte: ' + src.charCodeAt(0)); 692 } 693 } 694 695 return out; 696}; 697 698/** 699 * Compile Link 700 */ 701 702InlineLexer.prototype.outputLink = function(cap, link) { 703 var href = escape(link.href) 704 , title = link.title ? escape(link.title) : null; 705 706 return cap[0].charAt(0) !== '!' 707 ? this.renderer.link(href, title, this.output(cap[1])) 708 : this.renderer.image(href, title, escape(cap[1])); 709}; 710 711/** 712 * Smartypants Transformations 713 */ 714 715InlineLexer.prototype.smartypants = function(text) { 716 if (!this.options.smartypants) return text; 717 return text 718 // em-dashes 719 .replace(/---/g, '\u2014') 720 // en-dashes 721 .replace(/--/g, '\u2013') 722 // opening singles 723 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') 724 // closing singles & apostrophes 725 .replace(/'/g, '\u2019') 726 // opening doubles 727 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') 728 // closing doubles 729 .replace(/"/g, '\u201d') 730 // ellipses 731 .replace(/\.{3}/g, '\u2026'); 732}; 733 734/** 735 * Mangle Links 736 */ 737 738InlineLexer.prototype.mangle = function(text) { 739 if (!this.options.mangle) return text; 740 var out = '' 741 , l = text.length 742 , i = 0 743 , ch; 744 745 for (; i < l; i++) { 746 ch = text.charCodeAt(i); 747 if (Math.random() > 0.5) { 748 ch = 'x' + ch.toString(16); 749 } 750 out += '&#' + ch + ';'; 751 } 752 753 return out; 754}; 755 756/** 757 * Renderer 758 */ 759 760function Renderer(options) { 761 this.options = options || {}; 762} 763 764Renderer.prototype.code = function(code, lang, escaped) { 765 if (this.options.highlight) { 766 var out = this.options.highlight(code, lang); 767 if (out != null && out !== code) { 768 escaped = true; 769 code = out; 770 } 771 } 772 773 if (!lang) { 774 return '<pre><code>' 775 + (escaped ? code : escape(code, true)) 776 + '\n</code></pre>'; 777 } 778 779 return '<pre><code class="' 780 + this.options.langPrefix 781 + escape(lang, true) 782 + '">' 783 + (escaped ? code : escape(code, true)) 784 + '\n</code></pre>\n'; 785}; 786 787Renderer.prototype.blockquote = function(quote) { 788 return '<blockquote>\n' + quote + '</blockquote>\n'; 789}; 790 791Renderer.prototype.html = function(html) { 792 return html; 793}; 794 795Renderer.prototype.heading = function(text, level, raw) { 796 return '<h' 797 + level 798 + ' id="' 799 + this.options.headerPrefix 800 + raw.toLowerCase().replace(/[^\w]+/g, '-') 801 + '">' 802 + text 803 + '</h' 804 + level 805 + '>\n'; 806}; 807 808Renderer.prototype.hr = function() { 809 return this.options.xhtml ? '<hr/>\n' : '<hr>\n'; 810}; 811 812Renderer.prototype.list = function(body, ordered) { 813 var type = ordered ? 'ol' : 'ul'; 814 return '<' + type + '>\n' + body + '</' + type + '>\n'; 815}; 816 817Renderer.prototype.listitem = function(text) { 818 return '<li>
818' + text + '</li>\n'; 819}; 820 821Renderer.prototype.paragraph = function(text) { 822 return '<p>' + text + '</p>\n'; 823}; 824 825Renderer.prototype.table = function(header, body) { 826 return '<table>\n' 827 + '<thead>\n' 828 + header 829 + '</thead>\n' 830 + '<tbody>\n' 831 + body 832 + '</tbody>\n' 833 + '</table>\n'; 834}; 835 836Renderer.prototype.tablerow = function(content) { 837 return '<tr>\n' + content + '</tr>\n'; 838}; 839 840Renderer.prototype.tablecell = function(content, flags) { 841 var type = flags.header ? 'th' : 'td'; 842 var tag = flags.align 843 ? '<' + type + ' style="text-align:' + flags.align + '">' 844 : '<' + type + '>'; 845 return tag + content + '</' + type + '>\n'; 846}; 847 848// span level renderer 849Renderer.prototype.strong = function(text) { 850 return '<strong>' + text + '</strong>'; 851}; 852 853Renderer.prototype.em = function(text) { 854 return '<em>' + text + '</em>'; 855}; 856 857Renderer.prototype.codespan = function(text) { 858 return '<code>' + text + '</code>'; 859}; 860 861Renderer.prototype.br = function() { 862 return this.options.xhtml ? '<br/>' : '<br>'; 863}; 864 865Renderer.prototype.del = function(text) { 866 return '<del>' + text + '</del>'; 867}; 868 869Renderer.prototype.link = function(href, title, text) { 870 if (this.options.sanitize) { 871 try { 872 var prot = decodeURIComponent(unescape(href)) 873 .replace(/[^\w:]/g, '') 874 .toLowerCase(); 875 } catch (e) { 876 return ''; 877 } 878 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) { 879 return ''; 880 } 881 } 882 var out = '<a href="' + href + '"'; 883 if (title) { 884 out += ' title="' + title + '"'; 885 } 886 out += '>
886' + text + '</a>'; 887 return out; 888}; 889 890Renderer.prototype.image = function(href, title, text) { 891 var out = '<img src="' + href + '" alt="' + text + '"'; 892 if (title) { 893 out += ' title="' + title + '"'; 894 } 895 out += this.options.xhtml ? '/>' : '>'; 896 return out; 897}; 898 899Renderer.prototype.text = function(text) { 900 return text; 901}; 902 903/** 904 * Parsing & Compiling 905 */ 906 907function Parser(options) { 908 this.tokens = []; 909 this.token = null; 910 this.options = options || marked.defaults; 911 this.options.renderer = this.options.renderer || new Renderer; 912 this.renderer = this.options.renderer; 913 this.renderer.options = this.options; 914} 915 916/** 917 * Static Parse Method 918 */ 919 920Parser.parse = function(src, options, renderer) { 921 var parser = new Parser(options, renderer); 922 return parser.parse(src); 923}; 924 925/** 926 * Parse Loop 927 */ 928 929Parser.prototype.parse = function(src) { 930 this.inline = new InlineLexer(src.links, this.options, this.renderer); 931 this.tokens = src.reverse(); 932 933 var out = ''; 934 while (this.next()) { 935 out += this.tok(); 936 } 937 938 return out; 939}; 940 941/** 942 * Next Token 943 */ 944 945Parser.prototype.next = function() { 946 return this.token = this.tokens.pop(); 947}; 948 949/** 950 * Preview Next Token 951 */ 952 953Parser.prototype.peek = function() { 954 return this.tokens[this.tokens.length - 1] || 0; 955}; 956 957/** 958 * Parse Text Tokens 959 */ 960 961Parser.prototype.parseText = function() { 962 var body = this.token.text; 963 964 while (this.peek().type === 'text') { 965 body += '\n' + this.next().text; 966 } 967 968 return this.inline.output(body); 969}; 970 971/** 972 * Parse Current Token 973 */ 974 975Parser.prototype.tok = function() { 976 switch (this.token.type) { 977 case 'space': { 978 return ''; 979 } 980 case 'hr': { 981 return this.renderer.hr(); 982 } 983 case 'heading': { 984 return this.renderer.heading( 985 this.inline.output(this.token.text), 986 this.token.depth, 987 this.token.text); 988 } 989 case 'code': { 990 return this.renderer.code(this.token.text, 991 this.token.lang, 992 this.token.escaped); 993 } 994 case 'table': { 995 var header = '' 996 , body = '' 997 , i 998 , row 999 , cell 1000 , flags 1001 , j; 1002 1003 // header 1004 cell = ''; 1005 for (i = 0; i < this.token.header.length; i++) { 1006 flags = { header: true, align: this.token.align[i] }; 1007 cell += this.renderer.tablecell( 1008 this.inline.output(this.token.header[i]), 1009 { header: true, align: this.token.align[i] } 1010 ); 1011 } 1012 header += this.renderer.tablerow(cell); 1013 1014 for (i = 0; i < this.token.cells.length; i++) { 1015 row = this.token.cells[i]; 1016 1017 cell = ''; 1018 for (j = 0; j < row.length; j++) { 1019 cell += this.renderer.tablecell( 1020 this.inline.output(row[j]), 1021 { header: false, align: this.token.align[j] } 1022 ); 1023 } 1024 1025 body += this.renderer.tablerow(cell); 1026 } 1027 return this.renderer.table(header, body); 1028 } 1029 case 'blockquote_start': { 1030 var body = ''; 1031 1032 while (this.next().type !== 'blockquote_end') { 1033 body += this.tok(); 1034 } 1035 1036 return this.renderer.blockquote(body); 1037 } 1038 case 'list_start': { 1039 var body = '' 1040 , ordered = this.token.ordered; 1041 1042 while (this.next().type !== 'list_end') { 1043 body += this.tok(); 1044 } 1045 1046 return this.renderer.list(body, ordered); 1047 } 1048 case 'list_item_start': { 1049 var body = ''; 1050 1051 while (this.next().type !== 'list_item_end') { 1052 body += this.token.type === 'text' 1053 ? this.parseText() 1054 : this.tok(); 1055 } 1056 1057 return this.renderer.listitem(body); 1058 } 1059 case 'loose_item_start': { 1060 var body = ''; 1061 1062 while (this.next().type !== 'list_item_end') { 1063 body += this.tok(); 1064 } 1065 1066 return this.renderer.listitem(body); 1067 } 1068 case 'html': { 1069 var html = !this.token.pre && !this.options.pedantic 1070 ? this.inline.output(this.token.text) 1071 : this.token.text; 1072 return this.renderer.html(html); 1073 } 1074 case 'paragraph': { 1075 return this.renderer.paragraph(this.inline.output(this.token.text)); 1076 } 1077 case 'text': { 1078 return this.renderer.paragraph(this.parseText()); 1079 } 1080 } 1081}; 1082 1083/** 1084 * Helpers 1085 */ 1086 1087function escape(html, encode) { 1088 return html 1089 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') 1090 .replace(/</g, '<') 1091 .replace(/>/g, '>') 1092 .replace(/"/g, '"') 1093 .replace(/'/g, '''); 1094} 1095 1096function unescape(html) { 1097 // explicitly match decimal, hex, and named HTML entities 1098 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) { 1099 n = n.toLowerCase(); 1100 if (n === 'colon') return ':'; 1101 if (n.charAt(0) === '#') { 1102 return n.charAt(1) === 'x' 1103 ? String.fromCharCode(parseInt(n.substring(2), 16)) 1104 : String.fromCharCode(+n.substring(1)); 1105 } 1106 return ''; 1107 }); 1108} 1109 1110function replace(regex, opt) { 1111 regex = regex.source; 1112 opt = opt || ''; 1113 return function self(name, val) { 1114 if (!name) return new RegExp(regex, opt); 1115 val = val.source || val; 1116 val = val.replace(/(^|[^\[])\^/g, '$1'); 1117 regex = regex.replace(name, val); 1118 return self; 1119 }; 1120} 1121 1122function noop() {} 1123noop.exec = noop; 1124 1125function merge(obj) { 1126 var i = 1 1127 , target 1128 , key; 1129 1130 for (; i < arguments.length; i++) { 1131 target = arguments[i]; 1132 for (key in target) { 1133 if (Object.prototype.hasOwnProperty.call(target, key)) { 1134 obj[key] = target[key]; 1135 } 1136 } 1137 } 1138 1139 return obj; 1140} 1141 1142 1143/** 1144 * Marked 1145 */ 1146 1147function marked(src, opt, callback) { 1148 if (callback || typeof opt === 'function') { 1149 if (!callback) { 1150 callback = opt; 1151 opt = null; 1152 } 1153 1154 opt = merge({}, marked.defaults, opt || {}); 1155 1156 var highlight = opt.highlight 1157 , tokens 1158 , pending 1159 , i = 0; 1160 1161 try { 1162 tokens = Lexer.lex(src, opt) 1163 } catch (e) { 1164 return callback(e); 1165 } 1166 1167 pending = tokens.length; 1168 1169 var done = function(err) { 1170 if (err) { 1171 opt.highlight = highlight; 1172 return callback(err); 1173 } 1174 1175 var out; 1176
1177 try { 1178 out = Parser.parse(tokens, opt); 1179 } catch (e) { 1180 err = e; 1181 } 1182 1183 opt.highlight = highlight; 1184 1185 return err 1186 ? callback(err) 1187 : callback(null, out); 1188 }; 1189 1190 if (!highlight || highlight.length < 3) { 1191 return done(); 1192 } 1193 1194 delete opt.highlight; 1195 1196 if (!pending) return done(); 1197 1198 for (; i < tokens.length; i++) { 1199 (function(token) { 1200 if (token.type !== 'code') { 1201 return --pending || done(); 1202 } 1203 return highlight(token.text, token.lang, function(err, code) { 1204 if (err) return done(err); 1205 if (code == null || code === token.text) { 1206 return --pending || done(); 1207 } 1208 token.text = code; 1209 token.escaped = true; 1210 --pending || done(); 1211 }); 1212 })(tokens[i]); 1213 } 1214 1215 return; 1216 } 1217 try { 1218 if (opt) opt = merge({}, marked.defaults, opt); 1219 return Parser.parse(Lexer.lex(src, opt), opt); 1220 } catch (e) { 1221 e.message += '\nPlease report this to https://github.com/chjj/marked.'; 1222 if ((opt || marked.defaults).silent) { 1223 return '<p>An error occured:</p><pre>' 1224 + escape(e.message + '', true) 1225 + '</pre>'; 1226 } 1227 throw e; 1228 } 1229} 1230 1231/** 1232 * Options 1233 */ 1234 1235marked.options = 1236marked.setOptions = function(opt) { 1237 merge(marked.defaults, opt); 1238 return marked; 1239}; 1240 1241marked.defaults = { 1242 gfm: true, 1243 tables: true, 1244 breaks: false, 1245 pedantic: false, 1246 sanitize: false, 1247 sanitizer: null, 1248 mangle: true, 1249 smartLists: false, 1250 silent: false, 1251 highlight: null, 1252 langPrefix: 'lang-', 1253 smartypants: false, 1254 headerPrefix: '', 1255 renderer: new Renderer, 1256 xhtml: false 1257}; 1258 1259/** 1260 * Expose 1261 */ 1262 1263marked.Parser = Parser; 1264marked.parser = Parser.parse; 1265 1266marked.Renderer = Renderer; 1267 1268marked.Lexer = Lexer; 1269marked.lexer = Lexer.lex; 1270 1271marked.InlineLexer = InlineLexer; 1272marked.inlineLexer = InlineLexer.output; 1273 1274marked.parse = marked; 1275 1276if (typeof module !== 'undefined' && typeof exports === 'object') { 1277 module.exports = marked; 1278} else if (typeof define === 'function' && define.amd) { 1279 define(function() { return marked; }); 1280} else { 1281 this.marked = marked; 1282} 1283 1284}).call(function() { 1285 return this || (typeof window !== 'undefined' ? window : global); 1286}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.