git ssb

16+

cel / patchfoo



Tree: 50a93d0c463cd37de0b35d49fef7daf6e9e287db

Files: 50a93d0c463cd37de0b35d49fef7daf6e9e287db / vendor / ssb-marked.js

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

Built with git-ssb-web