1272 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1272 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * marked - a markdown parser
 | |
|  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
 | |
|  * https://github.com/chjj/marked
 | |
|  */
 | |
| 
 | |
| ;(function() {
 | |
| 
 | |
| /**
 | |
|  * Block-Level Grammar
 | |
|  */
 | |
| 
 | |
| var block = {
 | |
|   newline: /^\n+/,
 | |
|   code: /^( {4}[^\n]+\n*)+/,
 | |
|   fences: noop,
 | |
|   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
 | |
|   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
 | |
|   nptable: noop,
 | |
|   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
 | |
|   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*/,
 | |
|   text: /^[^\n]+/
 | |
| };
 | |
| 
 | |
| block.bullet = /(?:[*+-]|\d+\.)/;
 | |
| block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
 | |
| block.item = replace(block.item, 'gm')
 | |
|   (/bull/g, block.bullet)
 | |
|   ();
 | |
| 
 | |
| block.list = replace(block.list)
 | |
|   (/bull/g, block.bullet)
 | |
|   ('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+(?!:/|[^\\w\\s@]*@)\\b';
 | |
| 
 | |
| block.html = replace(block.html)
 | |
|   ('comment', /<!--[\s\S]*?-->/)
 | |
|   ('closed', /<(tag)[\s\S]+?<\/\1>/)
 | |
|   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
 | |
|   (/tag/g, block._tag)
 | |
|   ();
 | |
| 
 | |
| block.paragraph = replace(block.paragraph)
 | |
|   ('hr', block.hr)
 | |
|   ('heading', block.heading)
 | |
|   ('lheading', block.lheading)
 | |
|   ('blockquote', block.blockquote)
 | |
|   ('tag', '<' + block._tag)
 | |
|   ('def', block.def)
 | |
|   ();
 | |
| 
 | |
| /**
 | |
|  * Normal Block Grammar
 | |
|  */
 | |
| 
 | |
| block.normal = merge({}, block);
 | |
| 
 | |
| /**
 | |
|  * GFM Block Grammar
 | |
|  */
 | |
| 
 | |
| block.gfm = merge({}, block.normal, {
 | |
|   fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
 | |
|   paragraph: /^/
 | |
| });
 | |
| 
 | |
| block.gfm.paragraph = replace(block.paragraph)
 | |
|   ('(?!', '(?!'
 | |
|     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
 | |
|     + block.list.source.replace('\\1', '\\3') + '|')
 | |
|   ();
 | |
| 
 | |
| /**
 | |
|  * GFM + Tables Block Grammar
 | |
|  */
 | |
| 
 | |
| block.tables = merge({}, block.gfm, {
 | |
|   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
 | |
|   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * Block Lexer
 | |
|  */
 | |
| 
 | |
| function Lexer(options) {
 | |
|   this.tokens = [];
 | |
|   this.tokens.links = {};
 | |
|   this.options = options || marked.defaults;
 | |
|   this.rules = block.normal;
 | |
| 
 | |
|   if (this.options.gfm) {
 | |
|     if (this.options.tables) {
 | |
|       this.rules = block.tables;
 | |
|     } else {
 | |
|       this.rules = block.gfm;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Expose Block Rules
 | |
|  */
 | |
| 
 | |
| Lexer.rules = block;
 | |
| 
 | |
| /**
 | |
|  * Static Lex Method
 | |
|  */
 | |
| 
 | |
| Lexer.lex = function(src, options) {
 | |
|   var lexer = new Lexer(options);
 | |
|   return lexer.lex(src);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Preprocessing
 | |
|  */
 | |
| 
 | |
| Lexer.prototype.lex = function(src) {
 | |
|   src = src
 | |
|     .replace(/\r\n|\r/g, '\n')
 | |
|     .replace(/\t/g, '    ')
 | |
|     .replace(/\u00a0/g, ' ')
 | |
|     .replace(/\u2424/g, '\n');
 | |
| 
 | |
|   return this.token(src, true);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Lexing
 | |
|  */
 | |
| 
 | |
| Lexer.prototype.token = function(src, top, bq) {
 | |
|   var src = src.replace(/^ +$/gm, '')
 | |
|     , next
 | |
|     , loose
 | |
|     , cap
 | |
|     , bull
 | |
|     , b
 | |
|     , item
 | |
|     , space
 | |
|     , i
 | |
|     , l;
 | |
| 
 | |
|   while (src) {
 | |
|     // newline
 | |
|     if (cap = this.rules.newline.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       if (cap[0].length > 1) {
 | |
|         this.tokens.push({
 | |
|           type: 'space'
 | |
|         });
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // code
 | |
|     if (cap = this.rules.code.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       cap = cap[0].replace(/^ {4}/gm, '');
 | |
|       this.tokens.push({
 | |
|         type: 'code',
 | |
|         text: !this.options.pedantic
 | |
|           ? cap.replace(/\n+$/, '')
 | |
|           : cap
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // fences (gfm)
 | |
|     if (cap = this.rules.fences.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'code',
 | |
|         lang: cap[2],
 | |
|         text: cap[3]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // heading
 | |
|     if (cap = this.rules.heading.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'heading',
 | |
|         depth: cap[1].length,
 | |
|         text: cap[2]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // table no leading pipe (gfm)
 | |
|     if (top && (cap = this.rules.nptable.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
| 
 | |
|       item = {
 | |
|         type: 'table',
 | |
|         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
 | |
|         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
 | |
|         cells: cap[3].replace(/\n$/, '').split('\n')
 | |
|       };
 | |
| 
 | |
|       for (i = 0; i < item.align.length; i++) {
 | |
|         if (/^ *-+: *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'right';
 | |
|         } else if (/^ *:-+: *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'center';
 | |
|         } else if (/^ *:-+ *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'left';
 | |
|         } else {
 | |
|           item.align[i] = null;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       for (i = 0; i < item.cells.length; i++) {
 | |
|         item.cells[i] = item.cells[i].split(/ *\| */);
 | |
|       }
 | |
| 
 | |
|       this.tokens.push(item);
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // lheading
 | |
|     if (cap = this.rules.lheading.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'heading',
 | |
|         depth: cap[2] === '=' ? 1 : 2,
 | |
|         text: cap[1]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // hr
 | |
|     if (cap = this.rules.hr.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'hr'
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // blockquote
 | |
|     if (cap = this.rules.blockquote.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
| 
 | |
|       this.tokens.push({
 | |
|         type: 'blockquote_start'
 | |
|       });
 | |
| 
 | |
|       cap = cap[0].replace(/^ *> ?/gm, '');
 | |
| 
 | |
|       // Pass `top` to keep the current
 | |
|       // "toplevel" state. This is exactly
 | |
|       // how markdown.pl works.
 | |
|       this.token(cap, top, true);
 | |
| 
 | |
|       this.tokens.push({
 | |
|         type: 'blockquote_end'
 | |
|       });
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // list
 | |
|     if (cap = this.rules.list.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       bull = cap[2];
 | |
| 
 | |
|       this.tokens.push({
 | |
|         type: 'list_start',
 | |
|         ordered: bull.length > 1
 | |
|       });
 | |
| 
 | |
|       // Get each top-level item.
 | |
|       cap = cap[0].match(this.rules.item);
 | |
| 
 | |
|       next = false;
 | |
|       l = cap.length;
 | |
|       i = 0;
 | |
| 
 | |
|       for (; i < l; i++) {
 | |
|         item = cap[i];
 | |
| 
 | |
|         // Remove the list item's bullet
 | |
|         // so it is seen as the next token.
 | |
|         space = item.length;
 | |
|         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
 | |
| 
 | |
|         // Outdent whatever the
 | |
|         // list item contains. Hacky.
 | |
|         if (~item.indexOf('\n ')) {
 | |
|           space -= item.length;
 | |
|           item = !this.options.pedantic
 | |
|             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
 | |
|             : item.replace(/^ {1,4}/gm, '');
 | |
|         }
 | |
| 
 | |
|         // Determine whether the next list item belongs here.
 | |
|         // Backpedal if it does not belong in this list.
 | |
|         if (this.options.smartLists && i !== l - 1) {
 | |
|           b = block.bullet.exec(cap[i + 1])[0];
 | |
|           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
 | |
|             src = cap.slice(i + 1).join('\n') + src;
 | |
|             i = l - 1;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         // Determine whether item is loose or not.
 | |
|         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
 | |
|         // for discount behavior.
 | |
|         loose = next || /\n\n(?!\s*$)/.test(item);
 | |
|         if (i !== l - 1) {
 | |
|           next = item.charAt(item.length - 1) === '\n';
 | |
|           if (!loose) loose = next;
 | |
|         }
 | |
| 
 | |
|         this.tokens.push({
 | |
|           type: loose
 | |
|             ? 'loose_item_start'
 | |
|             : 'list_item_start'
 | |
|         });
 | |
| 
 | |
|         // Recurse.
 | |
|         this.token(item, false, bq);
 | |
| 
 | |
|         this.tokens.push({
 | |
|           type: 'list_item_end'
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       this.tokens.push({
 | |
|         type: 'list_end'
 | |
|       });
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // html
 | |
|     if (cap = this.rules.html.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: this.options.sanitize
 | |
|           ? 'paragraph'
 | |
|           : 'html',
 | |
|         pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
 | |
|         text: cap[0]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // def
 | |
|     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.links[cap[1].toLowerCase()] = {
 | |
|         href: cap[2],
 | |
|         title: cap[3]
 | |
|       };
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // table (gfm)
 | |
|     if (top && (cap = this.rules.table.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
| 
 | |
|       item = {
 | |
|         type: 'table',
 | |
|         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
 | |
|         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
 | |
|         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
 | |
|       };
 | |
| 
 | |
|       for (i = 0; i < item.align.length; i++) {
 | |
|         if (/^ *-+: *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'right';
 | |
|         } else if (/^ *:-+: *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'center';
 | |
|         } else if (/^ *:-+ *$/.test(item.align[i])) {
 | |
|           item.align[i] = 'left';
 | |
|         } else {
 | |
|           item.align[i] = null;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       for (i = 0; i < item.cells.length; i++) {
 | |
|         item.cells[i] = item.cells[i]
 | |
|           .replace(/^ *\| *| *\| *$/g, '')
 | |
|           .split(/ *\| */);
 | |
|       }
 | |
| 
 | |
|       this.tokens.push(item);
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // top-level paragraph
 | |
|     if (top && (cap = this.rules.paragraph.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'paragraph',
 | |
|         text: cap[1].charAt(cap[1].length - 1) === '\n'
 | |
|           ? cap[1].slice(0, -1)
 | |
|           : cap[1]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // text
 | |
|     if (cap = this.rules.text.exec(src)) {
 | |
|       // Top-level should never reach here.
 | |
|       src = src.substring(cap[0].length);
 | |
|       this.tokens.push({
 | |
|         type: 'text',
 | |
|         text: cap[0]
 | |
|       });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (src) {
 | |
|       throw new
 | |
|         Error('Infinite loop on byte: ' + src.charCodeAt(0));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return this.tokens;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Inline-Level Grammar
 | |
|  */
 | |
| 
 | |
| var inline = {
 | |
|   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
 | |
|   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
 | |
|   url: noop,
 | |
|   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
 | |
|   link: /^!?\[(inside)\]\(href\)/,
 | |
|   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
 | |
|   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
 | |
|   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
 | |
|   em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
 | |
|   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
 | |
|   br: /^ {2,}\n(?!\s*$)/,
 | |
|   del: noop,
 | |
|   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
 | |
| };
 | |
| 
 | |
| inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
 | |
| inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
 | |
| 
 | |
| inline.link = replace(inline.link)
 | |
|   ('inside', inline._inside)
 | |
|   ('href', inline._href)
 | |
|   ();
 | |
| 
 | |
| inline.reflink = replace(inline.reflink)
 | |
|   ('inside', inline._inside)
 | |
|   ();
 | |
| 
 | |
| /**
 | |
|  * Normal Inline Grammar
 | |
|  */
 | |
| 
 | |
| inline.normal = merge({}, inline);
 | |
| 
 | |
| /**
 | |
|  * Pedantic Inline Grammar
 | |
|  */
 | |
| 
 | |
| inline.pedantic = merge({}, inline.normal, {
 | |
|   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
 | |
|   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * GFM Inline Grammar
 | |
|  */
 | |
| 
 | |
| inline.gfm = merge({}, inline.normal, {
 | |
|   escape: replace(inline.escape)('])', '~|])')(),
 | |
|   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
 | |
|   del: /^~~(?=\S)([\s\S]*?\S)~~/,
 | |
|   text: replace(inline.text)
 | |
|     (']|', '~]|')
 | |
|     ('|', '|https?://|')
 | |
|     ()
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * GFM + Line Breaks Inline Grammar
 | |
|  */
 | |
| 
 | |
| inline.breaks = merge({}, inline.gfm, {
 | |
|   br: replace(inline.br)('{2,}', '*')(),
 | |
|   text: replace(inline.gfm.text)('{2,}', '*')()
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * Inline Lexer & Compiler
 | |
|  */
 | |
| 
 | |
| 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
 | |
|       Error('Tokens array requires a `links` property.');
 | |
|   }
 | |
| 
 | |
|   if (this.options.gfm) {
 | |
|     if (this.options.breaks) {
 | |
|       this.rules = inline.breaks;
 | |
|     } else {
 | |
|       this.rules = inline.gfm;
 | |
|     }
 | |
|   } else if (this.options.pedantic) {
 | |
|     this.rules = inline.pedantic;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Expose Inline Rules
 | |
|  */
 | |
| 
 | |
| InlineLexer.rules = inline;
 | |
| 
 | |
| /**
 | |
|  * Static Lexing/Compiling Method
 | |
|  */
 | |
| 
 | |
| InlineLexer.output = function(src, links, options) {
 | |
|   var inline = new InlineLexer(links, options);
 | |
|   return inline.output(src);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Lexing/Compiling
 | |
|  */
 | |
| 
 | |
| InlineLexer.prototype.output = function(src) {
 | |
|   var out = ''
 | |
|     , link
 | |
|     , text
 | |
|     , href
 | |
|     , cap;
 | |
| 
 | |
|   while (src) {
 | |
|     // escape
 | |
|     if (cap = this.rules.escape.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       out += cap[1];
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // autolink
 | |
|     if (cap = this.rules.autolink.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       if (cap[2] === '@') {
 | |
|         text = cap[1].charAt(6) === ':'
 | |
|           ? this.mangle(cap[1].substring(7))
 | |
|           : this.mangle(cap[1]);
 | |
|         href = this.mangle('mailto:') + text;
 | |
|       } else {
 | |
|         text = escape(cap[1]);
 | |
|         href = text;
 | |
|       }
 | |
|       out += this.renderer.link(href, null, text);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // url (gfm)
 | |
|     if (!this.inLink && (cap = this.rules.url.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       text = escape(cap[1]);
 | |
|       href = text;
 | |
|       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];
 | |
|       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;
 | |
|     }
 | |
| 
 | |
|     // reflink, nolink
 | |
|     if ((cap = this.rules.reflink.exec(src))
 | |
|         || (cap = this.rules.nolink.exec(src))) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
 | |
|       link = this.links[link.toLowerCase()];
 | |
|       if (!link || !link.href) {
 | |
|         out += cap[0].charAt(0);
 | |
|         src = cap[0].substring(1) + src;
 | |
|         continue;
 | |
|       }
 | |
|       this.inLink = true;
 | |
|       out += this.outputLink(cap, link);
 | |
|       this.inLink = false;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // strong
 | |
|     if (cap = this.rules.strong.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       out += this.renderer.strong(this.output(cap[2] || cap[1]));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // em
 | |
|     if (cap = this.rules.em.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       out += this.renderer.em(this.output(cap[2] || cap[1]));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // code
 | |
|     if (cap = this.rules.code.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       out += this.renderer.codespan(escape(cap[2], true));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // br
 | |
|     if (cap = this.rules.br.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       out += this.renderer.br();
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // del (gfm)
 | |
|     if (cap = this.rules.del.exec(src)) {
 | |
|       src = src.substring(cap[0].length);
 | |
|       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]));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (src) {
 | |
|       throw new
 | |
|         Error('Infinite loop on byte: ' + src.charCodeAt(0));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return out;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Compile Link
 | |
|  */
 | |
| 
 | |
| InlineLexer.prototype.outputLink = function(cap, link) {
 | |
|   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]));
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Smartypants Transformations
 | |
|  */
 | |
| 
 | |
| InlineLexer.prototype.smartypants = function(text) {
 | |
|   if (!this.options.smartypants) return text;
 | |
|   return text
 | |
|     // em-dashes
 | |
|     .replace(/--/g, '\u2014')
 | |
|     // opening singles
 | |
|     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
 | |
|     // closing singles & apostrophes
 | |
|     .replace(/'/g, '\u2019')
 | |
|     // opening doubles
 | |
|     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
 | |
|     // closing doubles
 | |
|     .replace(/"/g, '\u201d')
 | |
|     // ellipses
 | |
|     .replace(/\.{3}/g, '\u2026');
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Mangle Links
 | |
|  */
 | |
| 
 | |
| InlineLexer.prototype.mangle = function(text) {
 | |
|   var out = ''
 | |
|     , l = text.length
 | |
|     , i = 0
 | |
|     , ch;
 | |
| 
 | |
|   for (; i < l; i++) {
 | |
|     ch = text.charCodeAt(i);
 | |
|     if (Math.random() > 0.5) {
 | |
|       ch = 'x' + ch.toString(16);
 | |
|     }
 | |
|     out += '&#' + ch + ';';
 | |
|   }
 | |
| 
 | |
|   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) {
 | |
|       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;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Parsing & Compiling
 | |
|  */
 | |
| 
 | |
| 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, renderer) {
 | |
|   var parser = new Parser(options, renderer);
 | |
|   return parser.parse(src);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Parse Loop
 | |
|  */
 | |
| 
 | |
| Parser.prototype.parse = function(src) {
 | |
|   this.inline = new InlineLexer(src.links, this.options, this.renderer);
 | |
|   this.tokens = src.reverse();
 | |
| 
 | |
|   var out = '';
 | |
|   while (this.next()) {
 | |
|     out += this.tok();
 | |
|   }
 | |
| 
 | |
|   return out;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Next Token
 | |
|  */
 | |
| 
 | |
| Parser.prototype.next = function() {
 | |
|   return this.token = this.tokens.pop();
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Preview Next Token
 | |
|  */
 | |
| 
 | |
| Parser.prototype.peek = function() {
 | |
|   return this.tokens[this.tokens.length - 1] || 0;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Parse Text Tokens
 | |
|  */
 | |
| 
 | |
| Parser.prototype.parseText = function() {
 | |
|   var body = this.token.text;
 | |
| 
 | |
|   while (this.peek().type === 'text') {
 | |
|     body += '\n' + this.next().text;
 | |
|   }
 | |
| 
 | |
|   return this.inline.output(body);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Parse Current Token
 | |
|  */
 | |
| 
 | |
| Parser.prototype.tok = function() {
 | |
|   switch (this.token.type) {
 | |
|     case 'space': {
 | |
|       return '';
 | |
|     }
 | |
|     case 'hr': {
 | |
|       return this.renderer.hr();
 | |
|     }
 | |
|     case 'heading': {
 | |
|       return this.renderer.heading(
 | |
|         this.inline.output(this.token.text),
 | |
|         this.token.depth,
 | |
|         this.token.text);
 | |
|     }
 | |
|     case 'code': {
 | |
|       return this.renderer.code(this.token.text,
 | |
|         this.token.lang,
 | |
|         this.token.escaped);
 | |
|     }
 | |
|     case 'table': {
 | |
|       var header = ''
 | |
|         , body = ''
 | |
|         , i
 | |
|         , row
 | |
|         , cell
 | |
|         , flags
 | |
|         , j;
 | |
| 
 | |
|       // header
 | |
|       cell = '';
 | |
|       for (i = 0; i < this.token.header.length; i++) {
 | |
|         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] }
 | |
|         );
 | |
|       }
 | |
|       header += this.renderer.tablerow(cell);
 | |
| 
 | |
|       for (i = 0; i < this.token.cells.length; i++) {
 | |
|         row = this.token.cells[i];
 | |
| 
 | |
|         cell = '';
 | |
|         for (j = 0; j < row.length; j++) {
 | |
|           cell += this.renderer.tablecell(
 | |
|             this.inline.output(row[j]),
 | |
|             { header: false, align: this.token.align[j] }
 | |
|           );
 | |
|         }
 | |
| 
 | |
|         body += this.renderer.tablerow(cell);
 | |
|       }
 | |
|       return this.renderer.table(header, body);
 | |
|     }
 | |
|     case 'blockquote_start': {
 | |
|       var body = '';
 | |
| 
 | |
|       while (this.next().type !== 'blockquote_end') {
 | |
|         body += this.tok();
 | |
|       }
 | |
| 
 | |
|       return this.renderer.blockquote(body);
 | |
|     }
 | |
|     case 'list_start': {
 | |
|       var body = ''
 | |
|         , ordered = this.token.ordered;
 | |
| 
 | |
|       while (this.next().type !== 'list_end') {
 | |
|         body += this.tok();
 | |
|       }
 | |
| 
 | |
|       return this.renderer.list(body, ordered);
 | |
|     }
 | |
|     case 'list_item_start': {
 | |
|       var body = '';
 | |
| 
 | |
|       while (this.next().type !== 'list_item_end') {
 | |
|         body += this.token.type === 'text'
 | |
|           ? this.parseText()
 | |
|           : this.tok();
 | |
|       }
 | |
| 
 | |
|       return this.renderer.listitem(body);
 | |
|     }
 | |
|     case 'loose_item_start': {
 | |
|       var body = '';
 | |
| 
 | |
|       while (this.next().type !== 'list_item_end') {
 | |
|         body += this.tok();
 | |
|       }
 | |
| 
 | |
|       return this.renderer.listitem(body);
 | |
|     }
 | |
|     case 'html': {
 | |
|       var html = !this.token.pre && !this.options.pedantic
 | |
|         ? this.inline.output(this.token.text)
 | |
|         : this.token.text;
 | |
|       return this.renderer.html(html);
 | |
|     }
 | |
|     case 'paragraph': {
 | |
|       return this.renderer.paragraph(this.inline.output(this.token.text));
 | |
|     }
 | |
|     case 'text': {
 | |
|       return this.renderer.paragraph(this.parseText());
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Helpers
 | |
|  */
 | |
| 
 | |
| function escape(html, encode) {
 | |
|   return html
 | |
|     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
 | |
|     .replace(/</g, '<')
 | |
|     .replace(/>/g, '>')
 | |
|     .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) {
 | |
|   regex = regex.source;
 | |
|   opt = opt || '';
 | |
|   return function self(name, val) {
 | |
|     if (!name) return new RegExp(regex, opt);
 | |
|     val = val.source || val;
 | |
|     val = val.replace(/(^|[^\[])\^/g, '$1');
 | |
|     regex = regex.replace(name, val);
 | |
|     return self;
 | |
|   };
 | |
| }
 | |
| 
 | |
| function noop() {}
 | |
| noop.exec = noop;
 | |
| 
 | |
| function merge(obj) {
 | |
|   var i = 1
 | |
|     , target
 | |
|     , key;
 | |
| 
 | |
|   for (; i < arguments.length; i++) {
 | |
|     target = arguments[i];
 | |
|     for (key in target) {
 | |
|       if (Object.prototype.hasOwnProperty.call(target, key)) {
 | |
|         obj[key] = target[key];
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Marked
 | |
|  */
 | |
| 
 | |
| function marked(src, opt, callback) {
 | |
|   if (callback || typeof opt === 'function') {
 | |
|     if (!callback) {
 | |
|       callback = opt;
 | |
|       opt = null;
 | |
|     }
 | |
| 
 | |
|     opt = merge({}, marked.defaults, opt || {});
 | |
| 
 | |
|     var highlight = opt.highlight
 | |
|       , tokens
 | |
|       , pending
 | |
|       , i = 0;
 | |
| 
 | |
|     try {
 | |
|       tokens = Lexer.lex(src, opt)
 | |
|     } catch (e) {
 | |
|       return callback(e);
 | |
|     }
 | |
| 
 | |
|     pending = tokens.length;
 | |
| 
 | |
|     var done = function(err) {
 | |
|       if (err) {
 | |
|         opt.highlight = highlight;
 | |
|         return callback(err);
 | |
|       }
 | |
| 
 | |
|       var out;
 | |
| 
 | |
|       try {
 | |
|         out = Parser.parse(tokens, opt);
 | |
|       } catch (e) {
 | |
|         err = e;
 | |
|       }
 | |
| 
 | |
|       opt.highlight = highlight;
 | |
| 
 | |
|       return err
 | |
|         ? callback(err)
 | |
|         : callback(null, out);
 | |
|     };
 | |
| 
 | |
|     if (!highlight || highlight.length < 3) {
 | |
|       return done();
 | |
|     }
 | |
| 
 | |
|     delete opt.highlight;
 | |
| 
 | |
|     if (!pending) return done();
 | |
| 
 | |
|     for (; i < tokens.length; i++) {
 | |
|       (function(token) {
 | |
|         if (token.type !== 'code') {
 | |
|           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();
 | |
|           }
 | |
|           token.text = code;
 | |
|           token.escaped = true;
 | |
|           --pending || done();
 | |
|         });
 | |
|       })(tokens[i]);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
|   }
 | |
|   try {
 | |
|     if (opt) opt = merge({}, marked.defaults, opt);
 | |
|     return Parser.parse(Lexer.lex(src, opt), opt);
 | |
|   } catch (e) {
 | |
|     e.message += '\nPlease report this to https://github.com/chjj/marked.';
 | |
|     if ((opt || marked.defaults).silent) {
 | |
|       return '<p>An error occured:</p><pre>'
 | |
|         + escape(e.message + '', true)
 | |
|         + '</pre>';
 | |
|     }
 | |
|     throw e;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Options
 | |
|  */
 | |
| 
 | |
| marked.options =
 | |
| marked.setOptions = function(opt) {
 | |
|   merge(marked.defaults, opt);
 | |
|   return marked;
 | |
| };
 | |
| 
 | |
| marked.defaults = {
 | |
|   gfm: true,
 | |
|   tables: true,
 | |
|   breaks: false,
 | |
|   pedantic: false,
 | |
|   sanitize: false,
 | |
|   smartLists: false,
 | |
|   silent: false,
 | |
|   highlight: null,
 | |
|   langPrefix: 'lang-',
 | |
|   smartypants: false,
 | |
|   headerPrefix: '',
 | |
|   renderer: new Renderer,
 | |
|   xhtml: false
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Expose
 | |
|  */
 | |
| 
 | |
| marked.Parser = Parser;
 | |
| marked.parser = Parser.parse;
 | |
| 
 | |
| marked.Renderer = Renderer;
 | |
| 
 | |
| marked.Lexer = Lexer;
 | |
| marked.lexer = Lexer.lex;
 | |
| 
 | |
| marked.InlineLexer = InlineLexer;
 | |
| marked.inlineLexer = InlineLexer.output;
 | |
| 
 | |
| marked.parse = marked;
 | |
| 
 | |
| if (typeof module !== 'undefined' && typeof exports === 'object') {
 | |
|   module.exports = marked;
 | |
| } else if (typeof define === 'function' && define.amd) {
 | |
|   define(function() { return marked; });
 | |
| } else {
 | |
|   this.marked = marked;
 | |
| }
 | |
| 
 | |
| }).call(function() {
 | |
|   return this || (typeof window !== 'undefined' ? window : global);
 | |
| }()); | 
