@markuplint/ml-core 2.0.0-rc.0 → 2.0.0-rc.6
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/lib/index.d.ts +1 -1
- package/lib/index.js +3 -3
- package/lib/ml-core.d.ts +3 -2
- package/lib/ml-core.js +51 -28
- package/lib/ml-dom/document.d.ts +9 -1
- package/lib/ml-dom/document.js +38 -27
- package/lib/ml-dom/helper/match-selector.d.ts +12 -1
- package/lib/ml-dom/helper/match-selector.js +105 -87
- package/lib/ml-dom/helper/node-store.js +7 -2
- package/lib/ml-dom/helper/selector.d.ts +5 -3
- package/lib/ml-dom/helper/selector.js +264 -85
- package/lib/ml-dom/rule-mapper.d.ts +2 -1
- package/lib/ml-dom/rule-mapper.js +15 -9
- package/lib/ml-dom/tokens/abstract-element.d.ts +1 -0
- package/lib/ml-dom/tokens/abstract-element.js +31 -6
- package/lib/ml-dom/tokens/attribute.d.ts +1 -0
- package/lib/ml-dom/tokens/attribute.js +7 -0
- package/lib/ml-dom/tokens/node.d.ts +6 -5
- package/lib/ml-dom/tokens/node.js +20 -9
- package/lib/ml-dom/tokens/preprocessor-specific-attribute.d.ts +1 -0
- package/lib/ml-dom/tokens/preprocessor-specific-attribute.js +3 -0
- package/lib/ml-rule/ml-rule.d.ts +5 -2
- package/lib/ml-rule/ml-rule.js +17 -3
- package/lib/ml-rule/types.d.ts +3 -3
- package/markuplint-recommended.json +151 -11
- package/package.json +8 -7
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,50 +1,86 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_isAdded, _SelectorTarget_combinatedFrom;
|
|
2
|
+
var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_tagNameCaseSensitive, _SelectorTarget_isAdded, _SelectorTarget_combinatedFrom;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.createSelector = void 0;
|
|
4
|
+
exports.compareSpecificity = exports.createSelector = void 0;
|
|
5
5
|
const tslib_1 = require("tslib");
|
|
6
6
|
const postcss_selector_parser_1 = (0, tslib_1.__importDefault)(require("postcss-selector-parser"));
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const debug_1 = require("../../debug");
|
|
8
|
+
const log = debug_1.log.extend('selector');
|
|
9
|
+
const resLog = log.extend('result');
|
|
10
|
+
function createSelector(selector, tagNameCaseSensitive) {
|
|
11
|
+
return new Selector(selector, !!tagNameCaseSensitive);
|
|
9
12
|
}
|
|
10
13
|
exports.createSelector = createSelector;
|
|
14
|
+
function compareSpecificity(a, b) {
|
|
15
|
+
if (a[0] < b[0]) {
|
|
16
|
+
return -1;
|
|
17
|
+
}
|
|
18
|
+
else if (a[0] > b[0]) {
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
else if (a[1] < b[1]) {
|
|
22
|
+
return -1;
|
|
23
|
+
}
|
|
24
|
+
else if (a[1] > b[1]) {
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
else if (a[2] < b[2]) {
|
|
28
|
+
return -1;
|
|
29
|
+
}
|
|
30
|
+
else if (a[2] > b[2]) {
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
exports.compareSpecificity = compareSpecificity;
|
|
11
36
|
class Selector {
|
|
12
|
-
constructor(selector) {
|
|
37
|
+
constructor(selector, tagNameCaseSensitive) {
|
|
13
38
|
_Selector_ruleset.set(this, void 0);
|
|
14
|
-
(0, tslib_1.__classPrivateFieldSet)(this, _Selector_ruleset, Ruleset.parse(selector), "f");
|
|
39
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _Selector_ruleset, Ruleset.parse(selector, tagNameCaseSensitive), "f");
|
|
15
40
|
}
|
|
16
41
|
match(el, caller = el) {
|
|
17
|
-
|
|
42
|
+
const results = (0, tslib_1.__classPrivateFieldGet)(this, _Selector_ruleset, "f").match(el, caller);
|
|
43
|
+
for (const result of results) {
|
|
44
|
+
if (result.matched) {
|
|
45
|
+
return result.specificity;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
18
49
|
}
|
|
19
50
|
}
|
|
20
51
|
_Selector_ruleset = new WeakMap();
|
|
21
52
|
class Ruleset {
|
|
22
|
-
constructor(selectors) {
|
|
53
|
+
constructor(selectors, tagNameCaseSensitive) {
|
|
23
54
|
_Ruleset_selectorGroup.set(this, []);
|
|
24
|
-
(0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector)));
|
|
55
|
+
(0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector, tagNameCaseSensitive)));
|
|
25
56
|
}
|
|
26
|
-
static parse(selector) {
|
|
57
|
+
static parse(selector, tagNameCaseSensitive) {
|
|
27
58
|
const selectors = [];
|
|
28
59
|
(0, postcss_selector_parser_1.default)(root => {
|
|
29
60
|
selectors.push(...root.nodes);
|
|
30
61
|
}).processSync(selector);
|
|
31
|
-
return new Ruleset(selectors);
|
|
62
|
+
return new Ruleset(selectors, tagNameCaseSensitive);
|
|
32
63
|
}
|
|
33
64
|
match(el, caller) {
|
|
34
|
-
|
|
65
|
+
log('%s', el.raw);
|
|
66
|
+
return (0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").map(selector => {
|
|
67
|
+
const res = selector.match(el, caller);
|
|
68
|
+
resLog('%s => %o', selector.selector, res);
|
|
69
|
+
return res;
|
|
70
|
+
});
|
|
35
71
|
}
|
|
36
72
|
}
|
|
37
73
|
_Ruleset_selectorGroup = new WeakMap();
|
|
38
74
|
class StructuredSelector {
|
|
39
|
-
constructor(selector) {
|
|
75
|
+
constructor(selector, tagNameCaseSensitive) {
|
|
40
76
|
_StructuredSelector_edge.set(this, void 0);
|
|
41
77
|
_StructuredSelector_selector.set(this, void 0);
|
|
42
78
|
(0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_selector, selector, "f");
|
|
43
|
-
(0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, new SelectorTarget(), "f");
|
|
79
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, new SelectorTarget(tagNameCaseSensitive), "f");
|
|
44
80
|
(0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_selector, "f").nodes.forEach(node => {
|
|
45
81
|
switch (node.type) {
|
|
46
82
|
case 'combinator': {
|
|
47
|
-
const combinatedTarget = new SelectorTarget();
|
|
83
|
+
const combinatedTarget = new SelectorTarget(tagNameCaseSensitive);
|
|
48
84
|
combinatedTarget.from((0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_edge, "f"), node);
|
|
49
85
|
(0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, combinatedTarget, "f");
|
|
50
86
|
break;
|
|
@@ -65,76 +101,146 @@ class StructuredSelector {
|
|
|
65
101
|
}
|
|
66
102
|
});
|
|
67
103
|
}
|
|
104
|
+
get selector() {
|
|
105
|
+
return (0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_selector, "f").nodes.join('');
|
|
106
|
+
}
|
|
68
107
|
match(el, caller) {
|
|
69
108
|
return (0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_edge, "f").match(el, caller);
|
|
70
109
|
}
|
|
71
110
|
}
|
|
72
111
|
_StructuredSelector_edge = new WeakMap(), _StructuredSelector_selector = new WeakMap();
|
|
73
112
|
class SelectorTarget {
|
|
74
|
-
constructor() {
|
|
113
|
+
constructor(tagNameCaseSensitive) {
|
|
75
114
|
this.tag = null;
|
|
76
115
|
this.id = [];
|
|
77
116
|
this.class = [];
|
|
78
117
|
this.attr = [];
|
|
79
118
|
this.pseudo = [];
|
|
119
|
+
_SelectorTarget_tagNameCaseSensitive.set(this, void 0);
|
|
80
120
|
_SelectorTarget_isAdded.set(this, false);
|
|
81
121
|
_SelectorTarget_combinatedFrom.set(this, null);
|
|
122
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_tagNameCaseSensitive, tagNameCaseSensitive, "f");
|
|
82
123
|
}
|
|
83
124
|
match(el, caller) {
|
|
84
|
-
const
|
|
85
|
-
if (!matched) {
|
|
86
|
-
return
|
|
125
|
+
const unitCheck = this._matchWithoutCombinateChecking(el, caller);
|
|
126
|
+
if (!unitCheck.matched) {
|
|
127
|
+
return unitCheck;
|
|
87
128
|
}
|
|
88
129
|
if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_combinatedFrom, "f")) {
|
|
89
|
-
return
|
|
130
|
+
return unitCheck;
|
|
90
131
|
}
|
|
91
132
|
const { target, combinator } = (0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_combinatedFrom, "f");
|
|
92
133
|
switch (combinator.value) {
|
|
93
134
|
// Descendant combinator
|
|
94
135
|
case ' ': {
|
|
95
|
-
let ancestor = el.
|
|
136
|
+
let ancestor = el.getParentElement();
|
|
137
|
+
let matched = false;
|
|
138
|
+
let specificity;
|
|
96
139
|
while (ancestor) {
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
99
|
-
|
|
140
|
+
const res = target.match(ancestor, caller);
|
|
141
|
+
if (!specificity) {
|
|
142
|
+
specificity = [
|
|
143
|
+
unitCheck.specificity[0] + res.specificity[0],
|
|
144
|
+
unitCheck.specificity[1] + res.specificity[1],
|
|
145
|
+
unitCheck.specificity[2] + res.specificity[2],
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
if (res.matched) {
|
|
149
|
+
matched = true;
|
|
100
150
|
}
|
|
101
|
-
ancestor = ancestor.
|
|
151
|
+
ancestor = ancestor.getParentElement();
|
|
102
152
|
}
|
|
103
|
-
|
|
153
|
+
if (!specificity) {
|
|
154
|
+
const res = target.match(el, caller);
|
|
155
|
+
specificity = [
|
|
156
|
+
unitCheck.specificity[0] + res.specificity[0],
|
|
157
|
+
unitCheck.specificity[1] + res.specificity[1],
|
|
158
|
+
unitCheck.specificity[2] + res.specificity[2],
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
specificity,
|
|
163
|
+
matched,
|
|
164
|
+
};
|
|
104
165
|
}
|
|
105
166
|
// Child combinator
|
|
106
167
|
case '>': {
|
|
107
|
-
|
|
108
|
-
|
|
168
|
+
let matched;
|
|
169
|
+
const specificity = unitCheck.specificity;
|
|
170
|
+
const parentNode = el.getParentElement();
|
|
171
|
+
if (parentNode) {
|
|
172
|
+
const res = target.match(parentNode, caller);
|
|
173
|
+
specificity[0] += res.specificity[0];
|
|
174
|
+
specificity[1] += res.specificity[1];
|
|
175
|
+
specificity[2] += res.specificity[2];
|
|
176
|
+
matched = res.matched;
|
|
109
177
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
178
|
+
else {
|
|
179
|
+
const res = target.match(el, caller);
|
|
180
|
+
specificity[0] += res.specificity[0];
|
|
181
|
+
specificity[1] += res.specificity[1];
|
|
182
|
+
specificity[2] += res.specificity[2];
|
|
183
|
+
matched = false;
|
|
113
184
|
}
|
|
114
|
-
return
|
|
185
|
+
return {
|
|
186
|
+
specificity,
|
|
187
|
+
matched,
|
|
188
|
+
};
|
|
115
189
|
}
|
|
116
190
|
// Next-sibling combinator
|
|
117
191
|
case '+': {
|
|
118
|
-
|
|
119
|
-
|
|
192
|
+
let matched;
|
|
193
|
+
const specificity = unitCheck.specificity;
|
|
194
|
+
if (el.previousElementSibling) {
|
|
195
|
+
const res = target.match(el.previousElementSibling, caller);
|
|
196
|
+
specificity[0] += res.specificity[0];
|
|
197
|
+
specificity[1] += res.specificity[1];
|
|
198
|
+
specificity[2] += res.specificity[2];
|
|
199
|
+
matched = res.matched;
|
|
120
200
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
201
|
+
else {
|
|
202
|
+
const res = target.match(el, caller);
|
|
203
|
+
specificity[0] += res.specificity[0];
|
|
204
|
+
specificity[1] += res.specificity[1];
|
|
205
|
+
specificity[2] += res.specificity[2];
|
|
206
|
+
matched = false;
|
|
124
207
|
}
|
|
125
|
-
return
|
|
208
|
+
return {
|
|
209
|
+
specificity,
|
|
210
|
+
matched,
|
|
211
|
+
};
|
|
126
212
|
}
|
|
127
|
-
// Subsequent-sibling combinator
|
|
213
|
+
// // Subsequent-sibling combinator
|
|
128
214
|
case '~': {
|
|
129
215
|
let prev = el.previousElementSibling;
|
|
216
|
+
let matched = false;
|
|
217
|
+
let specificity;
|
|
130
218
|
while (prev) {
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
|
|
219
|
+
const res = target.match(prev, caller);
|
|
220
|
+
if (!specificity) {
|
|
221
|
+
specificity = [
|
|
222
|
+
unitCheck.specificity[0] + res.specificity[0],
|
|
223
|
+
unitCheck.specificity[1] + res.specificity[1],
|
|
224
|
+
unitCheck.specificity[2] + res.specificity[2],
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
if (res.matched) {
|
|
228
|
+
matched = true;
|
|
134
229
|
}
|
|
135
230
|
prev = prev.previousElementSibling;
|
|
136
231
|
}
|
|
137
|
-
|
|
232
|
+
if (!specificity) {
|
|
233
|
+
const res = target.match(el, caller);
|
|
234
|
+
specificity = [
|
|
235
|
+
unitCheck.specificity[0] + res.specificity[0],
|
|
236
|
+
unitCheck.specificity[1] + res.specificity[1],
|
|
237
|
+
unitCheck.specificity[2] + res.specificity[2],
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
specificity,
|
|
242
|
+
matched,
|
|
243
|
+
};
|
|
138
244
|
}
|
|
139
245
|
// Column combinator
|
|
140
246
|
case '||': {
|
|
@@ -146,27 +252,48 @@ class SelectorTarget {
|
|
|
146
252
|
}
|
|
147
253
|
}
|
|
148
254
|
_matchWithoutCombinateChecking(el, caller) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (this.tag.value.toLowerCase() !== el.nodeName.toLowerCase()) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
255
|
+
const specificity = [0, 0, 0];
|
|
256
|
+
let matched = true;
|
|
257
|
+
if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_isAdded, "f") && !isScope(el, caller)) {
|
|
258
|
+
matched = false;
|
|
156
259
|
}
|
|
157
260
|
if (!this.id.every(id => id.value === el.id)) {
|
|
158
|
-
|
|
261
|
+
matched = false;
|
|
159
262
|
}
|
|
263
|
+
specificity[0] += this.id.length;
|
|
160
264
|
if (!this.class.every(className => el.classList.includes(className.value))) {
|
|
161
|
-
|
|
265
|
+
matched = false;
|
|
162
266
|
}
|
|
267
|
+
specificity[1] += this.class.length;
|
|
163
268
|
if (!this.attr.every(attr => attrMatch(attr, el))) {
|
|
164
|
-
|
|
269
|
+
matched = false;
|
|
165
270
|
}
|
|
166
|
-
|
|
167
|
-
|
|
271
|
+
specificity[1] += this.attr.length;
|
|
272
|
+
for (const pseudo of this.pseudo) {
|
|
273
|
+
const pseudoRes = pseudoMatch(pseudo, el, caller, (0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_tagNameCaseSensitive, "f"));
|
|
274
|
+
specificity[0] += pseudoRes.specificity[0];
|
|
275
|
+
specificity[1] += pseudoRes.specificity[1];
|
|
276
|
+
specificity[2] += pseudoRes.specificity[2];
|
|
277
|
+
if (!pseudoRes.matched) {
|
|
278
|
+
matched = false;
|
|
279
|
+
}
|
|
168
280
|
}
|
|
169
|
-
|
|
281
|
+
if (this.tag && this.tag.type === 'tag') {
|
|
282
|
+
specificity[2] += 1;
|
|
283
|
+
let a = this.tag.value;
|
|
284
|
+
let b = el.nodeName;
|
|
285
|
+
if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_tagNameCaseSensitive, "f")) {
|
|
286
|
+
a = a.toLowerCase();
|
|
287
|
+
b = b.toLowerCase();
|
|
288
|
+
}
|
|
289
|
+
if (a !== b) {
|
|
290
|
+
matched = false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
specificity,
|
|
295
|
+
matched,
|
|
296
|
+
};
|
|
170
297
|
}
|
|
171
298
|
add(selector) {
|
|
172
299
|
(0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_isAdded, true, "f");
|
|
@@ -198,7 +325,7 @@ class SelectorTarget {
|
|
|
198
325
|
(0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_combinatedFrom, { target, combinator }, "f");
|
|
199
326
|
}
|
|
200
327
|
}
|
|
201
|
-
_SelectorTarget_isAdded = new WeakMap(), _SelectorTarget_combinatedFrom = new WeakMap();
|
|
328
|
+
_SelectorTarget_tagNameCaseSensitive = new WeakMap(), _SelectorTarget_isAdded = new WeakMap(), _SelectorTarget_combinatedFrom = new WeakMap();
|
|
202
329
|
function attrMatch(attr, el) {
|
|
203
330
|
return el.attributes.some(attrOfEl => {
|
|
204
331
|
if (attr.attribute !== attrOfEl.getName().potential) {
|
|
@@ -253,58 +380,94 @@ function attrMatch(attr, el) {
|
|
|
253
380
|
return true;
|
|
254
381
|
});
|
|
255
382
|
}
|
|
256
|
-
function pseudoMatch(pseudo, el, caller) {
|
|
383
|
+
function pseudoMatch(pseudo, el, caller, tagNameCaseSensitive) {
|
|
257
384
|
switch (pseudo.value) {
|
|
258
385
|
/**
|
|
259
386
|
* Below, markuplint Specific Selector
|
|
260
387
|
*/
|
|
261
388
|
case ':closest': {
|
|
262
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
263
|
-
|
|
389
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
390
|
+
const specificity = getSpecificity(ruleset.match(el, caller));
|
|
391
|
+
let parent = el.getParentElement();
|
|
264
392
|
while (parent) {
|
|
265
|
-
if (ruleset.match(parent, caller)) {
|
|
266
|
-
return
|
|
393
|
+
if (ruleset.match(parent, caller).some(r => r.matched)) {
|
|
394
|
+
return {
|
|
395
|
+
specificity,
|
|
396
|
+
matched: true,
|
|
397
|
+
};
|
|
267
398
|
}
|
|
268
|
-
parent = parent.
|
|
399
|
+
parent = parent.getParentElement();
|
|
269
400
|
}
|
|
270
|
-
return
|
|
401
|
+
return {
|
|
402
|
+
specificity,
|
|
403
|
+
matched: false,
|
|
404
|
+
};
|
|
271
405
|
}
|
|
272
406
|
/**
|
|
273
407
|
* Below, Selector Level 4
|
|
274
408
|
*/
|
|
275
409
|
case ':not': {
|
|
276
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
410
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
411
|
+
const resList = ruleset.match(el, caller);
|
|
412
|
+
const specificity = getSpecificity(resList);
|
|
413
|
+
const matched = resList.every(r => !r.matched);
|
|
414
|
+
return {
|
|
415
|
+
specificity,
|
|
416
|
+
matched,
|
|
417
|
+
};
|
|
281
418
|
}
|
|
282
419
|
case ':is': {
|
|
283
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
420
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
421
|
+
const resList = ruleset.match(el, caller);
|
|
422
|
+
const specificity = getSpecificity(resList);
|
|
423
|
+
const matched = resList.some(r => r.matched);
|
|
424
|
+
return {
|
|
425
|
+
specificity,
|
|
426
|
+
matched,
|
|
427
|
+
};
|
|
288
428
|
}
|
|
289
429
|
case ':has': {
|
|
290
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
430
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
431
|
+
const specificity = getSpecificity(ruleset.match(el, caller));
|
|
291
432
|
const descendants = getDescendants(el);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
433
|
+
const matched = descendants.some(desc => ruleset.match(desc, caller).some(m => m.matched));
|
|
434
|
+
return {
|
|
435
|
+
specificity,
|
|
436
|
+
matched,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
case ':where': {
|
|
440
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
441
|
+
const resList = ruleset.match(el, caller);
|
|
442
|
+
const matched = resList.some(r => r.matched);
|
|
443
|
+
return {
|
|
444
|
+
specificity: [0, 0, 0],
|
|
445
|
+
matched,
|
|
446
|
+
};
|
|
296
447
|
}
|
|
297
448
|
case ':scope': {
|
|
298
449
|
if (!isScope(el, caller)) {
|
|
299
|
-
return
|
|
450
|
+
return {
|
|
451
|
+
specificity: [0, 1, 0],
|
|
452
|
+
matched: false,
|
|
453
|
+
};
|
|
300
454
|
}
|
|
301
|
-
|
|
455
|
+
return {
|
|
456
|
+
specificity: [0, 1, 0],
|
|
457
|
+
matched: true,
|
|
458
|
+
};
|
|
302
459
|
}
|
|
303
460
|
case ':root': {
|
|
304
461
|
if (!(!el.isInFragmentDocument && el.parentNode === null)) {
|
|
305
|
-
return
|
|
462
|
+
return {
|
|
463
|
+
specificity: [0, 1, 0],
|
|
464
|
+
matched: false,
|
|
465
|
+
};
|
|
306
466
|
}
|
|
307
|
-
|
|
467
|
+
return {
|
|
468
|
+
specificity: [0, 1, 0],
|
|
469
|
+
matched: true,
|
|
470
|
+
};
|
|
308
471
|
}
|
|
309
472
|
case ':enable':
|
|
310
473
|
case ':disable':
|
|
@@ -337,7 +500,6 @@ function pseudoMatch(pseudo, el, caller) {
|
|
|
337
500
|
case ':nth-col': {
|
|
338
501
|
throw new Error(`Unsupported pseudo ${pseudo.toString()} selector yet. If you want it, please request it as the issue (https://github.com/markuplint/markuplint/issues/new).`);
|
|
339
502
|
}
|
|
340
|
-
case ':where':
|
|
341
503
|
case ':dir':
|
|
342
504
|
case ':lang':
|
|
343
505
|
case ':any-link':
|
|
@@ -360,7 +522,6 @@ function pseudoMatch(pseudo, el, caller) {
|
|
|
360
522
|
throw new Error(`Unsupported pseudo ${pseudo.toString()} selector.`);
|
|
361
523
|
}
|
|
362
524
|
}
|
|
363
|
-
return true;
|
|
364
525
|
}
|
|
365
526
|
function isScope(el, caller) {
|
|
366
527
|
return el.uuid === (caller === null || caller === void 0 ? void 0 : caller.uuid) || (!el.isInFragmentDocument && el.parentNode === null);
|
|
@@ -368,3 +529,21 @@ function isScope(el, caller) {
|
|
|
368
529
|
function getDescendants(el, includeSelf = false) {
|
|
369
530
|
return [...el.children.map(child => getDescendants(child, true)).flat(), ...(includeSelf ? [el] : [])];
|
|
370
531
|
}
|
|
532
|
+
function getSpecificity(result) {
|
|
533
|
+
let specificity;
|
|
534
|
+
for (const res of result) {
|
|
535
|
+
if (specificity) {
|
|
536
|
+
const order = compareSpecificity(specificity, res.specificity);
|
|
537
|
+
if (order === -1) {
|
|
538
|
+
specificity = res.specificity;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
specificity = res.specificity;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (!specificity) {
|
|
546
|
+
throw new Error('Result is empty');
|
|
547
|
+
}
|
|
548
|
+
return specificity;
|
|
549
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { Specificity } from './helper/selector';
|
|
1
2
|
import type { AnonymousNode } from './types';
|
|
2
3
|
import type { AnyRule } from '@markuplint/ml-config';
|
|
3
4
|
declare type RuleType = 'rules' | 'nodeRules' | 'childNodeRules';
|
|
4
5
|
declare type MappingLayer = {
|
|
5
6
|
from: RuleType;
|
|
6
|
-
|
|
7
|
+
specificity: Specificity;
|
|
7
8
|
rule: AnyRule;
|
|
8
9
|
};
|
|
9
10
|
export declare class RuleMapper<N extends AnonymousNode<any, any> = AnonymousNode<any, any>> {
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.RuleMapper = void 0;
|
|
5
5
|
const tslib_1 = require("tslib");
|
|
6
6
|
const debug_1 = require("../debug");
|
|
7
|
+
const selector_1 = require("./helper/selector");
|
|
7
8
|
const ruleMapperLog = debug_1.log.extend('rule-mapper');
|
|
8
9
|
const ruleMapperNodeLog = ruleMapperLog.extend('node');
|
|
9
10
|
const ruleMapperNodeRuleLog = ruleMapperNodeLog.extend('rule');
|
|
@@ -14,20 +15,25 @@ class RuleMapper {
|
|
|
14
15
|
(0, tslib_1.__classPrivateFieldSet)(this, _RuleMapper_nodeList, nodeList, "f");
|
|
15
16
|
}
|
|
16
17
|
set(node, ruleName, rule) {
|
|
18
|
+
if (node.type === 'ElementCloseTag') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
17
21
|
const rules = (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").get(node.uuid) || {};
|
|
18
22
|
const currentRule = rules[ruleName];
|
|
19
23
|
if (currentRule) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
else {
|
|
24
|
-
ruleMapperLog("Don't set %o (%d vs %d)", rule, currentRule.index, rule.index);
|
|
24
|
+
const order = (0, selector_1.compareSpecificity)(currentRule.specificity, rule.specificity);
|
|
25
|
+
if (order === 1) {
|
|
26
|
+
ruleMapperLog("Don't set %o ([%s] vs [%s])", rule, currentRule.specificity, rule.specificity);
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
29
|
+
ruleMapperLog('Unset %o from %s', currentRule, node);
|
|
27
30
|
}
|
|
28
31
|
rules[ruleName] = rule;
|
|
29
32
|
(0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").set(node.uuid, rules);
|
|
30
|
-
|
|
33
|
+
if (node.type === 'Element' && node.closeTag) {
|
|
34
|
+
(0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").set(node.closeTag.uuid, rules);
|
|
35
|
+
}
|
|
36
|
+
ruleMapperLog('Set to %s from %s (%o): %O', node.raw, rule.from, rule.specificity, rule.rule);
|
|
31
37
|
}
|
|
32
38
|
apply() {
|
|
33
39
|
ruleMapperLog('ruleTree:');
|
|
@@ -36,13 +42,13 @@ class RuleMapper {
|
|
|
36
42
|
if (!rules) {
|
|
37
43
|
return;
|
|
38
44
|
}
|
|
39
|
-
const
|
|
45
|
+
const slash = node.type === 'ElementCloseTag' ? '/' : '';
|
|
40
46
|
const nodeName = 'nodeName' in node ? node.nodeName : `#${node.type}`;
|
|
41
|
-
ruleMapperNodeLog('<%s%s>',
|
|
47
|
+
ruleMapperNodeLog('<%s%s>', slash, nodeName);
|
|
42
48
|
Object.keys(rules).forEach(ruleName => {
|
|
43
49
|
const rule = rules[ruleName];
|
|
44
50
|
node.rules[ruleName] = rule.rule;
|
|
45
|
-
ruleMapperNodeRuleLog('[from: %s(%
|
|
51
|
+
ruleMapperNodeRuleLog('[from: %s(%s)] %s: %o', rule.from, rule.specificity, ruleName, rule.rule);
|
|
46
52
|
});
|
|
47
53
|
});
|
|
48
54
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _MLDOMAbstractElement_fixedNodeName;
|
|
2
|
+
var _MLDOMAbstractElement_fixedNodeName, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, _MLDOMAbstractElement_normalizedString;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
@@ -15,6 +15,8 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
15
15
|
this.childModels = new Set();
|
|
16
16
|
this.descendantModels = new Set();
|
|
17
17
|
_MLDOMAbstractElement_fixedNodeName.set(this, void 0);
|
|
18
|
+
_MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache.set(this, null);
|
|
19
|
+
_MLDOMAbstractElement_normalizedString.set(this, null);
|
|
18
20
|
this.nodeName = astNode.nodeName;
|
|
19
21
|
(0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_fixedNodeName, astNode.nodeName, "f");
|
|
20
22
|
this.namespaceURI = astNode.namespace;
|
|
@@ -113,7 +115,7 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
113
115
|
if (selecor.match(el, this)) {
|
|
114
116
|
return el;
|
|
115
117
|
}
|
|
116
|
-
el = el.
|
|
118
|
+
el = el.getParentElement();
|
|
117
119
|
} while (el !== null && el.type === 'Element');
|
|
118
120
|
return null;
|
|
119
121
|
}
|
|
@@ -145,12 +147,15 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
145
147
|
return !!this.getAttributeToken(attrName).length;
|
|
146
148
|
}
|
|
147
149
|
matches(selector) {
|
|
148
|
-
return (0, helper_1.createSelector)(selector).match(this);
|
|
150
|
+
return !!(0, helper_1.createSelector)(selector).match(this);
|
|
149
151
|
}
|
|
150
152
|
fixNodeName(name) {
|
|
151
153
|
(0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_fixedNodeName, name, "f");
|
|
152
154
|
}
|
|
153
155
|
getChildElementsAndTextNodeWithoutWhitespaces() {
|
|
156
|
+
if ((0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f")) {
|
|
157
|
+
return (0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f");
|
|
158
|
+
}
|
|
154
159
|
const filteredNodes = [];
|
|
155
160
|
this.childNodes.forEach(node => {
|
|
156
161
|
if (node.type === 'Element') {
|
|
@@ -164,6 +169,7 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
164
169
|
filteredNodes.push(...children);
|
|
165
170
|
}
|
|
166
171
|
});
|
|
172
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, filteredNodes, "f");
|
|
167
173
|
return filteredNodes;
|
|
168
174
|
}
|
|
169
175
|
/**
|
|
@@ -173,7 +179,7 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
173
179
|
return this.childNodes.some(node => node.type === 'PSBlock');
|
|
174
180
|
}
|
|
175
181
|
isDescendantByUUIDList(uuidList) {
|
|
176
|
-
let el = this.
|
|
182
|
+
let el = this.getParentElement();
|
|
177
183
|
if (el === null) {
|
|
178
184
|
return false;
|
|
179
185
|
}
|
|
@@ -181,10 +187,29 @@ class MLDOMAbstractElement extends node_1.default {
|
|
|
181
187
|
if (uuidList.includes(el.uuid)) {
|
|
182
188
|
return true;
|
|
183
189
|
}
|
|
184
|
-
el = el.
|
|
190
|
+
el = el.getParentElement();
|
|
185
191
|
} while (el !== null && el.type === 'Element');
|
|
186
192
|
return false;
|
|
187
193
|
}
|
|
194
|
+
toNormalizeString() {
|
|
195
|
+
if ((0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_normalizedString, "f")) {
|
|
196
|
+
return (0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_normalizedString, "f");
|
|
197
|
+
}
|
|
198
|
+
const children = this.getChildElementsAndTextNodeWithoutWhitespaces();
|
|
199
|
+
const attrs = this.attributes.map(attr => attr.toNormalizeString());
|
|
200
|
+
const attrString = attrs.length ? ' ' + attrs.join('') : '';
|
|
201
|
+
const startTag = `<${this.nodeName}${attrString}>`;
|
|
202
|
+
const childNodes = children.map(node => {
|
|
203
|
+
if (node.type === 'Element') {
|
|
204
|
+
return node.toNormalizeString();
|
|
205
|
+
}
|
|
206
|
+
return node.originRaw;
|
|
207
|
+
});
|
|
208
|
+
const endTag = `</${this.nodeName}>`;
|
|
209
|
+
const normalizedString = `${startTag}${childNodes.join('')}${endTag}`;
|
|
210
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_normalizedString, normalizedString, "f");
|
|
211
|
+
return normalizedString;
|
|
212
|
+
}
|
|
188
213
|
}
|
|
189
214
|
exports.default = MLDOMAbstractElement;
|
|
190
|
-
_MLDOMAbstractElement_fixedNodeName = new WeakMap();
|
|
215
|
+
_MLDOMAbstractElement_fixedNodeName = new WeakMap(), _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache = new WeakMap(), _MLDOMAbstractElement_normalizedString = new WeakMap();
|