marked-rails 0.3.2.0 → 9.1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1266 +1,2412 @@
1
1
  /**
2
- * marked - a markdown parser
3
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4
- * https://github.com/chjj/marked
2
+ * marked v9.1.2 - a markdown parser
3
+ * Copyright (c) 2011-2023, Christopher Jeffrey. (MIT Licensed)
4
+ * https://github.com/markedjs/marked
5
5
  */
6
6
 
7
- ;(function() {
8
-
9
7
  /**
10
- * Block-Level Grammar
8
+ * DO NOT EDIT THIS FILE
9
+ * The code in this file is generated from files in ./src/
11
10
  */
12
11
 
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|closed|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.bullet = /(?:[*+-]|\d+\.)/;
31
- block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
32
- block.item = replace(block.item, 'gm')
33
- (/bull/g, block.bullet)
34
- ();
35
-
36
- block.list = replace(block.list)
37
- (/bull/g, block.bullet)
38
- ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
39
- ('def', '\\n+(?=' + block.def.source + ')')
40
- ();
41
-
42
- block.blockquote = replace(block.blockquote)
43
- ('def', block.def)
44
- ();
45
-
46
- block._tag = '(?!(?:'
47
- + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
48
- + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
49
- + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
50
-
51
- block.html = replace(block.html)
52
- ('comment', /<!--[\s\S]*?-->/)
53
- ('closed', /<(tag)[\s\S]+?<\/\1>/)
54
- ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
55
- (/tag/g, block._tag)
56
- ();
57
-
58
- block.paragraph = replace(block.paragraph)
59
- ('hr', block.hr)
60
- ('heading', block.heading)
61
- ('lheading', block.lheading)
62
- ('blockquote', block.blockquote)
63
- ('tag', '<' + block._tag)
64
- ('def', block.def)
65
- ();
66
-
67
- /**
68
- * Normal Block Grammar
69
- */
70
-
71
- block.normal = merge({}, block);
72
-
73
- /**
74
- * GFM Block Grammar
75
- */
76
-
77
- block.gfm = merge({}, block.normal, {
78
- fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
79
- paragraph: /^/
80
- });
81
-
82
- block.gfm.paragraph = replace(block.paragraph)
83
- ('(?!', '(?!'
84
- + block.gfm.fences.source.replace('\\1', '\\2') + '|'
85
- + block.list.source.replace('\\1', '\\3') + '|')
86
- ();
87
-
88
- /**
89
- * GFM + Tables Block Grammar
90
- */
91
-
92
- block.tables = merge({}, block.gfm, {
93
- nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
94
- table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
95
- });
96
-
97
- /**
98
- * Block Lexer
99
- */
100
-
101
- function Lexer(options) {
102
- this.tokens = [];
103
- this.tokens.links = {};
104
- this.options = options || marked.defaults;
105
- this.rules = block.normal;
106
-
107
- if (this.options.gfm) {
108
- if (this.options.tables) {
109
- this.rules = block.tables;
110
- } else {
111
- this.rules = block.gfm;
112
- }
113
- }
114
- }
115
-
116
- /**
117
- * Expose Block Rules
118
- */
119
-
120
- Lexer.rules = block;
121
-
122
- /**
123
- * Static Lex Method
124
- */
125
-
126
- Lexer.lex = function(src, options) {
127
- var lexer = new Lexer(options);
128
- return lexer.lex(src);
129
- };
130
-
131
- /**
132
- * Preprocessing
133
- */
134
-
135
- Lexer.prototype.lex = function(src) {
136
- src = src
137
- .replace(/\r\n|\r/g, '\n')
138
- .replace(/\t/g, ' ')
139
- .replace(/\u00a0/g, ' ')
140
- .replace(/\u2424/g, '\n');
141
-
142
- return this.token(src, true);
143
- };
144
-
145
- /**
146
- * Lexing
147
- */
148
-
149
- Lexer.prototype.token = function(src, top, bq) {
150
- var src = src.replace(/^ +$/gm, '')
151
- , next
152
- , loose
153
- , cap
154
- , bull
155
- , b
156
- , item
157
- , space
158
- , i
159
- , l;
160
-
161
- while (src) {
162
- // newline
163
- if (cap = this.rules.newline.exec(src)) {
164
- src = src.substring(cap[0].length);
165
- if (cap[0].length > 1) {
166
- this.tokens.push({
167
- type: 'space'
168
- });
169
- }
170
- }
171
-
172
- // code
173
- if (cap = this.rules.code.exec(src)) {
174
- src = src.substring(cap[0].length);
175
- cap = cap[0].replace(/^ {4}/gm, '');
176
- this.tokens.push({
177
- type: 'code',
178
- text: !this.options.pedantic
179
- ? cap.replace(/\n+$/, '')
180
- : cap
181
- });
182
- continue;
183
- }
184
-
185
- // fences (gfm)
186
- if (cap = this.rules.fences.exec(src)) {
187
- src = src.substring(cap[0].length);
188
- this.tokens.push({
189
- type: 'code',
190
- lang: cap[2],
191
- text: cap[3]
192
- });
193
- continue;
12
+ (function (global, factory) {
13
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
14
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
15
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.marked = {}));
16
+ })(this, (function (exports) { 'use strict';
17
+
18
+ /**
19
+ * Gets the original marked default options.
20
+ */
21
+ function _getDefaults() {
22
+ return {
23
+ async: false,
24
+ breaks: false,
25
+ extensions: null,
26
+ gfm: true,
27
+ hooks: null,
28
+ pedantic: false,
29
+ renderer: null,
30
+ silent: false,
31
+ tokenizer: null,
32
+ walkTokens: null
33
+ };
194
34
  }
195
-
196
- // heading
197
- if (cap = this.rules.heading.exec(src)) {
198
- src = src.substring(cap[0].length);
199
- this.tokens.push({
200
- type: 'heading',
201
- depth: cap[1].length,
202
- text: cap[2]
203
- });
204
- continue;
35
+ exports.defaults = _getDefaults();
36
+ function changeDefaults(newDefaults) {
37
+ exports.defaults = newDefaults;
205
38
  }
206
39
 
207
- // table no leading pipe (gfm)
208
- if (top && (cap = this.rules.nptable.exec(src))) {
209
- src = src.substring(cap[0].length);
210
-
211
- item = {
212
- type: 'table',
213
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
214
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
215
- cells: cap[3].replace(/\n$/, '').split('\n')
216
- };
217
-
218
- for (i = 0; i < item.align.length; i++) {
219
- if (/^ *-+: *$/.test(item.align[i])) {
220
- item.align[i] = 'right';
221
- } else if (/^ *:-+: *$/.test(item.align[i])) {
222
- item.align[i] = 'center';
223
- } else if (/^ *:-+ *$/.test(item.align[i])) {
224
- item.align[i] = 'left';
225
- } else {
226
- item.align[i] = null;
227
- }
228
- }
229
-
230
- for (i = 0; i < item.cells.length; i++) {
231
- item.cells[i] = item.cells[i].split(/ *\| */);
232
- }
233
-
234
- this.tokens.push(item);
235
-
236
- continue;
40
+ /**
41
+ * Helpers
42
+ */
43
+ const escapeTest = /[&<>"']/;
44
+ const escapeReplace = new RegExp(escapeTest.source, 'g');
45
+ const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
46
+ const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
47
+ const escapeReplacements = {
48
+ '&': '&amp;',
49
+ '<': '&lt;',
50
+ '>': '&gt;',
51
+ '"': '&quot;',
52
+ "'": '&#39;'
53
+ };
54
+ const getEscapeReplacement = (ch) => escapeReplacements[ch];
55
+ function escape(html, encode) {
56
+ if (encode) {
57
+ if (escapeTest.test(html)) {
58
+ return html.replace(escapeReplace, getEscapeReplacement);
59
+ }
60
+ }
61
+ else {
62
+ if (escapeTestNoEncode.test(html)) {
63
+ return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
64
+ }
65
+ }
66
+ return html;
237
67
  }
238
-
239
- // lheading
240
- if (cap = this.rules.lheading.exec(src)) {
241
- src = src.substring(cap[0].length);
242
- this.tokens.push({
243
- type: 'heading',
244
- depth: cap[2] === '=' ? 1 : 2,
245
- text: cap[1]
246
- });
247
- continue;
68
+ const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
69
+ function unescape(html) {
70
+ // explicitly match decimal, hex, and named HTML entities
71
+ return html.replace(unescapeTest, (_, n) => {
72
+ n = n.toLowerCase();
73
+ if (n === 'colon')
74
+ return ':';
75
+ if (n.charAt(0) === '#') {
76
+ return n.charAt(1) === 'x'
77
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
78
+ : String.fromCharCode(+n.substring(1));
79
+ }
80
+ return '';
81
+ });
248
82
  }
249
-
250
- // hr
251
- if (cap = this.rules.hr.exec(src)) {
252
- src = src.substring(cap[0].length);
253
- this.tokens.push({
254
- type: 'hr'
255
- });
256
- continue;
83
+ const caret = /(^|[^\[])\^/g;
84
+ function edit(regex, opt) {
85
+ regex = typeof regex === 'string' ? regex : regex.source;
86
+ opt = opt || '';
87
+ const obj = {
88
+ replace: (name, val) => {
89
+ val = typeof val === 'object' && 'source' in val ? val.source : val;
90
+ val = val.replace(caret, '$1');
91
+ regex = regex.replace(name, val);
92
+ return obj;
93
+ },
94
+ getRegex: () => {
95
+ return new RegExp(regex, opt);
96
+ }
97
+ };
98
+ return obj;
257
99
  }
258
-
259
- // blockquote
260
- if (cap = this.rules.blockquote.exec(src)) {
261
- src = src.substring(cap[0].length);
262
-
263
- this.tokens.push({
264
- type: 'blockquote_start'
265
- });
266
-
267
- cap = cap[0].replace(/^ *> ?/gm, '');
268
-
269
- // Pass `top` to keep the current
270
- // "toplevel" state. This is exactly
271
- // how markdown.pl works.
272
- this.token(cap, top, true);
273
-
274
- this.tokens.push({
275
- type: 'blockquote_end'
276
- });
277
-
278
- continue;
100
+ function cleanUrl(href) {
101
+ try {
102
+ href = encodeURI(href).replace(/%25/g, '%');
103
+ }
104
+ catch (e) {
105
+ return null;
106
+ }
107
+ return href;
279
108
  }
280
-
281
- // list
282
- if (cap = this.rules.list.exec(src)) {
283
- src = src.substring(cap[0].length);
284
- bull = cap[2];
285
-
286
- this.tokens.push({
287
- type: 'list_start',
288
- ordered: bull.length > 1
289
- });
290
-
291
- // Get each top-level item.
292
- cap = cap[0].match(this.rules.item);
293
-
294
- next = false;
295
- l = cap.length;
296
- i = 0;
297
-
298
- for (; i < l; i++) {
299
- item = cap[i];
300
-
301
- // Remove the list item's bullet
302
- // so it is seen as the next token.
303
- space = item.length;
304
- item = item.replace(/^ *([*+-]|\d+\.) +/, '');
305
-
306
- // Outdent whatever the
307
- // list item contains. Hacky.
308
- if (~item.indexOf('\n ')) {
309
- space -= item.length;
310
- item = !this.options.pedantic
311
- ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
312
- : item.replace(/^ {1,4}/gm, '');
109
+ const noopTest = { exec: () => null };
110
+ function splitCells(tableRow, count) {
111
+ // ensure that every cell-delimiting pipe has a space
112
+ // before it to distinguish it from an escaped pipe
113
+ const row = tableRow.replace(/\|/g, (match, offset, str) => {
114
+ let escaped = false;
115
+ let curr = offset;
116
+ while (--curr >= 0 && str[curr] === '\\')
117
+ escaped = !escaped;
118
+ if (escaped) {
119
+ // odd number of slashes means | is escaped
120
+ // so we leave it alone
121
+ return '|';
122
+ }
123
+ else {
124
+ // add space before unescaped |
125
+ return ' |';
126
+ }
127
+ }), cells = row.split(/ \|/);
128
+ let i = 0;
129
+ // First/last cell in a row cannot be empty if it has no leading/trailing pipe
130
+ if (!cells[0].trim()) {
131
+ cells.shift();
313
132
  }
314
-
315
- // Determine whether the next list item belongs here.
316
- // Backpedal if it does not belong in this list.
317
- if (this.options.smartLists && i !== l - 1) {
318
- b = block.bullet.exec(cap[i + 1])[0];
319
- if (bull !== b && !(bull.length > 1 && b.length > 1)) {
320
- src = cap.slice(i + 1).join('\n') + src;
321
- i = l - 1;
322
- }
133
+ if (cells.length > 0 && !cells[cells.length - 1].trim()) {
134
+ cells.pop();
323
135
  }
324
-
325
- // Determine whether item is loose or not.
326
- // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
327
- // for discount behavior.
328
- loose = next || /\n\n(?!\s*$)/.test(item);
329
- if (i !== l - 1) {
330
- next = item.charAt(item.length - 1) === '\n';
331
- if (!loose) loose = next;
136
+ if (count) {
137
+ if (cells.length > count) {
138
+ cells.splice(count);
139
+ }
140
+ else {
141
+ while (cells.length < count)
142
+ cells.push('');
143
+ }
332
144
  }
333
-
334
- this.tokens.push({
335
- type: loose
336
- ? 'loose_item_start'
337
- : 'list_item_start'
338
- });
339
-
340
- // Recurse.
341
- this.token(item, false, bq);
342
-
343
- this.tokens.push({
344
- type: 'list_item_end'
345
- });
346
- }
347
-
348
- this.tokens.push({
349
- type: 'list_end'
350
- });
351
-
352
- continue;
353
- }
354
-
355
- // html
356
- if (cap = this.rules.html.exec(src)) {
357
- src = src.substring(cap[0].length);
358
- this.tokens.push({
359
- type: this.options.sanitize
360
- ? 'paragraph'
361
- : 'html',
362
- pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
363
- text: cap[0]
364
- });
365
- continue;
366
- }
367
-
368
- // def
369
- if ((!bq && top) && (cap = this.rules.def.exec(src))) {
370
- src = src.substring(cap[0].length);
371
- this.tokens.links[cap[1].toLowerCase()] = {
372
- href: cap[2],
373
- title: cap[3]
374
- };
375
- continue;
376
- }
377
-
378
- // table (gfm)
379
- if (top && (cap = this.rules.table.exec(src))) {
380
- src = src.substring(cap[0].length);
381
-
382
- item = {
383
- type: 'table',
384
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
385
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
386
- cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
387
- };
388
-
389
- for (i = 0; i < item.align.length; i++) {
390
- if (/^ *-+: *$/.test(item.align[i])) {
391
- item.align[i] = 'right';
392
- } else if (/^ *:-+: *$/.test(item.align[i])) {
393
- item.align[i] = 'center';
394
- } else if (/^ *:-+ *$/.test(item.align[i])) {
395
- item.align[i] = 'left';
396
- } else {
397
- item.align[i] = null;
398
- }
399
- }
400
-
401
- for (i = 0; i < item.cells.length; i++) {
402
- item.cells[i] = item.cells[i]
403
- .replace(/^ *\| *| *\| *$/g, '')
404
- .split(/ *\| */);
405
- }
406
-
407
- this.tokens.push(item);
408
-
409
- continue;
410
- }
411
-
412
- // top-level paragraph
413
- if (top && (cap = this.rules.paragraph.exec(src))) {
414
- src = src.substring(cap[0].length);
415
- this.tokens.push({
416
- type: 'paragraph',
417
- text: cap[1].charAt(cap[1].length - 1) === '\n'
418
- ? cap[1].slice(0, -1)
419
- : cap[1]
420
- });
421
- continue;
422
- }
423
-
424
- // text
425
- if (cap = this.rules.text.exec(src)) {
426
- // Top-level should never reach here.
427
- src = src.substring(cap[0].length);
428
- this.tokens.push({
429
- type: 'text',
430
- text: cap[0]
431
- });
432
- continue;
433
- }
434
-
435
- if (src) {
436
- throw new
437
- Error('Infinite loop on byte: ' + src.charCodeAt(0));
438
- }
439
- }
440
-
441
- return this.tokens;
442
- };
443
-
444
- /**
445
- * Inline-Level Grammar
446
- */
447
-
448
- var inline = {
449
- escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
450
- autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
451
- url: noop,
452
- tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
453
- link: /^!?\[(inside)\]\(href\)/,
454
- reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
455
- nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
456
- strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
457
- em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
458
- code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
459
- br: /^ {2,}\n(?!\s*$)/,
460
- del: noop,
461
- text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
462
- };
463
-
464
- inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
465
- inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
466
-
467
- inline.link = replace(inline.link)
468
- ('inside', inline._inside)
469
- ('href', inline._href)
470
- ();
471
-
472
- inline.reflink = replace(inline.reflink)
473
- ('inside', inline._inside)
474
- ();
475
-
476
- /**
477
- * Normal Inline Grammar
478
- */
479
-
480
- inline.normal = merge({}, inline);
481
-
482
- /**
483
- * Pedantic Inline Grammar
484
- */
485
-
486
- inline.pedantic = merge({}, inline.normal, {
487
- strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
488
- em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
489
- });
490
-
491
- /**
492
- * GFM Inline Grammar
493
- */
494
-
495
- inline.gfm = merge({}, inline.normal, {
496
- escape: replace(inline.escape)('])', '~|])')(),
497
- url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
498
- del: /^~~(?=\S)([\s\S]*?\S)~~/,
499
- text: replace(inline.text)
500
- (']|', '~]|')
501
- ('|', '|https?://|')
502
- ()
503
- });
504
-
505
- /**
506
- * GFM + Line Breaks Inline Grammar
507
- */
508
-
509
- inline.breaks = merge({}, inline.gfm, {
510
- br: replace(inline.br)('{2,}', '*')(),
511
- text: replace(inline.gfm.text)('{2,}', '*')()
512
- });
513
-
514
- /**
515
- * Inline Lexer & Compiler
516
- */
517
-
518
- function InlineLexer(links, options) {
519
- this.options = options || marked.defaults;
520
- this.links = links;
521
- this.rules = inline.normal;
522
- this.renderer = this.options.renderer || new Renderer;
523
- this.renderer.options = this.options;
524
-
525
- if (!this.links) {
526
- throw new
527
- Error('Tokens array requires a `links` property.');
528
- }
529
-
530
- if (this.options.gfm) {
531
- if (this.options.breaks) {
532
- this.rules = inline.breaks;
533
- } else {
534
- this.rules = inline.gfm;
535
- }
536
- } else if (this.options.pedantic) {
537
- this.rules = inline.pedantic;
538
- }
539
- }
540
-
541
- /**
542
- * Expose Inline Rules
543
- */
544
-
545
- InlineLexer.rules = inline;
546
-
547
- /**
548
- * Static Lexing/Compiling Method
549
- */
550
-
551
- InlineLexer.output = function(src, links, options) {
552
- var inline = new InlineLexer(links, options);
553
- return inline.output(src);
554
- };
555
-
556
- /**
557
- * Lexing/Compiling
558
- */
559
-
560
- InlineLexer.prototype.output = function(src) {
561
- var out = ''
562
- , link
563
- , text
564
- , href
565
- , cap;
566
-
567
- while (src) {
568
- // escape
569
- if (cap = this.rules.escape.exec(src)) {
570
- src = src.substring(cap[0].length);
571
- out += cap[1];
572
- continue;
573
- }
574
-
575
- // autolink
576
- if (cap = this.rules.autolink.exec(src)) {
577
- src = src.substring(cap[0].length);
578
- if (cap[2] === '@') {
579
- text = cap[1].charAt(6) === ':'
580
- ? this.mangle(cap[1].substring(7))
581
- : this.mangle(cap[1]);
582
- href = this.mangle('mailto:') + text;
583
- } else {
584
- text = escape(cap[1]);
585
- href = text;
586
- }
587
- out += this.renderer.link(href, null, text);
588
- continue;
589
- }
590
-
591
- // url (gfm)
592
- if (!this.inLink && (cap = this.rules.url.exec(src))) {
593
- src = src.substring(cap[0].length);
594
- text = escape(cap[1]);
595
- href = text;
596
- out += this.renderer.link(href, null, text);
597
- continue;
598
- }
599
-
600
- // tag
601
- if (cap = this.rules.tag.exec(src)) {
602
- if (!this.inLink && /^<a /i.test(cap[0])) {
603
- this.inLink = true;
604
- } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
605
- this.inLink = false;
606
- }
607
- src = src.substring(cap[0].length);
608
- out += this.options.sanitize
609
- ? escape(cap[0])
610
- : cap[0];
611
- continue;
612
- }
613
-
614
- // link
615
- if (cap = this.rules.link.exec(src)) {
616
- src = src.substring(cap[0].length);
617
- this.inLink = true;
618
- out += this.outputLink(cap, {
619
- href: cap[2],
620
- title: cap[3]
621
- });
622
- this.inLink = false;
623
- continue;
624
- }
625
-
626
- // reflink, nolink
627
- if ((cap = this.rules.reflink.exec(src))
628
- || (cap = this.rules.nolink.exec(src))) {
629
- src = src.substring(cap[0].length);
630
- link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
631
- link = this.links[link.toLowerCase()];
632
- if (!link || !link.href) {
633
- out += cap[0].charAt(0);
634
- src = cap[0].substring(1) + src;
635
- continue;
636
- }
637
- this.inLink = true;
638
- out += this.outputLink(cap, link);
639
- this.inLink = false;
640
- continue;
641
- }
642
-
643
- // strong
644
- if (cap = this.rules.strong.exec(src)) {
645
- src = src.substring(cap[0].length);
646
- out += this.renderer.strong(this.output(cap[2] || cap[1]));
647
- continue;
648
- }
649
-
650
- // em
651
- if (cap = this.rules.em.exec(src)) {
652
- src = src.substring(cap[0].length);
653
- out += this.renderer.em(this.output(cap[2] || cap[1]));
654
- continue;
655
- }
656
-
657
- // code
658
- if (cap = this.rules.code.exec(src)) {
659
- src = src.substring(cap[0].length);
660
- out += this.renderer.codespan(escape(cap[2], true));
661
- continue;
662
- }
663
-
664
- // br
665
- if (cap = this.rules.br.exec(src)) {
666
- src = src.substring(cap[0].length);
667
- out += this.renderer.br();
668
- continue;
669
- }
670
-
671
- // del (gfm)
672
- if (cap = this.rules.del.exec(src)) {
673
- src = src.substring(cap[0].length);
674
- out += this.renderer.del(this.output(cap[1]));
675
- continue;
676
- }
677
-
678
- // text
679
- if (cap = this.rules.text.exec(src)) {
680
- src = src.substring(cap[0].length);
681
- out += escape(this.smartypants(cap[0]));
682
- continue;
683
- }
684
-
685
- if (src) {
686
- throw new
687
- Error('Infinite loop on byte: ' + src.charCodeAt(0));
688
- }
689
- }
690
-
691
- return out;
692
- };
693
-
694
- /**
695
- * Compile Link
696
- */
697
-
698
- InlineLexer.prototype.outputLink = function(cap, link) {
699
- var href = escape(link.href)
700
- , title = link.title ? escape(link.title) : null;
701
-
702
- return cap[0].charAt(0) !== '!'
703
- ? this.renderer.link(href, title, this.output(cap[1]))
704
- : this.renderer.image(href, title, escape(cap[1]));
705
- };
706
-
707
- /**
708
- * Smartypants Transformations
709
- */
710
-
711
- InlineLexer.prototype.smartypants = function(text) {
712
- if (!this.options.smartypants) return text;
713
- return text
714
- // em-dashes
715
- .replace(/--/g, '\u2014')
716
- // opening singles
717
- .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
718
- // closing singles & apostrophes
719
- .replace(/'/g, '\u2019')
720
- // opening doubles
721
- .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
722
- // closing doubles
723
- .replace(/"/g, '\u201d')
724
- // ellipses
725
- .replace(/\.{3}/g, '\u2026');
726
- };
727
-
728
- /**
729
- * Mangle Links
730
- */
731
-
732
- InlineLexer.prototype.mangle = function(text) {
733
- var out = ''
734
- , l = text.length
735
- , i = 0
736
- , ch;
737
-
738
- for (; i < l; i++) {
739
- ch = text.charCodeAt(i);
740
- if (Math.random() > 0.5) {
741
- ch = 'x' + ch.toString(16);
742
- }
743
- out += '&#' + ch + ';';
744
- }
745
-
746
- return out;
747
- };
748
-
749
- /**
750
- * Renderer
751
- */
752
-
753
- function Renderer(options) {
754
- this.options = options || {};
755
- }
756
-
757
- Renderer.prototype.code = function(code, lang, escaped) {
758
- if (this.options.highlight) {
759
- var out = this.options.highlight(code, lang);
760
- if (out != null && out !== code) {
761
- escaped = true;
762
- code = out;
145
+ for (; i < cells.length; i++) {
146
+ // leading or trailing whitespace is ignored per the gfm spec
147
+ cells[i] = cells[i].trim().replace(/\\\|/g, '|');
148
+ }
149
+ return cells;
763
150
  }
764
- }
765
-
766
- if (!lang) {
767
- return '<pre><code>'
768
- + (escaped ? code : escape(code, true))
769
- + '\n</code></pre>';
770
- }
771
-
772
- return '<pre><code class="'
773
- + this.options.langPrefix
774
- + escape(lang, true)
775
- + '">'
776
- + (escaped ? code : escape(code, true))
777
- + '\n</code></pre>\n';
778
- };
779
-
780
- Renderer.prototype.blockquote = function(quote) {
781
- return '<blockquote>\n' + quote + '</blockquote>\n';
782
- };
783
-
784
- Renderer.prototype.html = function(html) {
785
- return html;
786
- };
787
-
788
- Renderer.prototype.heading = function(text, level, raw) {
789
- return '<h'
790
- + level
791
- + ' id="'
792
- + this.options.headerPrefix
793
- + raw.toLowerCase().replace(/[^\w]+/g, '-')
794
- + '">'
795
- + text
796
- + '</h'
797
- + level
798
- + '>\n';
799
- };
800
-
801
- Renderer.prototype.hr = function() {
802
- return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
803
- };
804
-
805
- Renderer.prototype.list = function(body, ordered) {
806
- var type = ordered ? 'ol' : 'ul';
807
- return '<' + type + '>\n' + body + '</' + type + '>\n';
808
- };
809
-
810
- Renderer.prototype.listitem = function(text) {
811
- return '<li>' + text + '</li>\n';
812
- };
813
-
814
- Renderer.prototype.paragraph = function(text) {
815
- return '<p>' + text + '</p>\n';
816
- };
817
-
818
- Renderer.prototype.table = function(header, body) {
819
- return '<table>\n'
820
- + '<thead>\n'
821
- + header
822
- + '</thead>\n'
823
- + '<tbody>\n'
824
- + body
825
- + '</tbody>\n'
826
- + '</table>\n';
827
- };
828
-
829
- Renderer.prototype.tablerow = function(content) {
830
- return '<tr>\n' + content + '</tr>\n';
831
- };
832
-
833
- Renderer.prototype.tablecell = function(content, flags) {
834
- var type = flags.header ? 'th' : 'td';
835
- var tag = flags.align
836
- ? '<' + type + ' style="text-align:' + flags.align + '">'
837
- : '<' + type + '>';
838
- return tag + content + '</' + type + '>\n';
839
- };
840
-
841
- // span level renderer
842
- Renderer.prototype.strong = function(text) {
843
- return '<strong>' + text + '</strong>';
844
- };
845
-
846
- Renderer.prototype.em = function(text) {
847
- return '<em>' + text + '</em>';
848
- };
849
-
850
- Renderer.prototype.codespan = function(text) {
851
- return '<code>' + text + '</code>';
852
- };
853
-
854
- Renderer.prototype.br = function() {
855
- return this.options.xhtml ? '<br/>' : '<br>';
856
- };
857
-
858
- Renderer.prototype.del = function(text) {
859
- return '<del>' + text + '</del>';
860
- };
861
-
862
- Renderer.prototype.link = function(href, title, text) {
863
- if (this.options.sanitize) {
864
- try {
865
- var prot = decodeURIComponent(unescape(href))
866
- .replace(/[^\w:]/g, '')
867
- .toLowerCase();
868
- } catch (e) {
869
- return '';
151
+ /**
152
+ * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
153
+ * /c*$/ is vulnerable to REDOS.
154
+ *
155
+ * @param str
156
+ * @param c
157
+ * @param invert Remove suffix of non-c chars instead. Default falsey.
158
+ */
159
+ function rtrim(str, c, invert) {
160
+ const l = str.length;
161
+ if (l === 0) {
162
+ return '';
163
+ }
164
+ // Length of suffix matching the invert condition.
165
+ let suffLen = 0;
166
+ // Step left until we fail to match the invert condition.
167
+ while (suffLen < l) {
168
+ const currChar = str.charAt(l - suffLen - 1);
169
+ if (currChar === c && !invert) {
170
+ suffLen++;
171
+ }
172
+ else if (currChar !== c && invert) {
173
+ suffLen++;
174
+ }
175
+ else {
176
+ break;
177
+ }
178
+ }
179
+ return str.slice(0, l - suffLen);
870
180
  }
871
- if (prot.indexOf('javascript:') === 0) {
872
- return '';
181
+ function findClosingBracket(str, b) {
182
+ if (str.indexOf(b[1]) === -1) {
183
+ return -1;
184
+ }
185
+ let level = 0;
186
+ for (let i = 0; i < str.length; i++) {
187
+ if (str[i] === '\\') {
188
+ i++;
189
+ }
190
+ else if (str[i] === b[0]) {
191
+ level++;
192
+ }
193
+ else if (str[i] === b[1]) {
194
+ level--;
195
+ if (level < 0) {
196
+ return i;
197
+ }
198
+ }
199
+ }
200
+ return -1;
873
201
  }
874
- }
875
- var out = '<a href="' + href + '"';
876
- if (title) {
877
- out += ' title="' + title + '"';
878
- }
879
- out += '>' + text + '</a>';
880
- return out;
881
- };
882
-
883
- Renderer.prototype.image = function(href, title, text) {
884
- var out = '<img src="' + href + '" alt="' + text + '"';
885
- if (title) {
886
- out += ' title="' + title + '"';
887
- }
888
- out += this.options.xhtml ? '/>' : '>';
889
- return out;
890
- };
891
-
892
- /**
893
- * Parsing & Compiling
894
- */
895
-
896
- function Parser(options) {
897
- this.tokens = [];
898
- this.token = null;
899
- this.options = options || marked.defaults;
900
- this.options.renderer = this.options.renderer || new Renderer;
901
- this.renderer = this.options.renderer;
902
- this.renderer.options = this.options;
903
- }
904
-
905
- /**
906
- * Static Parse Method
907
- */
908
-
909
- Parser.parse = function(src, options, renderer) {
910
- var parser = new Parser(options, renderer);
911
- return parser.parse(src);
912
- };
913
-
914
- /**
915
- * Parse Loop
916
- */
917
-
918
- Parser.prototype.parse = function(src) {
919
- this.inline = new InlineLexer(src.links, this.options, this.renderer);
920
- this.tokens = src.reverse();
921
-
922
- var out = '';
923
- while (this.next()) {
924
- out += this.tok();
925
- }
926
-
927
- return out;
928
- };
929
-
930
- /**
931
- * Next Token
932
- */
933
-
934
- Parser.prototype.next = function() {
935
- return this.token = this.tokens.pop();
936
- };
937
-
938
- /**
939
- * Preview Next Token
940
- */
941
-
942
- Parser.prototype.peek = function() {
943
- return this.tokens[this.tokens.length - 1] || 0;
944
- };
945
-
946
- /**
947
- * Parse Text Tokens
948
- */
949
-
950
- Parser.prototype.parseText = function() {
951
- var body = this.token.text;
952
-
953
- while (this.peek().type === 'text') {
954
- body += '\n' + this.next().text;
955
- }
956
202
 
957
- return this.inline.output(body);
958
- };
959
-
960
- /**
961
- * Parse Current Token
962
- */
963
-
964
- Parser.prototype.tok = function() {
965
- switch (this.token.type) {
966
- case 'space': {
967
- return '';
968
- }
969
- case 'hr': {
970
- return this.renderer.hr();
971
- }
972
- case 'heading': {
973
- return this.renderer.heading(
974
- this.inline.output(this.token.text),
975
- this.token.depth,
976
- this.token.text);
977
- }
978
- case 'code': {
979
- return this.renderer.code(this.token.text,
980
- this.token.lang,
981
- this.token.escaped);
203
+ function outputLink(cap, link, raw, lexer) {
204
+ const href = link.href;
205
+ const title = link.title ? escape(link.title) : null;
206
+ const text = cap[1].replace(/\\([\[\]])/g, '$1');
207
+ if (cap[0].charAt(0) !== '!') {
208
+ lexer.state.inLink = true;
209
+ const token = {
210
+ type: 'link',
211
+ raw,
212
+ href,
213
+ title,
214
+ text,
215
+ tokens: lexer.inlineTokens(text)
216
+ };
217
+ lexer.state.inLink = false;
218
+ return token;
219
+ }
220
+ return {
221
+ type: 'image',
222
+ raw,
223
+ href,
224
+ title,
225
+ text: escape(text)
226
+ };
982
227
  }
983
- case 'table': {
984
- var header = ''
985
- , body = ''
986
- , i
987
- , row
988
- , cell
989
- , flags
990
- , j;
991
-
992
- // header
993
- cell = '';
994
- for (i = 0; i < this.token.header.length; i++) {
995
- flags = { header: true, align: this.token.align[i] };
996
- cell += this.renderer.tablecell(
997
- this.inline.output(this.token.header[i]),
998
- { header: true, align: this.token.align[i] }
999
- );
1000
- }
1001
- header += this.renderer.tablerow(cell);
1002
-
1003
- for (i = 0; i < this.token.cells.length; i++) {
1004
- row = this.token.cells[i];
1005
-
1006
- cell = '';
1007
- for (j = 0; j < row.length; j++) {
1008
- cell += this.renderer.tablecell(
1009
- this.inline.output(row[j]),
1010
- { header: false, align: this.token.align[j] }
1011
- );
228
+ function indentCodeCompensation(raw, text) {
229
+ const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
230
+ if (matchIndentToCode === null) {
231
+ return text;
1012
232
  }
1013
-
1014
- body += this.renderer.tablerow(cell);
1015
- }
1016
- return this.renderer.table(header, body);
233
+ const indentToCode = matchIndentToCode[1];
234
+ return text
235
+ .split('\n')
236
+ .map(node => {
237
+ const matchIndentInNode = node.match(/^\s+/);
238
+ if (matchIndentInNode === null) {
239
+ return node;
240
+ }
241
+ const [indentInNode] = matchIndentInNode;
242
+ if (indentInNode.length >= indentToCode.length) {
243
+ return node.slice(indentToCode.length);
244
+ }
245
+ return node;
246
+ })
247
+ .join('\n');
1017
248
  }
1018
- case 'blockquote_start': {
1019
- var body = '';
1020
-
1021
- while (this.next().type !== 'blockquote_end') {
1022
- body += this.tok();
1023
- }
1024
-
1025
- return this.renderer.blockquote(body);
249
+ /**
250
+ * Tokenizer
251
+ */
252
+ class _Tokenizer {
253
+ options;
254
+ // TODO: Fix this rules type
255
+ rules;
256
+ lexer;
257
+ constructor(options) {
258
+ this.options = options || exports.defaults;
259
+ }
260
+ space(src) {
261
+ const cap = this.rules.block.newline.exec(src);
262
+ if (cap && cap[0].length > 0) {
263
+ return {
264
+ type: 'space',
265
+ raw: cap[0]
266
+ };
267
+ }
268
+ }
269
+ code(src) {
270
+ const cap = this.rules.block.code.exec(src);
271
+ if (cap) {
272
+ const text = cap[0].replace(/^ {1,4}/gm, '');
273
+ return {
274
+ type: 'code',
275
+ raw: cap[0],
276
+ codeBlockStyle: 'indented',
277
+ text: !this.options.pedantic
278
+ ? rtrim(text, '\n')
279
+ : text
280
+ };
281
+ }
282
+ }
283
+ fences(src) {
284
+ const cap = this.rules.block.fences.exec(src);
285
+ if (cap) {
286
+ const raw = cap[0];
287
+ const text = indentCodeCompensation(raw, cap[3] || '');
288
+ return {
289
+ type: 'code',
290
+ raw,
291
+ lang: cap[2] ? cap[2].trim().replace(this.rules.inline._escapes, '$1') : cap[2],
292
+ text
293
+ };
294
+ }
295
+ }
296
+ heading(src) {
297
+ const cap = this.rules.block.heading.exec(src);
298
+ if (cap) {
299
+ let text = cap[2].trim();
300
+ // remove trailing #s
301
+ if (/#$/.test(text)) {
302
+ const trimmed = rtrim(text, '#');
303
+ if (this.options.pedantic) {
304
+ text = trimmed.trim();
305
+ }
306
+ else if (!trimmed || / $/.test(trimmed)) {
307
+ // CommonMark requires space before trailing #s
308
+ text = trimmed.trim();
309
+ }
310
+ }
311
+ return {
312
+ type: 'heading',
313
+ raw: cap[0],
314
+ depth: cap[1].length,
315
+ text,
316
+ tokens: this.lexer.inline(text)
317
+ };
318
+ }
319
+ }
320
+ hr(src) {
321
+ const cap = this.rules.block.hr.exec(src);
322
+ if (cap) {
323
+ return {
324
+ type: 'hr',
325
+ raw: cap[0]
326
+ };
327
+ }
328
+ }
329
+ blockquote(src) {
330
+ const cap = this.rules.block.blockquote.exec(src);
331
+ if (cap) {
332
+ const text = rtrim(cap[0].replace(/^ *>[ \t]?/gm, ''), '\n');
333
+ const top = this.lexer.state.top;
334
+ this.lexer.state.top = true;
335
+ const tokens = this.lexer.blockTokens(text);
336
+ this.lexer.state.top = top;
337
+ return {
338
+ type: 'blockquote',
339
+ raw: cap[0],
340
+ tokens,
341
+ text
342
+ };
343
+ }
344
+ }
345
+ list(src) {
346
+ let cap = this.rules.block.list.exec(src);
347
+ if (cap) {
348
+ let bull = cap[1].trim();
349
+ const isordered = bull.length > 1;
350
+ const list = {
351
+ type: 'list',
352
+ raw: '',
353
+ ordered: isordered,
354
+ start: isordered ? +bull.slice(0, -1) : '',
355
+ loose: false,
356
+ items: []
357
+ };
358
+ bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
359
+ if (this.options.pedantic) {
360
+ bull = isordered ? bull : '[*+-]';
361
+ }
362
+ // Get next list item
363
+ const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
364
+ let raw = '';
365
+ let itemContents = '';
366
+ let endsWithBlankLine = false;
367
+ // Check if current bullet point can start a new List Item
368
+ while (src) {
369
+ let endEarly = false;
370
+ if (!(cap = itemRegex.exec(src))) {
371
+ break;
372
+ }
373
+ if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)
374
+ break;
375
+ }
376
+ raw = cap[0];
377
+ src = src.substring(raw.length);
378
+ let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length));
379
+ let nextLine = src.split('\n', 1)[0];
380
+ let indent = 0;
381
+ if (this.options.pedantic) {
382
+ indent = 2;
383
+ itemContents = line.trimStart();
384
+ }
385
+ else {
386
+ indent = cap[2].search(/[^ ]/); // Find first non-space char
387
+ indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
388
+ itemContents = line.slice(indent);
389
+ indent += cap[1].length;
390
+ }
391
+ let blankLine = false;
392
+ if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line
393
+ raw += nextLine + '\n';
394
+ src = src.substring(nextLine.length + 1);
395
+ endEarly = true;
396
+ }
397
+ if (!endEarly) {
398
+ const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`);
399
+ const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
400
+ const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
401
+ const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
402
+ // Check if following lines should be included in List Item
403
+ while (src) {
404
+ const rawLine = src.split('\n', 1)[0];
405
+ nextLine = rawLine;
406
+ // Re-align to follow commonmark nesting rules
407
+ if (this.options.pedantic) {
408
+ nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
409
+ }
410
+ // End list item if found code fences
411
+ if (fencesBeginRegex.test(nextLine)) {
412
+ break;
413
+ }
414
+ // End list item if found start of new heading
415
+ if (headingBeginRegex.test(nextLine)) {
416
+ break;
417
+ }
418
+ // End list item if found start of new bullet
419
+ if (nextBulletRegex.test(nextLine)) {
420
+ break;
421
+ }
422
+ // Horizontal rule found
423
+ if (hrRegex.test(src)) {
424
+ break;
425
+ }
426
+ if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible
427
+ itemContents += '\n' + nextLine.slice(indent);
428
+ }
429
+ else {
430
+ // not enough indentation
431
+ if (blankLine) {
432
+ break;
433
+ }
434
+ // paragraph continuation unless last line was a different block level element
435
+ if (line.search(/[^ ]/) >= 4) { // indented code block
436
+ break;
437
+ }
438
+ if (fencesBeginRegex.test(line)) {
439
+ break;
440
+ }
441
+ if (headingBeginRegex.test(line)) {
442
+ break;
443
+ }
444
+ if (hrRegex.test(line)) {
445
+ break;
446
+ }
447
+ itemContents += '\n' + nextLine;
448
+ }
449
+ if (!blankLine && !nextLine.trim()) { // Check if current line is blank
450
+ blankLine = true;
451
+ }
452
+ raw += rawLine + '\n';
453
+ src = src.substring(rawLine.length + 1);
454
+ line = nextLine.slice(indent);
455
+ }
456
+ }
457
+ if (!list.loose) {
458
+ // If the previous item ended with a blank line, the list is loose
459
+ if (endsWithBlankLine) {
460
+ list.loose = true;
461
+ }
462
+ else if (/\n *\n *$/.test(raw)) {
463
+ endsWithBlankLine = true;
464
+ }
465
+ }
466
+ let istask = null;
467
+ let ischecked;
468
+ // Check for task list items
469
+ if (this.options.gfm) {
470
+ istask = /^\[[ xX]\] /.exec(itemContents);
471
+ if (istask) {
472
+ ischecked = istask[0] !== '[ ] ';
473
+ itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
474
+ }
475
+ }
476
+ list.items.push({
477
+ type: 'list_item',
478
+ raw,
479
+ task: !!istask,
480
+ checked: ischecked,
481
+ loose: false,
482
+ text: itemContents,
483
+ tokens: []
484
+ });
485
+ list.raw += raw;
486
+ }
487
+ // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
488
+ list.items[list.items.length - 1].raw = raw.trimEnd();
489
+ list.items[list.items.length - 1].text = itemContents.trimEnd();
490
+ list.raw = list.raw.trimEnd();
491
+ // Item child tokens handled here at end because we needed to have the final item to trim it first
492
+ for (let i = 0; i < list.items.length; i++) {
493
+ this.lexer.state.top = false;
494
+ list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
495
+ if (!list.loose) {
496
+ // Check if list should be loose
497
+ const spacers = list.items[i].tokens.filter(t => t.type === 'space');
498
+ const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw));
499
+ list.loose = hasMultipleLineBreaks;
500
+ }
501
+ }
502
+ // Set all items to loose if list is loose
503
+ if (list.loose) {
504
+ for (let i = 0; i < list.items.length; i++) {
505
+ list.items[i].loose = true;
506
+ }
507
+ }
508
+ return list;
509
+ }
510
+ }
511
+ html(src) {
512
+ const cap = this.rules.block.html.exec(src);
513
+ if (cap) {
514
+ const token = {
515
+ type: 'html',
516
+ block: true,
517
+ raw: cap[0],
518
+ pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
519
+ text: cap[0]
520
+ };
521
+ return token;
522
+ }
523
+ }
524
+ def(src) {
525
+ const cap = this.rules.block.def.exec(src);
526
+ if (cap) {
527
+ const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
528
+ const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline._escapes, '$1') : '';
529
+ const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline._escapes, '$1') : cap[3];
530
+ return {
531
+ type: 'def',
532
+ tag,
533
+ raw: cap[0],
534
+ href,
535
+ title
536
+ };
537
+ }
538
+ }
539
+ table(src) {
540
+ const cap = this.rules.block.table.exec(src);
541
+ if (cap) {
542
+ if (!/[:|]/.test(cap[2])) {
543
+ // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
544
+ return;
545
+ }
546
+ const item = {
547
+ type: 'table',
548
+ raw: cap[0],
549
+ header: splitCells(cap[1]).map(c => {
550
+ return { text: c, tokens: [] };
551
+ }),
552
+ align: cap[2].replace(/^\||\| *$/g, '').split('|'),
553
+ rows: cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : []
554
+ };
555
+ if (item.header.length === item.align.length) {
556
+ let l = item.align.length;
557
+ let i, j, k, row;
558
+ for (i = 0; i < l; i++) {
559
+ const align = item.align[i];
560
+ if (align) {
561
+ if (/^ *-+: *$/.test(align)) {
562
+ item.align[i] = 'right';
563
+ }
564
+ else if (/^ *:-+: *$/.test(align)) {
565
+ item.align[i] = 'center';
566
+ }
567
+ else if (/^ *:-+ *$/.test(align)) {
568
+ item.align[i] = 'left';
569
+ }
570
+ else {
571
+ item.align[i] = null;
572
+ }
573
+ }
574
+ }
575
+ l = item.rows.length;
576
+ for (i = 0; i < l; i++) {
577
+ item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => {
578
+ return { text: c, tokens: [] };
579
+ });
580
+ }
581
+ // parse child tokens inside headers and cells
582
+ // header child tokens
583
+ l = item.header.length;
584
+ for (j = 0; j < l; j++) {
585
+ item.header[j].tokens = this.lexer.inline(item.header[j].text);
586
+ }
587
+ // cell child tokens
588
+ l = item.rows.length;
589
+ for (j = 0; j < l; j++) {
590
+ row = item.rows[j];
591
+ for (k = 0; k < row.length; k++) {
592
+ row[k].tokens = this.lexer.inline(row[k].text);
593
+ }
594
+ }
595
+ return item;
596
+ }
597
+ }
598
+ }
599
+ lheading(src) {
600
+ const cap = this.rules.block.lheading.exec(src);
601
+ if (cap) {
602
+ return {
603
+ type: 'heading',
604
+ raw: cap[0],
605
+ depth: cap[2].charAt(0) === '=' ? 1 : 2,
606
+ text: cap[1],
607
+ tokens: this.lexer.inline(cap[1])
608
+ };
609
+ }
610
+ }
611
+ paragraph(src) {
612
+ const cap = this.rules.block.paragraph.exec(src);
613
+ if (cap) {
614
+ const text = cap[1].charAt(cap[1].length - 1) === '\n'
615
+ ? cap[1].slice(0, -1)
616
+ : cap[1];
617
+ return {
618
+ type: 'paragraph',
619
+ raw: cap[0],
620
+ text,
621
+ tokens: this.lexer.inline(text)
622
+ };
623
+ }
624
+ }
625
+ text(src) {
626
+ const cap = this.rules.block.text.exec(src);
627
+ if (cap) {
628
+ return {
629
+ type: 'text',
630
+ raw: cap[0],
631
+ text: cap[0],
632
+ tokens: this.lexer.inline(cap[0])
633
+ };
634
+ }
635
+ }
636
+ escape(src) {
637
+ const cap = this.rules.inline.escape.exec(src);
638
+ if (cap) {
639
+ return {
640
+ type: 'escape',
641
+ raw: cap[0],
642
+ text: escape(cap[1])
643
+ };
644
+ }
645
+ }
646
+ tag(src) {
647
+ const cap = this.rules.inline.tag.exec(src);
648
+ if (cap) {
649
+ if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
650
+ this.lexer.state.inLink = true;
651
+ }
652
+ else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
653
+ this.lexer.state.inLink = false;
654
+ }
655
+ if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
656
+ this.lexer.state.inRawBlock = true;
657
+ }
658
+ else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
659
+ this.lexer.state.inRawBlock = false;
660
+ }
661
+ return {
662
+ type: 'html',
663
+ raw: cap[0],
664
+ inLink: this.lexer.state.inLink,
665
+ inRawBlock: this.lexer.state.inRawBlock,
666
+ block: false,
667
+ text: cap[0]
668
+ };
669
+ }
670
+ }
671
+ link(src) {
672
+ const cap = this.rules.inline.link.exec(src);
673
+ if (cap) {
674
+ const trimmedUrl = cap[2].trim();
675
+ if (!this.options.pedantic && /^</.test(trimmedUrl)) {
676
+ // commonmark requires matching angle brackets
677
+ if (!(/>$/.test(trimmedUrl))) {
678
+ return;
679
+ }
680
+ // ending angle bracket cannot be escaped
681
+ const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
682
+ if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
683
+ return;
684
+ }
685
+ }
686
+ else {
687
+ // find closing parenthesis
688
+ const lastParenIndex = findClosingBracket(cap[2], '()');
689
+ if (lastParenIndex > -1) {
690
+ const start = cap[0].indexOf('!') === 0 ? 5 : 4;
691
+ const linkLen = start + cap[1].length + lastParenIndex;
692
+ cap[2] = cap[2].substring(0, lastParenIndex);
693
+ cap[0] = cap[0].substring(0, linkLen).trim();
694
+ cap[3] = '';
695
+ }
696
+ }
697
+ let href = cap[2];
698
+ let title = '';
699
+ if (this.options.pedantic) {
700
+ // split pedantic href and title
701
+ const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
702
+ if (link) {
703
+ href = link[1];
704
+ title = link[3];
705
+ }
706
+ }
707
+ else {
708
+ title = cap[3] ? cap[3].slice(1, -1) : '';
709
+ }
710
+ href = href.trim();
711
+ if (/^</.test(href)) {
712
+ if (this.options.pedantic && !(/>$/.test(trimmedUrl))) {
713
+ // pedantic allows starting angle bracket without ending angle bracket
714
+ href = href.slice(1);
715
+ }
716
+ else {
717
+ href = href.slice(1, -1);
718
+ }
719
+ }
720
+ return outputLink(cap, {
721
+ href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
722
+ title: title ? title.replace(this.rules.inline._escapes, '$1') : title
723
+ }, cap[0], this.lexer);
724
+ }
725
+ }
726
+ reflink(src, links) {
727
+ let cap;
728
+ if ((cap = this.rules.inline.reflink.exec(src))
729
+ || (cap = this.rules.inline.nolink.exec(src))) {
730
+ let link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
731
+ link = links[link.toLowerCase()];
732
+ if (!link) {
733
+ const text = cap[0].charAt(0);
734
+ return {
735
+ type: 'text',
736
+ raw: text,
737
+ text
738
+ };
739
+ }
740
+ return outputLink(cap, link, cap[0], this.lexer);
741
+ }
742
+ }
743
+ emStrong(src, maskedSrc, prevChar = '') {
744
+ let match = this.rules.inline.emStrong.lDelim.exec(src);
745
+ if (!match)
746
+ return;
747
+ // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
748
+ if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
749
+ return;
750
+ const nextChar = match[1] || match[2] || '';
751
+ if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
752
+ // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
753
+ const lLength = [...match[0]].length - 1;
754
+ let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
755
+ const endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
756
+ endReg.lastIndex = 0;
757
+ // Clip maskedSrc to same section of string as src (move to lexer?)
758
+ maskedSrc = maskedSrc.slice(-1 * src.length + match[0].length - 1);
759
+ while ((match = endReg.exec(maskedSrc)) != null) {
760
+ rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
761
+ if (!rDelim)
762
+ continue; // skip single * in __abc*abc__
763
+ rLength = [...rDelim].length;
764
+ if (match[3] || match[4]) { // found another Left Delim
765
+ delimTotal += rLength;
766
+ continue;
767
+ }
768
+ else if (match[5] || match[6]) { // either Left or Right Delim
769
+ if (lLength % 3 && !((lLength + rLength) % 3)) {
770
+ midDelimTotal += rLength;
771
+ continue; // CommonMark Emphasis Rules 9-10
772
+ }
773
+ }
774
+ delimTotal -= rLength;
775
+ if (delimTotal > 0)
776
+ continue; // Haven't found enough closing delimiters
777
+ // Remove extra characters. *a*** -> *a*
778
+ rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
779
+ const raw = [...src].slice(0, lLength + match.index + rLength + 1).join('');
780
+ // Create `em` if smallest delimiter has odd char count. *a***
781
+ if (Math.min(lLength, rLength) % 2) {
782
+ const text = raw.slice(1, -1);
783
+ return {
784
+ type: 'em',
785
+ raw,
786
+ text,
787
+ tokens: this.lexer.inlineTokens(text)
788
+ };
789
+ }
790
+ // Create 'strong' if smallest delimiter has even char count. **a***
791
+ const text = raw.slice(2, -2);
792
+ return {
793
+ type: 'strong',
794
+ raw,
795
+ text,
796
+ tokens: this.lexer.inlineTokens(text)
797
+ };
798
+ }
799
+ }
800
+ }
801
+ codespan(src) {
802
+ const cap = this.rules.inline.code.exec(src);
803
+ if (cap) {
804
+ let text = cap[2].replace(/\n/g, ' ');
805
+ const hasNonSpaceChars = /[^ ]/.test(text);
806
+ const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
807
+ if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
808
+ text = text.substring(1, text.length - 1);
809
+ }
810
+ text = escape(text, true);
811
+ return {
812
+ type: 'codespan',
813
+ raw: cap[0],
814
+ text
815
+ };
816
+ }
817
+ }
818
+ br(src) {
819
+ const cap = this.rules.inline.br.exec(src);
820
+ if (cap) {
821
+ return {
822
+ type: 'br',
823
+ raw: cap[0]
824
+ };
825
+ }
826
+ }
827
+ del(src) {
828
+ const cap = this.rules.inline.del.exec(src);
829
+ if (cap) {
830
+ return {
831
+ type: 'del',
832
+ raw: cap[0],
833
+ text: cap[2],
834
+ tokens: this.lexer.inlineTokens(cap[2])
835
+ };
836
+ }
837
+ }
838
+ autolink(src) {
839
+ const cap = this.rules.inline.autolink.exec(src);
840
+ if (cap) {
841
+ let text, href;
842
+ if (cap[2] === '@') {
843
+ text = escape(cap[1]);
844
+ href = 'mailto:' + text;
845
+ }
846
+ else {
847
+ text = escape(cap[1]);
848
+ href = text;
849
+ }
850
+ return {
851
+ type: 'link',
852
+ raw: cap[0],
853
+ text,
854
+ href,
855
+ tokens: [
856
+ {
857
+ type: 'text',
858
+ raw: text,
859
+ text
860
+ }
861
+ ]
862
+ };
863
+ }
864
+ }
865
+ url(src) {
866
+ let cap;
867
+ if (cap = this.rules.inline.url.exec(src)) {
868
+ let text, href;
869
+ if (cap[2] === '@') {
870
+ text = escape(cap[0]);
871
+ href = 'mailto:' + text;
872
+ }
873
+ else {
874
+ // do extended autolink path validation
875
+ let prevCapZero;
876
+ do {
877
+ prevCapZero = cap[0];
878
+ cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
879
+ } while (prevCapZero !== cap[0]);
880
+ text = escape(cap[0]);
881
+ if (cap[1] === 'www.') {
882
+ href = 'http://' + cap[0];
883
+ }
884
+ else {
885
+ href = cap[0];
886
+ }
887
+ }
888
+ return {
889
+ type: 'link',
890
+ raw: cap[0],
891
+ text,
892
+ href,
893
+ tokens: [
894
+ {
895
+ type: 'text',
896
+ raw: text,
897
+ text
898
+ }
899
+ ]
900
+ };
901
+ }
902
+ }
903
+ inlineText(src) {
904
+ const cap = this.rules.inline.text.exec(src);
905
+ if (cap) {
906
+ let text;
907
+ if (this.lexer.state.inRawBlock) {
908
+ text = cap[0];
909
+ }
910
+ else {
911
+ text = escape(cap[0]);
912
+ }
913
+ return {
914
+ type: 'text',
915
+ raw: cap[0],
916
+ text
917
+ };
918
+ }
919
+ }
1026
920
  }
1027
- case 'list_start': {
1028
- var body = ''
1029
- , ordered = this.token.ordered;
1030
921
 
1031
- while (this.next().type !== 'list_end') {
1032
- body += this.tok();
1033
- }
922
+ /**
923
+ * Block-Level Grammar
924
+ */
925
+ // Not all rules are defined in the object literal
926
+ // @ts-expect-error
927
+ const block = {
928
+ newline: /^(?: *(?:\n|$))+/,
929
+ code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
930
+ fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
931
+ hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
932
+ heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
933
+ blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
934
+ list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
935
+ html: '^ {0,3}(?:' // optional indentation
936
+ + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
937
+ + '|comment[^\\n]*(\\n+|$)' // (2)
938
+ + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
939
+ + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
940
+ + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
941
+ + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
942
+ + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
943
+ + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
944
+ + ')',
945
+ def: /^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
946
+ table: noopTest,
947
+ lheading: /^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
948
+ // regex template, placeholders will be replaced according to different paragraph
949
+ // interruption rules of commonmark and the original markdown spec:
950
+ _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
951
+ text: /^[^\n]+/
952
+ };
953
+ block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
954
+ block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
955
+ block.def = edit(block.def)
956
+ .replace('label', block._label)
957
+ .replace('title', block._title)
958
+ .getRegex();
959
+ block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
960
+ block.listItemStart = edit(/^( *)(bull) */)
961
+ .replace('bull', block.bullet)
962
+ .getRegex();
963
+ block.list = edit(block.list)
964
+ .replace(/bull/g, block.bullet)
965
+ .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
966
+ .replace('def', '\\n+(?=' + block.def.source + ')')
967
+ .getRegex();
968
+ block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
969
+ + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
970
+ + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
971
+ + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
972
+ + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
973
+ + '|track|ul';
974
+ block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
975
+ block.html = edit(block.html, 'i')
976
+ .replace('comment', block._comment)
977
+ .replace('tag', block._tag)
978
+ .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
979
+ .getRegex();
980
+ block.lheading = edit(block.lheading)
981
+ .replace(/bull/g, block.bullet) // lists can interrupt
982
+ .getRegex();
983
+ block.paragraph = edit(block._paragraph)
984
+ .replace('hr', block.hr)
985
+ .replace('heading', ' {0,3}#{1,6} ')
986
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
987
+ .replace('|table', '')
988
+ .replace('blockquote', ' {0,3}>')
989
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
990
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
991
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
992
+ .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
993
+ .getRegex();
994
+ block.blockquote = edit(block.blockquote)
995
+ .replace('paragraph', block.paragraph)
996
+ .getRegex();
997
+ /**
998
+ * Normal Block Grammar
999
+ */
1000
+ block.normal = { ...block };
1001
+ /**
1002
+ * GFM Block Grammar
1003
+ */
1004
+ block.gfm = {
1005
+ ...block.normal,
1006
+ table: '^ *([^\\n ].*)\\n' // Header
1007
+ + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
1008
+ + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
1009
+ };
1010
+ block.gfm.table = edit(block.gfm.table)
1011
+ .replace('hr', block.hr)
1012
+ .replace('heading', ' {0,3}#{1,6} ')
1013
+ .replace('blockquote', ' {0,3}>')
1014
+ .replace('code', ' {4}[^\\n]')
1015
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1016
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1017
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1018
+ .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
1019
+ .getRegex();
1020
+ block.gfm.paragraph = edit(block._paragraph)
1021
+ .replace('hr', block.hr)
1022
+ .replace('heading', ' {0,3}#{1,6} ')
1023
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1024
+ .replace('table', block.gfm.table) // interrupt paragraphs with table
1025
+ .replace('blockquote', ' {0,3}>')
1026
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1027
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1028
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1029
+ .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1030
+ .getRegex();
1031
+ /**
1032
+ * Pedantic grammar (original John Gruber's loose markdown specification)
1033
+ */
1034
+ block.pedantic = {
1035
+ ...block.normal,
1036
+ html: edit('^ *(?:comment *(?:\\n|\\s*$)'
1037
+ + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
1038
+ + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
1039
+ .replace('comment', block._comment)
1040
+ .replace(/tag/g, '(?!(?:'
1041
+ + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
1042
+ + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
1043
+ + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
1044
+ .getRegex(),
1045
+ def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
1046
+ heading: /^(#{1,6})(.*)(?:\n+|$)/,
1047
+ fences: noopTest,
1048
+ lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
1049
+ paragraph: edit(block.normal._paragraph)
1050
+ .replace('hr', block.hr)
1051
+ .replace('heading', ' *#{1,6} *[^\n]')
1052
+ .replace('lheading', block.lheading)
1053
+ .replace('blockquote', ' {0,3}>')
1054
+ .replace('|fences', '')
1055
+ .replace('|list', '')
1056
+ .replace('|html', '')
1057
+ .getRegex()
1058
+ };
1059
+ /**
1060
+ * Inline-Level Grammar
1061
+ */
1062
+ // Not all rules are defined in the object literal
1063
+ // @ts-expect-error
1064
+ const inline = {
1065
+ escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
1066
+ autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
1067
+ url: noopTest,
1068
+ tag: '^comment'
1069
+ + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
1070
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
1071
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
1072
+ + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
1073
+ + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
1074
+ link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
1075
+ reflink: /^!?\[(label)\]\[(ref)\]/,
1076
+ nolink: /^!?\[(ref)\](?:\[\])?/,
1077
+ reflinkSearch: 'reflink|nolink(?!\\()',
1078
+ emStrong: {
1079
+ lDelim: /^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,
1080
+ // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
1081
+ // | Skip orphan inside strong | Consume to delim | (1) #*** | (2) a***#, a*** | (3) #***a, ***a | (4) ***# | (5) #***# | (6) a***a
1082
+ rDelimAst: /^[^_*]*?__[^_*]*?\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\*)[punct](\*+)(?=[\s]|$)|[^punct\s](\*+)(?!\*)(?=[punct\s]|$)|(?!\*)[punct\s](\*+)(?=[^punct\s])|[\s](\*+)(?!\*)(?=[punct])|(?!\*)[punct](\*+)(?!\*)(?=[punct])|[^punct\s](\*+)(?=[^punct\s])/,
1083
+ rDelimUnd: /^[^_*]*?\*\*[^_*]*?_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\s]|$)|[^punct\s](_+)(?!_)(?=[punct\s]|$)|(?!_)[punct\s](_+)(?=[^punct\s])|[\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])/ // ^- Not allowed for _
1084
+ },
1085
+ code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
1086
+ br: /^( {2,}|\\)\n(?!\s*$)/,
1087
+ del: noopTest,
1088
+ text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
1089
+ punctuation: /^((?![*_])[\spunctuation])/
1090
+ };
1091
+ // list of unicode punctuation marks, plus any missing characters from CommonMark spec
1092
+ inline._punctuation = '\\p{P}$+<=>`^|~';
1093
+ inline.punctuation = edit(inline.punctuation, 'u').replace(/punctuation/g, inline._punctuation).getRegex();
1094
+ // sequences em should skip over [title](link), `code`, <html>
1095
+ inline.blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
1096
+ inline.anyPunctuation = /\\[punct]/g;
1097
+ inline._escapes = /\\([punct])/g;
1098
+ inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
1099
+ inline.emStrong.lDelim = edit(inline.emStrong.lDelim, 'u')
1100
+ .replace(/punct/g, inline._punctuation)
1101
+ .getRegex();
1102
+ inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'gu')
1103
+ .replace(/punct/g, inline._punctuation)
1104
+ .getRegex();
1105
+ inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'gu')
1106
+ .replace(/punct/g, inline._punctuation)
1107
+ .getRegex();
1108
+ inline.anyPunctuation = edit(inline.anyPunctuation, 'gu')
1109
+ .replace(/punct/g, inline._punctuation)
1110
+ .getRegex();
1111
+ inline._escapes = edit(inline._escapes, 'gu')
1112
+ .replace(/punct/g, inline._punctuation)
1113
+ .getRegex();
1114
+ inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
1115
+ inline._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])?)+(?![-_])/;
1116
+ inline.autolink = edit(inline.autolink)
1117
+ .replace('scheme', inline._scheme)
1118
+ .replace('email', inline._email)
1119
+ .getRegex();
1120
+ inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
1121
+ inline.tag = edit(inline.tag)
1122
+ .replace('comment', inline._comment)
1123
+ .replace('attribute', inline._attribute)
1124
+ .getRegex();
1125
+ inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
1126
+ inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
1127
+ inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
1128
+ inline.link = edit(inline.link)
1129
+ .replace('label', inline._label)
1130
+ .replace('href', inline._href)
1131
+ .replace('title', inline._title)
1132
+ .getRegex();
1133
+ inline.reflink = edit(inline.reflink)
1134
+ .replace('label', inline._label)
1135
+ .replace('ref', block._label)
1136
+ .getRegex();
1137
+ inline.nolink = edit(inline.nolink)
1138
+ .replace('ref', block._label)
1139
+ .getRegex();
1140
+ inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
1141
+ .replace('reflink', inline.reflink)
1142
+ .replace('nolink', inline.nolink)
1143
+ .getRegex();
1144
+ /**
1145
+ * Normal Inline Grammar
1146
+ */
1147
+ inline.normal = { ...inline };
1148
+ /**
1149
+ * Pedantic Inline Grammar
1150
+ */
1151
+ inline.pedantic = {
1152
+ ...inline.normal,
1153
+ strong: {
1154
+ start: /^__|\*\*/,
1155
+ middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
1156
+ endAst: /\*\*(?!\*)/g,
1157
+ endUnd: /__(?!_)/g
1158
+ },
1159
+ em: {
1160
+ start: /^_|\*/,
1161
+ middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
1162
+ endAst: /\*(?!\*)/g,
1163
+ endUnd: /_(?!_)/g
1164
+ },
1165
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
1166
+ .replace('label', inline._label)
1167
+ .getRegex(),
1168
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
1169
+ .replace('label', inline._label)
1170
+ .getRegex()
1171
+ };
1172
+ /**
1173
+ * GFM Inline Grammar
1174
+ */
1175
+ inline.gfm = {
1176
+ ...inline.normal,
1177
+ escape: edit(inline.escape).replace('])', '~|])').getRegex(),
1178
+ _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
1179
+ url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
1180
+ _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
1181
+ del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
1182
+ text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
1183
+ };
1184
+ inline.gfm.url = edit(inline.gfm.url, 'i')
1185
+ .replace('email', inline.gfm._extended_email)
1186
+ .getRegex();
1187
+ /**
1188
+ * GFM + Line Breaks Inline Grammar
1189
+ */
1190
+ inline.breaks = {
1191
+ ...inline.gfm,
1192
+ br: edit(inline.br).replace('{2,}', '*').getRegex(),
1193
+ text: edit(inline.gfm.text)
1194
+ .replace('\\b_', '\\b_| {2,}\\n')
1195
+ .replace(/\{2,\}/g, '*')
1196
+ .getRegex()
1197
+ };
1034
1198
 
1035
- return this.renderer.list(body, ordered);
1199
+ /**
1200
+ * Block Lexer
1201
+ */
1202
+ class _Lexer {
1203
+ tokens;
1204
+ options;
1205
+ state;
1206
+ tokenizer;
1207
+ inlineQueue;
1208
+ constructor(options) {
1209
+ // TokenList cannot be created in one go
1210
+ // @ts-expect-error
1211
+ this.tokens = [];
1212
+ this.tokens.links = Object.create(null);
1213
+ this.options = options || exports.defaults;
1214
+ this.options.tokenizer = this.options.tokenizer || new _Tokenizer();
1215
+ this.tokenizer = this.options.tokenizer;
1216
+ this.tokenizer.options = this.options;
1217
+ this.tokenizer.lexer = this;
1218
+ this.inlineQueue = [];
1219
+ this.state = {
1220
+ inLink: false,
1221
+ inRawBlock: false,
1222
+ top: true
1223
+ };
1224
+ const rules = {
1225
+ block: block.normal,
1226
+ inline: inline.normal
1227
+ };
1228
+ if (this.options.pedantic) {
1229
+ rules.block = block.pedantic;
1230
+ rules.inline = inline.pedantic;
1231
+ }
1232
+ else if (this.options.gfm) {
1233
+ rules.block = block.gfm;
1234
+ if (this.options.breaks) {
1235
+ rules.inline = inline.breaks;
1236
+ }
1237
+ else {
1238
+ rules.inline = inline.gfm;
1239
+ }
1240
+ }
1241
+ this.tokenizer.rules = rules;
1242
+ }
1243
+ /**
1244
+ * Expose Rules
1245
+ */
1246
+ static get rules() {
1247
+ return {
1248
+ block,
1249
+ inline
1250
+ };
1251
+ }
1252
+ /**
1253
+ * Static Lex Method
1254
+ */
1255
+ static lex(src, options) {
1256
+ const lexer = new _Lexer(options);
1257
+ return lexer.lex(src);
1258
+ }
1259
+ /**
1260
+ * Static Lex Inline Method
1261
+ */
1262
+ static lexInline(src, options) {
1263
+ const lexer = new _Lexer(options);
1264
+ return lexer.inlineTokens(src);
1265
+ }
1266
+ /**
1267
+ * Preprocessing
1268
+ */
1269
+ lex(src) {
1270
+ src = src
1271
+ .replace(/\r\n|\r/g, '\n');
1272
+ this.blockTokens(src, this.tokens);
1273
+ let next;
1274
+ while (next = this.inlineQueue.shift()) {
1275
+ this.inlineTokens(next.src, next.tokens);
1276
+ }
1277
+ return this.tokens;
1278
+ }
1279
+ blockTokens(src, tokens = []) {
1280
+ if (this.options.pedantic) {
1281
+ src = src.replace(/\t/g, ' ').replace(/^ +$/gm, '');
1282
+ }
1283
+ else {
1284
+ src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
1285
+ return leading + ' '.repeat(tabs.length);
1286
+ });
1287
+ }
1288
+ let token;
1289
+ let lastToken;
1290
+ let cutSrc;
1291
+ let lastParagraphClipped;
1292
+ while (src) {
1293
+ if (this.options.extensions
1294
+ && this.options.extensions.block
1295
+ && this.options.extensions.block.some((extTokenizer) => {
1296
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
1297
+ src = src.substring(token.raw.length);
1298
+ tokens.push(token);
1299
+ return true;
1300
+ }
1301
+ return false;
1302
+ })) {
1303
+ continue;
1304
+ }
1305
+ // newline
1306
+ if (token = this.tokenizer.space(src)) {
1307
+ src = src.substring(token.raw.length);
1308
+ if (token.raw.length === 1 && tokens.length > 0) {
1309
+ // if there's a single \n as a spacer, it's terminating the last line,
1310
+ // so move it there so that we don't get unnecessary paragraph tags
1311
+ tokens[tokens.length - 1].raw += '\n';
1312
+ }
1313
+ else {
1314
+ tokens.push(token);
1315
+ }
1316
+ continue;
1317
+ }
1318
+ // code
1319
+ if (token = this.tokenizer.code(src)) {
1320
+ src = src.substring(token.raw.length);
1321
+ lastToken = tokens[tokens.length - 1];
1322
+ // An indented code block cannot interrupt a paragraph.
1323
+ if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
1324
+ lastToken.raw += '\n' + token.raw;
1325
+ lastToken.text += '\n' + token.text;
1326
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
1327
+ }
1328
+ else {
1329
+ tokens.push(token);
1330
+ }
1331
+ continue;
1332
+ }
1333
+ // fences
1334
+ if (token = this.tokenizer.fences(src)) {
1335
+ src = src.substring(token.raw.length);
1336
+ tokens.push(token);
1337
+ continue;
1338
+ }
1339
+ // heading
1340
+ if (token = this.tokenizer.heading(src)) {
1341
+ src = src.substring(token.raw.length);
1342
+ tokens.push(token);
1343
+ continue;
1344
+ }
1345
+ // hr
1346
+ if (token = this.tokenizer.hr(src)) {
1347
+ src = src.substring(token.raw.length);
1348
+ tokens.push(token);
1349
+ continue;
1350
+ }
1351
+ // blockquote
1352
+ if (token = this.tokenizer.blockquote(src)) {
1353
+ src = src.substring(token.raw.length);
1354
+ tokens.push(token);
1355
+ continue;
1356
+ }
1357
+ // list
1358
+ if (token = this.tokenizer.list(src)) {
1359
+ src = src.substring(token.raw.length);
1360
+ tokens.push(token);
1361
+ continue;
1362
+ }
1363
+ // html
1364
+ if (token = this.tokenizer.html(src)) {
1365
+ src = src.substring(token.raw.length);
1366
+ tokens.push(token);
1367
+ continue;
1368
+ }
1369
+ // def
1370
+ if (token = this.tokenizer.def(src)) {
1371
+ src = src.substring(token.raw.length);
1372
+ lastToken = tokens[tokens.length - 1];
1373
+ if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
1374
+ lastToken.raw += '\n' + token.raw;
1375
+ lastToken.text += '\n' + token.raw;
1376
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
1377
+ }
1378
+ else if (!this.tokens.links[token.tag]) {
1379
+ this.tokens.links[token.tag] = {
1380
+ href: token.href,
1381
+ title: token.title
1382
+ };
1383
+ }
1384
+ continue;
1385
+ }
1386
+ // table (gfm)
1387
+ if (token = this.tokenizer.table(src)) {
1388
+ src = src.substring(token.raw.length);
1389
+ tokens.push(token);
1390
+ continue;
1391
+ }
1392
+ // lheading
1393
+ if (token = this.tokenizer.lheading(src)) {
1394
+ src = src.substring(token.raw.length);
1395
+ tokens.push(token);
1396
+ continue;
1397
+ }
1398
+ // top-level paragraph
1399
+ // prevent paragraph consuming extensions by clipping 'src' to extension start
1400
+ cutSrc = src;
1401
+ if (this.options.extensions && this.options.extensions.startBlock) {
1402
+ let startIndex = Infinity;
1403
+ const tempSrc = src.slice(1);
1404
+ let tempStart;
1405
+ this.options.extensions.startBlock.forEach((getStartIndex) => {
1406
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc);
1407
+ if (typeof tempStart === 'number' && tempStart >= 0) {
1408
+ startIndex = Math.min(startIndex, tempStart);
1409
+ }
1410
+ });
1411
+ if (startIndex < Infinity && startIndex >= 0) {
1412
+ cutSrc = src.substring(0, startIndex + 1);
1413
+ }
1414
+ }
1415
+ if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
1416
+ lastToken = tokens[tokens.length - 1];
1417
+ if (lastParagraphClipped && lastToken.type === 'paragraph') {
1418
+ lastToken.raw += '\n' + token.raw;
1419
+ lastToken.text += '\n' + token.text;
1420
+ this.inlineQueue.pop();
1421
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
1422
+ }
1423
+ else {
1424
+ tokens.push(token);
1425
+ }
1426
+ lastParagraphClipped = (cutSrc.length !== src.length);
1427
+ src = src.substring(token.raw.length);
1428
+ continue;
1429
+ }
1430
+ // text
1431
+ if (token = this.tokenizer.text(src)) {
1432
+ src = src.substring(token.raw.length);
1433
+ lastToken = tokens[tokens.length - 1];
1434
+ if (lastToken && lastToken.type === 'text') {
1435
+ lastToken.raw += '\n' + token.raw;
1436
+ lastToken.text += '\n' + token.text;
1437
+ this.inlineQueue.pop();
1438
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
1439
+ }
1440
+ else {
1441
+ tokens.push(token);
1442
+ }
1443
+ continue;
1444
+ }
1445
+ if (src) {
1446
+ const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
1447
+ if (this.options.silent) {
1448
+ console.error(errMsg);
1449
+ break;
1450
+ }
1451
+ else {
1452
+ throw new Error(errMsg);
1453
+ }
1454
+ }
1455
+ }
1456
+ this.state.top = true;
1457
+ return tokens;
1458
+ }
1459
+ inline(src, tokens = []) {
1460
+ this.inlineQueue.push({ src, tokens });
1461
+ return tokens;
1462
+ }
1463
+ /**
1464
+ * Lexing/Compiling
1465
+ */
1466
+ inlineTokens(src, tokens = []) {
1467
+ let token, lastToken, cutSrc;
1468
+ // String with links masked to avoid interference with em and strong
1469
+ let maskedSrc = src;
1470
+ let match;
1471
+ let keepPrevChar, prevChar;
1472
+ // Mask out reflinks
1473
+ if (this.tokens.links) {
1474
+ const links = Object.keys(this.tokens.links);
1475
+ if (links.length > 0) {
1476
+ while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
1477
+ if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
1478
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
1479
+ }
1480
+ }
1481
+ }
1482
+ }
1483
+ // Mask out other blocks
1484
+ while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
1485
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
1486
+ }
1487
+ // Mask out escaped characters
1488
+ while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
1489
+ maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
1490
+ }
1491
+ while (src) {
1492
+ if (!keepPrevChar) {
1493
+ prevChar = '';
1494
+ }
1495
+ keepPrevChar = false;
1496
+ // extensions
1497
+ if (this.options.extensions
1498
+ && this.options.extensions.inline
1499
+ && this.options.extensions.inline.some((extTokenizer) => {
1500
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
1501
+ src = src.substring(token.raw.length);
1502
+ tokens.push(token);
1503
+ return true;
1504
+ }
1505
+ return false;
1506
+ })) {
1507
+ continue;
1508
+ }
1509
+ // escape
1510
+ if (token = this.tokenizer.escape(src)) {
1511
+ src = src.substring(token.raw.length);
1512
+ tokens.push(token);
1513
+ continue;
1514
+ }
1515
+ // tag
1516
+ if (token = this.tokenizer.tag(src)) {
1517
+ src = src.substring(token.raw.length);
1518
+ lastToken = tokens[tokens.length - 1];
1519
+ if (lastToken && token.type === 'text' && lastToken.type === 'text') {
1520
+ lastToken.raw += token.raw;
1521
+ lastToken.text += token.text;
1522
+ }
1523
+ else {
1524
+ tokens.push(token);
1525
+ }
1526
+ continue;
1527
+ }
1528
+ // link
1529
+ if (token = this.tokenizer.link(src)) {
1530
+ src = src.substring(token.raw.length);
1531
+ tokens.push(token);
1532
+ continue;
1533
+ }
1534
+ // reflink, nolink
1535
+ if (token = this.tokenizer.reflink(src, this.tokens.links)) {
1536
+ src = src.substring(token.raw.length);
1537
+ lastToken = tokens[tokens.length - 1];
1538
+ if (lastToken && token.type === 'text' && lastToken.type === 'text') {
1539
+ lastToken.raw += token.raw;
1540
+ lastToken.text += token.text;
1541
+ }
1542
+ else {
1543
+ tokens.push(token);
1544
+ }
1545
+ continue;
1546
+ }
1547
+ // em & strong
1548
+ if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
1549
+ src = src.substring(token.raw.length);
1550
+ tokens.push(token);
1551
+ continue;
1552
+ }
1553
+ // code
1554
+ if (token = this.tokenizer.codespan(src)) {
1555
+ src = src.substring(token.raw.length);
1556
+ tokens.push(token);
1557
+ continue;
1558
+ }
1559
+ // br
1560
+ if (token = this.tokenizer.br(src)) {
1561
+ src = src.substring(token.raw.length);
1562
+ tokens.push(token);
1563
+ continue;
1564
+ }
1565
+ // del (gfm)
1566
+ if (token = this.tokenizer.del(src)) {
1567
+ src = src.substring(token.raw.length);
1568
+ tokens.push(token);
1569
+ continue;
1570
+ }
1571
+ // autolink
1572
+ if (token = this.tokenizer.autolink(src)) {
1573
+ src = src.substring(token.raw.length);
1574
+ tokens.push(token);
1575
+ continue;
1576
+ }
1577
+ // url (gfm)
1578
+ if (!this.state.inLink && (token = this.tokenizer.url(src))) {
1579
+ src = src.substring(token.raw.length);
1580
+ tokens.push(token);
1581
+ continue;
1582
+ }
1583
+ // text
1584
+ // prevent inlineText consuming extensions by clipping 'src' to extension start
1585
+ cutSrc = src;
1586
+ if (this.options.extensions && this.options.extensions.startInline) {
1587
+ let startIndex = Infinity;
1588
+ const tempSrc = src.slice(1);
1589
+ let tempStart;
1590
+ this.options.extensions.startInline.forEach((getStartIndex) => {
1591
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc);
1592
+ if (typeof tempStart === 'number' && tempStart >= 0) {
1593
+ startIndex = Math.min(startIndex, tempStart);
1594
+ }
1595
+ });
1596
+ if (startIndex < Infinity && startIndex >= 0) {
1597
+ cutSrc = src.substring(0, startIndex + 1);
1598
+ }
1599
+ }
1600
+ if (token = this.tokenizer.inlineText(cutSrc)) {
1601
+ src = src.substring(token.raw.length);
1602
+ if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
1603
+ prevChar = token.raw.slice(-1);
1604
+ }
1605
+ keepPrevChar = true;
1606
+ lastToken = tokens[tokens.length - 1];
1607
+ if (lastToken && lastToken.type === 'text') {
1608
+ lastToken.raw += token.raw;
1609
+ lastToken.text += token.text;
1610
+ }
1611
+ else {
1612
+ tokens.push(token);
1613
+ }
1614
+ continue;
1615
+ }
1616
+ if (src) {
1617
+ const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
1618
+ if (this.options.silent) {
1619
+ console.error(errMsg);
1620
+ break;
1621
+ }
1622
+ else {
1623
+ throw new Error(errMsg);
1624
+ }
1625
+ }
1626
+ }
1627
+ return tokens;
1628
+ }
1036
1629
  }
1037
- case 'list_item_start': {
1038
- var body = '';
1039
-
1040
- while (this.next().type !== 'list_item_end') {
1041
- body += this.token.type === 'text'
1042
- ? this.parseText()
1043
- : this.tok();
1044
- }
1045
1630
 
1046
- return this.renderer.listitem(body);
1631
+ /**
1632
+ * Renderer
1633
+ */
1634
+ class _Renderer {
1635
+ options;
1636
+ constructor(options) {
1637
+ this.options = options || exports.defaults;
1638
+ }
1639
+ code(code, infostring, escaped) {
1640
+ const lang = (infostring || '').match(/^\S*/)?.[0];
1641
+ code = code.replace(/\n$/, '') + '\n';
1642
+ if (!lang) {
1643
+ return '<pre><code>'
1644
+ + (escaped ? code : escape(code, true))
1645
+ + '</code></pre>\n';
1646
+ }
1647
+ return '<pre><code class="language-'
1648
+ + escape(lang)
1649
+ + '">'
1650
+ + (escaped ? code : escape(code, true))
1651
+ + '</code></pre>\n';
1652
+ }
1653
+ blockquote(quote) {
1654
+ return `<blockquote>\n${quote}</blockquote>\n`;
1655
+ }
1656
+ html(html, block) {
1657
+ return html;
1658
+ }
1659
+ heading(text, level, raw) {
1660
+ // ignore IDs
1661
+ return `<h${level}>${text}</h${level}>\n`;
1662
+ }
1663
+ hr() {
1664
+ return '<hr>\n';
1665
+ }
1666
+ list(body, ordered, start) {
1667
+ const type = ordered ? 'ol' : 'ul';
1668
+ const startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
1669
+ return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
1670
+ }
1671
+ listitem(text, task, checked) {
1672
+ return `<li>${text}</li>\n`;
1673
+ }
1674
+ checkbox(checked) {
1675
+ return '<input '
1676
+ + (checked ? 'checked="" ' : '')
1677
+ + 'disabled="" type="checkbox">';
1678
+ }
1679
+ paragraph(text) {
1680
+ return `<p>${text}</p>\n`;
1681
+ }
1682
+ table(header, body) {
1683
+ if (body)
1684
+ body = `<tbody>${body}</tbody>`;
1685
+ return '<table>\n'
1686
+ + '<thead>\n'
1687
+ + header
1688
+ + '</thead>\n'
1689
+ + body
1690
+ + '</table>\n';
1691
+ }
1692
+ tablerow(content) {
1693
+ return `<tr>\n${content}</tr>\n`;
1694
+ }
1695
+ tablecell(content, flags) {
1696
+ const type = flags.header ? 'th' : 'td';
1697
+ const tag = flags.align
1698
+ ? `<${type} align="${flags.align}">`
1699
+ : `<${type}>`;
1700
+ return tag + content + `</${type}>\n`;
1701
+ }
1702
+ /**
1703
+ * span level renderer
1704
+ */
1705
+ strong(text) {
1706
+ return `<strong>${text}</strong>`;
1707
+ }
1708
+ em(text) {
1709
+ return `<em>${text}</em>`;
1710
+ }
1711
+ codespan(text) {
1712
+ return `<code>${text}</code>`;
1713
+ }
1714
+ br() {
1715
+ return '<br>';
1716
+ }
1717
+ del(text) {
1718
+ return `<del>${text}</del>`;
1719
+ }
1720
+ link(href, title, text) {
1721
+ const cleanHref = cleanUrl(href);
1722
+ if (cleanHref === null) {
1723
+ return text;
1724
+ }
1725
+ href = cleanHref;
1726
+ let out = '<a href="' + href + '"';
1727
+ if (title) {
1728
+ out += ' title="' + title + '"';
1729
+ }
1730
+ out += '>' + text + '</a>';
1731
+ return out;
1732
+ }
1733
+ image(href, title, text) {
1734
+ const cleanHref = cleanUrl(href);
1735
+ if (cleanHref === null) {
1736
+ return text;
1737
+ }
1738
+ href = cleanHref;
1739
+ let out = `<img src="${href}" alt="${text}"`;
1740
+ if (title) {
1741
+ out += ` title="${title}"`;
1742
+ }
1743
+ out += '>';
1744
+ return out;
1745
+ }
1746
+ text(text) {
1747
+ return text;
1748
+ }
1047
1749
  }
1048
- case 'loose_item_start': {
1049
- var body = '';
1050
-
1051
- while (this.next().type !== 'list_item_end') {
1052
- body += this.tok();
1053
- }
1054
1750
 
1055
- return this.renderer.listitem(body);
1056
- }
1057
- case 'html': {
1058
- var html = !this.token.pre && !this.options.pedantic
1059
- ? this.inline.output(this.token.text)
1060
- : this.token.text;
1061
- return this.renderer.html(html);
1062
- }
1063
- case 'paragraph': {
1064
- return this.renderer.paragraph(this.inline.output(this.token.text));
1065
- }
1066
- case 'text': {
1067
- return this.renderer.paragraph(this.parseText());
1751
+ /**
1752
+ * TextRenderer
1753
+ * returns only the textual part of the token
1754
+ */
1755
+ class _TextRenderer {
1756
+ // no need for block level renderers
1757
+ strong(text) {
1758
+ return text;
1759
+ }
1760
+ em(text) {
1761
+ return text;
1762
+ }
1763
+ codespan(text) {
1764
+ return text;
1765
+ }
1766
+ del(text) {
1767
+ return text;
1768
+ }
1769
+ html(text) {
1770
+ return text;
1771
+ }
1772
+ text(text) {
1773
+ return text;
1774
+ }
1775
+ link(href, title, text) {
1776
+ return '' + text;
1777
+ }
1778
+ image(href, title, text) {
1779
+ return '' + text;
1780
+ }
1781
+ br() {
1782
+ return '';
1783
+ }
1068
1784
  }
1069
- }
1070
- };
1071
-
1072
- /**
1073
- * Helpers
1074
- */
1075
1785
 
1076
- function escape(html, encode) {
1077
- return html
1078
- .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
1079
- .replace(/</g, '&lt;')
1080
- .replace(/>/g, '&gt;')
1081
- .replace(/"/g, '&quot;')
1082
- .replace(/'/g, '&#39;');
1083
- }
1084
-
1085
- function unescape(html) {
1086
- return html.replace(/&([#\w]+);/g, function(_, n) {
1087
- n = n.toLowerCase();
1088
- if (n === 'colon') return ':';
1089
- if (n.charAt(0) === '#') {
1090
- return n.charAt(1) === 'x'
1091
- ? String.fromCharCode(parseInt(n.substring(2), 16))
1092
- : String.fromCharCode(+n.substring(1));
1786
+ /**
1787
+ * Parsing & Compiling
1788
+ */
1789
+ class _Parser {
1790
+ options;
1791
+ renderer;
1792
+ textRenderer;
1793
+ constructor(options) {
1794
+ this.options = options || exports.defaults;
1795
+ this.options.renderer = this.options.renderer || new _Renderer();
1796
+ this.renderer = this.options.renderer;
1797
+ this.renderer.options = this.options;
1798
+ this.textRenderer = new _TextRenderer();
1799
+ }
1800
+ /**
1801
+ * Static Parse Method
1802
+ */
1803
+ static parse(tokens, options) {
1804
+ const parser = new _Parser(options);
1805
+ return parser.parse(tokens);
1806
+ }
1807
+ /**
1808
+ * Static Parse Inline Method
1809
+ */
1810
+ static parseInline(tokens, options) {
1811
+ const parser = new _Parser(options);
1812
+ return parser.parseInline(tokens);
1813
+ }
1814
+ /**
1815
+ * Parse Loop
1816
+ */
1817
+ parse(tokens, top = true) {
1818
+ let out = '';
1819
+ for (let i = 0; i < tokens.length; i++) {
1820
+ const token = tokens[i];
1821
+ // Run any renderer extensions
1822
+ if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
1823
+ const genericToken = token;
1824
+ const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
1825
+ if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(genericToken.type)) {
1826
+ out += ret || '';
1827
+ continue;
1828
+ }
1829
+ }
1830
+ switch (token.type) {
1831
+ case 'space': {
1832
+ continue;
1833
+ }
1834
+ case 'hr': {
1835
+ out += this.renderer.hr();
1836
+ continue;
1837
+ }
1838
+ case 'heading': {
1839
+ const headingToken = token;
1840
+ out += this.renderer.heading(this.parseInline(headingToken.tokens), headingToken.depth, unescape(this.parseInline(headingToken.tokens, this.textRenderer)));
1841
+ continue;
1842
+ }
1843
+ case 'code': {
1844
+ const codeToken = token;
1845
+ out += this.renderer.code(codeToken.text, codeToken.lang, !!codeToken.escaped);
1846
+ continue;
1847
+ }
1848
+ case 'table': {
1849
+ const tableToken = token;
1850
+ let header = '';
1851
+ // header
1852
+ let cell = '';
1853
+ for (let j = 0; j < tableToken.header.length; j++) {
1854
+ cell += this.renderer.tablecell(this.parseInline(tableToken.header[j].tokens), { header: true, align: tableToken.align[j] });
1855
+ }
1856
+ header += this.renderer.tablerow(cell);
1857
+ let body = '';
1858
+ for (let j = 0; j < tableToken.rows.length; j++) {
1859
+ const row = tableToken.rows[j];
1860
+ cell = '';
1861
+ for (let k = 0; k < row.length; k++) {
1862
+ cell += this.renderer.tablecell(this.parseInline(row[k].tokens), { header: false, align: tableToken.align[k] });
1863
+ }
1864
+ body += this.renderer.tablerow(cell);
1865
+ }
1866
+ out += this.renderer.table(header, body);
1867
+ continue;
1868
+ }
1869
+ case 'blockquote': {
1870
+ const blockquoteToken = token;
1871
+ const body = this.parse(blockquoteToken.tokens);
1872
+ out += this.renderer.blockquote(body);
1873
+ continue;
1874
+ }
1875
+ case 'list': {
1876
+ const listToken = token;
1877
+ const ordered = listToken.ordered;
1878
+ const start = listToken.start;
1879
+ const loose = listToken.loose;
1880
+ let body = '';
1881
+ for (let j = 0; j < listToken.items.length; j++) {
1882
+ const item = listToken.items[j];
1883
+ const checked = item.checked;
1884
+ const task = item.task;
1885
+ let itemBody = '';
1886
+ if (item.task) {
1887
+ const checkbox = this.renderer.checkbox(!!checked);
1888
+ if (loose) {
1889
+ if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
1890
+ item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
1891
+ if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
1892
+ item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
1893
+ }
1894
+ }
1895
+ else {
1896
+ item.tokens.unshift({
1897
+ type: 'text',
1898
+ text: checkbox + ' '
1899
+ });
1900
+ }
1901
+ }
1902
+ else {
1903
+ itemBody += checkbox + ' ';
1904
+ }
1905
+ }
1906
+ itemBody += this.parse(item.tokens, loose);
1907
+ body += this.renderer.listitem(itemBody, task, !!checked);
1908
+ }
1909
+ out += this.renderer.list(body, ordered, start);
1910
+ continue;
1911
+ }
1912
+ case 'html': {
1913
+ const htmlToken = token;
1914
+ out += this.renderer.html(htmlToken.text, htmlToken.block);
1915
+ continue;
1916
+ }
1917
+ case 'paragraph': {
1918
+ const paragraphToken = token;
1919
+ out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens));
1920
+ continue;
1921
+ }
1922
+ case 'text': {
1923
+ let textToken = token;
1924
+ let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;
1925
+ while (i + 1 < tokens.length && tokens[i + 1].type === 'text') {
1926
+ textToken = tokens[++i];
1927
+ body += '\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);
1928
+ }
1929
+ out += top ? this.renderer.paragraph(body) : body;
1930
+ continue;
1931
+ }
1932
+ default: {
1933
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
1934
+ if (this.options.silent) {
1935
+ console.error(errMsg);
1936
+ return '';
1937
+ }
1938
+ else {
1939
+ throw new Error(errMsg);
1940
+ }
1941
+ }
1942
+ }
1943
+ }
1944
+ return out;
1945
+ }
1946
+ /**
1947
+ * Parse Inline Tokens
1948
+ */
1949
+ parseInline(tokens, renderer) {
1950
+ renderer = renderer || this.renderer;
1951
+ let out = '';
1952
+ for (let i = 0; i < tokens.length; i++) {
1953
+ const token = tokens[i];
1954
+ // Run any renderer extensions
1955
+ if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
1956
+ const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
1957
+ if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
1958
+ out += ret || '';
1959
+ continue;
1960
+ }
1961
+ }
1962
+ switch (token.type) {
1963
+ case 'escape': {
1964
+ const escapeToken = token;
1965
+ out += renderer.text(escapeToken.text);
1966
+ break;
1967
+ }
1968
+ case 'html': {
1969
+ const tagToken = token;
1970
+ out += renderer.html(tagToken.text);
1971
+ break;
1972
+ }
1973
+ case 'link': {
1974
+ const linkToken = token;
1975
+ out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer));
1976
+ break;
1977
+ }
1978
+ case 'image': {
1979
+ const imageToken = token;
1980
+ out += renderer.image(imageToken.href, imageToken.title, imageToken.text);
1981
+ break;
1982
+ }
1983
+ case 'strong': {
1984
+ const strongToken = token;
1985
+ out += renderer.strong(this.parseInline(strongToken.tokens, renderer));
1986
+ break;
1987
+ }
1988
+ case 'em': {
1989
+ const emToken = token;
1990
+ out += renderer.em(this.parseInline(emToken.tokens, renderer));
1991
+ break;
1992
+ }
1993
+ case 'codespan': {
1994
+ const codespanToken = token;
1995
+ out += renderer.codespan(codespanToken.text);
1996
+ break;
1997
+ }
1998
+ case 'br': {
1999
+ out += renderer.br();
2000
+ break;
2001
+ }
2002
+ case 'del': {
2003
+ const delToken = token;
2004
+ out += renderer.del(this.parseInline(delToken.tokens, renderer));
2005
+ break;
2006
+ }
2007
+ case 'text': {
2008
+ const textToken = token;
2009
+ out += renderer.text(textToken.text);
2010
+ break;
2011
+ }
2012
+ default: {
2013
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
2014
+ if (this.options.silent) {
2015
+ console.error(errMsg);
2016
+ return '';
2017
+ }
2018
+ else {
2019
+ throw new Error(errMsg);
2020
+ }
2021
+ }
2022
+ }
2023
+ }
2024
+ return out;
2025
+ }
1093
2026
  }
1094
- return '';
1095
- });
1096
- }
1097
2027
 
