@diplodoc/transform 4.19.1 → 4.21.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/dist/css/print.css.map +1 -1
- package/dist/css/yfm.css +3 -1
- package/dist/css/yfm.css.map +3 -3
- package/dist/css/yfm.min.css +1 -1
- package/dist/css/yfm.min.css.map +3 -3
- package/dist/js/yfm.js +69 -67
- package/dist/js/yfm.js.map +2 -2
- package/dist/js/yfm.min.js +1 -1
- package/dist/js/yfm.min.js.map +3 -3
- package/lib/plugins/anchors/index.js +1 -1
- package/lib/plugins/anchors/index.js.map +1 -1
- package/lib/plugins/table/index.js +15 -3
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/utils.d.ts +1 -8
- package/lib/plugins/table/utils.js +62 -20
- package/lib/plugins/table/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/js/term/utils.ts +12 -7
- package/src/scss/_term.scss +1 -1
- package/src/transform/plugins/anchors/index.ts +1 -1
- package/src/transform/plugins/table/index.ts +22 -4
- package/src/transform/plugins/table/utils.ts +81 -18
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import StateBlock from 'markdown-it/lib/rules_block/state_block';
|
|
2
2
|
import {MarkdownItPluginCb} from '../typings';
|
|
3
3
|
import Token from 'markdown-it/lib/token';
|
|
4
|
-
import {
|
|
4
|
+
import {parseAttrs} from './utils';
|
|
5
5
|
|
|
6
6
|
const pluginName = 'yfm_table';
|
|
7
7
|
const pipeChar = 0x7c; // |
|
|
@@ -96,6 +96,7 @@ class StateIterator {
|
|
|
96
96
|
interface RowPositions {
|
|
97
97
|
rows: [number, number, [Stats, Stats][]][];
|
|
98
98
|
endOfTable: number | null;
|
|
99
|
+
pos: number;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
function getTableRowPositions(
|
|
@@ -214,7 +215,17 @@ function getTableRowPositions(
|
|
|
214
215
|
|
|
215
216
|
iter.next();
|
|
216
217
|
}
|
|
217
|
-
|
|
218
|
+
|
|
219
|
+
const {pos} = iter;
|
|
220
|
+
|
|
221
|
+
return {rows, endOfTable, pos};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function extractAttributes(state: StateBlock, pos: number): Record<string, string[]> {
|
|
225
|
+
const attrsStringStart = state.skipSpaces(pos);
|
|
226
|
+
const attrsString = state.src.slice(attrsStringStart);
|
|
227
|
+
|
|
228
|
+
return parseAttrs(attrsString) ?? {};
|
|
218
229
|
}
|
|
219
230
|
|
|
220
231
|
/**
|
|
@@ -232,7 +243,7 @@ function extractAndApplyClassFromToken(contentToken: Token, tdOpenToken: Token):
|
|
|
232
243
|
if (!allAttrs) {
|
|
233
244
|
return;
|
|
234
245
|
}
|
|
235
|
-
const attrsClass =
|
|
246
|
+
const attrsClass = parseAttrs(allAttrs[0].trim())?.class.join(' ');
|
|
236
247
|
if (attrsClass) {
|
|
237
248
|
tdOpenToken.attrSet('class', attrsClass);
|
|
238
249
|
// remove the class from the token so that it's not propagated to tr or table level
|
|
@@ -363,13 +374,15 @@ const yfmTable: MarkdownItPluginCb = (md) => {
|
|
|
363
374
|
return true;
|
|
364
375
|
}
|
|
365
376
|
|
|
366
|
-
const {rows, endOfTable} = getTableRowPositions(
|
|
377
|
+
const {rows, endOfTable, pos} = getTableRowPositions(
|
|
367
378
|
state,
|
|
368
379
|
startPosition,
|
|
369
380
|
endPosition,
|
|
370
381
|
startLine,
|
|
371
382
|
);
|
|
372
383
|
|
|
384
|
+
const attrs = extractAttributes(state, pos);
|
|
385
|
+
|
|
373
386
|
if (!endOfTable) {
|
|
374
387
|
token = state.push('__yfm_lint', '', 0);
|
|
375
388
|
token.hidden = true;
|
|
@@ -385,6 +398,11 @@ const yfmTable: MarkdownItPluginCb = (md) => {
|
|
|
385
398
|
|
|
386
399
|
const tableStart = state.tokens.length;
|
|
387
400
|
token = state.push('yfm_table_open', 'table', 1);
|
|
401
|
+
|
|
402
|
+
for (const [property, values] of Object.entries(attrs)) {
|
|
403
|
+
token.attrJoin(property, values.join(' '));
|
|
404
|
+
}
|
|
405
|
+
|
|
388
406
|
token.map = [startLine, endOfTable];
|
|
389
407
|
|
|
390
408
|
token = state.push('yfm_tbody_open', 'tbody', 1);
|
|
@@ -1,13 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* Putting all the requirements in regex was more complicated than parsing a string char by char.
|
|
4
|
-
*
|
|
5
|
-
* @param {string} inputString - The string to parse.
|
|
6
|
-
* @returns {string|null} - The extracted class or null if there is none
|
|
7
|
-
*/
|
|
1
|
+
type DatasetKey = `data-${string}`;
|
|
2
|
+
type Attrs = 'class' | 'id' | DatasetKey;
|
|
8
3
|
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
type Selector = (value: string) => {
|
|
5
|
+
key: Attrs;
|
|
6
|
+
value: string;
|
|
7
|
+
} | null;
|
|
8
|
+
|
|
9
|
+
const wrapToData = (key: string): DatasetKey => {
|
|
10
|
+
if (key.startsWith('data-')) {
|
|
11
|
+
return key as DatasetKey;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return `data-${key}`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const selectors = {
|
|
18
|
+
class(value: string) {
|
|
19
|
+
if (value.startsWith('.')) {
|
|
20
|
+
return {
|
|
21
|
+
key: 'class',
|
|
22
|
+
value: value.slice(1),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
27
|
+
},
|
|
28
|
+
id(value: string) {
|
|
29
|
+
if (value.startsWith('#')) {
|
|
30
|
+
return {
|
|
31
|
+
key: 'id',
|
|
32
|
+
value: value.slice(1),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null;
|
|
37
|
+
},
|
|
38
|
+
attr(value: string) {
|
|
39
|
+
const parts = value.split('=');
|
|
40
|
+
|
|
41
|
+
if (parts.length === 2) {
|
|
42
|
+
return {
|
|
43
|
+
key: wrapToData(parts[0]) as DatasetKey,
|
|
44
|
+
value: parts[1],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
key: wrapToData(value) as DatasetKey,
|
|
50
|
+
value: 'true',
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handlers = Object.values(selectors) as Selector[];
|
|
56
|
+
|
|
57
|
+
export function parseAttrs(inputString: string) {
|
|
58
|
+
const validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ .=-_#';
|
|
11
59
|
|
|
12
60
|
if (!inputString.startsWith('{')) {
|
|
13
61
|
return null;
|
|
@@ -23,16 +71,31 @@ export function parseAttrsClass(inputString: string): string | null {
|
|
|
23
71
|
return null;
|
|
24
72
|
}
|
|
25
73
|
|
|
26
|
-
const parts = contentInside.split('
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
74
|
+
const parts = contentInside.split(' ');
|
|
75
|
+
|
|
76
|
+
const attrs: Record<string, string[]> = {
|
|
77
|
+
class: [],
|
|
78
|
+
id: [],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
parts.forEach((part) => {
|
|
82
|
+
const matched = handlers.find((test) => test(part));
|
|
83
|
+
|
|
84
|
+
if (!matched) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
89
|
+
const {key, value} = matched(part)!;
|
|
90
|
+
|
|
91
|
+
if (!attrs[key]) {
|
|
92
|
+
attrs[key] = [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
attrs[key].push(value);
|
|
96
|
+
});
|
|
34
97
|
|
|
35
|
-
return
|
|
98
|
+
return attrs;
|
|
36
99
|
}
|
|
37
100
|
|
|
38
101
|
if (!validChars.includes(char)) {
|