UNPKG

43.4 kBJavaScriptView Raw
1/**
2 * marked - a markdown parser
3 * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT Licensed)
4 * https://github.com/markedjs/marked
5 */
6
7;(function(root) {
8'use strict';
9
10/**
11 * Block-Level Grammar
12 */
13
14var block = {
15 newline: /^\n+/,
16 code: /^( {4}[^\n]+\n*)+/,
17 fences: /^ {0,3}(`{3,}|~{3,})([^`~\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
18 hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
19 heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
20 blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
21 list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
22 html: '^ {0,3}(?:' // optional indentation
23 + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
24 + '|comment[^\\n]*(\\n+|$)' // (2)
25 + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
26 + '|<![A-Z][\\s\\S]*?>\\n*' // (4)
27 + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
28 + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
29 + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
30 + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
31 + ')',
32 def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
33 nptable: noop,
34 table: noop,
35 lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
36 // regex template, placeholders will be replaced according to different paragraph
37 // interruption rules of commonmark and the original markdown spec:
38 _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
39 text: /^[^\n]+/
40};
41
42block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
43block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
44block.def = edit(block.def)
45 .replace('label', block._label)
46 .replace('title', block._title)
47 .getRegex();
48
49block.bullet = /(?:[*+-]|\d{1,9}\.)/;
50block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
51block.item = edit(block.item, 'gm')
52 .replace(/bull/g, block.bullet)
53 .getRegex();
54
55block.list = edit(block.list)
56 .replace(/bull/g, block.bullet)
57 .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
58 .replace('def', '\\n+(?=' + block.def.source + ')')
59 .getRegex();
60
61block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
62 + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
63 + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
64 + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
65 + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
66 + '|track|ul';
67block._comment = /<!--(?!-?>)[\s\S]*?-->/;
68block.html = edit(block.html, 'i')
69 .replace('comment', block._comment)
70 .replace('tag', block._tag)
71 .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
72 .getRegex();
73
74block.paragraph = edit(block._paragraph)
75 .replace('hr', block.hr)
76 .replace('heading', ' {0,3}#{1,6} +')
77 .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
78 .replace('blockquote', ' {0,3}>')
79 .replace('fences', ' {0,3}(?:`{3,}|~{3,})[^`\\n]*\\n')
80 .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
81 .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)')
82 .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
83 .getRegex();
84
85block.blockquote = edit(block.blockquote)
86 .replace('paragraph', block.paragraph)
87 .getRegex();
88
89/**
90 * Normal Block Grammar
91 */
92
93block.normal = merge({}, block);
94
95/**
96 * GFM Block Grammar
97 */
98
99block.gfm = merge({}, block.normal, {
100 nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,
101 table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/
102});
103
104/**
105 * Pedantic grammar (original John Gruber's loose markdown specification)
106 */
107
108block.pedantic = merge({}, block.normal, {
109 html: edit(
110 '^ *(?:comment *(?:\\n|\\s*$)'
111 + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
112 + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
113 .replace('comment', block._comment)
114 .replace(/tag/g, '(?!(?:'
115 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
116 + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
117 + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
118 .getRegex(),
119 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
120 heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
121 fences: noop, // fences not supported
122 paragraph: edit(block.normal._paragraph)
123 .replace('hr', block.hr)
124 .replace('heading', ' *#{1,6} *[^\n]')
125 .replace('lheading', block.lheading)
126 .replace('blockquote', ' {0,3}>')
127 .replace('|fences', '')
128 .replace('|list', '')
129 .replace('|html', '')
130 .getRegex()
131});
132
133/**
134 * Block Lexer
135 */
136
137function Lexer(options) {
138 this.tokens = [];
139 this.tokens.links = Object.create(null);
140 this.options = options || marked.defaults;
141 this.rules = block.normal;
142
143 if (this.options.pedantic) {
144 this.rules = block.pedantic;
145 } else if (this.options.gfm) {
146 this.rules = block.gfm;
147 }
148}
149
150/**
151 * Expose Block Rules
152 */
153
154Lexer.rules = block;
155
156/**
157 * Static Lex Method
158 */
159
160Lexer.lex = function(src, options) {
161 var lexer = new Lexer(options);
162 return lexer.lex(src);
163};
164
165/**
166 * Preprocessing
167 */
168
169Lexer.prototype.lex = function(src) {
170 src = src
171 .replace(/\r\n|\r/g, '\n')
172 .replace(/\t/g, ' ')
173 .replace(/\u00a0/g, ' ')
174 .replace(/\u2424/g, '\n');
175
176 return this.token(src, true);
177};
178
179/**
180 * Lexing
181 */
182
183Lexer.prototype.token = function(src, top) {
184 src = src.replace(/^ +$/gm, '');
185 var next,
186 loose,
187 cap,
188 bull,
189 b,
190 item,
191 listStart,
192 listItems,
193 t,
194 space,
195 i,
196 tag,
197 l,
198 isordered,
199 istask,
200 ischecked;
201
202 while (src) {
203 // newline
204 if (cap = this.rules.newline.exec(src)) {
205 src = src.substring(cap[0].length);
206 if (cap[0].length > 1) {
207 this.tokens.push({
208 type: 'space'
209 });
210 }
211 }
212
213 // code
214 if (cap = this.rules.code.exec(src)) {
215 var lastToken = this.tokens[this.tokens.length - 1];
216 src = src.substring(cap[0].length);
217 // An indented code block cannot interrupt a paragraph.
218 if (lastToken && lastToken.type === 'paragraph') {
219 lastToken.text += '\n' + cap[0].trimRight();
220 } else {
221 cap = cap[0].replace(/^ {4}/gm, '');
222 this.tokens.push({
223 type: 'code',
224 codeBlockStyle: 'indented',
225 text: !this.options.pedantic
226 ? rtrim(cap, '\n')
227 : cap
228 });
229 }
230 continue;
231 }
232
233 // fences
234 if (cap = this.rules.fences.exec(src)) {
235 src = src.substring(cap[0].length);
236 this.tokens.push({
237 type: 'code',
238 lang: cap[2] ? cap[2].trim() : cap[2],
239 text: cap[3] || ''
240 });
241 continue;
242 }
243
244 // heading
245 if (cap = this.rules.heading.exec(src)) {
246 src = src.substring(cap[0].length);
247 this.tokens.push({
248 type: 'heading',
249 depth: cap[1].length,
250 text: cap[2]
251 });
252 continue;
253 }
254
255 // table no leading pipe (gfm)
256 if (cap = this.rules.nptable.exec(src)) {
257 item = {
258 type: 'table',
259 header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
260 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
261 cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
262 };
263
264 if (item.header.length === item.align.length) {
265 src = src.substring(cap[0].length);
266
267 for (i = 0; i < item.align.length; i++) {
268 if (/^ *-+: *$/.test(item.align[i])) {
269 item.align[i] = 'right';
270 } else if (/^ *:-+: *$/.test(item.align[i])) {
271 item.align[i] = 'center';
272 } else if (/^ *:-+ *$/.test(item.align[i])) {
273 item.align[i] = 'left';
274 } else {
275 item.align[i] = null;
276 }
277 }
278
279 for (i = 0; i < item.cells.length; i++) {
280 item.cells[i] = splitCells(item.cells[i], item.header.length);
281 }
282
283 this.tokens.push(item);
284
285 continue;
286 }
287 }
288
289 // hr
290 if (cap = this.rules.hr.exec(src)) {
291 src = src.substring(cap[0].length);
292 this.tokens.push({
293 type: 'hr'
294 });
295 continue;
296 }
297
298 // blockquote
299 if (cap = this.rules.blockquote.exec(src)) {
300 src = src.substring(cap[0].length);
301
302 this.tokens.push({
303 type: 'blockquote_start'
304 });
305
306 cap = cap[0].replace(/^ *> ?/gm, '');
307
308 // Pass `top` to keep the current
309 // "toplevel" state. This is exactly
310 // how markdown.pl works.
311 this.token(cap, top);
312
313 this.tokens.push({
314 type: 'blockquote_end'
315 });
316
317 continue;
318 }
319
320 // list
321 if (cap = this.rules.list.exec(src)) {
322 src = src.substring(cap[0].length);
323 bull = cap[2];
324 isordered = bull.length > 1;
325
326 listStart = {
327 type: 'list_start',
328 ordered: isordered,
329 start: isordered ? +bull : '',
330 loose: false
331 };
332
333 this.tokens.push(listStart);
334
335 // Get each top-level item.
336 cap = cap[0].match(this.rules.item);
337
338 listItems = [];
339 next = false;
340 l = cap.length;
341 i = 0;
342
343 for (; i < l; i++) {
344 item = cap[i];
345
346 // Remove the list item's bullet
347 // so it is seen as the next token.
348 space = item.length;
349 item = item.replace(/^ *([*+-]|\d+\.) */, '');
350
351 // Outdent whatever the
352 // list item contains. Hacky.
353 if (~item.indexOf('\n ')) {
354 space -= item.length;
355 item = !this.options.pedantic
356 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
357 : item.replace(/^ {1,4}/gm, '');
358 }
359
360 // Determine whether the next list item belongs here.
361 // Backpedal if it does not belong in this list.
362 if (i !== l - 1) {
363 b = block.bullet.exec(cap[i + 1])[0];
364 if (bull.length > 1 ? b.length === 1
365 : (b.length > 1 || (this.options.smartLists && b !== bull))) {
366 src = cap.slice(i + 1).join('\n') + src;
367 i = l - 1;
368 }
369 }
370
371 // Determine whether item is loose or not.
372 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
373 // for discount behavior.
374 loose = next || /\n\n(?!\s*$)/.test(item);
375 if (i !== l - 1) {
376 next = item.charAt(item.length - 1) === '\n';
377 if (!loose) loose = next;
378 }
379
380 if (loose) {
381 listStart.loose = true;
382 }
383
384 // Check for task list items
385 istask = /^\[[ xX]\] /.test(item);
386 ischecked = undefined;
387 if (istask) {
388 ischecked = item[1] !== ' ';
389 item = item.replace(/^\[[ xX]\] +/, '');
390 }
391
392 t = {
393 type: 'list_item_start',
394 task: istask,
395 checked: ischecked,
396 loose: loose
397 };
398
399 listItems.push(t);
400 this.tokens.push(t);
401
402 // Recurse.
403 this.token(item, false);
404
405 this.tokens.push({
406 type: 'list_item_end'
407 });
408 }
409
410 if (listStart.loose) {
411 l = listItems.length;
412 i = 0;
413 for (; i < l; i++) {
414 listItems[i].loose = true;
415 }
416 }
417
418 this.tokens.push({
419 type: 'list_end'
420 });
421
422 continue;
423 }
424
425 // html
426 if (cap = this.rules.html.exec(src)) {
427 src = src.substring(cap[0].length);
428 this.tokens.push({
429 type: this.options.sanitize
430 ? 'paragraph'
431 : 'html',
432 pre: !this.options.sanitizer
433 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
434 text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]
435 });
436 continue;
437 }
438
439 // def
440 if (top && (cap = this.rules.def.exec(src))) {
441 src = src.substring(cap[0].length);
442 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
443 tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
444 if (!this.tokens.links[tag]) {
445 this.tokens.links[tag] = {
446 href: cap[2],
447 title: cap[3]
448 };
449 }
450 continue;
451 }
452
453 // table (gfm)
454 if (cap = this.rules.table.exec(src)) {
455 item = {
456 type: 'table',
457 header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
458 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
459 cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
460 };
461
462 if (item.header.length === item.align.length) {
463 src = src.substring(cap[0].length);
464
465 for (i = 0; i < item.align.length; i++) {
466 if (/^ *-+: *$/.test(item.align[i])) {
467 item.align[i] = 'right';
468 } else if (/^ *:-+: *$/.test(item.align[i])) {
469 item.align[i] = 'center';
470 } else if (/^ *:-+ *$/.test(item.align[i])) {
471 item.align[i] = 'left';
472 } else {
473 item.align[i] = null;
474 }
475 }
476
477 for (i = 0; i < item.cells.length; i++) {
478 item.cells[i] = splitCells(
479 item.cells[i].replace(/^ *\| *| *\| *$/g, ''),
480 item.header.length);
481 }
482
483 this.tokens.push(item);
484
485 continue;
486 }
487 }
488
489 // lheading
490 if (cap = this.rules.lheading.exec(src)) {
491 src = src.substring(cap[0].length);
492 this.tokens.push({
493 type: 'heading',
494 depth: cap[2].charAt(0) === '=' ? 1 : 2,
495 text: cap[1]
496 });
497 continue;
498 }
499
500 // top-level paragraph
501 if (top && (cap = this.rules.paragraph.exec(src))) {
502 src = src.substring(cap[0].length);
503 this.tokens.push({
504 type: 'paragraph',
505 text: cap[1].charAt(cap[1].length - 1) === '\n'
506 ? cap[1].slice(0, -1)
507 : cap[1]
508 });
509 continue;
510 }
511
512 // text
513 if (cap = this.rules.text.exec(src)) {
514 // Top-level should never reach here.
515 src = src.substring(cap[0].length);
516 this.tokens.push({
517 type: 'text',
518 text: cap[0]
519 });
520 continue;
521 }
522
523 if (src) {
524 throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
525 }
526 }
527
528 return this.tokens;
529};
530
531/**
532 * Inline-Level Grammar
533 */
534
535var inline = {
536 escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
537 autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
538 url: noop,
539 tag: '^comment'
540 + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
541 + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
542 + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
543 + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
544 + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
545 link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
546 reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
547 nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
548 strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
549 em: /^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
550 code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
551 br: /^( {2,}|\\)\n(?!\s*$)/,
552 del: noop,
553 text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
554};
555
556// list of punctuation marks from common mark spec
557// without ` and ] to workaround Rule 17 (inline code blocks/links)
558inline._punctuation = '!"#$%&\'()*+,\\-./:;<=>?@\\[^_{|}~';
559inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();
560
561inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
562
563inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
564inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
565inline.autolink = edit(inline.autolink)
566 .replace('scheme', inline._scheme)
567 .replace('email', inline._email)
568 .getRegex();
569
570inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
571
572inline.tag = edit(inline.tag)
573 .replace('comment', block._comment)
574 .replace('attribute', inline._attribute)
575 .getRegex();
576
577inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
578inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
579inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
580
581inline.link = edit(inline.link)
582 .replace('label', inline._label)
583 .replace('href', inline._href)
584 .replace('title', inline._title)
585 .getRegex();
586
587inline.reflink = edit(inline.reflink)
588 .replace('label', inline._label)
589 .getRegex();
590
591/**
592 * Normal Inline Grammar
593 */
594
595inline.normal = merge({}, inline);
596
597/**
598 * Pedantic Inline Grammar
599 */
600
601inline.pedantic = merge({}, inline.normal, {
602 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
603 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
604 link: edit(/^!?\[(label)\]\((.*?)\)/)
605 .replace('label', inline._label)
606 .getRegex(),
607 reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
608 .replace('label', inline._label)
609 .getRegex()
610});
611
612/**
613 * GFM Inline Grammar
614 */
615
616inline.gfm = merge({}, inline.normal, {
617 escape: edit(inline.escape).replace('])', '~|])').getRegex(),
618 _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
619 url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
620 _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
621 del: /^~+(?=\S)([\s\S]*?\S)~+/,
622 text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
623});
624
625inline.gfm.url = edit(inline.gfm.url, 'i')
626 .replace('email', inline.gfm._extended_email)
627 .getRegex();
628/**
629 * GFM + Line Breaks Inline Grammar
630 */
631
632inline.breaks = merge({}, inline.gfm, {
633 br: edit(inline.br).replace('{2,}', '*').getRegex(),
634 text: edit(inline.gfm.text)
635 .replace('\\b_', '\\b_| {2,}\\n')
636 .replace(/\{2,\}/g, '*')
637 .getRegex()
638});
639
640/**
641 * Inline Lexer & Compiler
642 */
643
644function InlineLexer(links, options) {
645 this.options = options || marked.defaults;
646 this.links = links;
647 this.rules = inline.normal;
648 this.renderer = this.options.renderer || new Renderer();
649 this.renderer.options = this.options;
650
651 if (!this.links) {
652 throw new Error('Tokens array requires a `links` property.');
653 }
654
655 if (this.options.pedantic) {
656 this.rules = inline.pedantic;
657 } else if (this.options.gfm) {
658 if (this.options.breaks) {
659 this.rules = inline.breaks;
660 } else {
661 this.rules = inline.gfm;
662 }
663 }
664}
665
666/**
667 * Expose Inline Rules
668 */
669
670InlineLexer.rules = inline;
671
672/**
673 * Static Lexing/Compiling Method
674 */
675
676InlineLexer.output = function(src, links, options) {
677 var inline = new InlineLexer(links, options);
678 return inline.output(src);
679};
680
681/**
682 * Lexing/Compiling
683 */
684
685InlineLexer.prototype.output = function(src) {
686 var out = '',
687 link,
688 text,
689 href,
690 title,
691 cap,
692 prevCapZero;
693
694 while (src) {
695 // escape
696 if (cap = this.rules.escape.exec(src)) {
697 src = src.substring(cap[0].length);
698 out += escape(cap[1]);
699 continue;
700 }
701
702 // tag
703 if (cap = this.rules.tag.exec(src)) {
704 if (!this.inLink && /^<a /i.test(cap[0])) {
705 this.inLink = true;
706 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
707 this.inLink = false;
708 }
709 if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
710 this.inRawBlock = true;
711 } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
712 this.inRawBlock = false;
713 }
714
715 src = src.substring(cap[0].length);
716 out += this.options.sanitize
717 ? this.options.sanitizer
718 ? this.options.sanitizer(cap[0])
719 : escape(cap[0])
720 : cap[0];
721 continue;
722 }
723
724 // link
725 if (cap = this.rules.link.exec(src)) {
726 var lastParenIndex = findClosingBracket(cap[2], '()');
727 if (lastParenIndex > -1) {
728 var linkLen = 4 + cap[1].length + lastParenIndex;
729 cap[2] = cap[2].substring(0, lastParenIndex);
730 cap[0] = cap[0].substring(0, linkLen).trim();
731 cap[3] = '';
732 }
733 src = src.substring(cap[0].length);
734 this.inLink = true;
735 href = cap[2];
736 if (this.options.pedantic) {
737 link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
738
739 if (link) {
740 href = link[1];
741 title = link[3];
742 } else {
743 title = '';
744 }
745 } else {
746 title = cap[3] ? cap[3].slice(1, -1) : '';
747 }
748 href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
749 out += this.outputLink(cap, {
750 href: InlineLexer.escapes(href),
751 title: InlineLexer.escapes(title)
752 });
753 this.inLink = false;
754 continue;
755 }
756
757 // reflink, nolink
758 if ((cap = this.rules.reflink.exec(src))
759 || (cap = this.rules.nolink.exec(src))) {
760 src = src.substring(cap[0].length);
761 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
762 link = this.links[link.toLowerCase()];
763 if (!link || !link.href) {
764 out += cap[0].charAt(0);
765 src = cap[0].substring(1) + src;
766 continue;
767 }
768 this.inLink = true;
769 out += this.outputLink(cap, link);
770 this.inLink = false;
771 continue;
772 }
773
774 // strong
775 if (cap = this.rules.strong.exec(src)) {
776 src = src.substring(cap[0].length);
777 out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1]));
778 continue;
779 }
780
781 // em
782 if (cap = this.rules.em.exec(src)) {
783 src = src.substring(cap[0].length);
784 out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]));
785 continue;
786 }
787
788 // code
789 if (cap = this.rules.code.exec(src)) {
790 src = src.substring(cap[0].length);
791 out += this.renderer.codespan(escape(cap[2].trim(), true));
792 continue;
793 }
794
795 // br
796 if (cap = this.rules.br.exec(src)) {
797 src = src.substring(cap[0].length);
798 out += this.renderer.br();
799 continue;
800 }
801
802 // del (gfm)
803 if (cap = this.rules.del.exec(src)) {
804 src = src.substring(cap[0].length);
805 out += this.renderer.del(this.output(cap[1]));
806 continue;
807 }
808
809 // autolink
810 if (cap = this.rules.autolink.exec(src)) {
811 src = src.substring(cap[0].length);
812 if (cap[2] === '@') {
813 text = escape(this.mangle(cap[1]));
814 href = 'mailto:' + text;
815 } else {
816 text = escape(cap[1]);
817 href = text;
818 }
819 out += this.renderer.link(href, null, text);
820 continue;
821 }
822
823 // url (gfm)
824 if (!this.inLink && (cap = this.rules.url.exec(src))) {
825 if (cap[2] === '@') {
826 text = escape(cap[0]);
827 href = 'mailto:' + text;
828 } else {
829 // do extended autolink path validation
830 do {
831 prevCapZero = cap[0];
832 cap[0] = this.rules._backpedal.exec(cap[0])[0];
833 } while (prevCapZero !== cap[0]);
834 text = escape(cap[0]);
835 if (cap[1] === 'www.') {
836 href = 'http://' + text;
837 } else {
838 href = text;
839 }
840 }
841 src = src.substring(cap[0].length);
842 out += this.renderer.link(href, null, text);
843 continue;
844 }
845
846 // text
847 if (cap = this.rules.text.exec(src)) {
848 src = src.substring(cap[0].length);
849 if (this.inRawBlock) {
850 out += this.renderer.text(this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]);
851 } else {
852 out += this.renderer.text(escape(this.smartypants(cap[0])));
853 }
854 continue;
855 }
856
857 if (src) {
858 throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
859 }
860 }
861
862 return out;
863};
864
865InlineLexer.escapes = function(text) {
866 return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
867};
868
869/**
870 * Compile Link
871 */
872
873InlineLexer.prototype.outputLink = function(cap, link) {
874 var href = link.href,
875 title = link.title ? escape(link.title) : null;
876
877 return cap[0].charAt(0) !== '!'
878 ? this.renderer.link(href, title, this.output(cap[1]))
879 : this.renderer.image(href, title, escape(cap[1]));
880};
881
882/**
883 * Smartypants Transformations
884 */
885
886InlineLexer.prototype.smartypants = function(text) {
887 if (!this.options.smartypants) return text;
888 return text
889 // em-dashes
890 .replace(/---/g, '\u2014')
891 // en-dashes
892 .replace(/--/g, '\u2013')
893 // opening singles
894 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
895 // closing singles & apostrophes
896 .replace(/'/g, '\u2019')
897 // opening doubles
898 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
899 // closing doubles
900 .replace(/"/g, '\u201d')
901 // ellipses
902 .replace(/\.{3}/g, '\u2026');
903};
904
905/**
906 * Mangle Links
907 */
908
909InlineLexer.prototype.mangle = function(text) {
910 if (!this.options.mangle) return text;
911 var out = '',
912 l = text.length,
913 i = 0,
914 ch;
915
916 for (; i < l; i++) {
917 ch = text.charCodeAt(i);
918 if (Math.random() > 0.5) {
919 ch = 'x' + ch.toString(16);
920 }
921 out += '&#' + ch + ';';
922 }
923
924 return out;
925};
926
927/**
928 * Renderer
929 */
930
931function Renderer(options) {
932 this.options = options || marked.defaults;
933}
934
935Renderer.prototype.code = function(code, infostring, escaped) {
936 var lang = (infostring || '').match(/\S*/)[0];
937 if (this.options.highlight) {
938 var out = this.options.highlight(code, lang);
939 if (out != null && out !== code) {
940 escaped = true;
941 code = out;
942 }
943 }
944
945 if (!lang) {
946 return '<pre><code>'
947 + (escaped ? code : escape(code, true))
948 + '</code></pre>';
949 }
950
951 return '<pre><code class="'
952 + this.options.langPrefix
953 + escape(lang, true)
954 + '">'
955 + (escaped ? code : escape(code, true))
956 + '</code></pre>\n';
957};
958
959Renderer.prototype.blockquote = function(quote) {
960 return '<blockquote>\n' + quote + '</blockquote>\n';
961};
962
963Renderer.prototype.html = function(html) {
964 return html;
965};
966
967Renderer.prototype.heading = function(text, level, raw, slugger) {
968 if (this.options.headerIds) {
969 return '<h'
970 + level
971 + ' id="'
972 + this.options.headerPrefix
973 + slugger.slug(raw)
974 + '">'
975 + text
976 + '</h'
977 + level
978 + '>\n';
979 }
980 // ignore IDs
981 return '<h' + level + '>' + text + '</h' + level + '>\n';
982};
983
984Renderer.prototype.hr = function() {
985 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
986};
987
988Renderer.prototype.list = function(body, ordered, start) {
989 var type = ordered ? 'ol' : 'ul',
990 startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
991 return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
992};
993
994Renderer.prototype.listitem = function(text) {
995 return '<li>' + text + '</li>\n';
996};
997
998Renderer.prototype.checkbox = function(checked) {
999 return '<input '
1000 + (checked ? 'checked="" ' : '')
1001 + 'disabled="" type="checkbox"'
1002 + (this.options.xhtml ? ' /' : '')
1003 + '> ';
1004};
1005
1006Renderer.prototype.paragraph = function(text) {
1007 return '<p>' + text + '</p>\n';
1008};
1009
1010Renderer.prototype.table = function(header, body) {
1011 if (body) body = '<tbody>' + body + '</tbody>';
1012
1013 return '<table>\n'
1014 + '<thead>\n'
1015 + header
1016 + '</thead>\n'
1017 + body
1018 + '</table>\n';
1019};
1020
1021Renderer.prototype.tablerow = function(content) {
1022 return '<tr>\n' + content + '</tr>\n';
1023};
1024
1025Renderer.prototype.tablecell = function(content, flags) {
1026 var type = flags.header ? 'th' : 'td';
1027 var tag = flags.align
1028 ? '<' + type + ' align="' + flags.align + '">'
1029 : '<' + type + '>';
1030 return tag + content + '</' + type + '>\n';
1031};
1032
1033// span level renderer
1034Renderer.prototype.strong = function(text) {
1035 return '<strong>' + text + '</strong>';
1036};
1037
1038Renderer.prototype.em = function(text) {
1039 return '<em>' + text + '</em>';
1040};
1041
1042Renderer.prototype.codespan = function(text) {
1043 return '<code>' + text + '</code>';
1044};
1045
1046Renderer.prototype.br = function() {
1047 return this.options.xhtml ? '<br/>' : '<br>';
1048};
1049
1050Renderer.prototype.del = function(text) {
1051 return '<del>' + text + '</del>';
1052};
1053
1054Renderer.prototype.link = function(href, title, text) {
1055 href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
1056 if (href === null) {
1057 return text;
1058 }
1059 var out = '<a href="' + escape(href) + '"';
1060 if (title) {
1061 out += ' title="' + title + '"';
1062 }
1063 out += '>' + text + '</a>';
1064 return out;
1065};
1066
1067Renderer.prototype.image = function(href, title, text) {
1068 href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
1069 if (href === null) {
1070 return text;
1071 }
1072
1073 var out = '<img src="' + href + '" alt="' + text + '"';
1074 if (title) {
1075 out += ' title="' + title + '"';
1076 }
1077 out += this.options.xhtml ? '/>' : '>';
1078 return out;
1079};
1080
1081Renderer.prototype.text = function(text) {
1082 return text;
1083};
1084
1085/**
1086 * TextRenderer
1087 * returns only the textual part of the token
1088 */
1089
1090function TextRenderer() {}
1091
1092// no need for block level renderers
1093
1094TextRenderer.prototype.strong =
1095TextRenderer.prototype.em =
1096TextRenderer.prototype.codespan =
1097TextRenderer.prototype.del =
1098TextRenderer.prototype.text = function(text) {
1099 return text;
1100};
1101
1102TextRenderer.prototype.link =
1103TextRenderer.prototype.image = function(href, title, text) {
1104 return '' + text;
1105};
1106
1107TextRenderer.prototype.br = function() {
1108 return '';
1109};
1110
1111/**
1112 * Parsing & Compiling
1113 */
1114
1115function Parser(options) {
1116 this.tokens = [];
1117 this.token = null;
1118 this.options = options || marked.defaults;
1119 this.options.renderer = this.options.renderer || new Renderer();
1120 this.renderer = this.options.renderer;
1121 this.renderer.options = this.options;
1122 this.slugger = new Slugger();
1123}
1124
1125/**
1126 * Static Parse Method
1127 */
1128
1129Parser.parse = function(src, options) {
1130 var parser = new Parser(options);
1131 return parser.parse(src);
1132};
1133
1134/**
1135 * Parse Loop
1136 */
1137
1138Parser.prototype.parse = function(src) {
1139 this.inline = new InlineLexer(src.links, this.options);
1140 // use an InlineLexer with a TextRenderer to extract pure text
1141 this.inlineText = new InlineLexer(
1142 src.links,
1143 merge({}, this.options, { renderer: new TextRenderer() })
1144 );
1145 this.tokens = src.reverse();
1146
1147 var out = '';
1148 while (this.next()) {
1149 out += this.tok();
1150 }
1151
1152 return out;
1153};
1154
1155/**
1156 * Next Token
1157 */
1158
1159Parser.prototype.next = function() {
1160 this.token = this.tokens.pop();
1161 return this.token;
1162};
1163
1164/**
1165 * Preview Next Token
1166 */
1167
1168Parser.prototype.peek = function() {
1169 return this.tokens[this.tokens.length - 1] || 0;
1170};
1171
1172/**
1173 * Parse Text Tokens
1174 */
1175
1176Parser.prototype.parseText = function() {
1177 var body = this.token.text;
1178
1179 while (this.peek().type === 'text') {
1180 body += '\n' + this.next().text;
1181 }
1182
1183 return this.inline.output(body);
1184};
1185
1186/**
1187 * Parse Current Token
1188 */
1189
1190Parser.prototype.tok = function() {
1191 switch (this.token.type) {
1192 case 'space': {
1193 return '';
1194 }
1195 case 'hr': {
1196 return this.renderer.hr();
1197 }
1198 case 'heading': {
1199 return this.renderer.heading(
1200 this.inline.output(this.token.text),
1201 this.token.depth,
1202 unescape(this.inlineText.output(this.token.text)),
1203 this.slugger);
1204 }
1205 case 'code': {
1206 return this.renderer.code(this.token.text,
1207 this.token.lang,
1208 this.token.escaped);
1209 }
1210 case 'table': {
1211 var header = '',
1212 body = '',
1213 i,
1214 row,
1215 cell,
1216 j;
1217
1218 // header
1219 cell = '';
1220 for (i = 0; i < this.token.header.length; i++) {
1221 cell += this.renderer.tablecell(
1222 this.inline.output(this.token.header[i]),
1223 { header: true, align: this.token.align[i] }
1224 );
1225 }
1226 header += this.renderer.tablerow(cell);
1227
1228 for (i = 0; i < this.token.cells.length; i++) {
1229 row = this.token.cells[i];
1230
1231 cell = '';
1232 for (j = 0; j < row.length; j++) {
1233 cell += this.renderer.tablecell(
1234 this.inline.output(row[j]),
1235 { header: false, align: this.token.align[j] }
1236 );
1237 }
1238
1239 body += this.renderer.tablerow(cell);
1240 }
1241 return this.renderer.table(header, body);
1242 }
1243 case 'blockquote_start': {
1244 body = '';
1245
1246 while (this.next().type !== 'blockquote_end') {
1247 body += this.tok();
1248 }
1249
1250 return this.renderer.blockquote(body);
1251 }
1252 case 'list_start': {
1253 body = '';
1254 var ordered = this.token.ordered,
1255 start = this.token.start;
1256
1257 while (this.next().type !== 'list_end') {
1258 body += this.tok();
1259 }
1260
1261 return this.renderer.list(body, ordered, start);
1262 }
1263 case 'list_item_start': {
1264 body = '';
1265 var loose = this.token.loose;
1266 var checked = this.token.checked;
1267 var task = this.token.task;
1268
1269 if (this.token.task) {
1270 body += this.renderer.checkbox(checked);
1271 }
1272
1273 while (this.next().type !== 'list_item_end') {
1274 body += !loose && this.token.type === 'text'
1275 ? this.parseText()
1276 : this.tok();
1277 }
1278 return this.renderer.listitem(body, task, checked);
1279 }
1280 case 'html': {
1281 // TODO parse inline content if parameter markdown=1
1282 return this.renderer.html(this.token.text);
1283 }
1284 case 'paragraph': {
1285 return this.renderer.paragraph(this.inline.output(this.token.text));
1286 }
1287 case 'text': {
1288 return this.renderer.paragraph(this.parseText());
1289 }
1290 default: {
1291 var errMsg = 'Token with "' + this.token.type + '" type was not found.';
1292 if (this.options.silent) {
1293 console.log(errMsg);
1294 } else {
1295 throw new Error(errMsg);
1296 }
1297 }
1298 }
1299};
1300
1301/**
1302 * Slugger generates header id
1303 */
1304
1305function Slugger() {
1306 this.seen = {};
1307}
1308
1309/**
1310 * Convert string to unique id
1311 */
1312
1313Slugger.prototype.slug = function(value) {
1314 var slug = value
1315 .toLowerCase()
1316 .trim()
1317 .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '')
1318 .replace(/\s/g, '-');
1319
1320 if (this.seen.hasOwnProperty(slug)) {
1321 var originalSlug = slug;
1322 do {
1323 this.seen[originalSlug]++;
1324 slug = originalSlug + '-' + this.seen[originalSlug];
1325 } while (this.seen.hasOwnProperty(slug));
1326 }
1327 this.seen[slug] = 0;
1328
1329 return slug;
1330};
1331
1332/**
1333 * Helpers
1334 */
1335
1336function escape(html, encode) {
1337 if (encode) {
1338 if (escape.escapeTest.test(html)) {
1339 return html.replace(escape.escapeReplace, function(ch) { return escape.replacements[ch]; });
1340 }
1341 } else {
1342 if (escape.escapeTestNoEncode.test(html)) {
1343 return html.replace(escape.escapeReplaceNoEncode, function(ch) { return escape.replacements[ch]; });
1344 }
1345 }
1346
1347 return html;
1348}
1349
1350escape.escapeTest = /[&<>"']/;
1351escape.escapeReplace = /[&<>"']/g;
1352escape.replacements = {
1353 '&': '&amp;',
1354 '<': '&lt;',
1355 '>': '&gt;',
1356 '"': '&quot;',
1357 "'": '&#39;'
1358};
1359
1360escape.escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
1361escape.escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
1362
1363function unescape(html) {
1364 // explicitly match decimal, hex, and named HTML entities
1365 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
1366 n = n.toLowerCase();
1367 if (n === 'colon') return ':';
1368 if (n.charAt(0) === '#') {
1369 return n.charAt(1) === 'x'
1370 ? String.fromCharCode(parseInt(n.substring(2), 16))
1371 : String.fromCharCode(+n.substring(1));
1372 }
1373 return '';
1374 });
1375}
1376
1377function edit(regex, opt) {
1378 regex = regex.source || regex;
1379 opt = opt || '';
1380 return {
1381 replace: function(name, val) {
1382 val = val.source || val;
1383 val = val.replace(/(^|[^\[])\^/g, '$1');
1384 regex = regex.replace(name, val);
1385 return this;
1386 },
1387 getRegex: function() {
1388 return new RegExp(regex, opt);
1389 }
1390 };
1391}
1392
1393function cleanUrl(sanitize, base, href) {
1394 if (sanitize) {
1395 try {
1396 var prot = decodeURIComponent(unescape(href))
1397 .replace(/[^\w:]/g, '')
1398 .toLowerCase();
1399 } catch (e) {
1400 return null;
1401 }
1402 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
1403 return null;
1404 }
1405 }
1406 if (base && !originIndependentUrl.test(href)) {
1407 href = resolveUrl(base, href);
1408 }
1409 try {
1410 href = encodeURI(href).replace(/%25/g, '%');
1411 } catch (e) {
1412 return null;
1413 }
1414 return href;
1415}
1416
1417function resolveUrl(base, href) {
1418 if (!baseUrls[' ' + base]) {
1419 // we can ignore everything in base after the last slash of its path component,
1420 // but we might need to add _that_
1421 // https://tools.ietf.org/html/rfc3986#section-3
1422 if (/^[^:]+:\/*[^/]*$/.test(base)) {
1423 baseUrls[' ' + base] = base + '/';
1424 } else {
1425 baseUrls[' ' + base] = rtrim(base, '/', true);
1426 }
1427 }
1428 base = baseUrls[' ' + base];
1429
1430 if (href.slice(0, 2) === '//') {
1431 return base.replace(/:[\s\S]*/, ':') + href;
1432 } else if (href.charAt(0) === '/') {
1433 return base.replace(/(:\/*[^/]*)[\s\S]*/, '$1') + href;
1434 } else {
1435 return base + href;
1436 }
1437}
1438var baseUrls = {};
1439var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
1440
1441function noop() {}
1442noop.exec = noop;
1443
1444function merge(obj) {
1445 var i = 1,
1446 target,
1447 key;
1448
1449 for (; i < arguments.length; i++) {
1450 target = arguments[i];
1451 for (key in target) {
1452 if (Object.prototype.hasOwnProperty.call(target, key)) {
1453 obj[key] = target[key];
1454 }
1455 }
1456 }
1457
1458 return obj;
1459}
1460
1461function splitCells(tableRow, count) {
1462 // ensure that every cell-delimiting pipe has a space
1463 // before it to distinguish it from an escaped pipe
1464 var row = tableRow.replace(/\|/g, function(match, offset, str) {
1465 var escaped = false,
1466 curr = offset;
1467 while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
1468 if (escaped) {
1469 // odd number of slashes means | is escaped
1470 // so we leave it alone
1471 return '|';
1472 } else {
1473 // add space before unescaped |
1474 return ' |';
1475 }
1476 }),
1477 cells = row.split(/ \|/),
1478 i = 0;
1479
1480 if (cells.length > count) {
1481 cells.splice(count);
1482 } else {
1483 while (cells.length < count) cells.push('');
1484 }
1485
1486 for (; i < cells.length; i++) {
1487 // leading or trailing whitespace is ignored per the gfm spec
1488 cells[i] = cells[i].trim().replace(/\\\|/g, '|');
1489 }
1490 return cells;
1491}
1492
1493// Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
1494// /c*$/ is vulnerable to REDOS.
1495// invert: Remove suffix of non-c chars instead. Default falsey.
1496function rtrim(str, c, invert) {
1497 if (str.length === 0) {
1498 return '';
1499 }
1500
1501 // Length of suffix matching the invert condition.
1502 var suffLen = 0;
1503
1504 // Step left until we fail to match the invert condition.
1505 while (suffLen < str.length) {
1506 var currChar = str.charAt(str.length - suffLen - 1);
1507 if (currChar === c && !invert) {
1508 suffLen++;
1509 } else if (currChar !== c && invert) {
1510 suffLen++;
1511 } else {
1512 break;
1513 }
1514 }
1515
1516 return str.substr(0, str.length - suffLen);
1517}
1518
1519function findClosingBracket(str, b) {
1520 if (str.indexOf(b[1]) === -1) {
1521 return -1;
1522 }
1523 var level = 0;
1524 for (var i = 0; i < str.length; i++) {
1525 if (str[i] === '\\') {
1526 i++;
1527 } else if (str[i] === b[0]) {
1528 level++;
1529 } else if (str[i] === b[1]) {
1530 level--;
1531 if (level < 0) {
1532 return i;
1533 }
1534 }
1535 }
1536 return -1;
1537}
1538
1539function checkSanitizeDeprecation(opt) {
1540 if (opt && opt.sanitize && !opt.silent) {
1541 console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
1542 }
1543}
1544
1545/**
1546 * Marked
1547 */
1548
1549function marked(src, opt, callback) {
1550 // throw error in case of non string input
1551 if (typeof src === 'undefined' || src === null) {
1552 throw new Error('marked(): input parameter is undefined or null');
1553 }
1554 if (typeof src !== 'string') {
1555 throw new Error('marked(): input parameter is of type '
1556 + Object.prototype.toString.call(src) + ', string expected');
1557 }
1558
1559 if (callback || typeof opt === 'function') {
1560 if (!callback) {
1561 callback = opt;
1562 opt = null;
1563 }
1564
1565 opt = merge({}, marked.defaults, opt || {});
1566 checkSanitizeDeprecation(opt);
1567
1568 var highlight = opt.highlight,
1569 tokens,
1570 pending,
1571 i = 0;
1572
1573 try {
1574 tokens = Lexer.lex(src, opt);
1575 } catch (e) {
1576 return callback(e);
1577 }
1578
1579 pending = tokens.length;
1580
1581 var done = function(err) {
1582 if (err) {
1583 opt.highlight = highlight;
1584 return callback(err);
1585 }
1586
1587 var out;
1588
1589 try {
1590 out = Parser.parse(tokens, opt);
1591 } catch (e) {
1592 err = e;
1593 }
1594
1595 opt.highlight = highlight;
1596
1597 return err
1598 ? callback(err)
1599 : callback(null, out);
1600 };
1601
1602 if (!highlight || highlight.length < 3) {
1603 return done();
1604 }
1605
1606 delete opt.highlight;
1607
1608 if (!pending) return done();
1609
1610 for (; i < tokens.length; i++) {
1611 (function(token) {
1612 if (token.type !== 'code') {
1613 return --pending || done();
1614 }
1615 return highlight(token.text, token.lang, function(err, code) {
1616 if (err) return done(err);
1617 if (code == null || code === token.text) {
1618 return --pending || done();
1619 }
1620 token.text = code;
1621 token.escaped = true;
1622 --pending || done();
1623 });
1624 })(tokens[i]);
1625 }
1626
1627 return;
1628 }
1629 try {
1630 if (opt) opt = merge({}, marked.defaults, opt);
1631 checkSanitizeDeprecation(opt);
1632 return Parser.parse(Lexer.lex(src, opt), opt);
1633 } catch (e) {
1634 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
1635 if ((opt || marked.defaults).silent) {
1636 return '<p>An error occurred:</p><pre>'
1637 + escape(e.message + '', true)
1638 + '</pre>';
1639 }
1640 throw e;
1641 }
1642}
1643
1644/**
1645 * Options
1646 */
1647
1648marked.options =
1649marked.setOptions = function(opt) {
1650 merge(marked.defaults, opt);
1651 return marked;
1652};
1653
1654marked.getDefaults = function() {
1655 return {
1656 baseUrl: null,
1657 breaks: false,
1658 gfm: true,
1659 headerIds: true,
1660 headerPrefix: '',
1661 highlight: null,
1662 langPrefix: 'language-',
1663 mangle: true,
1664 pedantic: false,
1665 renderer: new Renderer(),
1666 sanitize: false,
1667 sanitizer: null,
1668 silent: false,
1669 smartLists: false,
1670 smartypants: false,
1671 xhtml: false
1672 };
1673};
1674
1675marked.defaults = marked.getDefaults();
1676
1677/**
1678 * Expose
1679 */
1680
1681marked.Parser = Parser;
1682marked.parser = Parser.parse;
1683
1684marked.Renderer = Renderer;
1685marked.TextRenderer = TextRenderer;
1686
1687marked.Lexer = Lexer;
1688marked.lexer = Lexer.lex;
1689
1690marked.InlineLexer = InlineLexer;
1691marked.inlineLexer = InlineLexer.output;
1692
1693marked.Slugger = Slugger;
1694
1695marked.parse = marked;
1696
1697if (typeof module !== 'undefined' && typeof exports === 'object') {
1698 module.exports = marked;
1699} else if (typeof define === 'function' && define.amd) {
1700 define(function() { return marked; });
1701} else {
1702 root.marked = marked;
1703}
1704})(this || (typeof window !== 'undefined' ? window : global));