@adobe/helix-markdown-support 6.2.1 → 6.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/.circleci/config.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/package.json +6 -6
- package/src/mdast-sanitize-text-and-formats.js +109 -35
package/.circleci/config.yml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [6.3.1](https://github.com/adobe/helix-markdown-support/compare/v6.3.0...v6.3.1) (2023-08-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* properly handle whitespace after sort ([#211](https://github.com/adobe/helix-markdown-support/issues/211)) ([03bf02a](https://github.com/adobe/helix-markdown-support/commit/03bf02a249f594e03c5d523d876e0b6522ad6ed5))
|
|
7
|
+
|
|
8
|
+
# [6.3.0](https://github.com/adobe/helix-markdown-support/compare/v6.2.1...v6.3.0) (2023-07-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* sort formats ([#206](https://github.com/adobe/helix-markdown-support/issues/206)) ([b734a35](https://github.com/adobe/helix-markdown-support/commit/b734a359e764ac4630b7b2418c0e71e342ad52b6))
|
|
14
|
+
|
|
1
15
|
## [6.2.1](https://github.com/adobe/helix-markdown-support/compare/v6.2.0...v6.2.1) (2023-07-18)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-markdown-support",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.1",
|
|
4
4
|
"description": "Helix Markdown Support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -58,20 +58,20 @@
|
|
|
58
58
|
"node": ">=14"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@adobe/eslint-config-helix": "2.0.
|
|
61
|
+
"@adobe/eslint-config-helix": "2.0.3",
|
|
62
62
|
"@adobe/remark-gridtables": "1.0.4",
|
|
63
63
|
"@semantic-release/changelog": "6.0.3",
|
|
64
64
|
"@semantic-release/git": "10.0.1",
|
|
65
|
-
"c8": "8.0.
|
|
66
|
-
"eslint": "8.
|
|
65
|
+
"c8": "8.0.1",
|
|
66
|
+
"eslint": "8.47.0",
|
|
67
67
|
"husky": "8.0.3",
|
|
68
68
|
"junit-report-builder": "3.0.1",
|
|
69
|
-
"lint-staged": "13.
|
|
69
|
+
"lint-staged": "13.3.0",
|
|
70
70
|
"mdast-builder": "1.1.1",
|
|
71
71
|
"mocha": "10.2.0",
|
|
72
72
|
"mocha-multi-reporters": "1.5.1",
|
|
73
73
|
"rehype-format": "4.0.1",
|
|
74
|
-
"rehype-stringify": "9.0.
|
|
74
|
+
"rehype-stringify": "9.0.4",
|
|
75
75
|
"remark-gfm": "3.0.1",
|
|
76
76
|
"remark-parse": "10.0.2",
|
|
77
77
|
"remark-rehype": "10.1.0",
|
|
@@ -25,22 +25,56 @@ function isSnug(type) {
|
|
|
25
25
|
return type === 'superscript' || type === 'subscript';
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
const FLOW_SORT_ORDER = [
|
|
29
|
+
'delete',
|
|
30
|
+
'strong',
|
|
31
|
+
'emphasis',
|
|
32
|
+
'link',
|
|
33
|
+
'underline',
|
|
34
|
+
'subscript',
|
|
35
|
+
'superscript',
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
export function sort(tree) {
|
|
39
|
+
if (!tree.children) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < tree.children.length; i += 1) {
|
|
43
|
+
let node = tree.children[i];
|
|
44
|
+
let key = FLOW_SORT_ORDER.indexOf(node.type);
|
|
45
|
+
if (key >= 0) {
|
|
46
|
+
// find the longest chain of formats
|
|
47
|
+
const chain = [];
|
|
48
|
+
while (key >= 0) {
|
|
49
|
+
chain.push({ node, key });
|
|
50
|
+
node = node.children?.length === 1 ? node.children[0] : null;
|
|
51
|
+
key = node ? FLOW_SORT_ORDER.indexOf(node?.type) : -1;
|
|
52
|
+
}
|
|
53
|
+
if (chain.length > 1) {
|
|
54
|
+
// remember children of last node in chain
|
|
55
|
+
const lastChildren = chain[chain.length - 1].node.children;
|
|
56
|
+
|
|
57
|
+
// sort chain
|
|
58
|
+
chain.sort((n0, n1) => (n0.key - n1.key));
|
|
59
|
+
|
|
60
|
+
// relink chain
|
|
61
|
+
for (let j = 0; j < chain.length - 1; j += 1) {
|
|
62
|
+
chain[j].node.children = [chain[j + 1].node];
|
|
63
|
+
}
|
|
64
|
+
chain[chain.length - 1].node.children = lastChildren;
|
|
65
|
+
|
|
66
|
+
// eslint-disable-next-line no-param-reassign
|
|
67
|
+
tree.children[i] = chain[0].node;
|
|
68
|
+
}
|
|
69
|
+
// continue on last node
|
|
70
|
+
sort(chain[chain.length - 1].node);
|
|
71
|
+
} else {
|
|
72
|
+
sort(node);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function collapse(tree) {
|
|
44
78
|
visit(tree, (node, index, parent) => {
|
|
45
79
|
const { children: siblings = [] } = parent || {};
|
|
46
80
|
const { children = [] } = node;
|
|
@@ -56,7 +90,17 @@ export default function sanitizeTextAndFormats(tree) {
|
|
|
56
90
|
siblings.splice(index, 1);
|
|
57
91
|
return index - 1;
|
|
58
92
|
}
|
|
93
|
+
}
|
|
94
|
+
return CONTINUE;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
59
97
|
|
|
98
|
+
function whitespace(tree) {
|
|
99
|
+
visit(tree, (node, index, parent) => {
|
|
100
|
+
const { children: siblings = [] } = parent || {};
|
|
101
|
+
const { children = [] } = node;
|
|
102
|
+
|
|
103
|
+
if (isFormat(node.type)) {
|
|
60
104
|
// check if last text block has trailing whitespace
|
|
61
105
|
const last = children[children.length - 1];
|
|
62
106
|
if (last?.type === 'text') {
|
|
@@ -127,7 +171,9 @@ export default function sanitizeTextAndFormats(tree) {
|
|
|
127
171
|
}
|
|
128
172
|
return CONTINUE;
|
|
129
173
|
});
|
|
174
|
+
}
|
|
130
175
|
|
|
176
|
+
function cleanup(tree) {
|
|
131
177
|
visit(tree, (node, index, parent) => {
|
|
132
178
|
const { children: siblings = [] } = parent || {};
|
|
133
179
|
|
|
@@ -177,28 +223,56 @@ export default function sanitizeTextAndFormats(tree) {
|
|
|
177
223
|
|
|
178
224
|
return CONTINUE;
|
|
179
225
|
});
|
|
226
|
+
}
|
|
180
227
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
children.splice(i, 1);
|
|
193
|
-
i -= 1;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (type === 'paragraph' || isFormat(type)) {
|
|
197
|
-
return children.length === 0;
|
|
198
|
-
}
|
|
228
|
+
/**
|
|
229
|
+
* remove empty text, formats, paragraphs
|
|
230
|
+
* @param node
|
|
231
|
+
* @return {boolean}
|
|
232
|
+
*/
|
|
233
|
+
function prune(node) {
|
|
234
|
+
const { children, type } = node;
|
|
235
|
+
if (type === 'text') {
|
|
236
|
+
return !node.value;
|
|
237
|
+
}
|
|
238
|
+
if (!children) {
|
|
199
239
|
return false;
|
|
200
240
|
}
|
|
201
|
-
|
|
241
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
242
|
+
if (prune(children[i])) {
|
|
243
|
+
children.splice(i, 1);
|
|
244
|
+
i -= 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (type === 'paragraph' || isFormat(type)) {
|
|
248
|
+
return children.length === 0;
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
202
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Sanitizes text:
|
|
255
|
+
* - collapses consecutive formats
|
|
256
|
+
* - collapses consecutive text blocks
|
|
257
|
+
* - trims ends of texts before break
|
|
258
|
+
* - trims ends of texts at the end
|
|
259
|
+
* - moves leading and trailing whitespaces out of formats
|
|
260
|
+
* - ensures spaces after formats
|
|
261
|
+
* - removes trailing breaks in containers
|
|
262
|
+
* see https://github.com/micromark/micromark/issues/118#issuecomment-1238225086
|
|
263
|
+
* - removes empty text blocks, formats, paragraphs
|
|
264
|
+
*
|
|
265
|
+
* @param {object} tree
|
|
266
|
+
* @returns {object} The modified (original) tree.
|
|
267
|
+
*/
|
|
268
|
+
export default function sanitizeTextAndFormats(tree) {
|
|
269
|
+
collapse(tree);
|
|
270
|
+
prune(tree);
|
|
271
|
+
sort(tree);
|
|
272
|
+
// collapse again, because sorting the nodes might have produce new collapsable siblings
|
|
273
|
+
collapse(tree);
|
|
274
|
+
whitespace(tree);
|
|
275
|
+
cleanup(tree);
|
|
276
|
+
prune(tree);
|
|
203
277
|
return tree;
|
|
204
278
|
}
|