@markuplint/ml-core 2.0.0-rc.0 → 2.0.0-rc.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/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/ml-core.d.ts +1 -1
- package/lib/ml-core.js +16 -14
- package/lib/ml-dom/document.js +32 -23
- package/lib/ml-dom/helper/match-selector.d.ts +12 -1
- package/lib/ml-dom/helper/match-selector.js +103 -85
- package/lib/ml-dom/helper/selector.d.ts +3 -1
- package/lib/ml-dom/helper/selector.js +237 -66
- 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 +144 -11
- package/package.json +7 -7
- package/tsconfig.tsbuildinfo +1 -1
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.enableDebug = exports.getIndent = exports.Ruleset = exports.MLParseError = void 0;
|
|
3
|
+
exports.enableDebug = exports.getIndent = exports.Ruleset = exports.MLParseError = exports.getAttrSpecs = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
var ml_spec_1 = require("@markuplint/ml-spec");
|
|
6
|
+
Object.defineProperty(exports, "getAttrSpecs", { enumerable: true, get: function () { return ml_spec_1.getAttrSpecs; } });
|
|
5
7
|
(0, tslib_1.__exportStar)(require("./convert-ruleset"), exports);
|
|
6
8
|
(0, tslib_1.__exportStar)(require("./ml-core"), exports);
|
|
7
9
|
(0, tslib_1.__exportStar)(require("./ml-rule"), exports);
|
package/lib/ml-core.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare type MLCoreParams = {
|
|
|
10
10
|
export declare class MLCore {
|
|
11
11
|
#private;
|
|
12
12
|
constructor({ parser, sourceCode, ruleset, rules, locale, schemas, parserOptions, filename, debug }: MLCoreParams);
|
|
13
|
-
get document():
|
|
13
|
+
get document(): Document<RuleConfigValue, unknown> | MLParseError;
|
|
14
14
|
verify(fix?: boolean): Promise<Violation[]>;
|
|
15
15
|
setCode(sourceCode: string): void;
|
|
16
16
|
update({ parser, ruleset, rules, locale, schemas, parserOptions }: Partial<MLFabric>): void;
|
package/lib/ml-core.js
CHANGED
|
@@ -58,8 +58,8 @@ class MLCore {
|
|
|
58
58
|
return violations;
|
|
59
59
|
}
|
|
60
60
|
for (const rule of (0, tslib_1.__classPrivateFieldGet)(this, _MLCore_rules, "f")) {
|
|
61
|
-
const ruleInfo = rule.
|
|
62
|
-
if (ruleInfo.disabled) {
|
|
61
|
+
const ruleInfo = rule.getRuleInfo((0, tslib_1.__classPrivateFieldGet)(this, _MLCore_ruleset, "f"), rule.name);
|
|
62
|
+
if (ruleInfo.disabled && ruleInfo.nodeRules.length === 0 && ruleInfo.childNodeRules.length === 0) {
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
65
65
|
(0, debug_1.log)('%s Rule: verify', rule.name);
|
|
@@ -85,18 +85,20 @@ class MLCore {
|
|
|
85
85
|
}
|
|
86
86
|
(0, debug_1.log)('%s Rule: verify end', rule.name);
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
if (resultLog.enabled) {
|
|
89
|
+
const { e, w, i } = violations.reduce((c, v) => {
|
|
90
|
+
if (v.severity === 'error')
|
|
91
|
+
c.e += 1;
|
|
92
|
+
if (v.severity === 'warning')
|
|
93
|
+
c.w += 1;
|
|
94
|
+
if (v.severity === 'info')
|
|
95
|
+
c.i += 1;
|
|
96
|
+
return c;
|
|
97
|
+
}, { e: 0, w: 0, i: 0 });
|
|
98
|
+
resultLog('Error: %d', e);
|
|
99
|
+
resultLog('Warning: %d', w);
|
|
100
|
+
resultLog('Info: %d', i);
|
|
101
|
+
}
|
|
100
102
|
(0, debug_1.log)('verify: end');
|
|
101
103
|
return violations;
|
|
102
104
|
}
|
package/lib/ml-dom/document.js
CHANGED
|
@@ -129,51 +129,58 @@ class MLDOMDocument {
|
|
|
129
129
|
const ruleMapper = new rule_mapper_1.RuleMapper(this.nodeList);
|
|
130
130
|
// add rules to node
|
|
131
131
|
for (const node of this.nodeList) {
|
|
132
|
-
|
|
132
|
+
if (node.type === 'ElementCloseTag') {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (docLog.enabled) {
|
|
136
|
+
docLog('Add rules to node <%s>', 'nodeName' in node ? node.nodeName : `#${node.type}`);
|
|
137
|
+
}
|
|
133
138
|
// global rules
|
|
134
139
|
Object.keys(ruleset.rules).forEach(ruleName => {
|
|
135
140
|
const rule = ruleset.rules[ruleName];
|
|
136
141
|
ruleMapper.set(node, ruleName, {
|
|
137
142
|
from: 'rules',
|
|
138
|
-
|
|
143
|
+
specificity: [0, 0, 0],
|
|
139
144
|
rule,
|
|
140
145
|
});
|
|
141
146
|
});
|
|
142
|
-
if (node.type !== 'Element' &&
|
|
143
|
-
node.type !== 'OmittedElement' &&
|
|
144
|
-
node.type !== 'ElementCloseTag' &&
|
|
145
|
-
node.type !== 'Text') {
|
|
147
|
+
if (node.type !== 'Element' && node.type !== 'OmittedElement' && node.type !== 'Text') {
|
|
146
148
|
continue;
|
|
147
149
|
}
|
|
148
|
-
const selectorTarget = node.type === 'Element' || node.type === 'OmittedElement'
|
|
149
|
-
? node
|
|
150
|
-
: node.type === 'ElementCloseTag'
|
|
151
|
-
? node.startTag
|
|
152
|
-
: null;
|
|
150
|
+
const selectorTarget = node.type === 'Element' || node.type === 'OmittedElement' ? node : null;
|
|
153
151
|
// node specs and special rules for node by selector
|
|
154
152
|
ruleset.nodeRules.forEach((nodeRule, i) => {
|
|
155
153
|
if (!nodeRule.rules) {
|
|
156
154
|
return;
|
|
157
155
|
}
|
|
156
|
+
if (!selectorTarget) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
158
159
|
const selector = nodeRule.selector || nodeRule.regexSelector || nodeRule.tagName;
|
|
159
|
-
const
|
|
160
|
+
const matches =
|
|
160
161
|
/**
|
|
161
162
|
* Forward v1.x compatibility
|
|
162
163
|
*/
|
|
163
164
|
nodeRule.tagName && /^#text$/i.test(nodeRule.tagName) && node.type === 'Text'
|
|
164
|
-
? {
|
|
165
|
+
? {
|
|
166
|
+
matched: true,
|
|
167
|
+
selector: '#text',
|
|
168
|
+
specificity: [0, 0, 0],
|
|
169
|
+
}
|
|
165
170
|
: /**
|
|
166
171
|
* v2.0.0 or later
|
|
167
172
|
*/
|
|
168
|
-
|
|
169
|
-
if (!matched) {
|
|
173
|
+
(0, match_selector_1.matchSelector)(selectorTarget, selector);
|
|
174
|
+
if (!matches.matched) {
|
|
170
175
|
return;
|
|
171
176
|
}
|
|
172
|
-
|
|
177
|
+
if (docLog.enabled) {
|
|
178
|
+
docLog('Matched nodeRule: <%s>(%s)', 'nodeName' in node ? node.nodeName : node.type, matches.selector || '*');
|
|
179
|
+
}
|
|
173
180
|
const ruleList = Object.keys(nodeRule.rules);
|
|
174
181
|
for (const ruleName of ruleList) {
|
|
175
182
|
const rule = nodeRule.rules[ruleName];
|
|
176
|
-
const convertedRule = (0, ml_config_1.exchangeValueOnRule)(rule,
|
|
183
|
+
const convertedRule = (0, ml_config_1.exchangeValueOnRule)(rule, matches.data || {});
|
|
177
184
|
if (convertedRule === undefined) {
|
|
178
185
|
continue;
|
|
179
186
|
}
|
|
@@ -182,7 +189,7 @@ class MLDOMDocument {
|
|
|
182
189
|
ruleLog('↑ nodeRule (%s): %O', ruleName, mergedRule);
|
|
183
190
|
ruleMapper.set(node, ruleName, {
|
|
184
191
|
from: 'nodeRules',
|
|
185
|
-
|
|
192
|
+
specificity: matches.specificity,
|
|
186
193
|
rule: mergedRule,
|
|
187
194
|
});
|
|
188
195
|
}
|
|
@@ -206,15 +213,17 @@ class MLDOMDocument {
|
|
|
206
213
|
if (!selector) {
|
|
207
214
|
return;
|
|
208
215
|
}
|
|
209
|
-
const
|
|
210
|
-
if (!matched) {
|
|
216
|
+
const matches = (0, match_selector_1.matchSelector)(selectorTarget, selector);
|
|
217
|
+
if (!matches.matched) {
|
|
211
218
|
return;
|
|
212
219
|
}
|
|
213
|
-
|
|
220
|
+
if (docLog.enabled) {
|
|
221
|
+
docLog('Matched childNodeRule: <%s>(%s), inheritance: %o', selectorTarget.nodeName, matches.selector || '*', !!nodeRule.inheritance);
|
|
222
|
+
}
|
|
214
223
|
const targetDescendants = nodeRule.inheritance ? descendants : children;
|
|
215
224
|
Object.keys(nodeRuleRules).forEach(ruleName => {
|
|
216
225
|
const rule = nodeRuleRules[ruleName];
|
|
217
|
-
const convertedRule = (0, ml_config_1.exchangeValueOnRule)(rule,
|
|
226
|
+
const convertedRule = (0, ml_config_1.exchangeValueOnRule)(rule, matches.data || {});
|
|
218
227
|
if (convertedRule === undefined) {
|
|
219
228
|
return;
|
|
220
229
|
}
|
|
@@ -224,7 +233,7 @@ class MLDOMDocument {
|
|
|
224
233
|
targetDescendants.forEach(descendant => {
|
|
225
234
|
ruleMapper.set(descendant, ruleName, {
|
|
226
235
|
from: 'childNodeRules',
|
|
227
|
-
|
|
236
|
+
specificity: matches.specificity,
|
|
228
237
|
rule: mergedRule,
|
|
229
238
|
});
|
|
230
239
|
});
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type MLDOMAbstractElement from '../tokens/abstract-element';
|
|
2
|
+
import type { Specificity } from './selector';
|
|
2
3
|
import type { RegexSelector } from '@markuplint/ml-config';
|
|
4
|
+
export declare type SelectorMatches = SelectorMatched | SelectorUnmatched;
|
|
5
|
+
declare type SelectorMatched = {
|
|
6
|
+
matched: true;
|
|
7
|
+
selector: string;
|
|
8
|
+
specificity: Specificity;
|
|
9
|
+
data?: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
declare type SelectorUnmatched = {
|
|
12
|
+
matched: false;
|
|
13
|
+
};
|
|
3
14
|
declare type TargetElement = MLDOMAbstractElement<any, any>;
|
|
4
|
-
export declare function matchSelector(el: TargetElement, selector: string | RegexSelector | undefined):
|
|
15
|
+
export declare function matchSelector(el: TargetElement, selector: string | RegexSelector | undefined): SelectorMatches;
|
|
5
16
|
export {};
|
|
@@ -5,12 +5,23 @@ const ml_config_1 = require("@markuplint/ml-config");
|
|
|
5
5
|
const selector_1 = require("./selector");
|
|
6
6
|
function matchSelector(el, selector) {
|
|
7
7
|
if (!selector) {
|
|
8
|
-
return
|
|
8
|
+
return {
|
|
9
|
+
matched: false,
|
|
10
|
+
};
|
|
9
11
|
}
|
|
10
12
|
if (typeof selector === 'string') {
|
|
11
13
|
const sel = (0, selector_1.createSelector)(selector);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
+
const specificity = sel.match(el);
|
|
15
|
+
if (specificity) {
|
|
16
|
+
return {
|
|
17
|
+
matched: true,
|
|
18
|
+
selector,
|
|
19
|
+
specificity,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
matched: false,
|
|
24
|
+
};
|
|
14
25
|
}
|
|
15
26
|
return regexSelect(el, selector);
|
|
16
27
|
}
|
|
@@ -36,113 +47,86 @@ class SelectorTarget {
|
|
|
36
47
|
};
|
|
37
48
|
}
|
|
38
49
|
match(el) {
|
|
39
|
-
const
|
|
40
|
-
if (!matched) {
|
|
41
|
-
return
|
|
50
|
+
const unitCheck = this._matchWithoutCombinateChecking(el);
|
|
51
|
+
if (!unitCheck.matched) {
|
|
52
|
+
return unitCheck;
|
|
42
53
|
}
|
|
43
54
|
if (!this._combinatedFrom) {
|
|
44
|
-
return
|
|
55
|
+
return unitCheck;
|
|
45
56
|
}
|
|
46
57
|
const { target, combinator } = this._combinatedFrom;
|
|
47
58
|
switch (combinator) {
|
|
48
59
|
// Descendant combinator
|
|
49
60
|
case ' ': {
|
|
50
|
-
let ancestor = el.
|
|
61
|
+
let ancestor = el.getParentElement();
|
|
51
62
|
while (ancestor) {
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
...ancestorMatched,
|
|
56
|
-
...matched,
|
|
57
|
-
__node: `${ancestorMatched.__node} ${matched.__node}`,
|
|
58
|
-
};
|
|
59
|
-
return res;
|
|
63
|
+
const matches = target.match(ancestor);
|
|
64
|
+
if (matches.matched) {
|
|
65
|
+
return mergeMatches(matches, unitCheck, ' ');
|
|
60
66
|
}
|
|
61
|
-
ancestor = ancestor.
|
|
67
|
+
ancestor = ancestor.getParentElement();
|
|
62
68
|
}
|
|
63
|
-
return
|
|
69
|
+
return {
|
|
70
|
+
matched: false,
|
|
71
|
+
};
|
|
64
72
|
}
|
|
65
73
|
// Child combinator
|
|
66
74
|
case '>': {
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
const parentNode = el.getParentElement();
|
|
76
|
+
if (!parentNode) {
|
|
77
|
+
return { matched: false };
|
|
69
78
|
}
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
...parentMatched,
|
|
74
|
-
...matched,
|
|
75
|
-
__node: `${parentMatched.__node} > ${matched.__node}`,
|
|
76
|
-
};
|
|
77
|
-
return res;
|
|
79
|
+
const matches = target.match(parentNode);
|
|
80
|
+
if (matches.matched) {
|
|
81
|
+
return mergeMatches(matches, unitCheck, ' > ');
|
|
78
82
|
}
|
|
79
|
-
return
|
|
83
|
+
return { matched: false };
|
|
80
84
|
}
|
|
81
85
|
// Next-sibling combinator
|
|
82
86
|
case '+': {
|
|
83
87
|
if (!el.previousElementSibling) {
|
|
84
|
-
return
|
|
88
|
+
return { matched: false };
|
|
85
89
|
}
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
...prevMatched,
|
|
90
|
-
...matched,
|
|
91
|
-
__node: `${prevMatched.__node} + ${matched.__node}`,
|
|
92
|
-
};
|
|
93
|
-
return res;
|
|
90
|
+
const matches = target.match(el.previousElementSibling);
|
|
91
|
+
if (matches.matched) {
|
|
92
|
+
return mergeMatches(matches, unitCheck, ' + ');
|
|
94
93
|
}
|
|
95
|
-
return
|
|
94
|
+
return { matched: false };
|
|
96
95
|
}
|
|
97
96
|
// Subsequent-sibling combinator
|
|
98
97
|
case '~': {
|
|
99
98
|
let prev = el.previousElementSibling;
|
|
100
99
|
while (prev) {
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
...prevMatched,
|
|
105
|
-
...matched,
|
|
106
|
-
__node: `${prevMatched.__node} ~ ${matched.__node}`,
|
|
107
|
-
};
|
|
108
|
-
return res;
|
|
100
|
+
const matches = target.match(prev);
|
|
101
|
+
if (matches.matched) {
|
|
102
|
+
return mergeMatches(matches, unitCheck, ' ~ ');
|
|
109
103
|
}
|
|
110
104
|
prev = prev.previousElementSibling;
|
|
111
105
|
}
|
|
112
|
-
return
|
|
106
|
+
return { matched: false };
|
|
113
107
|
}
|
|
114
108
|
// Prev-sibling combinator
|
|
115
109
|
case ':has(+)': {
|
|
116
110
|
if (!el.nextElementSibling) {
|
|
117
|
-
return
|
|
111
|
+
return { matched: false };
|
|
118
112
|
}
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
...nextMatched,
|
|
123
|
-
...matched,
|
|
124
|
-
__node: `${nextMatched.__node}:has(+ ${matched.__node})`,
|
|
125
|
-
};
|
|
126
|
-
return res;
|
|
113
|
+
const matches = target.match(el.nextElementSibling);
|
|
114
|
+
if (matches.matched) {
|
|
115
|
+
return mergeMatches(matches, unitCheck, ':has(+ ', true);
|
|
127
116
|
}
|
|
128
|
-
return
|
|
117
|
+
return { matched: false };
|
|
129
118
|
}
|
|
130
119
|
// Subsequent-sibling (in front) combinator
|
|
131
120
|
case ':has(~)': {
|
|
132
121
|
let next = el.nextElementSibling;
|
|
133
122
|
while (next) {
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
...nextMatched,
|
|
138
|
-
...matched,
|
|
139
|
-
__node: `${nextMatched.__node}:has(~ ${matched.__node})`,
|
|
140
|
-
};
|
|
141
|
-
return res;
|
|
123
|
+
const matches = target.match(next);
|
|
124
|
+
if (matches.matched) {
|
|
125
|
+
return mergeMatches(matches, unitCheck, ':has(~ ', true);
|
|
142
126
|
}
|
|
143
127
|
next = next.nextElementSibling;
|
|
144
128
|
}
|
|
145
|
-
return
|
|
129
|
+
return { matched: false };
|
|
146
130
|
}
|
|
147
131
|
default: {
|
|
148
132
|
throw new Error(`Unsupported ${this._combinatedFrom.combinator} combinator in selector`);
|
|
@@ -157,18 +141,25 @@ class SelectorTarget {
|
|
|
157
141
|
}
|
|
158
142
|
}
|
|
159
143
|
function uncombinatedRegexSelect(el, selector) {
|
|
160
|
-
let
|
|
144
|
+
let matched = true;
|
|
145
|
+
let data = {};
|
|
146
|
+
let tagSelector = '';
|
|
147
|
+
const specificity = [0, 0, 0];
|
|
148
|
+
const specifiedAttr = new Map();
|
|
161
149
|
if (selector.nodeName) {
|
|
162
150
|
const matchedNodeName = (0, ml_config_1.regexSelectorMatches)(selector.nodeName, el.nodeName);
|
|
163
|
-
if (
|
|
164
|
-
|
|
151
|
+
if (matchedNodeName) {
|
|
152
|
+
delete matchedNodeName.$0;
|
|
165
153
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
154
|
+
else {
|
|
155
|
+
matched = false;
|
|
156
|
+
}
|
|
157
|
+
data = {
|
|
158
|
+
...data,
|
|
169
159
|
...matchedNodeName,
|
|
170
|
-
__node: el.nodeName,
|
|
171
160
|
};
|
|
161
|
+
tagSelector = el.nodeName;
|
|
162
|
+
specificity[2] = 1;
|
|
172
163
|
}
|
|
173
164
|
if (selector.attrName) {
|
|
174
165
|
const selectorAttrName = selector.attrName;
|
|
@@ -177,16 +168,16 @@ function uncombinatedRegexSelect(el, selector) {
|
|
|
177
168
|
const matchedAttrName = (0, ml_config_1.regexSelectorMatches)(selectorAttrName, attrName);
|
|
178
169
|
if (matchedAttrName) {
|
|
179
170
|
delete matchedAttrName.$0;
|
|
180
|
-
|
|
181
|
-
...
|
|
171
|
+
data = {
|
|
172
|
+
...data,
|
|
182
173
|
...matchedAttrName,
|
|
183
|
-
__node: matchedMap.__node ? `${matchedMap.__node}[${attrName}]` : `[${attrName}]`,
|
|
184
174
|
};
|
|
175
|
+
specifiedAttr.set(attrName, '');
|
|
185
176
|
}
|
|
186
177
|
return matchedAttrName;
|
|
187
178
|
});
|
|
188
179
|
if (!matchedAttrNameList.some(_ => !!_)) {
|
|
189
|
-
|
|
180
|
+
matched = false;
|
|
190
181
|
}
|
|
191
182
|
}
|
|
192
183
|
if (selector.attrValue) {
|
|
@@ -197,19 +188,46 @@ function uncombinatedRegexSelect(el, selector) {
|
|
|
197
188
|
const matchedAttrValue = (0, ml_config_1.regexSelectorMatches)(selectorAttrValue, attrValue);
|
|
198
189
|
if (matchedAttrValue) {
|
|
199
190
|
delete matchedAttrValue.$0;
|
|
200
|
-
|
|
201
|
-
...
|
|
191
|
+
data = {
|
|
192
|
+
...data,
|
|
202
193
|
...matchedAttrValue,
|
|
203
|
-
__node: matchedMap.__node
|
|
204
|
-
? `${matchedMap.__node}[${attrName}="${attrValue}"]`
|
|
205
|
-
: `[${attrName}="${attrValue}"]`,
|
|
206
194
|
};
|
|
195
|
+
specifiedAttr.set(attrName, attrValue);
|
|
207
196
|
}
|
|
208
197
|
return matchedAttrValue;
|
|
209
198
|
});
|
|
210
199
|
if (!matchedAttrValueList.some(_ => !!_)) {
|
|
211
|
-
|
|
200
|
+
matched = false;
|
|
212
201
|
}
|
|
213
202
|
}
|
|
214
|
-
|
|
203
|
+
const attrSelector = Array.from(specifiedAttr.entries())
|
|
204
|
+
.map(([name, value]) => {
|
|
205
|
+
return `[${name}${value ? `="${value}"` : ''}]`;
|
|
206
|
+
})
|
|
207
|
+
.join('');
|
|
208
|
+
specificity[1] += specifiedAttr.size;
|
|
209
|
+
if (matched) {
|
|
210
|
+
return {
|
|
211
|
+
matched,
|
|
212
|
+
selector: `${tagSelector}${attrSelector}`,
|
|
213
|
+
specificity,
|
|
214
|
+
data,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return { matched };
|
|
218
|
+
}
|
|
219
|
+
function mergeMatches(a, b, sep, close = false) {
|
|
220
|
+
return {
|
|
221
|
+
matched: true,
|
|
222
|
+
selector: `${a.selector}${sep}${b.selector}${close ? ')' : ''}`,
|
|
223
|
+
specificity: [
|
|
224
|
+
a.specificity[0] + b.specificity[0],
|
|
225
|
+
a.specificity[1] + b.specificity[1],
|
|
226
|
+
a.specificity[2] + b.specificity[2],
|
|
227
|
+
],
|
|
228
|
+
data: {
|
|
229
|
+
...a.data,
|
|
230
|
+
...b.data,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
215
233
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type MLDOMAbstractElement from '../tokens/abstract-element';
|
|
2
|
+
export declare type Specificity = [number, number, number];
|
|
2
3
|
export declare function createSelector(selector: string): Selector;
|
|
4
|
+
export declare function compareSpecificity(a: Specificity, b: Specificity): 0 | 1 | -1;
|
|
3
5
|
declare type TargetElement = MLDOMAbstractElement<any, any>;
|
|
4
6
|
declare class Selector {
|
|
5
7
|
#private;
|
|
6
8
|
constructor(selector: string);
|
|
7
|
-
match(el: TargetElement, caller?: TargetElement | null):
|
|
9
|
+
match(el: TargetElement, caller?: TargetElement | null): Specificity | false;
|
|
8
10
|
}
|
|
9
11
|
export {};
|