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 | |
13 | var block = { |
14 | newline: /^\n+/, |
15 | code: /^( {4}[^\n]+\n*)+/, |
16 | fences: noop, |
17 | hr: /^( *[-*_]){3,} *(?:\n+|$)/, |
18 | heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/, |
19 | nptable: noop, |
20 | lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, |
21 | blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, |
22 | list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, |
23 | html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, |
24 | def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, |
25 | table: noop, |
26 | paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, |
27 | text: /^[^\n]+/ |
28 | }; |
29 | |
30 | block.checkbox = /^\[([ x])\] +/; |
31 | block.bullet = /(?:[*+-]|\d+\.)/; |
32 | block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; |
33 | block.item = replace(block.item, 'gm') |
34 | (/bull/g, block.bullet) |
35 | (); |
36 | |
37 | block.list = replace(block.list) |
38 | (/bull/g, block.bullet) |
39 | ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') |
40 | ('def', '\\n+(?=' + block.def.source + ')') |
41 | (); |
42 | |
43 | block.blockquote = replace(block.blockquote) |
44 | ('def', block.def) |
45 | (); |
46 | |
47 | block._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 | |
52 | block.html = replace(block.html) |
53 | ('comment', /<!--[\s\S]*?-->/) |
54 | ('closed', /<(tag)[\s\S]+?<\/\1>/) |
55 | ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/) |
56 | (/tag/g, block._tag) |
57 | (); |
58 | |
59 | block.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 | |
72 | block.normal = merge({}, block); |
73 | |
74 | /** |
75 | * GFM Block Grammar |
76 | */ |
77 | |
78 | block.gfm = merge({}, block.normal, { |
79 | fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, |
80 | paragraph: /^/ |
81 | }); |
82 | |
83 | block.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 | |
93 | block.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 | |
102 | function 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 | |
121 | Lexer.rules = block; |
122 | |
123 | /** |
124 | * Static Lex Method |
125 | */ |
126 | |
127 | Lexer.lex = function(src, options) { |
128 | var lexer = new Lexer(options); |
129 | return lexer.lex(src); |
130 | }; |
131 | |
132 | /** |
133 | * Preprocessing |
134 | */ |
135 | |
136 | Lexer.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 | |
150 | Lexer.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 | |
462 | var 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 | |
482 | inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/; |
483 | inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/; |
484 | |
485 | inline.link = replace(inline.link) |
486 | ('inside', inline._inside) |
487 | ('href', inline._href) |
488 | (); |
489 | |
490 | inline.reflink = replace(inline.reflink) |
491 | ('inside', inline._inside) |
492 | (); |
493 | |
494 | /** |
495 | * Normal Inline Grammar |
496 | */ |
497 | |
498 | inline.normal = merge({}, inline); |
499 | |
500 | /** |
501 | * Pedantic Inline Grammar |
502 | */ |
503 | |
504 | inline.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 | |
513 | var 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 | |
527 | inline.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 | |
538 | inline.gfm.url = replace(inline.gfm.url)('https?:\\/\\/', urlPrefix)() |
539 | inline.gfm.text = replace(inline.gfm.text)('https?:\\/\\/', urlPrefix)() |
540 | |
541 | /** |
542 | * GFM + Line Breaks Inline Grammar |
543 | */ |
544 | |
545 | inline.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 | |
554 | function 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 | |
583 | InlineLexer.rules = inline; |
584 | |
585 | /** |
586 | * Static Lexing/Compiling Method |
587 | */ |
588 | |
589 | InlineLexer.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 | |
598 | InlineLexer.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 | |
768 | InlineLexer.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 | |
781 | function 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 | |
795 | function 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 | |
811 | InlineLexer.prototype.emojiTemplate = emojiDefaultTemplate; |
812 | InlineLexer.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 | |
822 | InlineLexer.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 | |
843 | InlineLexer.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 | |
864 | function Renderer(options) { |
865 | this.options = options || {}; |
866 | } |
867 | |
868 | Renderer.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 | |
884 | Renderer.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 | |
907 | Renderer.prototype.blockquote = function(quote) { |
908 | return '<blockquote>\n' + quote + '</blockquote>\n'; |
909 | }; |
910 | |
911 | Renderer.prototype.html = function(html) { |
912 | return html; |
913 | }; |
914 | |
915 | Renderer.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 | |
928 | Renderer.prototype.hr = function() { |
929 | return this.options.xhtml ? '<hr/>\n' : '<hr>\n'; |
930 | }; |
931 | |
932 | Renderer.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 | |
938 | Renderer.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 | |
951 | Renderer.prototype.paragraph = function(text) { |
952 | return '<p>' + text + '</p>\n'; |
953 | }; |
954 | |
955 | Renderer.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 | |
966 | Renderer.prototype.tablerow = function(content) { |
967 | return '<tr>\n' + content + '</tr>\n'; |
968 | }; |
969 | |
970 | Renderer.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 |
979 | Renderer.prototype.strong = function(text) { |
980 | return '<strong>' + text + '</strong>'; |
981 | }; |
982 | |
983 | Renderer.prototype.em = function(text) { |
984 | return '<em>' + text + '</em>'; |
985 | }; |
986 | |
987 | Renderer.prototype.codespan = function(text) { |
988 | return '<code>' + text + '</code>'; |
989 | }; |
990 | |
991 | Renderer.prototype.br = function() { |
992 | return this.options.xhtml ? '<br/>' : '<br>'; |
993 | }; |
994 | |
995 | Renderer.prototype.del = function(text) { |
996 | return '<del>' + text + '</del>'; |
997 | }; |
998 | |
999 | Renderer.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 | |
1013 | Renderer.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 | |
1023 | Renderer.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 | |
1036 | Renderer.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 | |
1048 | function 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 | |
1061 | Parser.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 | |
1070 | Parser.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 | |
1086 | Parser.prototype.next = function() { |
1087 | return this.token = this.tokens.pop(); |
1088 | }; |
1089 | |
1090 | /** |
1091 | * Preview Next Token |
1092 | */ |
1093 | |
1094 | Parser.prototype.peek = function() { |
1095 | return this.tokens[this.tokens.length - 1] || 0; |
1096 | }; |
1097 | |
1098 | /** |
1099 | * Parse Text Tokens |
1100 | */ |
1101 | |
1102 | Parser.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 | |
1116 | Parser.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 | |
1234 | function escape(html, encode) { |
1235 | return html |
1236 | .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') |
1237 | .replace(/</g, '<') |
1238 | .replace(/>/g, '>') |
1239 | .replace(/"/g, '"') |
1240 | .replace(/'/g, '''); |
1241 | } |
1242 | function simpleEscape(html) { |
1243 | return html |
1244 | .replace(/</g, '<') |
1245 | .replace(/>/g, '>'); |
1246 | } |
1247 | |
1248 | function 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 | |
1261 | function 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 | |
1273 | function noop() {} |
1274 | noop.exec = noop; |
1275 | |
1276 | function 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 | |
1298 | function 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 | |
1386 | marked.options = |
1387 | marked.setOptions = function(opt) { |
1388 | merge(marked.defaults, opt); |
1389 | return marked; |
1390 | }; |
1391 | |
1392 | marked.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 | |
1416 | marked.Parser = Parser; |
1417 | marked.parser = Parser.parse; |
1418 | |
1419 | marked.Renderer = Renderer; |
1420 | |
1421 | marked.Lexer = Lexer; |
1422 | marked.lexer = Lexer.lex; |
1423 | |
1424 | marked.InlineLexer = InlineLexer; |
1425 | marked.inlineLexer = InlineLexer.output; |
1426 | |
1427 | marked.parse = marked; |
1428 | |
1429 | if (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