marked 4.0.2 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,7 +47,9 @@ Also read about:
47
47
 
48
48
  **CLI**
49
49
 
50
+
50
51
  ``` bash
52
+ # Example with stdin input
51
53
  $ marked -o hello.html
52
54
  hello world
53
55
  ^D
@@ -55,6 +57,11 @@ $ cat hello.html
55
57
  <p>hello world</p>
56
58
  ```
57
59
 
60
+ ```bash
61
+ # Print all options
62
+ $ marked --help
63
+ ```
64
+
58
65
  **Browser**
59
66
 
60
67
  ```html
package/bin/marked.js CHANGED
@@ -27,10 +27,16 @@ async function help() {
27
27
  const { dirname, resolve } = await import('path');
28
28
  const { fileURLToPath } = await import('url');
29
29
  const __dirname = dirname(fileURLToPath(import.meta.url));
30
- spawn('man', [resolve(__dirname, '../man/marked.1')], options)
31
- .on('error', async() => {
32
- console.log(await readFile(resolve(__dirname, '../man/marked.1.txt'), 'utf8'));
33
- });
30
+ const helpText = await readFile(resolve(__dirname, '../man/marked.1.txt'), 'utf8');
31
+
32
+ // eslint-disable-next-line promise/param-names
33
+ await new Promise(res => {
34
+ spawn('man', [resolve(__dirname, '../man/marked.1')], options)
35
+ .on('error', () => {
36
+ console.log(helpText);
37
+ })
38
+ .on('close', res);
39
+ });
34
40
  }
35
41
 
36
42
  async function version() {
@@ -149,7 +155,7 @@ async function main(argv) {
149
155
  : marked(data, options);
150
156
 
151
157
  if (output) {
152
- return await writeFile(output, data);
158
+ return await writeFile(output, html);
153
159
  }
154
160
 
155
161
  process.stdout.write(html + '\n');
package/lib/marked.cjs CHANGED
@@ -533,7 +533,7 @@ var Tokenizer = /*#__PURE__*/function () {
533
533
  var cap = this.rules.block.list.exec(src);
534
534
 
535
535
  if (cap) {
536
- var raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine, line, lines, itemContents;
536
+ var raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine, line, nextLine, rawLine, itemContents;
537
537
  var bull = cap[1].trim();
538
538
  var isordered = bull.length > 1;
539
539
  var list = {
@@ -551,83 +551,77 @@ var Tokenizer = /*#__PURE__*/function () {
551
551
  } // Get next list item
552
552
 
553
553
 
554
- var itemRegex = new RegExp("^( {0,3}" + bull + ")((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))"); // Get each top-level item
554
+ var itemRegex = new RegExp("^( {0,3}" + bull + ")((?: [^\\n]*)?(?:\\n|$))"); // Check if current bullet point can start a new List Item
555
555
 
556
556
  while (src) {
557
- if (this.rules.block.hr.test(src)) {
558
- // End list if we encounter an HR (possibly move into itemRegex?)
557
+ if (!(cap = itemRegex.exec(src))) {
559
558
  break;
560
559
  }
561
560
 
562
- if (!(cap = itemRegex.exec(src))) {
561
+ if (this.rules.block.hr.test(src)) {
562
+ // End list if bullet was actually HR (possibly move into itemRegex?)
563
563
  break;
564
564
  }
565
565
 
566
- lines = cap[2].split('\n');
566
+ raw = cap[0];
567
+ src = src.substring(raw.length);
568
+ line = cap[2].split('\n', 1)[0];
569
+ nextLine = src.split('\n', 1)[0];
567
570
 
568
571
  if (this.options.pedantic) {
569
572
  indent = 2;
570
- itemContents = lines[0].trimLeft();
573
+ itemContents = line.trimLeft();
571
574
  } else {
572
575
  indent = cap[2].search(/[^ ]/); // Find first non-space char
573
576
 
574
- indent = cap[1].length + (indent > 4 ? 1 : indent); // intented code blocks after 4 spaces; indent is always 1
577
+ indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
575
578
 
576
- itemContents = lines[0].slice(indent - cap[1].length);
579
+ itemContents = line.slice(indent);
580
+ indent += cap[1].length;
577
581
  }
578
582
 
579
583
  blankLine = false;
580
- raw = cap[0];
581
584
 
582
- if (!lines[0] && /^ *$/.test(lines[1])) {
583
- // items begin with at most one blank line
584
- raw = cap[1] + lines.slice(0, 2).join('\n') + '\n';
585
+ if (!line && /^ *$/.test(nextLine)) {
586
+ // Items begin with at most one blank line
587
+ raw += nextLine + '\n';
588
+ src = src.substring(nextLine.length + 1);
585
589
  list.loose = true;
586
- lines = [];
587
590
  }
588
591
 
589
- var nextBulletRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:[*+-]|\\d{1,9}[.)])");
592
+ var nextBulletRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:[*+-]|\\d{1,9}[.)])"); // Check if following lines should be included in List Item
590
593
 
591
- for (i = 1; i < lines.length; i++) {
592
- line = lines[i];
594
+ while (src && !list.loose) {
595
+ rawLine = src.split('\n', 1)[0];
596
+ line = rawLine; // Re-align to follow commonmark nesting rules
593
597
 
594
598
  if (this.options.pedantic) {
595
- // Re-align to follow commonmark nesting rules
596
599
  line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
597
600
  } // End list item if found start of new bullet
598
601
 
599
602
 
600
603
  if (nextBulletRegex.test(line)) {
601
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
602
604
  break;
603
- } // Until we encounter a blank line, item contents do not need indentation
604
-
605
-
606
- if (!blankLine) {
607
- if (!line.trim()) {
608
- // Check if current line is empty
609
- blankLine = true;
610
- } // Dedent if possible
611
-
612
-
613
- if (line.search(/[^ ]/) >= indent) {
614
- itemContents += '\n' + line.slice(indent);
615
- } else {
616
- itemContents += '\n' + line;
617
- }
618
-
619
- continue;
620
- } // Dedent this line
621
-
605
+ }
622
606
 
623
607
  if (line.search(/[^ ]/) >= indent || !line.trim()) {
608
+ // Dedent if possible
624
609
  itemContents += '\n' + line.slice(indent);
625
- continue;
610
+ } else if (!blankLine) {
611
+ // Until blank line, item doesn't need indentation
612
+ itemContents += '\n' + line;
626
613
  } else {
627
- // Line was not properly indented; end of this item
628
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
614
+ // Otherwise, improper indentation ends this item
629
615
  break;
630
616
  }
617
+
618
+ if (!blankLine && !line.trim()) {
619
+ // Check if current line is blank
620
+ blankLine = true;
621
+ }
622
+
623
+ raw += rawLine + '\n';
624
+ src = src.substring(rawLine.length + 1);
631
625
  }
632
626
 
633
627
  if (!list.loose) {
@@ -658,7 +652,6 @@ var Tokenizer = /*#__PURE__*/function () {
658
652
  text: itemContents
659
653
  });
660
654
  list.raw += raw;
661
- src = src.slice(raw.length);
662
655
  } // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
663
656
 
664
657
 
@@ -671,7 +664,7 @@ var Tokenizer = /*#__PURE__*/function () {
671
664
  this.lexer.state.top = false;
672
665
  list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
673
666
 
674
- if (list.items[i].tokens.some(function (t) {
667
+ if (!list.loose && list.items[i].tokens.some(function (t) {
675
668
  return t.type === 'space';
676
669
  })) {
677
670
  list.loose = true;
@@ -1190,7 +1183,7 @@ var block = {
1190
1183
  lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
1191
1184
  // regex template, placeholders will be replaced according to different paragraph
1192
1185
  // interruption rules of commonmark and the original markdown spec:
1193
- _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
1186
+ _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
1194
1187
  text: /^[^\n]+/
1195
1188
  };
1196
1189
  block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
@@ -1203,7 +1196,7 @@ block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|c
1203
1196
  block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
1204
1197
  block.html = edit(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
1205
1198
  block.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1206
- .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1199
+ .replace('|table', '').replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1207
1200
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1208
1201
  .getRegex();
1209
1202
  block.blockquote = edit(block.blockquote).replace('paragraph', block.paragraph).getRegex();
@@ -1225,6 +1218,11 @@ block.gfm = merge({}, block.normal, {
1225
1218
  block.gfm.table = edit(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1226
1219
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
1227
1220
  .getRegex();
1221
+ block.gfm.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1222
+ .replace('table', block.gfm.table) // interrupt paragraphs with table
1223
+ .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1224
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1225
+ .getRegex();
1228
1226
  /**
1229
1227
  * Pedantic grammar (original John Gruber's loose markdown specification)
1230
1228
  */
package/lib/marked.esm.js CHANGED
@@ -452,7 +452,7 @@ class Tokenizer {
452
452
  let cap = this.rules.block.list.exec(src);
453
453
  if (cap) {
454
454
  let raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine,
455
- line, lines, itemContents;
455
+ line, nextLine, rawLine, itemContents;
456
456
 
457
457
  let bull = cap[1].trim();
458
458
  const isordered = bull.length > 1;
@@ -473,76 +473,73 @@ class Tokenizer {
473
473
  }
474
474
 
475
475
  // Get next list item
476
- const itemRegex = new RegExp(`^( {0,3}${bull})((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))`);
476
+ const itemRegex = new RegExp(`^( {0,3}${bull})((?: [^\\n]*)?(?:\\n|$))`);
477
477
 
478
- // Get each top-level item
478
+ // Check if current bullet point can start a new List Item
479
479
  while (src) {
480
- if (this.rules.block.hr.test(src)) { // End list if we encounter an HR (possibly move into itemRegex?)
480
+ if (!(cap = itemRegex.exec(src))) {
481
481
  break;
482
482
  }
483
483
 
484
- if (!(cap = itemRegex.exec(src))) {
484
+ if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)
485
485
  break;
486
486
  }
487
487
 
488
- lines = cap[2].split('\n');
488
+ raw = cap[0];
489
+ src = src.substring(raw.length);
490
+
491
+ line = cap[2].split('\n', 1)[0];
492
+ nextLine = src.split('\n', 1)[0];
489
493
 
490
494
  if (this.options.pedantic) {
491
495
  indent = 2;
492
- itemContents = lines[0].trimLeft();
496
+ itemContents = line.trimLeft();
493
497
  } else {
494
498
  indent = cap[2].search(/[^ ]/); // Find first non-space char
495
- indent = cap[1].length + (indent > 4 ? 1 : indent); // intented code blocks after 4 spaces; indent is always 1
496
- itemContents = lines[0].slice(indent - cap[1].length);
499
+ indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
500
+ itemContents = line.slice(indent);
501
+ indent += cap[1].length;
497
502
  }
498
503
 
499
504
  blankLine = false;
500
- raw = cap[0];
501
505
 
502
- if (!lines[0] && /^ *$/.test(lines[1])) { // items begin with at most one blank line
503
- raw = cap[1] + lines.slice(0, 2).join('\n') + '\n';
506
+ if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line
507
+ raw += nextLine + '\n';
508
+ src = src.substring(nextLine.length + 1);
504
509
  list.loose = true;
505
- lines = [];
506
510
  }
507
511
 
508
512
  const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])`);
