@peaceroad/markdown-it-table-ex 0.1.0 → 0.2.0

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/index.js CHANGED
@@ -1,9 +1,158 @@
1
- const checkedTdReg = /^\*\*(?!.*\*\*.*\*\*)[\s\S]*?\*\*$/
1
+ const checkedTdReg = /^\*\*[\s\S]*?\*\*$/;
2
+
3
+ const createTokenTemplate = (tokenType, tag, nesting, level) => ({
4
+ type: tokenType,
5
+ tag: tag,
6
+ attrs: null,
7
+ map: null,
8
+ nesting: nesting,
9
+ level: level,
10
+ children: null,
11
+ content: '',
12
+ markup: '**',
13
+ info: '',
14
+ meta: null,
15
+ block: false,
16
+ hidden: false
17
+ });
18
+
19
+ // Helper function to remove strong tags that wrap the entire content
20
+ const removeStrongWrappers = (inline) => {
21
+ if (!Array.isArray(inline.children) || inline.children.length === 0) {
22
+ return;
23
+ }
24
+
25
+ const children = inline.children;
26
+ const content = inline.content;
27
+
28
+ // Quick check to avoid regex if obviously not matching
29
+ if (!content.startsWith('**') || !content.endsWith('**')) {
30
+ return;
31
+ }
32
+
33
+ // Check if the content matches the pattern **...** where entire content is wrapped
34
+ if (!checkedTdReg.test(content)) {
35
+ return;
36
+ }
37
+
38
+ // Find all strong open/close positions in one pass
39
+ const strongPositions = [];
40
+ for (let i = 0; i < children.length; i++) {
41
+ const type = children[i].type;
42
+ if (type === 'strong_open') {
43
+ strongPositions.push({ type: 'open', index: i });
44
+ } else if (type === 'strong_close') {
45
+ strongPositions.push({ type: 'close', index: i });
46
+ }
47
+ }
48
+
49
+ const openCount = strongPositions.filter(p => p.type === 'open').length;
50
+ const closeCount = strongPositions.filter(p => p.type === 'close').length;
51
+
52
+ if (openCount !== closeCount || openCount === 0) {
53
+ return;
54
+ }
55
+
56
+ if (openCount >= 2) {
57
+ // Multiple strong pairs case - find pairs by stack matching
58
+ const pairs = [];
59
+ const stack = [];
60
+
61
+ for (const pos of strongPositions) {
62
+ if (pos.type === 'open') {
63
+ stack.push(pos.index);
64
+ } else if (stack.length > 0) {
65
+ const openIdx = stack.pop();
66
+ pairs.push({ open: openIdx, close: pos.index });
67
+ }
68
+ }
69
+
70
+ if (pairs.length >= 2) {
71
+ const firstPair = pairs[0];
72
+ const lastPair = pairs[pairs.length - 1];
73
+
74
+ const newChildren = [];
75
+ const contentParts = [];
76
+
77
+ // Helper function to add children and build content
78
+ const addChildrenRange = (start, end) => {
79
+ for (let i = start; i < end; i++) {
80
+ newChildren.push(children[i]);
81
+ if (children[i].type === 'text') {
82
+ contentParts.push(children[i].content);
83
+ } else if (children[i].type === 'em_open' || children[i].type === 'em_close') {
84
+ contentParts.push('*');
85
+ }
86
+ }
87
+ };
88
+
89
+ // Add content before first pair
90
+ addChildrenRange(0, firstPair.open);
91
+
92
+ // Add content from first pair (without the strong tags)
93
+ addChildrenRange(firstPair.open + 1, firstPair.close);
94
+
95
+ // Add content between first and last pairs with strong wrapping
96
+ for (let i = firstPair.close + 1; i < lastPair.open; i++) {
97
+ if (children[i].type === 'text' && children[i].content.trim() !== '') {
98
+ // Create strong tokens more efficiently
99
+ const strongOpen = Object.create(children[i].constructor.prototype);
100
+ Object.assign(strongOpen, createTokenTemplate('strong_open', 'strong', 1, children[i].level));
101
+
102
+ const strongClose = Object.create(children[i].constructor.prototype);
103
+ Object.assign(strongClose, createTokenTemplate('strong_close', 'strong', -1, children[i].level));
104
+
105
+ newChildren.push(strongOpen, children[i], strongClose);
106
+ contentParts.push('**', children[i].content, '**');
107
+ } else {
108
+ newChildren.push(children[i]);
109
+ if (children[i].type === 'text') {
110
+ contentParts.push(children[i].content);
111
+ } else if (children[i].type === 'em_open' || children[i].type === 'em_close') {
112
+ contentParts.push('*');
113
+ }
114
+ }
115
+ }
116
+
117
+ // Add content from last pair (without the strong tags)
118
+ addChildrenRange(lastPair.open + 1, lastPair.close);
119
+
120
+ // Add content after last pair
121
+ addChildrenRange(lastPair.close + 1, children.length);
122
+
123
+ inline.content = contentParts.join('');
124
+ inline.children = newChildren;
125
+ }
126
+
127
+ } else if (openCount === 1) {
128
+ // Single strong pair: remove completely
129
+ const strongOpen = strongPositions.find(p => p.type === 'open').index;
130
+ const strongClose = strongPositions.find(p => p.type === 'close').index;
131
+
132
+ const newChildren = [];
133
+ const contentParts = [];
134
+
135
+ for (let i = 0; i < children.length; i++) {
136
+ if (i === strongOpen || i === strongClose) {
137
+ continue; // Skip strong tags
138
+ }
139
+ newChildren.push(children[i]);
140
+ if (children[i].type === 'text') {
141
+ contentParts.push(children[i].content);
142
+ } else if (children[i].type === 'em_open' || children[i].type === 'em_close') {
143
+ contentParts.push('*');
144
+ }
145
+ }
146
+
147
+ inline.content = contentParts.join('');
148
+ inline.children = newChildren;
149
+ }
150
+ }
2
151
 