1098
- function replace(regex, opt) {
1099
- regex = regex.source;
1100
- opt = opt || '';
1101
- return function self(name, val) {
1102
- if (!name) return new RegExp(regex, opt);
1103
- val = val.source || val;
1104
- val = val.replace(/(^|[^\[])\^/g, '$1');
1105
- regex = regex.replace(name, val);
1106
- return self;
1107
- };
1108
- }
1109
-
1110
- function noop() {}
1111
- noop.exec = noop;
1112
-
1113
- function merge(obj) {
1114
- var i = 1
1115
- , target
1116
- , key;
1117
-
1118
- for (; i < arguments.length; i++) {
1119
- target = arguments[i];
1120
- for (key in target) {
1121
- if (Object.prototype.hasOwnProperty.call(target, key)) {
1122
- obj[key] = target[key];
1123
- }
2028
+ class _Hooks {
2029
+ options;
2030
+ constructor(options) {
2031
+ this.options = options || exports.defaults;
2032
+ }
2033
+ static passThroughHooks = new Set([
2034
+ 'preprocess',
2035
+ 'postprocess'
2036
+ ]);
2037
+ /**
2038
+ * Process markdown before marked
2039
+ */
2040
+ preprocess(markdown) {
2041
+ return markdown;
2042
+ }
2043
+ /**
2044
+ * Process HTML after marked is finished
2045
+ */
2046
+ postprocess(html) {
2047
+ return html;
2048
+ }
1124
2049
  }
1125
- }
1126
-
1127
- return obj;
1128
- }
1129
2050
 
1130
-
1131
- /**
1132
- * Marked
1133
- */
1134
-
1135
- function marked(src, opt, callback) {
1136
- if (callback || typeof opt === 'function') {
1137
- if (!callback) {
1138
- callback = opt;
1139
- opt = null;
2051
+ class Marked {
2052
+ defaults = _getDefaults();
2053
+ options = this.setOptions;
2054
+ parse = this.#parseMarkdown(_Lexer.lex, _Parser.parse);
2055
+ parseInline = this.#parseMarkdown(_Lexer.lexInline, _Parser.parseInline);
2056
+ Parser = _Parser;
2057
+ parser = _Parser.parse;
2058
+ Renderer = _Renderer;
2059
+ TextRenderer = _TextRenderer;
2060
+ Lexer = _Lexer;
2061
+ lexer = _Lexer.lex;
2062
+ Tokenizer = _Tokenizer;
2063
+ Hooks = _Hooks;
2064
+ constructor(...args) {
2065
+ this.use(...args);
2066
+ }
2067
+ /**
2068
+ * Run callback for every token
2069
+ */
2070
+ walkTokens(tokens, callback) {
2071
+ let values = [];
2072
+ for (const token of tokens) {
2073
+ values = values.concat(callback.call(this, token));
2074
+ switch (token.type) {
2075
+ case 'table': {
2076
+ const tableToken = token;
2077
+ for (const cell of tableToken.header) {
2078
+ values = values.concat(this.walkTokens(cell.tokens, callback));
2079
+ }
2080
+ for (const row of tableToken.rows) {
2081
+ for (const cell of row) {
2082
+ values = values.concat(this.walkTokens(cell.tokens, callback));
2083
+ }
2084
+ }
2085
+ break;
2086
+ }
2087
+ case 'list': {
2088
+ const listToken = token;
2089
+ values = values.concat(this.walkTokens(listToken.items, callback));
2090
+ break;
2091
+ }
2092
+ default: {
2093
+ const genericToken = token;
2094
+ if (this.defaults.extensions?.childTokens?.[genericToken.type]) {
2095
+ this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
2096
+ values = values.concat(this.walkTokens(genericToken[childTokens], callback));
2097
+ });
2098
+ }
2099
+ else if (genericToken.tokens) {
2100
+ values = values.concat(this.walkTokens(genericToken.tokens, callback));
2101
+ }
2102
+ }
2103
+ }
2104
+ }
2105
+ return values;
2106
+ }
2107
+ use(...args) {
2108
+ const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
2109
+ args.forEach((pack) => {
2110
+ // copy options to new object
2111
+ const opts = { ...pack };
2112
+ // set async to true if it was set to true before
2113
+ opts.async = this.defaults.async || opts.async || false;
2114
+ // ==-- Parse "addon" extensions --== //
2115
+ if (pack.extensions) {
2116
+ pack.extensions.forEach((ext) => {
2117
+ if (!ext.name) {
2118
+ throw new Error('extension name required');
2119
+ }
2120
+ if ('renderer' in ext) { // Renderer extensions
2121
+ const prevRenderer = extensions.renderers[ext.name];
2122
+ if (prevRenderer) {
2123
+ // Replace extension with func to run new extension but fall back if false
2124
+ extensions.renderers[ext.name] = function (...args) {
2125
+ let ret = ext.renderer.apply(this, args);
2126
+ if (ret === false) {
2127
+ ret = prevRenderer.apply(this, args);
2128
+ }
2129
+ return ret;
2130
+ };
2131
+ }
2132
+ else {
2133
+ extensions.renderers[ext.name] = ext.renderer;
2134
+ }
2135
+ }
2136
+ if ('tokenizer' in ext) { // Tokenizer Extensions
2137
+ if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
2138
+ throw new Error("extension level must be 'block' or 'inline'");
2139
+ }
2140
+ const extLevel = extensions[ext.level];
2141
+ if (extLevel) {
2142
+ extLevel.unshift(ext.tokenizer);
2143
+ }
2144
+ else {
2145
+ extensions[ext.level] = [ext.tokenizer];
2146
+ }
2147
+ if (ext.start) { // Function to check for start of token
2148
+ if (ext.level === 'block') {
2149
+ if (extensions.startBlock) {
2150
+ extensions.startBlock.push(ext.start);
2151
+ }
2152
+ else {
2153
+ extensions.startBlock = [ext.start];
2154
+ }
2155
+ }
2156
+ else if (ext.level === 'inline') {
2157
+ if (extensions.startInline) {
2158
+ extensions.startInline.push(ext.start);
2159
+ }
2160
+ else {
2161
+ extensions.startInline = [ext.start];
2162
+ }
2163
+ }
2164
+ }
2165
+ }
2166
+ if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens
2167
+ extensions.childTokens[ext.name] = ext.childTokens;
2168
+ }
2169
+ });
2170
+ opts.extensions = extensions;
2171
+ }
2172
+ // ==-- Parse "overwrite" extensions --== //
2173
+ if (pack.renderer) {
2174
+ const renderer = this.defaults.renderer || new _Renderer(this.defaults);
2175
+ for (const prop in pack.renderer) {
2176
+ const rendererFunc = pack.renderer[prop];
2177
+ const rendererKey = prop;
2178
+ const prevRenderer = renderer[rendererKey];
2179
+ // Replace renderer with func to run extension, but fall back if false
2180
+ renderer[rendererKey] = (...args) => {
2181
+ let ret = rendererFunc.apply(renderer, args);
2182
+ if (ret === false) {
2183
+ ret = prevRenderer.apply(renderer, args);
2184
+ }
2185
+ return ret || '';
2186
+ };
2187
+ }
2188
+ opts.renderer = renderer;
2189
+ }
2190
+ if (pack.tokenizer) {
2191
+ const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
2192
+ for (const prop in pack.tokenizer) {
2193
+ const tokenizerFunc = pack.tokenizer[prop];
2194
+ const tokenizerKey = prop;
2195
+ const prevTokenizer = tokenizer[tokenizerKey];
2196
+ // Replace tokenizer with func to run extension, but fall back if false
2197
+ tokenizer[tokenizerKey] = (...args) => {
2198
+ let ret = tokenizerFunc.apply(tokenizer, args);
2199
+ if (ret === false) {
2200
+ ret = prevTokenizer.apply(tokenizer, args);
2201
+ }
2202
+ return ret;
2203
+ };
2204
+ }
2205
+ opts.tokenizer = tokenizer;
2206
+ }
2207
+ // ==-- Parse Hooks extensions --== //
2208
+ if (pack.hooks) {
2209
+ const hooks = this.defaults.hooks || new _Hooks();
2210
+ for (const prop in pack.hooks) {
2211
+ const hooksFunc = pack.hooks[prop];
2212
+ const hooksKey = prop;
2213
+ const prevHook = hooks[hooksKey];
2214
+ if (_Hooks.passThroughHooks.has(prop)) {
2215
+ hooks[hooksKey] = (arg) => {
2216
+ if (this.defaults.async) {
2217
+ return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {
2218
+ return prevHook.call(hooks, ret);
2219
+ });
2220
+ }
2221
+ const ret = hooksFunc.call(hooks, arg);
2222
+ return prevHook.call(hooks, ret);
2223
+ };
2224
+ }
2225
+ else {
2226
+ hooks[hooksKey] = (...args) => {
2227
+ let ret = hooksFunc.apply(hooks, args);
2228
+ if (ret === false) {
2229
+ ret = prevHook.apply(hooks, args);
2230
+ }
2231
+ return ret;
2232
+ };
2233
+ }
2234
+ }
2235
+ opts.hooks = hooks;
2236
+ }
2237
+ // ==-- Parse WalkTokens extensions --== //
2238
+ if (pack.walkTokens) {
2239
+ const walkTokens = this.defaults.walkTokens;
2240
+ const packWalktokens = pack.walkTokens;
2241
+ opts.walkTokens = function (token) {
2242
+ let values = [];
2243
+ values.push(packWalktokens.call(this, token));
2244
+ if (walkTokens) {
2245
+ values = values.concat(walkTokens.call(this, token));
2246
+ }
2247
+ return values;
2248
+ };
2249
+ }
2250
+ this.defaults = { ...this.defaults, ...opts };
2251
+ });
2252
+ return this;
2253
+ }
2254
+ setOptions(opt) {
2255
+ this.defaults = { ...this.defaults, ...opt };
2256
+ return this;
2257
+ }
2258
+ #parseMarkdown(lexer, parser) {
2259
+ return (src, options) => {
2260
+ const origOpt = { ...options };
2261
+ const opt = { ...this.defaults, ...origOpt };
2262
+ // Show warning if an extension set async to true but the parse was called with async: false
2263
+ if (this.defaults.async === true && origOpt.async === false) {
2264
+ if (!opt.silent) {
2265
+ console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.');
2266
+ }
2267
+ opt.async = true;
2268
+ }
2269
+ const throwError = this.#onError(!!opt.silent, !!opt.async);
2270
+ // throw error in case of non string input
2271
+ if (typeof src === 'undefined' || src === null) {
2272
+ return throwError(new Error('marked(): input parameter is undefined or null'));
2273
+ }
2274
+ if (typeof src !== 'string') {
2275
+ return throwError(new Error('marked(): input parameter is of type '
2276
+ + Object.prototype.toString.call(src) + ', string expected'));
2277
+ }
2278
+ if (opt.hooks) {
2279
+ opt.hooks.options = opt;
2280
+ }
2281
+ if (opt.async) {
2282
+ return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
2283
+ .then(src => lexer(src, opt))
2284
+ .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
2285
+ .then(tokens => parser(tokens, opt))
2286
+ .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
2287
+ .catch(throwError);
2288
+ }
2289
+ try {
2290
+ if (opt.hooks) {
2291
+ src = opt.hooks.preprocess(src);
2292
+ }
2293
+ const tokens = lexer(src, opt);
2294
+ if (opt.walkTokens) {
2295
+ this.walkTokens(tokens, opt.walkTokens);
2296
+ }
2297
+ let html = parser(tokens, opt);
2298
+ if (opt.hooks) {
2299
+ html = opt.hooks.postprocess(html);
2300
+ }
2301
+ return html;
2302
+ }
2303
+ catch (e) {
2304
+ return throwError(e);
2305
+ }
2306
+ };
2307
+ }
2308
+ #onError(silent, async) {
2309
+ return (e) => {
2310
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
2311
+ if (silent) {
2312
+ const msg = '<p>An error occurred:</p><pre>'
2313
+ + escape(e.message + '', true)
2314
+ + '</pre>';
2315
+ if (async) {
2316
+ return Promise.resolve(msg);
2317
+ }
2318
+ return msg;
2319
+ }
2320
+ if (async) {
2321
+ return Promise.reject(e);
2322
+ }
2323
+ throw e;
2324
+ };
2325
+ }
1140
2326
  }
