@peaceroad/markdown-it-table-ex 0.2.0 → 0.3.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/README.md +5 -1
- package/index.js +258 -188
- package/package.json +8 -3
- package/test/examples.txt +0 -411
- package/test/examples_colgroup.txt +0 -380
- package/test/examples_colgroup_with_no_asterisk.txt +0 -88
- package/test/examples_wrapper.txt +0 -119
- package/test/examples_wrapper_with_caption.txt +0 -141
- package/test/test.js +0 -136
package/index.js
CHANGED
|
@@ -1,4 +1,58 @@
|
|
|
1
|
-
const
|
|
1
|
+
const getLeadingStrongCloseIndex = (inline) => {
|
|
2
|
+
if (!inline || !Array.isArray(inline.children) || inline.children.length < 3) {
|
|
3
|
+
return -1;
|
|
4
|
+
}
|
|
5
|
+
const children = inline.children;
|
|
6
|
+
let start = 0;
|
|
7
|
+
while (start < children.length &&
|
|
8
|
+
children[start].type === 'text' &&
|
|
9
|
+
children[start].content === '') {
|
|
10
|
+
start++;
|
|
11
|
+
}
|
|
12
|
+
if (start >= children.length || children[start].type !== 'strong_open') {
|
|
13
|
+
return -1;
|
|
14
|
+
}
|
|
15
|
+
let depth = 0;
|
|
16
|
+
for (let i = start; i < children.length; i++) {
|
|
17
|
+
const type = children[i].type;
|
|
18
|
+
if (type === 'strong_open') {
|
|
19
|
+
depth++;
|
|
20
|
+
} else if (type === 'strong_close') {
|
|
21
|
+
depth--;
|
|
22
|
+
if (depth === 0) {
|
|
23
|
+
return i;
|
|
24
|
+
}
|
|
25
|
+
if (depth < 0) {
|
|
26
|
+
return -1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return -1;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const isStrongWrappedInline = (inline, allowFallback) => {
|
|
34
|
+
if (!inline || typeof inline.content !== 'string') return false;
|
|
35
|
+
const content = inline.content;
|
|
36
|
+
if (!content.startsWith('**') || !content.endsWith('**')) return false;
|
|
37
|
+
if (!Array.isArray(inline.children)) return !!allowFallback;
|
|
38
|
+
if (getLeadingStrongCloseIndex(inline) !== -1) return true;
|
|
39
|
+
return !!allowFallback;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const hasLeadingStrongMarker = (inline, allowFallback) => {
|
|
43
|
+
if (getLeadingStrongCloseIndex(inline) !== -1) return true;
|
|
44
|
+
if (!allowFallback || !inline || typeof inline.content !== 'string') return false;
|
|
45
|
+
return inline.content.startsWith('**');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const hasInlineRule = (md, name) => {
|
|
49
|
+
const rules = md && md.inline && md.inline.ruler && md.inline.ruler.__rules__;
|
|
50
|
+
if (!Array.isArray(rules)) return false;
|
|
51
|
+
for (let i = 0; i < rules.length; i++) {
|
|
52
|
+
if (rules[i].name === name) return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
};
|
|
2
56
|
|
|
3
57
|
const createTokenTemplate = (tokenType, tag, nesting, level) => ({
|
|
4
58
|
type: tokenType,
|
|
@@ -17,117 +71,123 @@ const createTokenTemplate = (tokenType, tag, nesting, level) => ({
|
|
|
17
71
|
});
|
|
18
72
|
|
|
19
73
|
// Helper function to remove strong tags that wrap the entire content
|
|
20
|
-
const removeStrongWrappers = (inline) => {
|
|
74
|
+
const removeStrongWrappers = (inline, allowFallback) => {
|
|
21
75
|
if (!Array.isArray(inline.children) || inline.children.length === 0) {
|
|
22
76
|
return;
|
|
23
77
|
}
|
|
24
78
|
|
|
25
79
|
const children = inline.children;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Quick check to avoid regex if obviously not matching
|
|
29
|
-
if (!content.startsWith('**') || !content.endsWith('**')) {
|
|
80
|
+
if (!isStrongWrappedInline(inline, allowFallback)) {
|
|
30
81
|
return;
|
|
31
82
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
83
|
+
|
|
84
|
+
if (children.length === 3 &&
|
|
85
|
+
children[0].type === 'strong_open' &&
|
|
86
|
+
children[2].type === 'strong_close' &&
|
|
87
|
+
children[1].type === 'text') {
|
|
88
|
+
inline.children = [children[1]];
|
|
89
|
+
inline.content = children[1].content;
|
|
35
90
|
return;
|
|
36
91
|
}
|
|
37
92
|
|
|
38
|
-
// Find
|
|
39
|
-
|
|
93
|
+
// Find strong open/close positions in one pass
|
|
94
|
+
let openCount = 0;
|
|
95
|
+
let closeCount = 0;
|
|
96
|
+
let firstOpen = -1;
|
|
97
|
+
let firstClose = -1;
|
|
98
|
+
let firstPair = null;
|
|
99
|
+
let lastPair = null;
|
|
100
|
+
const stack = [];
|
|
101
|
+
|
|
40
102
|
for (let i = 0; i < children.length; i++) {
|
|
41
103
|
const type = children[i].type;
|
|
42
104
|
if (type === 'strong_open') {
|
|
43
|
-
|
|
105
|
+
if (firstOpen === -1) {
|
|
106
|
+
firstOpen = i;
|
|
107
|
+
}
|
|
108
|
+
openCount++;
|
|
109
|
+
stack.push(i);
|
|
44
110
|
} else if (type === 'strong_close') {
|
|
45
|
-
|
|
111
|
+
if (firstClose === -1) {
|
|
112
|
+
firstClose = i;
|
|
113
|
+
}
|
|
114
|
+
closeCount++;
|
|
115
|
+
if (stack.length > 0) {
|
|
116
|
+
const openIdx = stack.pop();
|
|
117
|
+
if (!firstPair) {
|
|
118
|
+
firstPair = { open: openIdx, close: i };
|
|
119
|
+
}
|
|
120
|
+
lastPair = { open: openIdx, close: i };
|
|
121
|
+
}
|
|
46
122
|
}
|
|
47
123
|
}
|
|
48
124
|
|
|
49
|
-
const openCount = strongPositions.filter(p => p.type === 'open').length;
|
|
50
|
-
const closeCount = strongPositions.filter(p => p.type === 'close').length;
|
|
51
|
-
|
|
52
125
|
if (openCount !== closeCount || openCount === 0) {
|
|
53
126
|
return;
|
|
54
127
|
}
|
|
55
128
|
|
|
56
|
-
if (openCount >= 2) {
|
|
129
|
+
if (openCount >= 2 && firstPair && lastPair) {
|
|
57
130
|
// Multiple strong pairs case - find pairs by stack matching
|
|
58
|
-
const
|
|
59
|
-
const
|
|
131
|
+
const newChildren = [];
|
|
132
|
+
const contentParts = [];
|
|
60
133
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
134
|
+
// Helper function to add children and build content
|
|
135
|
+
const addChildrenRange = (start, end) => {
|
|
136
|
+
for (let i = start; i < end; i++) {
|
|
137
|
+
const child = children[i];
|
|
138
|
+
newChildren.push(child);
|
|
139
|
+
if (child.type === 'text') {
|
|
140
|
+
contentParts.push(child.content);
|
|
141
|
+
} else if (child.type === 'em_open' || child.type === 'em_close') {
|
|
142
|
+
contentParts.push('*');
|
|
143
|
+
}
|
|
67
144
|
}
|
|
68
|
-
}
|
|
145
|
+
};
|
|
69
146
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
}
|
|
147
|
+
// Add content before first pair
|
|
148
|
+
addChildrenRange(0, firstPair.open);
|
|
149
|
+
|
|
150
|
+
// Add content from first pair (without the strong tags)
|
|
151
|
+
addChildrenRange(firstPair.open + 1, firstPair.close);
|
|
152
|
+
|
|
153
|
+
// Add content between first and last pairs with strong wrapping
|
|
154
|
+
for (let i = firstPair.close + 1; i < lastPair.open; i++) {
|
|
155
|
+
const child = children[i];
|
|
156
|
+
if (child.type === 'text' && child.content.trim() !== '') {
|
|
157
|
+
// Create strong tokens more efficiently
|
|
158
|
+
const strongOpen = Object.create(child.constructor.prototype);
|
|
159
|
+
Object.assign(strongOpen, createTokenTemplate('strong_open', 'strong', 1, child.level));
|
|
160
|
+
|
|
161
|
+
const strongClose = Object.create(child.constructor.prototype);
|
|
162
|
+
Object.assign(strongClose, createTokenTemplate('strong_close', 'strong', -1, child.level));
|
|
163
|
+
|
|
164
|
+
newChildren.push(strongOpen, child, strongClose);
|
|
165
|
+
contentParts.push('**', child.content, '**');
|
|
166
|
+
} else {
|
|
167
|
+
newChildren.push(child);
|
|
168
|
+
if (child.type === 'text') {
|
|
169
|
+
contentParts.push(child.content);
|
|
170
|
+
} else if (child.type === 'em_open' || child.type === 'em_close') {
|
|
171
|
+
contentParts.push('*');
|
|
114
172
|
}
|
|
115
173
|
}
|
|
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
174
|
}
|
|
126
175
|
|
|
176
|
+
// Add content from last pair (without the strong tags)
|
|
177
|
+
addChildrenRange(lastPair.open + 1, lastPair.close);
|
|
178
|
+
|
|
179
|
+
// Add content after last pair
|
|
180
|
+
addChildrenRange(lastPair.close + 1, children.length);
|
|
181
|
+
|
|
182
|
+
inline.content = contentParts.join('');
|
|
183
|
+
inline.children = newChildren;
|
|
127
184
|
} else if (openCount === 1) {
|
|
128
185
|
// Single strong pair: remove completely
|
|
129
|
-
const strongOpen =
|
|
130
|
-
const strongClose =
|
|
186
|
+
const strongOpen = firstOpen;
|
|
187
|
+
const strongClose = firstClose;
|
|
188
|
+
if (strongOpen < 0 || strongClose < 0) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
131
191
|
|
|
132
192
|
const newChildren = [];
|
|
133
193
|
const contentParts = [];
|
|
@@ -149,74 +209,74 @@ const removeStrongWrappers = (inline) => {
|
|
|
149
209
|
}
|
|
150
210
|
}
|
|
151
211
|
|
|
152
|
-
const addTheadThScope = (state, theadVar) => {
|
|
153
|
-
|
|
212
|
+
const addTheadThScope = (state, theadVar, allowFallback) => {
|
|
213
|
+
const tokens = state.tokens;
|
|
154
214
|
let firstThPos = theadVar.pos;
|
|
155
215
|
let j = theadVar.i + 2;
|
|
156
216
|
//if (state.tokens[theadVar.i + 1].type !== 'tr_open') return threadVar
|
|
157
|
-
while (j <
|
|
158
|
-
if (
|
|
159
|
-
|
|
217
|
+
while (j < tokens.length) {
|
|
218
|
+
if (tokens[j].type === 'th_open') {
|
|
219
|
+
tokens[j].attrPush(['scope', 'col']);
|
|
160
220
|
if (j === theadVar.i + 2) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (
|
|
221
|
+
const inline = tokens[j + 1];
|
|
222
|
+
const content = inline.content;
|
|
223
|
+
if (content === '' || isStrongWrappedInline(inline, allowFallback)) {
|
|
164
224
|
firstThPos = j
|
|
165
225
|
// Only remove strong tags from the first th content for matrix processing
|
|
166
226
|
// The actual removal will be done in changeTdToTh if matrix conditions are met
|
|
167
|
-
} else if (isEmpty) {
|
|
168
|
-
firstThPos = j
|
|
169
227
|
}
|
|
170
228
|
}
|
|
171
229
|
}
|
|
172
|
-
if (
|
|
230
|
+
if (tokens[j].type === 'tr_close') break
|
|
173
231
|
j++
|
|
174
232
|
}
|
|
175
|
-
return {i: j, firstThPos: firstThPos
|
|
233
|
+
return {i: j, firstThPos: firstThPos}
|
|
176
234
|
}
|
|
177
235
|
|
|
178
|
-
const changeTdToTh = (state, tdPoses, hasThead) => {
|
|
236
|
+
const changeTdToTh = (state, tdPoses, hasThead, allowFallback) => {
|
|
179
237
|
//console.log('hasThead: ' + hasThead + ', tdPoses: ' + tdPoses)
|
|
238
|
+
const tokens = state.tokens;
|
|
180
239
|
let j = 0
|
|
181
240
|
while(j < tdPoses.length) {
|
|
182
241
|
//console.log('state.tokens[' + j + '].type: ' + state.tokens[tdPoses[j]].type)
|
|
183
242
|
const pos = tdPoses[j]
|
|
184
243
|
if (j > 0 || (!hasThead && j === 0)) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
244
|
+
tokens[pos].type = 'th_open';
|
|
245
|
+
tokens[pos].tag = 'th';
|
|
246
|
+
tokens[pos].attrPush(['scope', 'row']);
|
|
247
|
+
tokens[pos + 2].type = 'th_close';
|
|
248
|
+
tokens[pos + 2].tag = 'th';
|
|
190
249
|
}
|
|
191
250
|
|
|
192
251
|
// Remove strong tags that wrap the entire content
|
|
193
|
-
const inline =
|
|
194
|
-
removeStrongWrappers(inline);
|
|
252
|
+
const inline = tokens[pos + 1];
|
|
253
|
+
removeStrongWrappers(inline, allowFallback);
|
|
195
254
|
j++
|
|
196
255
|
}
|
|
197
256
|
}
|
|
198
257
|
|
|
199
|
-
const checkTbody = (state, tbodyVar) => {
|
|
258
|
+
const checkTbody = (state, tbodyVar, allowFallback) => {
|
|
259
|
+
const tokens = state.tokens;
|
|
200
260
|
let isAllFirstTh = true
|
|
201
261
|
let tbodyFirstThPoses = []
|
|
202
262
|
let j = tbodyVar.i + 1
|
|
203
|
-
while (j <
|
|
204
|
-
if (
|
|
263
|
+
while (j < tokens.length) {
|
|
264
|
+
if (tokens[j].type === 'tr_open') {
|
|
205
265
|
j++
|
|
206
|
-
if (
|
|
266
|
+
if (tokens[j].type === 'td_open' && isStrongWrappedInline(tokens[j + 1], allowFallback)) {
|
|
207
267
|
tbodyFirstThPoses.push(j)
|
|
208
268
|
} else {
|
|
209
269
|
isAllFirstTh = false
|
|
210
270
|
break
|
|
211
271
|
}
|
|
212
272
|
}
|
|
213
|
-
if (
|
|
273
|
+
if (tokens[j].type === 'tbody_close') break
|
|
214
274
|
j++
|
|
215
275
|
}
|
|
216
276
|
return { i: j, isAllFirstTh: isAllFirstTh, tbodyFirstThPoses: tbodyFirstThPoses}
|
|
217
277
|
}
|
|
218
278
|
|
|
219
|
-
const setColgroup = (state, tableOpenIdx, opt) => {
|
|
279
|
+
const setColgroup = (state, tableOpenIdx, opt, allowFallback) => {
|
|
220
280
|
const tokens = state.tokens;
|
|
221
281
|
const Token = state.Token;
|
|
222
282
|
|
|
@@ -244,23 +304,36 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
244
304
|
// Calculate group names and colspan for the first row of th
|
|
245
305
|
const groupData = {
|
|
246
306
|
spans: [],
|
|
247
|
-
names: [],
|
|
248
307
|
rawNames: [],
|
|
249
308
|
headerCount: 0
|
|
250
309
|
};
|
|
251
310
|
|
|
311
|
+
const colgroupMatchReg = opt.colgroupWithNoAsterisk
|
|
312
|
+
? /^([^::]+)(?::|:)\s*/
|
|
313
|
+
: /^\*\*([^*::]+)[::]\*\*\s*/;
|
|
314
|
+
const origColgroupMatchReg = opt.colgroupWithNoAsterisk
|
|
315
|
+
? /^[^::]+(?::|:)\s*(.*)$/
|
|
316
|
+
: /^\*\*[^*::]+[::]\*\*\s*(.*)$/;
|
|
317
|
+
|
|
252
318
|
let thIdx = tr1 + 1;
|
|
253
|
-
const
|
|
319
|
+
const origThs = [];
|
|
320
|
+
let trCloseIdx = -1;
|
|
254
321
|
|
|
255
|
-
while (thIdx < tokens.length
|
|
256
|
-
|
|
257
|
-
|
|
322
|
+
while (thIdx < tokens.length) {
|
|
323
|
+
const tokenType = tokens[thIdx].type;
|
|
324
|
+
if (tokenType === 'th_open') {
|
|
258
325
|
const inline = tokens[thIdx + 1];
|
|
326
|
+
origThs.push(inline);
|
|
259
327
|
const content = inline.content;
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
328
|
+
const hasLeadingStrong = hasLeadingStrongMarker(inline, allowFallback);
|
|
329
|
+
let match = null;
|
|
330
|
+
if (opt.colgroupWithNoAsterisk) {
|
|
331
|
+
if (content.indexOf(':') !== -1 || content.indexOf(':') !== -1) {
|
|
332
|
+
match = content.match(colgroupMatchReg);
|
|
333
|
+
}
|
|
334
|
+
} else if (hasLeadingStrong) {
|
|
335
|
+
match = content.match(colgroupMatchReg);
|
|
336
|
+
}
|
|
264
337
|
|
|
265
338
|
if (match) {
|
|
266
339
|
const group = match[1].trim();
|
|
@@ -277,6 +350,9 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
277
350
|
groupData.rawNames.push(null);
|
|
278
351
|
groupData.spans.push(1);
|
|
279
352
|
}
|
|
353
|
+
} else if (tokenType === 'tr_close') {
|
|
354
|
+
trCloseIdx = thIdx;
|
|
355
|
+
break;
|
|
280
356
|
}
|
|
281
357
|
thIdx++;
|
|
282
358
|
}
|
|
@@ -284,15 +360,7 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
284
360
|
// If there are not two or more grouped header cells, do not auto-generate
|
|
285
361
|
if (groupData.headerCount < 2) return;
|
|
286
362
|
|
|
287
|
-
|
|
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
|
-
}
|
|
363
|
+
const groupNames = groupData.rawNames;
|
|
296
364
|
|
|
297
365
|
// Generate colgroup if needed
|
|
298
366
|
const hasSpan = groupData.spans.some(span => span > 1);
|
|
@@ -322,13 +390,12 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
322
390
|
|
|
323
391
|
// Update indices
|
|
324
392
|
const offset = insertTokens.length;
|
|
325
|
-
theadOpen += offset;
|
|
326
393
|
tr1 += offset;
|
|
327
394
|
theadClose += offset;
|
|
395
|
+
trCloseIdx += offset;
|
|
328
396
|
}
|
|
329
397
|
|
|
330
398
|
// Generate two-row header
|
|
331
|
-
const trCloseIdx = tokens.findIndex((t, idx) => idx > tr1 && t.type === 'tr_close');
|
|
332
399
|
|
|
333
400
|
// Create new rows more efficiently
|
|
334
401
|
const newTr1 = [
|
|
@@ -342,37 +409,21 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
342
409
|
Object.assign(new Token('text', '', 0), { content: '\n' })
|
|
343
410
|
];
|
|
344
411
|
|
|
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
412
|
let thPtr = 0;
|
|
357
413
|
for (let i = 0; i < groupData.spans.length; i++) {
|
|
358
|
-
if (
|
|
414
|
+
if (groupNames[i] === null) {
|
|
359
415
|
// Leftmost cell: rowspan=2
|
|
360
416
|
const thOpen = new Token('th_open', 'th', 1);
|
|
361
417
|
thOpen.attrSet('rowspan', '2');
|
|
362
418
|
thOpen.attrSet('scope', 'col');
|
|
363
419
|
|
|
364
420
|
const thInline = new Token('inline', '', 0);
|
|
365
|
-
const origInline = origThs[thPtr]
|
|
421
|
+
const origInline = origThs[thPtr];
|
|
366
422
|
|
|
367
423
|
if (origInline) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
children: origInline.children ? [...origInline.children] : []
|
|
372
|
-
};
|
|
373
|
-
removeStrongWrappers(tempInline);
|
|
374
|
-
thInline.content = tempInline.content;
|
|
375
|
-
thInline.children = tempInline.children;
|
|
424
|
+
removeStrongWrappers(origInline, allowFallback);
|
|
425
|
+
thInline.content = origInline.content;
|
|
426
|
+
thInline.children = Array.isArray(origInline.children) ? origInline.children : [];
|
|
376
427
|
} else {
|
|
377
428
|
thInline.content = '';
|
|
378
429
|
thInline.children = [];
|
|
@@ -394,8 +445,8 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
394
445
|
thOpen.attrSet('scope', 'col');
|
|
395
446
|
|
|
396
447
|
const thInline = new Token('inline', '', 0);
|
|
397
|
-
thInline.content =
|
|
398
|
-
thInline.children = [{ type: 'text', content:
|
|
448
|
+
thInline.content = groupNames[i];
|
|
449
|
+
thInline.children = [{ type: 'text', content: groupNames[i], level: 0 }];
|
|
399
450
|
|
|
400
451
|
newTr1.push(
|
|
401
452
|
thOpen,
|
|
@@ -410,11 +461,16 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
410
461
|
th2Open.attrSet('scope', 'col');
|
|
411
462
|
|
|
412
463
|
const th2Inline = new Token('inline', '', 0);
|
|
413
|
-
const
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
464
|
+
const origInline = origThs[thPtr];
|
|
465
|
+
const orig = origInline?.content || '';
|
|
466
|
+
let match = null;
|
|
467
|
+
if (opt.colgroupWithNoAsterisk) {
|
|
468
|
+
if (orig.indexOf(':') !== -1 || orig.indexOf(':') !== -1) {
|
|
469
|
+
match = orig.match(origColgroupMatchReg);
|
|
470
|
+
}
|
|
471
|
+
} else if (hasLeadingStrongMarker(origInline, allowFallback)) {
|
|
472
|
+
match = orig.match(origColgroupMatchReg);
|
|
473
|
+
}
|
|
418
474
|
th2Inline.content = match ? match[1] : orig;
|
|
419
475
|
th2Inline.children = [{ type: 'text', content: th2Inline.content, level: 0 }];
|
|
420
476
|
|
|
@@ -469,11 +525,12 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
469
525
|
const tdIdx = j + 1;
|
|
470
526
|
if (tokens[tdIdx].type === 'td_open') {
|
|
471
527
|
const inline = tokens[tdIdx + 1];
|
|
472
|
-
if (inline && typeof inline.content === 'string' &&
|
|
528
|
+
if (inline && typeof inline.content === 'string' &&
|
|
529
|
+
isStrongWrappedInline(inline, allowFallback)) {
|
|
473
530
|
tokens[tdIdx].type = 'th_open';
|
|
474
531
|
tokens[tdIdx].tag = 'th';
|
|
475
532
|
tokens[tdIdx].attrSet('scope', 'row');
|
|
476
|
-
removeStrongWrappers(inline);
|
|
533
|
+
removeStrongWrappers(inline, allowFallback);
|
|
477
534
|
if (tokens[tdIdx + 2].type === 'td_close') {
|
|
478
535
|
tokens[tdIdx + 2].type = 'th_close';
|
|
479
536
|
tokens[tdIdx + 2].tag = 'th';
|
|
@@ -492,16 +549,20 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
492
549
|
// Calculate group names and colspan for multi-row case
|
|
493
550
|
const groupData = {
|
|
494
551
|
spans: [],
|
|
495
|
-
names: [],
|
|
496
552
|
rawNames: []
|
|
497
553
|
};
|
|
554
|
+
const groupMatchReg = /^\*\*([^*:]+):\*\*/;
|
|
498
555
|
|
|
499
556
|
let thIdx = tr1 + 1;
|
|
500
557
|
while (thIdx < tokens.length && tokens[thIdx].type !== 'tr_close') {
|
|
501
558
|
if (tokens[thIdx].type === 'th_open') {
|
|
502
559
|
const inline = tokens[thIdx + 1];
|
|
503
560
|
const content = inline.content;
|
|
504
|
-
const
|
|
561
|
+
const hasLeadingStrong = hasLeadingStrongMarker(inline, allowFallback);
|
|
562
|
+
let match = null;
|
|
563
|
+
if (hasLeadingStrong) {
|
|
564
|
+
match = content.match(groupMatchReg);
|
|
565
|
+
}
|
|
505
566
|
|
|
506
567
|
if (match) {
|
|
507
568
|
const group = match[1].trim();
|
|
@@ -521,7 +582,8 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
521
582
|
thIdx++;
|
|
522
583
|
}
|
|
523
584
|
|
|
524
|
-
|
|
585
|
+
const groupNames = groupData.rawNames;
|
|
586
|
+
const groupStripReg = /^\*\*[^*:]+:\*\*\s*(.*)$/;
|
|
525
587
|
|
|
526
588
|
// Generate colgroup if needed
|
|
527
589
|
const hasSpan = groupData.spans.some(span => span > 1);
|
|
@@ -544,11 +606,11 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
544
606
|
let th1 = tr1 + 1, th2 = tr2 + 1, groupIdx = 0;
|
|
545
607
|
while (th1 < tokens.length && tokens[th1].type !== 'tr_close') {
|
|
546
608
|
if (tokens[th1].type === 'th_open') {
|
|
547
|
-
if (
|
|
609
|
+
if (groupNames[groupIdx] === null) {
|
|
548
610
|
// Leftmost cell: rowspan=2
|
|
549
611
|
tokens[th1].attrSet('rowspan', '2');
|
|
550
612
|
tokens[th1].attrSet('scope', 'col');
|
|
551
|
-
removeStrongWrappers(tokens[th1 + 1]);
|
|
613
|
+
removeStrongWrappers(tokens[th1 + 1], allowFallback);
|
|
552
614
|
|
|
553
615
|
// Find corresponding th in second row
|
|
554
616
|
let t2 = th2;
|
|
@@ -567,7 +629,7 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
567
629
|
tokens[th1].attrSet('colspan', groupData.spans[groupIdx].toString());
|
|
568
630
|
}
|
|
569
631
|
tokens[th1].attrSet('scope', 'col');
|
|
570
|
-
tokens[th1 + 1].content =
|
|
632
|
+
tokens[th1 + 1].content = groupNames[groupIdx];
|
|
571
633
|
|
|
572
634
|
// Process corresponding ths in second row
|
|
573
635
|
let count = 0, t2 = th2;
|
|
@@ -575,8 +637,12 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
575
637
|
if (tokens[t2].type === 'th_open') {
|
|
576
638
|
tokens[t2].attrSet('scope', 'col');
|
|
577
639
|
// Remove group name part from content
|
|
578
|
-
const
|
|
579
|
-
const
|
|
640
|
+
const t2Inline = tokens[t2 + 1];
|
|
641
|
+
const t2content = t2Inline.content;
|
|
642
|
+
let t2match = null;
|
|
643
|
+
if (hasLeadingStrongMarker(t2Inline, allowFallback)) {
|
|
644
|
+
t2match = t2content.match(groupStripReg);
|
|
645
|
+
}
|
|
580
646
|
if (t2match) {
|
|
581
647
|
tokens[t2 + 1].content = t2match[1];
|
|
582
648
|
}
|
|
@@ -594,7 +660,8 @@ const setColgroup = (state, tableOpenIdx, opt) => {
|
|
|
594
660
|
|
|
595
661
|
const tableEx = (state, opt) => {
|
|
596
662
|
const tokens = state.tokens;
|
|
597
|
-
|
|
663
|
+
let tokenLength = tokens.length;
|
|
664
|
+
const allowStrongFallback = !hasInlineRule(state.md, 'strong_ja');
|
|
598
665
|
|
|
599
666
|
let idx = 0;
|
|
600
667
|
while (idx < tokenLength) {
|
|
@@ -611,54 +678,57 @@ const tableEx = (state, opt) => {
|
|
|
611
678
|
const linebreakToken = new state.Token('text', '', 0);
|
|
612
679
|
linebreakToken.content = '\n';
|
|
613
680
|
tokens.splice(idx, 0, wrapperStartToken, linebreakToken);
|
|
681
|
+
tokenLength += 2;
|
|
614
682
|
idx += 2;
|
|
615
683
|
}
|
|
616
684
|
|
|
617
685
|
let theadVar = {
|
|
618
686
|
i: idx + 1,
|
|
619
687
|
firstThPos: -1,
|
|
620
|
-
isEmpty: false,
|
|
621
688
|
};
|
|
622
689
|
|
|
623
690
|
const hasThead = tokens[theadVar.i] && tokens[theadVar.i].type === 'thead_open';
|
|
624
691
|
if (hasThead) {
|
|
625
|
-
theadVar = addTheadThScope(state, theadVar);
|
|
692
|
+
theadVar = addTheadThScope(state, theadVar, allowStrongFallback);
|
|
626
693
|
idx = theadVar.i + 1;
|
|
627
694
|
if (opt.colgroup) {
|
|
628
|
-
|
|
695
|
+
const beforeLength = tokens.length;
|
|
696
|
+
setColgroup(state, tableOpenIdx, opt, allowStrongFallback);
|
|
697
|
+
tokenLength += tokens.length - beforeLength;
|
|
629
698
|
}
|
|
630
699
|
}
|
|
631
700
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
if (theadVar.firstThPos && tbodyVar.isAllFirstTh) {
|
|
645
|
-
const firstTdPoses = [...tbodyVar.tbodyFirstThPoses];
|
|
646
|
-
if (hasThead) {
|
|
647
|
-
firstTdPoses.unshift(theadVar.firstThPos);
|
|
701
|
+
if (opt.matrix) {
|
|
702
|
+
let tbodyVar = {
|
|
703
|
+
i: idx + 1,
|
|
704
|
+
isAllFirstTh: false,
|
|
705
|
+
tbodyFirstThPoses: [],
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
const hasTbody = tokens[tbodyVar.i] && tokens[tbodyVar.i].type === 'tbody_open';
|
|
709
|
+
if (hasTbody) {
|
|
710
|
+
tbodyVar = checkTbody(state, tbodyVar, allowStrongFallback);
|
|
711
|
+
idx = tbodyVar.i + 1;
|
|
648
712
|
}
|
|
649
|
-
|
|
650
|
-
|
|
713
|
+
|
|
714
|
+
if (theadVar.firstThPos && tbodyVar.isAllFirstTh) {
|
|
715
|
+
const firstTdPoses = [...tbodyVar.tbodyFirstThPoses];
|
|
716
|
+
if (hasThead) {
|
|
717
|
+
firstTdPoses.unshift(theadVar.firstThPos);
|
|
718
|
+
}
|
|
719
|
+
changeTdToTh(state, firstTdPoses, hasThead, allowStrongFallback);
|
|
651
720
|
}
|
|
652
721
|
}
|
|
653
722
|
|
|
654
723
|
// Find table_close more efficiently
|
|
655
|
-
while (idx <
|
|
724
|
+
while (idx < tokenLength) {
|
|
656
725
|
if (tokens[idx].type === 'table_close') {
|
|
657
726
|
if (opt.wrapper) {
|
|
658
727
|
const wrapperEndToken = new state.Token('div_close', 'div', -1);
|
|
659
728
|
const linebreakToken = new state.Token('text', '', 0);
|
|
660
729
|
linebreakToken.content = '\n';
|
|
661
730
|
tokens.splice(idx + 1, 0, wrapperEndToken, linebreakToken);
|
|
731
|
+
tokenLength += 2;
|
|
662
732
|
idx += 2;
|
|
663
733
|
}
|
|
664
734
|
break;
|