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