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