1141
2327
 
1142
- opt = merge({}, marked.defaults, opt || {});
1143
-
1144
- var highlight = opt.highlight
1145
- , tokens
1146
- , pending
1147
- , i = 0;
1148
-
1149
- try {
1150
- tokens = Lexer.lex(src, opt)
1151
- } catch (e) {
1152
- return callback(e);
2328
+ const markedInstance = new Marked();
2329
+ function marked(src, opt) {
2330
+ return markedInstance.parse(src, opt);
1153
2331
  }
1154
-
1155
- pending = tokens.length;
1156
-
1157
- var done = function() {
1158
- var out, err;
1159
-
1160
- try {
1161
- out = Parser.parse(tokens, opt);
1162
- } catch (e) {
1163
- err = e;
1164
- }
1165
-
1166
- opt.highlight = highlight;
1167
-
1168
- return err
1169
- ? callback(err)
1170
- : callback(null, out);
2332
+ /**
2333
+ * Sets the default options.
2334
+ *
2335
+ * @param options Hash of options
2336
+ */
2337
+ marked.options =
2338
+ marked.setOptions = function (options) {
2339
+ markedInstance.setOptions(options);
2340
+ marked.defaults = markedInstance.defaults;
2341
+ changeDefaults(marked.defaults);
2342
+ return marked;
2343
+ };
2344
+ /**
2345
+ * Gets the original marked default options.
2346
+ */
2347
+ marked.getDefaults = _getDefaults;
2348
+ marked.defaults = exports.defaults;
2349
+ /**
2350
+ * Use Extension
2351
+ */
2352
+ marked.use = function (...args) {
2353
+ markedInstance.use(...args);
2354
+ marked.defaults = markedInstance.defaults;
2355
+ changeDefaults(marked.defaults);
2356
+ return marked;
1171
2357
  };
1172
-
1173
- if (!highlight || highlight.length < 3) {
1174
- return done();
1175
- }
1176
-
1177
- delete opt.highlight;
1178
-
1179
- if (!pending) return done();
1180
-
1181
- for (; i < tokens.length; i++) {
1182
- (function(token) {
1183
- if (token.type !== 'code') {
1184
- return --pending || done();
1185
- }
1186
- return highlight(token.text, token.lang, function(err, code) {
1187
- if (code == null || code === token.text) {
1188
- return --pending || done();
1189
- }
1190
- token.text = code;
1191
- token.escaped = true;
1192
- --pending || done();
1193
- });
1194
- })(tokens[i]);
1195
- }
1196
-
1197
- return;
1198
- }
1199
- try {
1200
- if (opt) opt = merge({}, marked.defaults, opt);
1201
- return Parser.parse(Lexer.lex(src, opt), opt);
1202
- } catch (e) {
1203
- e.message += '\nPlease report this to https://github.com/chjj/marked.';
1204
- if ((opt || marked.defaults).silent) {
1205
- return '<p>An error occured:</p><pre>'
1206
- + escape(e.message + '', true)
1207
- + '</pre>';
1208
- }
1209
- throw e;
1210
- }
1211
- }
1212
-
1213
- /**
1214
- * Options
1215
- */
1216
-
1217
- marked.options =
1218
- marked.setOptions = function(opt) {
1219
- merge(marked.defaults, opt);
1220
- return marked;
1221
- };
1222
-
1223
- marked.defaults = {
1224
- gfm: true,
1225
- tables: true,
1226
- breaks: false,
1227
- pedantic: false,
1228
- sanitize: false,
1229
- smartLists: false,
1230
- silent: false,
1231
- highlight: null,
1232
- langPrefix: 'lang-',
1233
- smartypants: false,
1234
- headerPrefix: '',
1235
- renderer: new Renderer,
1236
- xhtml: false
1237
- };
1238
-
1239
- /**
1240
- * Expose
1241
- */
1242
-
1243
- marked.Parser = Parser;
1244
- marked.parser = Parser.parse;
1245
-
1246
- marked.Renderer = Renderer;
1247
-
1248
- marked.Lexer = Lexer;
1249
- marked.lexer = Lexer.lex;
1250
-
1251
- marked.InlineLexer = InlineLexer;
1252
- marked.inlineLexer = InlineLexer.output;
1253
-
1254
- marked.parse = marked;
1255
-
1256
- if (typeof exports === 'object') {
1257
- module.exports = marked;
1258
- } else if (typeof define === 'function' && define.amd) {
1259
- define(function() { return marked; });
1260
- } else {
1261
- this.marked = marked;
1262
- }
1263
-
1264
- }).call(function() {
1265
- return this || (typeof window !== 'undefined' ? window : global);
1266
- }());
2358
+ /**
2359
+ * Run callback for every token
2360
+ */
2361
+ marked.walkTokens = function (tokens, callback) {
2362
+ return markedInstance.walkTokens(tokens, callback);
2363
+ };
2364
+ /**
2365
+ * Compiles markdown to HTML without enclosing `p` tag.
2366
+ *
2367
+ * @param src String of markdown source to be compiled
2368
+ * @param options Hash of options
2369
+ * @return String of compiled HTML
2370
+ */
2371
+ marked.parseInline = markedInstance.parseInline;
2372
+ /**
2373
+ * Expose
2374
+ */
2375
+ marked.Parser = _Parser;
2376
+ marked.parser = _Parser.parse;
2377
+ marked.Renderer = _Renderer;
2378
+ marked.TextRenderer = _TextRenderer;
2379
+ marked.Lexer = _Lexer;
2380
+ marked.lexer = _Lexer.lex;
2381
+ marked.Tokenizer = _Tokenizer;
2382
+ marked.Hooks = _Hooks;
2383
+ marked.parse = marked;
2384
+ const options = marked.options;
2385
+ const setOptions = marked.setOptions;
2386
+ const use = marked.use;
2387
+ const walkTokens = marked.walkTokens;
2388
+ const parseInline = marked.parseInline;
2389
+ const parse = marked;
2390
+ const parser = _Parser.parse;
2391
+ const lexer = _Lexer.lex;
2392
+
2393
+ exports.Hooks = _Hooks;
2394
+ exports.Lexer = _Lexer;
2395
+ exports.Marked = Marked;
2396
+ exports.Parser = _Parser;
2397
+ exports.Renderer = _Renderer;
2398
+ exports.TextRenderer = _TextRenderer;
2399
+ exports.Tokenizer = _Tokenizer;
2400
+ exports.getDefaults = _getDefaults;
2401
+ exports.lexer = lexer;
2402
+ exports.marked = marked;
2403
+ exports.options = options;
2404
+ exports.parse = parse;
2405
+ exports.parseInline = parseInline;
2406
+ exports.parser = parser;
2407
+ exports.setOptions = setOptions;
2408
+ exports.use = use;
2409
+ exports.walkTokens = walkTokens;
2410
+
2411
+ }));
2412
+ //# sourceMappingURL=marked.umd.js.map