@peaceroad/markdown-it-table-ex 0.3.1 → 0.3.2

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.
Files changed (2) hide show
  1. package/index.js +285 -172
  2. package/package.json +3 -3
package/index.js CHANGED
@@ -56,6 +56,84 @@ const hasInlineRule = (md, name) => {
56
56
  return false;
57
57
  };
58
58
 
59
+ const createNewlineToken = (Token) => {
60
+ const token = new Token('text', '', 0);
61
+ token.content = '\n';
62
+ return token;
63
+ };
64
+
65
+ const setInlineText = (inline, Token, text) => {
66
+ inline.content = text;
67
+ const textToken = new Token('text', '', 0);
68
+ textToken.content = text;
69
+ textToken.level = 0;
70
+ inline.children = [textToken];
71
+ };
72
+
73
+ const removeHeaderCellAt = (tokens, openIdx) => {
74
+ if (!tokens[openIdx] || tokens[openIdx].type !== 'th_open') return;
75
+ let deleteCount = 3;
76
+ const next = tokens[openIdx + 3];
77
+ if (next && next.type === 'text' && next.content === '\n') {
78
+ deleteCount += 1;
79
+ }
80
+ tokens.splice(openIdx, deleteCount);
81
+ };
82
+
83
+ const findFirstHeaderThPos = (tokens, tableOpenIdx, allowFallback) => {
84
+ let inThead = false;
85
+ for (let i = tableOpenIdx + 1; i < tokens.length; i++) {
86
+ const type = tokens[i].type;
87
+ if (type === 'table_close') break;
88
+ if (type === 'thead_open') {
89
+ inThead = true;
90
+ continue;
91
+ }
92
+ if (!inThead) continue;
93
+ if (type === 'thead_close') break;
94
+ if (type !== 'th_open') continue;
95
+ const inline = tokens[i + 1];
96
+ if (inline && (inline.content === '' || isStrongWrappedInline(inline, allowFallback))) {
97
+ return i;
98
+ }
99
+ return -1;
100
+ }
101
+ return -1;
102
+ };
103
+
104
+ const findFirstHeaderCellPos = (tokens, tableOpenIdx) => {
105
+ let inThead = false;
106
+ for (let i = tableOpenIdx + 1; i < tokens.length; i++) {
107
+ const type = tokens[i].type;
108
+ if (type === 'table_close') break;
109
+ if (type === 'thead_open') {
110
+ inThead = true;
111
+ continue;
112
+ }
113
+ if (!inThead) continue;
114
+ if (type === 'thead_close') break;
115
+ if (type === 'th_open') return i;
116
+ }
117
+ return -1;
118
+ };
119
+
120
+ const createColgroupRegexes = (colgroupWithNoAsterisk) => {
121
+ if (colgroupWithNoAsterisk) {
122
+ return {
123
+ singleHeaderGroup: /^([^::]+)(?::\s*|: +)/,
124
+ singleHeaderStrip: /^[^::]+(?::\s*|: +)(.*)$/,
125
+ multiHeaderGroup: /^([^::]+)(?::\s*|: +)/,
126
+ multiHeaderStrip: /^[^::]+(?::\s*|: +)(.*)$/
127
+ };
128
+ }
129
+ return {
130
+ singleHeaderGroup: /^\*\*([^*::]+)[::]\*\*\s*/,
131
+ singleHeaderStrip: /^\*\*[^*::]+[::]\*\*\s*(.*)$/,
132
+ multiHeaderGroup: /^\*\*([^*::]+)[::]\*\*/,
133
+ multiHeaderStrip: /^\*\*[^*::]+[::]\*\*\s*(.*)$/
134
+ };
135
+ };
136
+
59
137
  const createTokenTemplate = (tokenType, tag, nesting, level) => ({
60
138
  type: tokenType,
61
139
  tag: tag,
@@ -213,24 +291,28 @@ const removeStrongWrappers = (inline, allowFallback) => {
213
291
 
214
292
  const addTheadThScope = (state, theadVar, allowFallback) => {
215
293
  const tokens = state.tokens;
216
- let firstThPos = theadVar.pos;
217
- let j = theadVar.i + 2;
218
- //if (state.tokens[theadVar.i + 1].type !== 'tr_open') return threadVar
294
+ let firstThPos = theadVar.firstThPos;
295
+ let j = theadVar.i + 1;
296
+ let isFirstRow = true;
297
+ let firstRowFirstThSeen = false;
219
298
  while (j < tokens.length) {
220
- if (tokens[j].type === 'th_open') {
221
- tokens[j].attrPush(['scope', 'col']);
222
- if (j === theadVar.i + 2) {
299
+ const tokenType = tokens[j].type;
300
+ if (tokenType === 'th_open') {
301
+ tokens[j].attrSet('scope', 'col');
302
+ if (isFirstRow && !firstRowFirstThSeen) {
303
+ firstRowFirstThSeen = true;
223
304
  const inline = tokens[j + 1];
224
- const content = inline.content;
305
+ const content = inline && typeof inline.content === 'string' ? inline.content : '';
225
306
  if (content === '' || isStrongWrappedInline(inline, allowFallback)) {
226
- firstThPos = j
227
- // Only remove strong tags from the first th content for matrix processing
228
- // The actual removal will be done in changeTdToTh if matrix conditions are met
307
+ firstThPos = j;
229
308
  }
230
309
  }
310
+ } else if (tokenType === 'tr_close' && isFirstRow) {
311
+ isFirstRow = false;
312
+ } else if (tokenType === 'thead_close') {
313
+ break;
231
314
  }
232
- if (tokens[j].type === 'tr_close') break
233
- j++
315
+ j++;
234
316
  }
235
317
  return {i: j, firstThPos: firstThPos}
236
318
  }
@@ -278,7 +360,7 @@ const checkTbody = (state, tbodyVar, allowFallback) => {
278
360
  return { i: j, isAllFirstTh: isAllFirstTh, tbodyFirstThPoses: tbodyFirstThPoses}
279
361
  }
280
362
 
281
- const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
363
+ const setColgroup = (state, tableOpenIdx, opt, allowFallback, regexes) => {
282
364
  const tokens = state.tokens;
283
365
  const Token = state.Token;
284
366
 
@@ -310,12 +392,8 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
310
392
  headerCount: 0
311
393
  };
312
394
 
313
- const colgroupMatchReg = opt.colgroupWithNoAsterisk
314
- ? /^([^::]+)(?::|:)\s*/
315
- : /^\*\*([^*::]+)[::]\*\*\s*/;
316
- const origColgroupMatchReg = opt.colgroupWithNoAsterisk
317
- ? /^[^::]+(?::|:)\s*(.*)$/
318
- : /^\*\*[^*::]+[::]\*\*\s*(.*)$/;
395
+ const colgroupMatchReg = regexes.singleHeaderGroup;
396
+ const origColgroupMatchReg = regexes.singleHeaderStrip;
319
397
 
320
398
  let thIdx = tr1 + 1;
321
399
  const origThInfos = [];
@@ -375,7 +453,7 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
375
453
  if (hasSpan) {
376
454
  const insertTokens = [
377
455
  new Token('colgroup_open', 'colgroup', 1),
378
- Object.assign(new Token('text', '', 0), { content: '\n' })
456
+ createNewlineToken(Token)
379
457
  ];
380
458
 
381
459
  for (let i = 0; i < groupData.spans.length; i++) {
@@ -385,13 +463,13 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
385
463
  }
386
464
  insertTokens.push(
387
465
  colOpen,
388
- Object.assign(new Token('text', '', 0), { content: '\n' })
466
+ createNewlineToken(Token)
389
467
  );
390
468
  }
391
469
 
392
470
  insertTokens.push(
393
471
  new Token('colgroup_close', 'colgroup', -1),
394
- Object.assign(new Token('text', '', 0), { content: '\n' })
472
+ createNewlineToken(Token)
395
473
  );
396
474
 
397
475
  tokens.splice(tableOpenIdx + 1, 0, ...insertTokens);
@@ -399,7 +477,6 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
399
477
  // Update indices
400
478
  const offset = insertTokens.length;
401
479
  tr1 += offset;
402
- theadClose += offset;
403
480
  trCloseIdx += offset;
404
481
  }
405
482
 
@@ -407,14 +484,14 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
407
484
 
408
485
  // Create new rows more efficiently
409
486
  const newTr1 = [
410
- Object.assign(new Token('text', '', 0), { content: '\n' }),
487
+ createNewlineToken(Token),
411
488
  new Token('tr_open', 'tr', 1),
412
- Object.assign(new Token('text', '', 0), { content: '\n' })
489
+ createNewlineToken(Token)
413
490
  ];
414
491
 
415
492
  const newTr2 = [
416
493
  new Token('tr_open', 'tr', 1),
417
- Object.assign(new Token('text', '', 0), { content: '\n' })
494
+ createNewlineToken(Token)
418
495
  ];
419
496
 
420
497
  let thPtr = 0;
@@ -437,15 +514,14 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
437
514
  thInline.children = Array.isArray(origInline.children) ? origInline.children : [];
438
515
  if (cellMap) thInline.map = cellMap;
439
516
  } else {
440
- thInline.content = '';
441
- thInline.children = [];
517
+ setInlineText(thInline, Token, '');
442
518
  }
443
519
 
444
520
  newTr1.push(
445
521
  thOpen,
446
522
  thInline,
447
523
  new Token('th_close', 'th', -1),
448
- Object.assign(new Token('text', '', 0), { content: '\n' })
524
+ createNewlineToken(Token)
449
525
  );
450
526
  thPtr++;
451
527
  } else {
@@ -458,15 +534,14 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
458
534
  if (cellMap) thOpen.map = cellMap;
459
535
 
460
536
  const thInline = new Token('inline', '', 0);
461
- thInline.content = groupNames[i];
462
- thInline.children = [{ type: 'text', content: groupNames[i], level: 0 }];
537
+ setInlineText(thInline, Token, groupNames[i]);
463
538
  if (cellMap) thInline.map = cellMap;
464
539
 
465
540
  newTr1.push(
466
541
  thOpen,
467
542
  thInline,
468
543
  new Token('th_close', 'th', -1),
469
- Object.assign(new Token('text', '', 0), { content: '\n' })
544
+ createNewlineToken(Token)
470
545
  );
471
546
 
472
547
  // Second row: each item in the group
@@ -488,15 +563,14 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
488
563
  } else if (hasLeadingStrongMarker(origInline, allowFallback)) {
489
564
  match = orig.match(origColgroupMatchReg);
490
565
  }
491
- th2Inline.content = match ? match[1] : orig;
492
- th2Inline.children = [{ type: 'text', content: th2Inline.content, level: 0 }];
566
+ setInlineText(th2Inline, Token, match ? match[1] : orig);
493
567
  if (subMap) th2Inline.map = subMap;
494
568
 
495
569
  newTr2.push(
496
570
  th2Open,
497
571
  th2Inline,
498
572
  new Token('th_close', 'th', -1),
499
- Object.assign(new Token('text', '', 0), { content: '\n' })
573
+ createNewlineToken(Token)
500
574
  );
501
575
  thPtr++;
502
576
  }
@@ -505,12 +579,12 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
505
579
 
506
580
  newTr1.push(
507
581
  new Token('tr_close', 'tr', -1),
508
- Object.assign(new Token('text', '', 0), { content: '\n' })
582
+ createNewlineToken(Token)
509
583
  );
510
584
 
511
585
  newTr2.push(
512
586
  new Token('tr_close', 'tr', -1),
513
- Object.assign(new Token('text', '', 0), { content: '\n' })
587
+ createNewlineToken(Token)
514
588
  );
515
589
 
516
590
  // Clean up newlines before insertion
@@ -525,40 +599,6 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
525
599
 
526
600
  tokens.splice(tr1, trCloseIdx - tr1 + 1, ...newTr1, ...newTr2);
527
601
 
528
- // Handle tbody th conversion
529
- let tbodyOpen = -1, tbodyClose = -1;
530
- for (let i = theadClose + 1; i < tokens.length; i++) {
531
- if (tokens[i].type === 'tbody_open') {
532
- tbodyOpen = i;
533
- } else if (tbodyOpen >= 0 && tokens[i].type === 'tbody_close') {
534
- tbodyClose = i;
535
- break;
536
- }
537
- }
538
-
539
- if (tbodyOpen >= 0 && tbodyClose > tbodyOpen) {
540
- let j = tbodyOpen + 1;
541
- while (j < tbodyClose) {
542
- if (tokens[j].type === 'tr_open') {
543
- const tdIdx = j + 1;
544
- if (tokens[tdIdx].type === 'td_open') {
545
- const inline = tokens[tdIdx + 1];
546
- if (inline && typeof inline.content === 'string' &&
547
- isStrongWrappedInline(inline, allowFallback)) {
548
- tokens[tdIdx].type = 'th_open';
549
- tokens[tdIdx].tag = 'th';
550
- tokens[tdIdx].attrSet('scope', 'row');
551
- removeStrongWrappers(inline, allowFallback);
552
- if (tokens[tdIdx + 2].type === 'td_close') {
553
- tokens[tdIdx + 2].type = 'th_close';
554
- tokens[tdIdx + 2].tag = 'th';
555
- }
556
- }
557
- }
558
- }
559
- j++;
560
- }
561
- }
562
602
  return;
563
603
  }
