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