@markuplint/ml-core 2.0.0-dev.26 → 2.0.0-rc.5
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/convert-ruleset.d.ts +1 -1
- package/lib/convert-ruleset.js +1 -1
- package/lib/debug.js +8 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/ml-core.d.ts +2 -1
- package/lib/ml-core.js +25 -16
- package/lib/ml-dom/document.d.ts +5 -2
- package/lib/ml-dom/document.js +99 -51
- package/lib/ml-dom/helper/match-selector.d.ts +12 -1
- package/lib/ml-dom/helper/match-selector.js +108 -90
- package/lib/ml-dom/helper/selector.d.ts +5 -3
- package/lib/ml-dom/helper/selector.js +275 -79
- package/lib/ml-dom/helper/walkers.js +1 -1
- package/lib/ml-dom/rule-mapper.d.ts +16 -0
- package/lib/ml-dom/rule-mapper.js +57 -0
- 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 +8 -7
- package/lib/ml-dom/tokens/node.js +21 -13
- 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-dom/tokens/token.d.ts +0 -2
- package/lib/ml-dom/tokens/token.js +0 -1
- package/lib/ml-rule/ml-rule.d.ts +5 -2
- package/lib/ml-rule/ml-rule.js +19 -3
- package/lib/ml-rule/types.d.ts +3 -3
- package/lib/test/index.d.ts +8 -5
- package/lib/test/index.js +7 -7
- package/markuplint-recommended.json +150 -11
- package/package.json +7 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/create-rule.d.ts +0 -4
- package/lib/create-rule.js +0 -8
|
@@ -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();
|
|
152
|
+
}
|
|
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
|
+
];
|
|
102
160
|
}
|
|
103
|
-
return
|
|
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,41 +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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Below, markuplint Specific Selector
|
|
387
|
+
*/
|
|
388
|
+
case ':closest': {
|
|
389
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
390
|
+
const specificity = getSpecificity(ruleset.match(el, caller));
|
|
391
|
+
let parent = el.getParentElement();
|
|
392
|
+
while (parent) {
|
|
393
|
+
if (ruleset.match(parent, caller).some(r => r.matched)) {
|
|
394
|
+
return {
|
|
395
|
+
specificity,
|
|
396
|
+
matched: true,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
parent = parent.getParentElement();
|
|
262
400
|
}
|
|
263
|
-
|
|
401
|
+
return {
|
|
402
|
+
specificity,
|
|
403
|
+
matched: false,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Below, Selector Level 4
|
|
408
|
+
*/
|
|
409
|
+
case ':not': {
|
|
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
|
+
};
|
|
264
418
|
}
|
|
265
419
|
case ':is': {
|
|
266
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
+
};
|
|
271
428
|
}
|
|
272
429
|
case ':has': {
|
|
273
|
-
const ruleset = new Ruleset(pseudo.nodes);
|
|
430
|
+
const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
|
|
431
|
+
const specificity = getSpecificity(ruleset.match(el, caller));
|
|
274
432
|
const descendants = getDescendants(el);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
+
};
|
|
279
447
|
}
|
|
280
448
|
case ':scope': {
|
|
281
449
|
if (!isScope(el, caller)) {
|
|
282
|
-
return
|
|
450
|
+
return {
|
|
451
|
+
specificity: [0, 1, 0],
|
|
452
|
+
matched: false,
|
|
453
|
+
};
|
|
283
454
|
}
|
|
284
|
-
|
|
455
|
+
return {
|
|
456
|
+
specificity: [0, 1, 0],
|
|
457
|
+
matched: true,
|
|
458
|
+
};
|
|
285
459
|
}
|
|
286
460
|
case ':root': {
|
|
287
461
|
if (!(!el.isInFragmentDocument && el.parentNode === null)) {
|
|
288
|
-
return
|
|
462
|
+
return {
|
|
463
|
+
specificity: [0, 1, 0],
|
|
464
|
+
matched: false,
|
|
465
|
+
};
|
|
289
466
|
}
|
|
290
|
-
|
|
467
|
+
return {
|
|
468
|
+
specificity: [0, 1, 0],
|
|
469
|
+
matched: true,
|
|
470
|
+
};
|
|
291
471
|
}
|
|
292
472
|
case ':enable':
|
|
293
473
|
case ':disable':
|
|
@@ -320,7 +500,6 @@ function pseudoMatch(pseudo, el, caller) {
|
|
|
320
500
|
case ':nth-col': {
|
|
321
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).`);
|
|
322
502
|
}
|
|
323
|
-
case ':where':
|
|
324
503
|
case ':dir':
|
|
325
504
|
case ':lang':
|
|
326
505
|
case ':any-link':
|
|
@@ -343,7 +522,6 @@ function pseudoMatch(pseudo, el, caller) {
|
|
|
343
522
|
throw new Error(`Unsupported pseudo ${pseudo.toString()} selector.`);
|
|
344
523
|
}
|
|
345
524
|
}
|
|
346
|
-
return true;
|
|
347
525
|
}
|
|
348
526
|
function isScope(el, caller) {
|
|
349
527
|
return el.uuid === (caller === null || caller === void 0 ? void 0 : caller.uuid) || (!el.isInFragmentDocument && el.parentNode === null);
|
|
@@ -351,3 +529,21 @@ function isScope(el, caller) {
|
|
|
351
529
|
function getDescendants(el, includeSelf = false) {
|
|
352
530
|
return [...el.children.map(child => getDescendants(child, true)).flat(), ...(includeSelf ? [el] : [])];
|
|
353
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
|
+
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.syncWalk = void 0;
|
|
4
4
|
function syncWalk(nodeList, walker) {
|
|
5
5
|
for (const node of nodeList) {
|
|
6
|
-
if (node.type === 'Element' || node.type === 'OmittedElement') {
|
|
6
|
+
if (node.type === 'Element' || node.type === 'OmittedElement' || node.type === 'PSBlock') {
|
|
7
7
|
syncWalk(node.childNodes, walker);
|
|
8
8
|
}
|
|
9
9
|
walker(node);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Specificity } from './helper/selector';
|
|
2
|
+
import type { AnonymousNode } from './types';
|
|
3
|
+
import type { AnyRule } from '@markuplint/ml-config';
|
|
4
|
+
declare type RuleType = 'rules' | 'nodeRules' | 'childNodeRules';
|
|
5
|
+
declare type MappingLayer = {
|
|
6
|
+
from: RuleType;
|
|
7
|
+
specificity: Specificity;
|
|
8
|
+
rule: AnyRule;
|
|
9
|
+
};
|
|
10
|
+
export declare class RuleMapper<N extends AnonymousNode<any, any> = AnonymousNode<any, any>> {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(nodeList: ReadonlyArray<N>);
|
|
13
|
+
set(node: N, ruleName: string, rule: MappingLayer): void;
|
|
14
|
+
apply(): void;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _RuleMapper_nodeList, _RuleMapper_ruleMap;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RuleMapper = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const debug_1 = require("../debug");
|
|
7
|
+
const selector_1 = require("./helper/selector");
|
|
8
|
+
const ruleMapperLog = debug_1.log.extend('rule-mapper');
|
|
9
|
+
const ruleMapperNodeLog = ruleMapperLog.extend('node');
|
|
10
|
+
const ruleMapperNodeRuleLog = ruleMapperNodeLog.extend('rule');
|
|
11
|
+
class RuleMapper {
|
|
12
|
+
constructor(nodeList) {
|
|
13
|
+
_RuleMapper_nodeList.set(this, void 0);
|
|
14
|
+
_RuleMapper_ruleMap.set(this, new Map());
|
|
15
|
+
(0, tslib_1.__classPrivateFieldSet)(this, _RuleMapper_nodeList, nodeList, "f");
|
|
16
|
+
}
|
|
17
|
+
set(node, ruleName, rule) {
|
|
18
|
+
if (node.type === 'ElementCloseTag') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const rules = (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").get(node.uuid) || {};
|
|
22
|
+
const currentRule = rules[ruleName];
|
|
23
|
+
if (currentRule) {
|
|
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);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
ruleMapperLog('Unset %o from %s', currentRule, node);
|
|
30
|
+
}
|
|
31
|
+
rules[ruleName] = rule;
|
|
32
|
+
(0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").set(node.uuid, rules);
|
|
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);
|
|
37
|
+
}
|
|
38
|
+
apply() {
|
|
39
|
+
ruleMapperLog('ruleTree:');
|
|
40
|
+
(0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_nodeList, "f").forEach(node => {
|
|
41
|
+
const rules = (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").get(node.uuid);
|
|
42
|
+
if (!rules) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const slash = node.type === 'ElementCloseTag' ? '/' : '';
|
|
46
|
+
const nodeName = 'nodeName' in node ? node.nodeName : `#${node.type}`;
|
|
47
|
+
ruleMapperNodeLog('<%s%s>', slash, nodeName);
|
|
48
|
+
Object.keys(rules).forEach(ruleName => {
|
|
49
|
+
const rule = rules[ruleName];
|
|
50
|
+
node.rules[ruleName] = rule.rule;
|
|
51
|
+
ruleMapperNodeRuleLog('[from: %s(%s)] %s: %o', rule.from, rule.specificity, ruleName, rule.rule);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.RuleMapper = RuleMapper;
|
|
57
|
+
_RuleMapper_nodeList = new WeakMap(), _RuleMapper_ruleMap = new WeakMap();
|