509
513
 
510
- for (i = 1; i < lines.length; i++) {
511
- line = lines[i];
514
+ // Check if following lines should be included in List Item
515
+ while (src && !list.loose) {
516
+ rawLine = src.split('\n', 1)[0];
517
+ line = rawLine;
512
518
 
513
- if (this.options.pedantic) { // Re-align to follow commonmark nesting rules
519
+ // Re-align to follow commonmark nesting rules
520
+ if (this.options.pedantic) {
514
521
  line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
515
522
  }
516
523
 
517
524
  // End list item if found start of new bullet
518
525
  if (nextBulletRegex.test(line)) {
519
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
520
526
  break;
521
527
  }
522
528
 
523
- // Until we encounter a blank line, item contents do not need indentation
524
- if (!blankLine) {
525
- if (!line.trim()) { // Check if current line is empty
526
- blankLine = true;
527
- }
528
-
529
- // Dedent if possible
530
- if (line.search(/[^ ]/) >= indent) {
531
- itemContents += '\n' + line.slice(indent);
532
- } else {
533
- itemContents += '\n' + line;
534
- }
535
- continue;
536
- }
537
-
538
- // Dedent this line
539
- if (line.search(/[^ ]/) >= indent || !line.trim()) {
529
+ if (line.search(/[^ ]/) >= indent || !line.trim()) { // Dedent if possible
540
530
  itemContents += '\n' + line.slice(indent);
541
- continue;
542
- } else { // Line was not properly indented; end of this item
543
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
531
+ } else if (!blankLine) { // Until blank line, item doesn't need indentation
532
+ itemContents += '\n' + line;
533
+ } else { // Otherwise, improper indentation ends this item
544
534
  break;
545
535
  }
536
+
537
+ if (!blankLine && !line.trim()) { // Check if current line is blank
538
+ blankLine = true;
539
+ }
540
+
541
+ raw += rawLine + '\n';
542
+ src = src.substring(rawLine.length + 1);
546
543
  }
547
544
 
548
545
  if (!list.loose) {
@@ -573,7 +570,6 @@ class Tokenizer {
573
570
  });
574
571
 
575
572
  list.raw += raw;
576
- src = src.slice(raw.length);
577
573
  }
578
574
 
579
575
  // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
@@ -587,7 +583,7 @@ class Tokenizer {
587
583
  for (i = 0; i < l; i++) {
588
584
  this.lexer.state.top = false;
589
585
  list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
590
- if (list.items[i].tokens.some(t => t.type === 'space')) {
586
+ if (!list.loose && list.items[i].tokens.some(t => t.type === 'space')) {
591
587
  list.loose = true;
592
588
  list.items[i].loose = true;
593
589
  }
@@ -1063,7 +1059,7 @@ const block = {
1063
1059
  lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
1064
1060
  // regex template, placeholders will be replaced according to different paragraph
1065
1061
  // interruption rules of commonmark and the original markdown spec:
1066
- _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
1062
+ _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
1067
1063
  text: /^[^\n]+/
1068
1064
  };
1069
1065
 
@@ -1102,6 +1098,7 @@ block.paragraph = edit(block._paragraph)
1102
1098
  .replace('hr', block.hr)
1103
1099
  .replace('heading', ' {0,3}#{1,6} ')
1104
1100
  .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1101
+ .replace('|table', '')
1105
1102
  .replace('blockquote', ' {0,3}>')
1106
1103
  .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1107
1104
  .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
@@ -1140,6 +1137,17 @@ block.gfm.table = edit(block.gfm.table)
1140
1137
  .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
1141
1138
  .getRegex();
1142
1139
 
1140
+ block.gfm.paragraph = edit(block._paragraph)
1141
+ .replace('hr', block.hr)
1142
+ .replace('heading', ' {0,3}#{1,6} ')
1143
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1144
+ .replace('table', block.gfm.table) // interrupt paragraphs with table
1145
+ .replace('blockquote', ' {0,3}>')
1146
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1147
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1148
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1149
+ .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1150
+ .getRegex();
1143
1151
  /**
1144
1152
  * Pedantic grammar (original John Gruber's loose markdown specification)
1145
1153
  */
package/lib/marked.umd.js CHANGED
@@ -535,7 +535,7 @@
535
535
  var cap = this.rules.block.list.exec(src);
536
536
 
537
537
  if (cap) {
538
- var raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine, line, lines, itemContents;
538
+ var raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine, line, nextLine, rawLine, itemContents;
539
539
  var bull = cap[1].trim();
540
540
  var isordered = bull.length > 1;
541
541
  var list = {
@@ -553,83 +553,77 @@
553
553
  } // Get next list item
554
554
 
555
555
 
556
- var itemRegex = new RegExp("^( {0,3}" + bull + ")((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))"); // Get each top-level item
556
+ var itemRegex = new RegExp("^( {0,3}" + bull + ")((?: [^\\n]*)?(?:\\n|$))"); // Check if current bullet point can start a new List Item
557
557
 
558
558
  while (src) {
559
- if (this.rules.block.hr.test(src)) {
560
- // End list if we encounter an HR (possibly move into itemRegex?)
559
+ if (!(cap = itemRegex.exec(src))) {
561
560
  break;
562
561
  }
563
562
 
564
- if (!(cap = itemRegex.exec(src))) {
563
+ if (this.rules.block.hr.test(src)) {
564
+ // End list if bullet was actually HR (possibly move into itemRegex?)
565
565
  break;
566
566
  }
567
567
 
568
- lines = cap[2].split('\n');
568
+ raw = cap[0];
569
+ src = src.substring(raw.length);
570
+ line = cap[2].split('\n', 1)[0];
571
+ nextLine = src.split('\n', 1)[0];
569
572
 
570
573
  if (this.options.pedantic) {
571
574
  indent = 2;
572
- itemContents = lines[0].trimLeft();
575
+ itemContents = line.trimLeft();
573
576
  } else {
574
577
  indent = cap[2].search(/[^ ]/); // Find first non-space char
575
578
 
576
- indent = cap[1].length + (indent > 4 ? 1 : indent); // intented code blocks after 4 spaces; indent is always 1
579
+ indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
577
580
 
578
- itemContents = lines[0].slice(indent - cap[1].length);
581
+ itemContents = line.slice(indent);
582
+ indent += cap[1].length;
579
583
  }
580
584
 
581
585
  blankLine = false;
582
- raw = cap[0];
583
586
 
584
- if (!lines[0] && /^ *$/.test(lines[1])) {
585
- // items begin with at most one blank line
586
- raw = cap[1] + lines.slice(0, 2).join('\n') + '\n';
587
+ if (!line && /^ *$/.test(nextLine)) {
588
+ // Items begin with at most one blank line
589
+ raw += nextLine + '\n';
590
+ src = src.substring(nextLine.length + 1);
587
591
  list.loose = true;
588
- lines = [];
589
592
  }
590
593
 
591
- var nextBulletRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:[*+-]|\\d{1,9}[.)])");
594
+ var nextBulletRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:[*+-]|\\d{1,9}[.)])"); // Check if following lines should be included in List Item
592
595
 
593
- for (i = 1; i < lines.length; i++) {
594
- line = lines[i];
596
+ while (src && !list.loose) {
597
+ rawLine = src.split('\n', 1)[0];
598
+ line = rawLine; // Re-align to follow commonmark nesting rules
595
599
 
596
600
  if (this.options.pedantic) {
597
- // Re-align to follow commonmark nesting rules
598
601
  line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
599
602
  } // End list item if found start of new bullet
600
603
 
601
604
 
602
605
  if (nextBulletRegex.test(line)) {
603
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
604
606
  break;
605
- } // Until we encounter a blank line, item contents do not need indentation
606
-
607
-
608
- if (!blankLine) {
609
- if (!line.trim()) {
610
- // Check if current line is empty
611
- blankLine = true;
612
- } // Dedent if possible
613
-
614
-
615
- if (line.search(/[^ ]/) >= indent) {
616
- itemContents += '\n' + line.slice(indent);
617
- } else {
618
- itemContents += '\n' + line;
619
- }
620
-
621
- continue;
622
- } // Dedent this line
623
-
607
+ }
624
608
 
625
609
  if (line.search(/[^ ]/) >= indent || !line.trim()) {
610
+ // Dedent if possible
626
611
  itemContents += '\n' + line.slice(indent);
627
- continue;
612
+ } else if (!blankLine) {
613
+ // Until blank line, item doesn't need indentation
614
+ itemContents += '\n' + line;
628
615
  } else {
629
- // Line was not properly indented; end of this item
630
- raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
616
+ // Otherwise, improper indentation ends this item
631
617
  break;
632
618
  }
619
+
620
+ if (!blankLine && !line.trim()) {
621
+ // Check if current line is blank
622
+ blankLine = true;
623
+ }
624
+
625
+ raw += rawLine + '\n';
626
+ src = src.substring(rawLine.length + 1);
633
627
  }
634
628
 
635
629
  if (!list.loose) {
@@ -660,7 +654,6 @@
660
654
  text: itemContents
661
655
  });
662
656
  list.raw += raw;
663
- src = src.slice(raw.length);
664
657
  } // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
665
658
 
666
659
 
@@ -673,7 +666,7 @@
673
666
  this.lexer.state.top = false;
674
667
  list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
675
668
 
676
- if (list.items[i].tokens.some(function (t) {
669
+ if (!list.loose && list.items[i].tokens.some(function (t) {
677
670
  return t.type === 'space';
678
671
  })) {
679
672
  list.loose = true;
@@ -1192,7 +1185,7 @@
1192
1185
  lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
1193
1186
  // regex template, placeholders will be replaced according to different paragraph
1194
1187
  // interruption rules of commonmark and the original markdown spec:
1195
- _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
1188
+ _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
1196
1189
  text: /^[^\n]+/
1197
1190
  };
1198
1191
  block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
@@ -1205,7 +1198,7 @@
1205
1198
  block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
1206
1199
  block.html = edit(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
1207
1200
  block.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1208
- .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1201
+ .replace('|table', '').replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1209
1202
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1210
1203
  .getRegex();
1211
1204
  block.blockquote = edit(block.blockquote).replace('paragraph', block.paragraph).getRegex();
@@ -1227,6 +1220,11 @@
1227
1220
  block.gfm.table = edit(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1228
1221
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
1229
1222
  .getRegex();
1223
+ block.gfm.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1224
+ .replace('table', block.gfm.table) // interrupt paragraphs with table
1225
+ .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1226
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
1227
+ .getRegex();
1230
1228
  /**
1231
1229
  * Pedantic grammar (original John Gruber's loose markdown specification)
1232
1230
  */