564
604
 
@@ -567,116 +607,169 @@ const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
567
607
  // Calculate group names and colspan for multi-row case
568
608
  const groupData = {
569
609
  spans: [],
570
- rawNames: []
610
+ rawNames: [],
611
+ headerCount: 0
571
612
  };
572
- const groupMatchReg = /^\*\*([^*:]+):\*\*/;
613
+ const groupMatchReg = regexes.multiHeaderGroup;
614
+ const groupStripReg = regexes.multiHeaderStrip;
573
615
 
616
+ const firstRowCells = [];
617
+ let firstRowClose = -1;
574
618
  let thIdx = tr1 + 1;
575
- while (thIdx < tokens.length && tokens[thIdx].type !== 'tr_close') {
619
+ while (thIdx < tokens.length) {
620
+ if (tokens[thIdx].type === 'th_open') {
621
+ firstRowCells.push(thIdx);
622
+ } else if (tokens[thIdx].type === 'tr_close') {
623
+ firstRowClose = thIdx;
624
+ break;
625
+ }
626
+ thIdx++;
627
+ }
628
+ if (firstRowClose < 0 || firstRowCells.length === 0) return;
629
+
630
+ const secondRowCells = [];
631
+ let secondRowClose = -1;
632
+ thIdx = tr2 + 1;
633
+ while (thIdx < tokens.length) {
576
634
  if (tokens[thIdx].type === 'th_open') {
577
- const inline = tokens[thIdx + 1];
578
- const content = inline.content;
579
- const hasLeadingStrong = hasLeadingStrongMarker(inline, allowFallback);
580
- let match = null;
581
- if (hasLeadingStrong) {
635
+ secondRowCells.push(thIdx);
636
+ } else if (tokens[thIdx].type === 'tr_close') {
637
+ secondRowClose = thIdx;
638
+ break;
639
+ }
640
+ thIdx++;
641
+ }
642
+ if (secondRowClose < 0 || secondRowCells.length === 0) return;
643
+
644
+ for (let i = 0; i < firstRowCells.length; i++) {
645
+ const inline = tokens[firstRowCells[i] + 1];
646
+ const content = inline && typeof inline.content === 'string' ? inline.content : '';
647
+ let match = null;
648
+ if (opt.colgroupWithNoAsterisk) {
649
+ if (content.indexOf(':') !== -1 || content.indexOf(':') !== -1) {
582
650
  match = content.match(groupMatchReg);
583
651
  }
584
-
585
- if (match) {
586
- const group = match[1].trim();
587
- const lastGroup = groupData.rawNames[groupData.rawNames.length - 1];
588
-
589
- if (groupData.rawNames.length > 0 && lastGroup === group) {
590
- groupData.spans[groupData.spans.length - 1]++;
591
- } else {
592
- groupData.rawNames.push(group);
593
- groupData.spans.push(1);
594
- }
652
+ } else if (hasLeadingStrongMarker(inline, allowFallback)) {
653
+ match = content.match(groupMatchReg);
654
+ }
655
+
656
+ if (match) {
657
+ const group = match[1].trim();
658
+ const lastGroup = groupData.rawNames[groupData.rawNames.length - 1];
659
+ if (groupData.rawNames.length > 0 && lastGroup === group) {
660
+ groupData.spans[groupData.spans.length - 1]++;
595
661
  } else {
596
- groupData.rawNames.push(null);
662
+ groupData.rawNames.push(group);
597
663
  groupData.spans.push(1);
598
664
  }
665
+ groupData.headerCount++;
666
+ } else {
667
+ groupData.rawNames.push(null);
668
+ groupData.spans.push(1);
599
669
  }
600
- thIdx++;
601
670
  }
602
671
 
603
- const groupNames = groupData.rawNames;
604
- const groupStripReg = /^\*\*[^*:]+:\*\*\s*(.*)$/;
672
+ if (groupData.headerCount < 2) return;
605
673
 
606
- // Generate colgroup if needed
607
674
  const hasSpan = groupData.spans.some(span => span > 1);
608
- if (hasSpan) {
609
- const insertTokens = [new Token('colgroup_open', 'colgroup', 1)];
675
+
676
+ // Add colspan/rowspan to thead and strip group prefixes in the second row.
677
+ const firstRowRemove = [];
678
+ const secondRowRemove = [];
679
+ let firstPtr = 0;
680
+ let secondPtr = 0;
681
+ for (let groupIdx = 0; groupIdx < groupData.spans.length; groupIdx++) {
682
+ const span = groupData.spans[groupIdx];
683
+ const groupName = groupData.rawNames[groupIdx];
684
+ const firstOpen = firstRowCells[firstPtr];
685
+ if (typeof firstOpen !== 'number' || !tokens[firstOpen] || tokens[firstOpen].type !== 'th_open') {
686
+ break;
687
+ }
688
+ const firstInline = tokens[firstOpen + 1];
689
+
690
+ if (groupName === null) {
691
+ tokens[firstOpen].attrSet('rowspan', '2');
692
+ tokens[firstOpen].attrSet('scope', 'col');
693
+ removeStrongWrappers(firstInline, allowFallback);
694
+ const secondOpen = secondRowCells[secondPtr];
695
+ if (typeof secondOpen === 'number') {
696
+ secondRowRemove.push(secondOpen);
697
+ secondPtr += 1;
698
+ }
699
+ firstPtr += 1;
700
+ continue;
701
+ }
610
702
 
611
- for (let i = 0; i < groupData.spans.length; i++) {
612
- const colOpen = new Token('col_open', 'col', 1);
613
- if (groupData.spans[i] > 1) {
614
- colOpen.attrPush(['span', groupData.spans[i]]);
703
+ if (span > 1) {
704
+ tokens[firstOpen].attrSet('colspan', span.toString());
705
+ }
706
+ tokens[firstOpen].attrSet('scope', 'col');
707
+ if (firstInline) {
708
+ setInlineText(firstInline, Token, groupName);
709
+ }
710
+
711
+ for (let i = 1; i < span; i++) {
712
+ const extraFirst = firstRowCells[firstPtr + i];
713
+ if (typeof extraFirst === 'number') {
714
+ firstRowRemove.push(extraFirst);
615
715
  }
616
- insertTokens.push(colOpen, new Token('col_close', 'col', -1));
617
716
  }
618
717
 
619
- insertTokens.push(new Token('colgroup_close', 'colgroup', -1));
620
- tokens.splice(tableOpenIdx + 1, 0, ...insertTokens);
718
+ for (let i = 0; i < span; i++) {
719
+ const secondOpen = secondRowCells[secondPtr + i];
720
+ if (typeof secondOpen !== 'number' || !tokens[secondOpen] || tokens[secondOpen].type !== 'th_open') {
721
+ continue;
722
+ }
723
+ tokens[secondOpen].attrSet('scope', 'col');
724
+ const secondInline = tokens[secondOpen + 1];
725
+ if (!secondInline || typeof secondInline.content !== 'string') continue;
726
+ const secondContent = secondInline.content;
727
+ let secondMatch = null;
728
+ if (opt.colgroupWithNoAsterisk) {
729
+ if (secondContent.indexOf(':') !== -1 || secondContent.indexOf(':') !== -1) {
730
+ secondMatch = secondContent.match(groupStripReg);
731
+ }
732
+ } else if (hasLeadingStrongMarker(secondInline, allowFallback)) {
733
+ secondMatch = secondContent.match(groupStripReg);
734
+ }
735
+ if (secondMatch) {
736
+ setInlineText(secondInline, Token, secondMatch[1]);
737
+ }
738
+ }
739
+
740
+ secondPtr += span;
741
+ firstPtr += span;
621
742
  }
622
743
 
623
- // Add colspan/rowspan to thead
624
- let th1 = tr1 + 1, th2 = tr2 + 1, groupIdx = 0;
625
- while (th1 < tokens.length && tokens[th1].type !== 'tr_close') {
626
- if (tokens[th1].type === 'th_open') {
627
- if (groupNames[groupIdx] === null) {
628
- // Leftmost cell: rowspan=2
629
- tokens[th1].attrSet('rowspan', '2');
630
- tokens[th1].attrSet('scope', 'col');
631
- removeStrongWrappers(tokens[th1 + 1], allowFallback);
632
-
633
- // Find corresponding th in second row
634
- let t2 = th2;
635
- while (t2 < tokens.length && tokens[t2].type !== 'tr_close') {
636
- if (tokens[t2].type === 'th_open') {
637
- tokens[t2].attrSet('scope', 'col');
638
- th2 = t2 + 1;
639
- break;
640
- }
641
- t2++;
642
- }
643
- groupIdx++;
644
- } else {
645
- // Group cell
646
- if (groupData.spans[groupIdx] > 1) {
647
- tokens[th1].attrSet('colspan', groupData.spans[groupIdx].toString());
648
- }
649
- tokens[th1].attrSet('scope', 'col');
650
- tokens[th1 + 1].content = groupNames[groupIdx];
651
-
652
- // Process corresponding ths in second row
653
- let count = 0, t2 = th2;
654
- while (t2 < tokens.length && tokens[t2].type !== 'tr_close' && count < groupData.spans[groupIdx]) {
655
- if (tokens[t2].type === 'th_open') {
656
- tokens[t2].attrSet('scope', 'col');
657
- // Remove group name part from content
658
- const t2Inline = tokens[t2 + 1];
659
- const t2content = t2Inline.content;
660
- let t2match = null;
661
- if (hasLeadingStrongMarker(t2Inline, allowFallback)) {
662
- t2match = t2content.match(groupStripReg);
663
- }
664
- if (t2match) {
665
- tokens[t2 + 1].content = t2match[1];
666
- }
667
- count++;
668
- }
669
- t2++;
670
- }
671
- th2 = t2;
672
- groupIdx++;
744
+ if (firstRowRemove.length || secondRowRemove.length) {
745
+ const removeTargets = firstRowRemove.concat(secondRowRemove).sort((a, b) => b - a);
746
+ for (let i = 0; i < removeTargets.length; i++) {
747
+ removeHeaderCellAt(tokens, removeTargets[i]);
748
+ }
749
+ }
750
+
751
+ // Insert colgroup after header edits so index calculations above remain stable.
752
+ if (hasSpan) {
753
+ const insertTokens = [
754
+ new Token('colgroup_open', 'colgroup', 1),
755
+ createNewlineToken(Token)
756
+ ];
757
+ for (let i = 0; i < groupData.spans.length; i++) {
758
+ const colOpen = new Token('col_open', 'col', 1);
759
+ if (groupData.spans[i] > 1) {
760
+ colOpen.attrPush(['span', groupData.spans[i]]);
673
761
  }
762
+ insertTokens.push(colOpen, createNewlineToken(Token));
674
763
  }
675
- th1++;
764
+ insertTokens.push(
765
+ new Token('colgroup_close', 'colgroup', -1),
766
+ createNewlineToken(Token)
767
+ );
768
+ tokens.splice(tableOpenIdx + 1, 0, ...insertTokens);
676
769
  }
677
770
  };
678
771
 
679
- const tableEx = (state, opt) => {
772
+ const tableEx = (state, opt, regexes) => {
680
773
  const tokens = state.tokens;
681
774
  let tokenLength = tokens.length;
682
775
  const allowStrongFallback = !hasInlineRule(state.md, 'strong_ja');
@@ -688,7 +781,7 @@ const tableEx = (state, opt) => {
688
781
  continue;
689
782
  }
690
783
 
691
- const tableOpenIdx = idx;
784
+ let tableOpenIdx = idx;
692
785
 
693
786
  if (opt.wrapper) {
694
787
  const wrapperStartToken = new state.Token('div_open', 'div', 1);
@@ -696,11 +789,10 @@ const tableEx = (state, opt) => {
696
789
  if (Array.isArray(tokens[idx].map)) {
697
790
  wrapperStartToken.map = tokens[idx].map.slice();
698
791
  }
699
- const linebreakToken = new state.Token('text', '', 0);
700
- linebreakToken.content = '\n';
701
- tokens.splice(idx, 0, wrapperStartToken, linebreakToken);
792
+ tokens.splice(idx, 0, wrapperStartToken, createNewlineToken(state.Token));
702
793
  tokenLength += 2;
703
794
  idx += 2;
795
+ tableOpenIdx = idx;
704
796
  }
705
797
 
706
798
  let theadVar = {
@@ -712,27 +804,50 @@ const tableEx = (state, opt) => {
712
804
  if (hasThead) {
713
805
  theadVar = addTheadThScope(state, theadVar, allowStrongFallback);
714
806
  idx = theadVar.i + 1;
807
+ const hadMatrixAnchor = Number.isInteger(theadVar.firstThPos) && theadVar.firstThPos >= 0;
715
808
  if (opt.colgroup) {
716
809
  const beforeLength = tokens.length;
717
- setColgroup(state, tableOpenIdx, opt, allowStrongFallback);
810
+ setColgroup(state, tableOpenIdx, opt, allowStrongFallback, regexes);
718
811
  tokenLength += tokens.length - beforeLength;
719
812
  }
813
+ if (opt.matrix) {
814
+ let firstThPos = findFirstHeaderThPos(tokens, tableOpenIdx, allowStrongFallback);
815
+ if (firstThPos < 0 && hadMatrixAnchor) {
816
+ firstThPos = findFirstHeaderCellPos(tokens, tableOpenIdx);
817
+ }
818
+ theadVar.firstThPos = firstThPos;
819
+ }
720
820
  }
721
821
 
722
822
  if (opt.matrix) {
823
+ let tbodyOpenPos = -1;
824
+ for (let i = tableOpenIdx + 1; i < tokenLength; i++) {
825
+ const type = tokens[i].type;
826
+ if (type === 'tbody_open') {
827
+ tbodyOpenPos = i;
828
+ break;
829
+ }
830
+ if (type === 'table_close') {
831
+ break;
832
+ }
833
+ }
834
+
723
835
  let tbodyVar = {
724
- i: idx + 1,
836
+ i: tbodyOpenPos,
725
837
  isAllFirstTh: false,
726
838
  tbodyFirstThPoses: [],
727
839
  };
728
840
 
729
- const hasTbody = tokens[tbodyVar.i] && tokens[tbodyVar.i].type === 'tbody_open';
841
+ const hasTbody = tbodyVar.i >= 0;
730
842
  if (hasTbody) {
731
843
  tbodyVar = checkTbody(state, tbodyVar, allowStrongFallback);
732
844
  idx = tbodyVar.i + 1;
733
845
  }
734
846
 
735
- if (theadVar.firstThPos && tbodyVar.isAllFirstTh) {
847
+ const hasMatrixAnchor = hasThead
848
+ ? Number.isInteger(theadVar.firstThPos) && theadVar.firstThPos >= 0
849
+ : true;
850
+ if (hasMatrixAnchor && tbodyVar.isAllFirstTh) {
736
851
  const firstTdPoses = [...tbodyVar.tbodyFirstThPoses];
737
852
  if (hasThead) {
738
853
  firstTdPoses.unshift(theadVar.firstThPos);
@@ -746,9 +861,7 @@ const tableEx = (state, opt) => {
746
861
  if (tokens[idx].type === 'table_close') {
747
862
  if (opt.wrapper) {
748
863
  const wrapperEndToken = new state.Token('div_close', 'div', -1);
749
- const linebreakToken = new state.Token('text', '', 0);
750
- linebreakToken.content = '\n';
751
- tokens.splice(idx + 1, 0, wrapperEndToken, linebreakToken);
864
+ tokens.splice(idx + 1, 0, wrapperEndToken, createNewlineToken(state.Token));
752
865
  tokenLength += 2;
753
866
  idx += 2;
754
867
  }
@@ -761,17 +874,17 @@ const tableEx = (state, opt) => {
761
874
  };
762
875
 
763
876
  const mditTableEx = (md, option) => {
764
- let opt = {
877
+ const baseOpt = {
765
878
  matrix: true,
766
879
  wrapper: false,
767
880
  colgroup: false,
768
881
  colgroupWithNoAsterisk: false
769
882
  };
770
- for (let key in option) {
771
- opt[key] = option[key]
772
- }
883
+ const userOpt = (option && typeof option === 'object') ? option : {};
884
+ const opt = Object.assign({}, baseOpt, userOpt);
885
+ const regexes = createColgroupRegexes(opt.colgroupWithNoAsterisk);
773
886
  md.core.ruler.after('replacements', 'table-ex', (state) => {
774
- tableEx(state, opt);
887
+ tableEx(state, opt, regexes);
775
888
  });
776
889
  }
777
890
  export default mditTableEx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peaceroad/markdown-it-table-ex",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A markdown-it plugin. Add matrix and wrapper notation for table processing.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -16,8 +16,8 @@
16
16
  "author": "peaceroad <peaceroad@gmail.com>",
17
17
  "license": "MIT",
18
18
  "devDependencies": {
19
- "@peaceroad/markdown-it-figure-with-p-caption": "^0.15.1",
20
- "@peaceroad/markdown-it-strong-ja": "^0.6.1",
19
+ "@peaceroad/markdown-it-figure-with-p-caption": "^0.16.0",
20
+ "@peaceroad/markdown-it-strong-ja": "^0.7.2",
21
21
  "markdown-it": "^14.1.0",
22
22
  "markdown-it-multimd-table": "^4.2.3"
23
23
  }