3
152
  const addTheadThScope = (state, theadVar) => {
4
- let isEmpty = false
5
- let firstThPos = theadVar.pos
6
- let j = theadVar.i + 2
153
+ let isEmpty = false;
154
+ let firstThPos = theadVar.pos;
155
+ let j = theadVar.i + 2;
7
156
  //if (state.tokens[theadVar.i + 1].type !== 'tr_open') return threadVar
8
157
  while (j < state.tokens.length) {
9
158
  if (state.tokens[j].type === 'th_open') {
@@ -11,7 +160,13 @@ const addTheadThScope = (state, theadVar) => {
11
160
  if (j === theadVar.i + 2) {
12
161
  isEmpty = state.tokens[j+1].content === ''
13
162
  let isStrong = checkedTdReg.test(state.tokens[j+1].content)
14
- if (isStrong || isEmpty) firstThPos = j
163
+ if (isStrong) {
164
+ firstThPos = j
165
+ // Only remove strong tags from the first th content for matrix processing
166
+ // The actual removal will be done in changeTdToTh if matrix conditions are met
167
+ } else if (isEmpty) {
168
+ firstThPos = j
169
+ }
15
170
  }
16
171
  }
17
172
  if (state.tokens[j].type === 'tr_close') break
@@ -20,11 +175,11 @@ const addTheadThScope = (state, theadVar) => {
20
175
  return {i: j, firstThPos: firstThPos, isEmpty: isEmpty}
21
176
  }
22
177
 
23
-
24
178
  const changeTdToTh = (state, tdPoses, hasThead) => {
179
+ //console.log('hasThead: ' + hasThead + ', tdPoses: ' + tdPoses)
25
180
  let j = 0
26
181
  while(j < tdPoses.length) {
27
- //console.log('tdPos: ' + tdPoses[j] + ', state.tokens[j].type: ' + state.tokens[tdPoses[j]].type)
182
+ //console.log('state.tokens[' + j + '].type: ' + state.tokens[tdPoses[j]].type)
28
183
  const pos = tdPoses[j]
29
184
  if (j > 0 || (!hasThead && j === 0)) {
30
185
  state.tokens[pos].type = 'th_open';
@@ -34,22 +189,9 @@ const changeTdToTh = (state, tdPoses, hasThead) => {
34
189
  state.tokens[pos + 2].tag = 'th';
35
190
  }
36
191
 
37
- let ci = 0
38
- while (ci < state.tokens[pos + 1].children.length) {
39
- if (state.tokens[pos + 1].children[ci].type === 'strong_open') {
40
- state.tokens[pos + 1].children.splice(ci, 1)
41
- break
42
- }
43
- ci++
44
- }
45
- ci = state.tokens[pos + 1].children.length - 1
46
- while (0 < ci) {
47
- if (state.tokens[pos + 1].children[ci].type === 'strong_close') {
48
- state.tokens[pos + 1].children.splice(ci, 1)
49
- break
50
- }
51
- ci--
52
- }
192
+ // Remove strong tags that wrap the entire content
193
+ const inline = state.tokens[pos + 1];
194
+ removeStrongWrappers(inline);
53
195
  j++
54
196
  }
55
197
  }
@@ -71,79 +213,474 @@ const checkTbody = (state, tbodyVar) => {
71
213
  if (state.tokens[j].type === 'tbody_close') break
72
214
  j++
73
215
  }
74
- return { i: j ,isAllFirstTh: isAllFirstTh, tbodyFirstThPoses: tbodyFirstThPoses}
216
+ return { i: j, isAllFirstTh: isAllFirstTh, tbodyFirstThPoses: tbodyFirstThPoses}
75
217
  }
76
218
 
219
+ const setColgroup = (state, tableOpenIdx, opt) => {
220
+ const tokens = state.tokens;
221
+ const Token = state.Token;
222
+
223
+ // Find thead and tr positions in one pass
224
+ let theadOpen = -1, tr1 = -1, tr2 = -1, theadClose = -1;
225
+ for (let i = tableOpenIdx; i < tokens.length; i++) {
226
+ const tokenType = tokens[i].type;
227
+ if (tokenType === 'thead_open' && theadOpen === -1) {
228
+ theadOpen = i;
229
+ } else if (theadOpen >= 0 && tokenType === 'tr_open') {
230
+ if (tr1 === -1) {
231
+ tr1 = i;
232
+ } else if (tr2 === -1) {
233
+ tr2 = i;
234
+ break;
235
+ }
236
+ } else if (theadOpen >= 0 && tokenType === 'thead_close') {
237
+ theadClose = i;
238
+ break;
239
+ }
240
+ }
241
+
242
+ // If there is only one <tr>, auto-generate a two-row header
243
+ if (tr1 >= 0 && tr2 < 0 && theadClose > tr1) {
244
+ // Calculate group names and colspan for the first row of th
245
+ const groupData = {
246
+ spans: [],
247
+ names: [],
248
+ rawNames: [],
249
+ headerCount: 0
250
+ };
251
+
252
+ let thIdx = tr1 + 1;
253
+ const thTokens = [];
254
+
255
+ while (thIdx < tokens.length && tokens[thIdx].type !== 'tr_close') {
256
+ if (tokens[thIdx].type === 'th_open') {
257
+ thTokens.push(thIdx);
258
+ const inline = tokens[thIdx + 1];
259
+ const content = inline.content;
260
+ const colgroupMatchReg = opt.colgroupWithNoAsterisk
261
+ ? /^([^::]+)(?::|:)\s*/
262
+ : /^\*\*([^*::]+)[::]\*\*\s*/;
263
+ const match = content.match(colgroupMatchReg);
264
+
265
+ if (match) {
266
+ const group = match[1].trim();
267
+ const lastGroup = groupData.rawNames[groupData.rawNames.length - 1];
268
+
269
+ if (groupData.rawNames.length > 0 && lastGroup === group) {
270
+ groupData.spans[groupData.spans.length - 1]++;
271
+ } else {
272
+ groupData.rawNames.push(group);
273
+ groupData.spans.push(1);
274
+ }
275
+ groupData.headerCount++;
276
+ } else {
277
+ groupData.rawNames.push(null);
278
+ groupData.spans.push(1);
279
+ }
280
+ }
281
+ thIdx++;
282
+ }
283
+
284
+ // If there are not two or more grouped header cells, do not auto-generate
285
+ if (groupData.headerCount < 2) return;
286
+
287
+ // Determine group names
288
+ const nonNullGroups = groupData.rawNames.filter(name => name !== null);
289
+ const allSame = nonNullGroups.length > 0 && nonNullGroups.every(name => name === nonNullGroups[0]);
290
+
291
+ if (allSame) {
292
+ groupData.names = [...groupData.rawNames];
293
+ } else {
294
+ groupData.names = [...groupData.rawNames];
295
+ }
296
+
297
+ // Generate colgroup if needed
298
+ const hasSpan = groupData.spans.some(span => span > 1);
299
+ if (hasSpan) {
300
+ const insertTokens = [
301
+ new Token('colgroup_open', 'colgroup', 1),
302
+ Object.assign(new Token('text', '', 0), { content: '\n' })
303
+ ];
304
+
305
+ for (let i = 0; i < groupData.spans.length; i++) {
306
+ const colOpen = new Token('col_open', 'col', 1);
307
+ if (groupData.spans[i] > 1) {
308
+ colOpen.attrPush(['span', groupData.spans[i]]);
309
+ }
310
+ insertTokens.push(
311
+ colOpen,
312
+ Object.assign(new Token('text', '', 0), { content: '\n' })
313
+ );
314
+ }
315
+
316
+ insertTokens.push(
317
+ new Token('colgroup_close', 'colgroup', -1),
318
+ Object.assign(new Token('text', '', 0), { content: '\n' })
319
+ );
320
+
321
+ tokens.splice(tableOpenIdx + 1, 0, ...insertTokens);
322
+
323
+ // Update indices
324
+ const offset = insertTokens.length;
325
+ theadOpen += offset;
326
+ tr1 += offset;
327
+ theadClose += offset;
328
+ }
329
+
330
+ // Generate two-row header
331
+ const trCloseIdx = tokens.findIndex((t, idx) => idx > tr1 && t.type === 'tr_close');
332
+
333
+ // Create new rows more efficiently
334
+ const newTr1 = [
335
+ Object.assign(new Token('text', '', 0), { content: '\n' }),
336
+ new Token('tr_open', 'tr', 1),
337
+ Object.assign(new Token('text', '', 0), { content: '\n' })
338
+ ];
339
+
340
+ const newTr2 = [
341
+ new Token('tr_open', 'tr', 1),
342
+ Object.assign(new Token('text', '', 0), { content: '\n' })
343
+ ];
344
+
345
+ // Enumerate th_open/inline between tr1 and trCloseIdx
346
+ const origThs = [];
347
+ for (let i = tr1 + 1; i < trCloseIdx; i++) {
348
+ if (tokens[i].type === 'th_open') {
349
+ origThs.push({
350
+ th_open: tokens[i],
351
+ inline: tokens[i + 1]
352
+ });
353
+ }
354
+ }
355
+
356
+ let thPtr = 0;
357
+ for (let i = 0; i < groupData.spans.length; i++) {
358
+ if (groupData.names[i] === null) {
359
+ // Leftmost cell: rowspan=2
360
+ const thOpen = new Token('th_open', 'th', 1);
361
+ thOpen.attrSet('rowspan', '2');
362
+ thOpen.attrSet('scope', 'col');
363
+
364
+ const thInline = new Token('inline', '', 0);
365
+ const origInline = origThs[thPtr]?.inline;
366
+
367
+ if (origInline) {
368
+ // Create a copy for processing
369
+ const tempInline = {
370
+ content: origInline.content,
371
+ children: origInline.children ? [...origInline.children] : []
372
+ };
373
+ removeStrongWrappers(tempInline);
374
+ thInline.content = tempInline.content;
375
+ thInline.children = tempInline.children;
376
+ } else {
377
+ thInline.content = '';
378
+ thInline.children = [];
379
+ }
380
+
381
+ newTr1.push(
382
+ thOpen,
383
+ thInline,
384
+ new Token('th_close', 'th', -1),
385
+ Object.assign(new Token('text', '', 0), { content: '\n' })
386
+ );
387
+ thPtr++;
388
+ } else {
389
+ // Group cell
390
+ const thOpen = new Token('th_open', 'th', 1);
391
+ if (groupData.spans[i] > 1) {
392
+ thOpen.attrSet('colspan', groupData.spans[i].toString());
393
+ }
394
+ thOpen.attrSet('scope', 'col');
395
+
396
+ const thInline = new Token('inline', '', 0);
397
+ thInline.content = groupData.names[i];
398
+ thInline.children = [{ type: 'text', content: groupData.names[i], level: 0 }];
399
+
400
+ newTr1.push(
401
+ thOpen,
402
+ thInline,
403
+ new Token('th_close', 'th', -1),
404
+ Object.assign(new Token('text', '', 0), { content: '\n' })
405
+ );
406
+
407
+ // Second row: each item in the group
408
+ for (let j = 0; j < groupData.spans[i]; j++) {
409
+ const th2Open = new Token('th_open', 'th', 1);
410
+ th2Open.attrSet('scope', 'col');
411
+
412
+ const th2Inline = new Token('inline', '', 0);
413
+ const orig = origThs[thPtr]?.inline?.content || '';
414
+ const origColgroupMatchReg = opt.colgroupWithNoAsterisk
415
+ ? /^[^::]+(?::|:)\s*(.*)$/
416
+ : /^\*\*[^*::]+[::]\*\*\s*(.*)$/;
417
+ const match = orig.match(origColgroupMatchReg);
418
+ th2Inline.content = match ? match[1] : orig;
419
+ th2Inline.children = [{ type: 'text', content: th2Inline.content, level: 0 }];
420
+
421
+ newTr2.push(
422
+ th2Open,
423
+ th2Inline,
424
+ new Token('th_close', 'th', -1),
425
+ Object.assign(new Token('text', '', 0), { content: '\n' })
426
+ );
427
+ thPtr++;
428
+ }
429
+ }
430
+ }
431
+
432
+ newTr1.push(
433
+ new Token('tr_close', 'tr', -1),
434
+ Object.assign(new Token('text', '', 0), { content: '\n' })
435
+ );
436
+
437
+ newTr2.push(
438
+ new Token('tr_close', 'tr', -1),
439
+ Object.assign(new Token('text', '', 0), { content: '\n' })
440
+ );
441
+
442
+ // Clean up newlines before insertion
443
+ while (tokens[tr1 - 1] && tokens[tr1 - 1].type === 'text' && tokens[tr1 - 1].content === '\n') {
444
+ tokens.splice(tr1 - 1, 1);
445
+ tr1--;
446
+ }
447
+
448
+ while (newTr1.length && newTr1[0].type === 'text' && newTr1[0].content === '\n') {
449
+ newTr1.shift();
450
+ }
451
+
452
+ tokens.splice(tr1, trCloseIdx - tr1 + 1, ...newTr1, ...newTr2);
453
+
454
+ // Handle tbody th conversion
455
+ let tbodyOpen = -1, tbodyClose = -1;
456
+ for (let i = theadClose + 1; i < tokens.length; i++) {
457
+ if (tokens[i].type === 'tbody_open') {
458
+ tbodyOpen = i;
459
+ } else if (tbodyOpen >= 0 && tokens[i].type === 'tbody_close') {
460
+ tbodyClose = i;
461
+ break;
462
+ }
463
+ }
464
+
465
+ if (tbodyOpen >= 0 && tbodyClose > tbodyOpen) {
466
+ let j = tbodyOpen + 1;
467
+ while (j < tbodyClose) {
468
+ if (tokens[j].type === 'tr_open') {
469
+ const tdIdx = j + 1;
470
+ if (tokens[tdIdx].type === 'td_open') {
471
+ const inline = tokens[tdIdx + 1];
472
+ if (inline && typeof inline.content === 'string' && checkedTdReg.test(inline.content)) {
473
+ tokens[tdIdx].type = 'th_open';
474
+ tokens[tdIdx].tag = 'th';
475
+ tokens[tdIdx].attrSet('scope', 'row');
476
+ removeStrongWrappers(inline);
477
+ if (tokens[tdIdx + 2].type === 'td_close') {
478
+ tokens[tdIdx + 2].type = 'th_close';
479
+ tokens[tdIdx + 2].tag = 'th';
480
+ }
481
+ }
482
+ }
483
+ }
484
+ j++;
485
+ }
486
+ }
487
+ return;
488
+ }
489
+
490
+ if (tr1 < 0 || tr2 < 0) return;
491
+
492
+ // Calculate group names and colspan for multi-row case
493
+ const groupData = {
494
+ spans: [],
495
+ names: [],
496
+ rawNames: []
497
+ };
498
+
499
+ let thIdx = tr1 + 1;
500
+ while (thIdx < tokens.length && tokens[thIdx].type !== 'tr_close') {
501
+ if (tokens[thIdx].type === 'th_open') {
502
+ const inline = tokens[thIdx + 1];
503
+ const content = inline.content;
504
+ const match = content.match(/^\*\*([^*:]+):\*\*/);
505
+
506
+ if (match) {
507
+ const group = match[1].trim();
508
+ const lastGroup = groupData.rawNames[groupData.rawNames.length - 1];
509
+
510
+ if (groupData.rawNames.length > 0 && lastGroup === group) {
511
+ groupData.spans[groupData.spans.length - 1]++;
512
+ } else {
513
+ groupData.rawNames.push(group);
514
+ groupData.spans.push(1);
515
+ }
516
+ } else {
517
+ groupData.rawNames.push(null);
518
+ groupData.spans.push(1);
519
+ }
520
+ }
521
+ thIdx++;
522
+ }
523
+
524
+ groupData.names = [...groupData.rawNames];
525
+
526
+ // Generate colgroup if needed
527
+ const hasSpan = groupData.spans.some(span => span > 1);
528
+ if (hasSpan) {
529
+ const insertTokens = [new Token('colgroup_open', 'colgroup', 1)];
530
+
531
+ for (let i = 0; i < groupData.spans.length; i++) {
532
+ const colOpen = new Token('col_open', 'col', 1);
533
+ if (groupData.spans[i] > 1) {
534
+ colOpen.attrPush(['span', groupData.spans[i]]);
535
+ }
536
+ insertTokens.push(colOpen, new Token('col_close', 'col', -1));
537
+ }
538
+
539
+ insertTokens.push(new Token('colgroup_close', 'colgroup', -1));
540
+ tokens.splice(tableOpenIdx + 1, 0, ...insertTokens);
541
+ }
542
+
543
+ // Add colspan/rowspan to thead
544
+ let th1 = tr1 + 1, th2 = tr2 + 1, groupIdx = 0;
545
+ while (th1 < tokens.length && tokens[th1].type !== 'tr_close') {
546
+ if (tokens[th1].type === 'th_open') {
547
+ if (groupData.names[groupIdx] === null) {
548
+ // Leftmost cell: rowspan=2
549
+ tokens[th1].attrSet('rowspan', '2');
550
+ tokens[th1].attrSet('scope', 'col');
551
+ removeStrongWrappers(tokens[th1 + 1]);
552
+
553
+ // Find corresponding th in second row
554
+ let t2 = th2;
555
+ while (t2 < tokens.length && tokens[t2].type !== 'tr_close') {
556
+ if (tokens[t2].type === 'th_open') {
557
+ tokens[t2].attrSet('scope', 'col');
558
+ th2 = t2 + 1;
559
+ break;
560
+ }
561
+ t2++;
562
+ }
563
+ groupIdx++;
564
+ } else {
565
+ // Group cell
566
+ if (groupData.spans[groupIdx] > 1) {
567
+ tokens[th1].attrSet('colspan', groupData.spans[groupIdx].toString());
568
+ }
569
+ tokens[th1].attrSet('scope', 'col');
570
+ tokens[th1 + 1].content = groupData.names[groupIdx];
571
+
572
+ // Process corresponding ths in second row
573
+ let count = 0, t2 = th2;
574
+ while (t2 < tokens.length && tokens[t2].type !== 'tr_close' && count < groupData.spans[groupIdx]) {
575
+ if (tokens[t2].type === 'th_open') {
576
+ tokens[t2].attrSet('scope', 'col');
577
+ // Remove group name part from content
578
+ const t2content = tokens[t2 + 1].content;
579
+ const t2match = t2content.match(/^\*\*[^*:]+:\*\*\s*(.*)$/);
580
+ if (t2match) {
581
+ tokens[t2 + 1].content = t2match[1];
582
+ }
583
+ count++;
584
+ }
585
+ t2++;
586
+ }
587
+ th2 = t2;
588
+ groupIdx++;
589
+ }
590
+ }
591
+ th1++;
592
+ }
593
+ };
594
+
77
595
  const tableEx = (state, opt) => {
78
- let idx = 0
79
- while (idx < state.tokens.length) {
80
- if (state.tokens[idx].type !== 'table_open') { idx++; continue; }
596
+ const tokens = state.tokens;
597
+ const tokenLength = tokens.length;
598
+
599
+ let idx = 0;
600
+ while (idx < tokenLength) {
601
+ if (tokens[idx].type !== 'table_open') {
602
+ idx++;
603
+ continue;
604
+ }
605
+
606
+ const tableOpenIdx = idx;
607
+
81
608
  if (opt.wrapper) {
82
- const wrapperStartToken = new state.Token('div_open', 'div', 1)
83
- wrapperStartToken.attrPush(['class', 'table-wrapper'])
84
- const linebreakToken = new state.Token('text', '', 0)
85
- linebreakToken.content = '\n'
86
- state.tokens.splice(idx, 0, wrapperStartToken, linebreakToken)
87
- idx = idx + 2
609
+ const wrapperStartToken = new state.Token('div_open', 'div', 1);
610
+ wrapperStartToken.attrPush(['class', 'table-wrapper']);
611
+ const linebreakToken = new state.Token('text', '', 0);
612
+ linebreakToken.content = '\n';
613
+ tokens.splice(idx, 0, wrapperStartToken, linebreakToken);
614
+ idx += 2;
88
615
  }
616
+
89
617
  let theadVar = {
90
- i : idx + 1,
618
+ i: idx + 1,
91
619
  firstThPos: -1,
92
620
  isEmpty: false,
93
- }
94
- //console.log(theadVar.i, state.tokens[theadVar.i].type)
95
- const hasThead = state.tokens[theadVar.i].type === 'thead_open'
621
+ };
622
+
623
+ const hasThead = tokens[theadVar.i] && tokens[theadVar.i].type === 'thead_open';
96
624
  if (hasThead) {
97
- theadVar = addTheadThScope(state, theadVar)
98
- idx = theadVar.i + 1
625
+ theadVar = addTheadThScope(state, theadVar);
626
+ idx = theadVar.i + 1;
627
+ if (opt.colgroup) {
628
+ setColgroup(state, tableOpenIdx, opt);
629
+ }
99
630
  }
100
- //console.log('theadVar: ' + JSON.stringify(theadVar) + ', hasThead: ' + hasThead)
631
+
101
632
  let tbodyVar = {
102
633
  i: idx + 1,
103
634
  isAllFirstTh: false,
104
635
  tbodyFirstThPoses: [],
105
- }
106
- //console.log(tbodyVar.i, state.tokens[tbodyVar.i].type)
107
- const hasTbody = state.tokens[tbodyVar.i].type === 'tbody_open'
636
+ };
637
+
638
+ const hasTbody = tokens[tbodyVar.i] && tokens[tbodyVar.i].type === 'tbody_open';
108
639
  if (hasTbody) {
109
- tbodyVar = checkTbody(state, tbodyVar)
110
- idx = tbodyVar.i + 1
640
+ tbodyVar = checkTbody(state, tbodyVar);
641
+ idx = tbodyVar.i + 1;
111
642
  }
112
- //console.log('tbodyVar: ' + JSON.stringify(tbodyVar) + ', hasTbody: ' + hasTbody)
643
+
113
644
  if (theadVar.firstThPos && tbodyVar.isAllFirstTh) {
114
- let firstTdPoses = [...tbodyVar.tbodyFirstThPoses]
645
+ const firstTdPoses = [...tbodyVar.tbodyFirstThPoses];
115
646
  if (hasThead) {
116
- firstTdPoses.splice(0, 0, theadVar.firstThPos)
647
+ firstTdPoses.unshift(theadVar.firstThPos);
648
+ }
649
+ if (opt.matrix) {
650
+ changeTdToTh(state, firstTdPoses, hasThead, theadVar);
117
651
  }
118
- if (opt.matrix) changeTdToTh(state, firstTdPoses, hasThead, theadVar)
119
652
  }
120
- while (idx < state.tokens.length) {
121
- if (state.tokens[idx].type === 'table_close') {
653
+
654
+ // Find table_close more efficiently
655
+ while (idx < tokens.length) {
656
+ if (tokens[idx].type === 'table_close') {
122
657
  if (opt.wrapper) {
123
- const wrapperEndToken = new state.Token('div_close', 'div', -1)
124
- const linebreakToken = new state.Token('text', '', 0)
125
- linebreakToken.content = '\n'
126
- state.tokens.splice(idx + 1, 0, wrapperEndToken, linebreakToken)
127
- idx = idx + 2
658
+ const wrapperEndToken = new state.Token('div_close', 'div', -1);
659
+ const linebreakToken = new state.Token('text', '', 0);
660
+ linebreakToken.content = '\n';
661
+ tokens.splice(idx + 1, 0, wrapperEndToken, linebreakToken);
662
+ idx += 2;
128
663
  }
129
- break
664
+ break;
130
665
  }
131
- idx++
666
+ idx++;
132
667
  }
133
- idx++
668
+ idx++;
134
669
  }
135
- }
670
+ };
136
671
 
137
672
  const mditTableEx = (md, option) => {
138
673
  let opt = {
139
674
  matrix: true,
140
675
  wrapper: false,
141
- }
676
+ colgroup: false,
677
+ colgroupWithNoAsterisk: false
678
+ };
142
679
  for (let key in option) {
143
680
  opt[key] = option[key]
144
681
  }
145
682
  md.core.ruler.after('replacements', 'table-ex', (state) => {
146
- tableEx(state, opt)
147
- })
683
+ tableEx(state, opt);
684
+ });
148
685
  }
149
686
  export default mditTableEx