@markuplint/selector 3.0.0-canary.2421 → 3.0.0-dev.177
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/README.md +1 -1
- package/lib/extended-selector/aria-pseudo-class.js +8 -3
- package/lib/extended-selector/aria-role-pseudo-class.js +10 -4
- package/lib/extended-selector/content-model-pseudo-class.js +4 -2
- package/lib/invalid-selector-error.d.ts +1 -1
- package/lib/is.js +9 -3
- package/lib/match-selector.d.ts +5 -5
- package/lib/match-selector.js +17 -7
- package/lib/regex-selector-matches.d.ts +6 -2
- package/lib/regex-selector-matches.js +1 -1
- package/lib/selector.d.ts +5 -5
- package/lib/selector.js +89 -36
- package/lib/types.d.ts +14 -14
- package/package.json +12 -8
- package/test/create-selector.spec.js +44 -0
- package/test/match-selector.spec.js +342 -0
- package/test/regex-selector-matches.spec.js +16 -0
- package/test/selector.spec.js +284 -0
- package/tsconfig.test.json +0 -3
- package/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ For example, `:role(interactive)` matches `<a>`(with `href` attr), `<button>`, a
|
|
|
118
118
|
<details>
|
|
119
119
|
<summary>If you are installing purposely, how below:</summary>
|
|
120
120
|
|
|
121
|
-
```
|
|
121
|
+
```shell
|
|
122
122
|
$ npm install @markuplint/selector
|
|
123
123
|
|
|
124
124
|
$ yarn add @markuplint/selector
|
|
@@ -6,7 +6,9 @@ const ml_spec_1 = require("@markuplint/ml-spec");
|
|
|
6
6
|
* Version Syntax is not support yet.
|
|
7
7
|
*/
|
|
8
8
|
function ariaPseudoClass() {
|
|
9
|
-
return (content) => (
|
|
9
|
+
return (content) => (
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
11
|
+
el) => {
|
|
10
12
|
const aria = ariaPseudoClassParser(content);
|
|
11
13
|
const name = (0, ml_spec_1.getAccname)(el);
|
|
12
14
|
switch (aria.type) {
|
|
@@ -44,8 +46,11 @@ function ariaPseudoClass() {
|
|
|
44
46
|
exports.ariaPseudoClass = ariaPseudoClass;
|
|
45
47
|
function ariaPseudoClassParser(syntax) {
|
|
46
48
|
const [_query, _version] = syntax.split('|');
|
|
47
|
-
const query = _query.replace(/\s+/g, '').toLowerCase();
|
|
48
|
-
const version = _version
|
|
49
|
+
const query = _query === null || _query === void 0 ? void 0 : _query.replace(/\s+/g, '').toLowerCase();
|
|
50
|
+
const version = _version !== null && _version !== void 0 ? _version : ml_spec_1.ARIA_RECOMMENDED_VERSION;
|
|
51
|
+
if (!(0, ml_spec_1.validateAriaVersion)(version)) {
|
|
52
|
+
throw new SyntaxError(`Unsupported ARIA version: ${version}`);
|
|
53
|
+
}
|
|
49
54
|
switch (query) {
|
|
50
55
|
case 'hasname': {
|
|
51
56
|
return {
|
|
@@ -3,10 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ariaRolePseudoClass = void 0;
|
|
4
4
|
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
5
|
function ariaRolePseudoClass(specs) {
|
|
6
|
-
return (content) => (
|
|
6
|
+
return (content) => (
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
8
|
+
el) => {
|
|
7
9
|
var _a, _b;
|
|
8
10
|
const aria = ariaPseudoClassParser(content);
|
|
9
|
-
const computed = (0, ml_spec_1.getComputedRole)(specs, el, (_a = aria.version) !== null && _a !== void 0 ? _a :
|
|
11
|
+
const computed = (0, ml_spec_1.getComputedRole)(specs, el, (_a = aria.version) !== null && _a !== void 0 ? _a : ml_spec_1.ARIA_RECOMMENDED_VERSION);
|
|
10
12
|
if (((_b = computed.role) === null || _b === void 0 ? void 0 : _b.name) === aria.role) {
|
|
11
13
|
return {
|
|
12
14
|
specificity: [0, 1, 0],
|
|
@@ -23,10 +25,14 @@ function ariaRolePseudoClass(specs) {
|
|
|
23
25
|
}
|
|
24
26
|
exports.ariaRolePseudoClass = ariaRolePseudoClass;
|
|
25
27
|
function ariaPseudoClassParser(syntax) {
|
|
28
|
+
var _a;
|
|
26
29
|
const [roleName, _version] = syntax.split('|');
|
|
27
|
-
const version = _version
|
|
30
|
+
const version = _version !== null && _version !== void 0 ? _version : ml_spec_1.ARIA_RECOMMENDED_VERSION;
|
|
31
|
+
if (!(0, ml_spec_1.validateAriaVersion)(version)) {
|
|
32
|
+
throw new SyntaxError(`Unsupported ARIA version: ${version}`);
|
|
33
|
+
}
|
|
28
34
|
return {
|
|
29
|
-
role: roleName.trim().toLowerCase(),
|
|
35
|
+
role: (_a = roleName === null || roleName === void 0 ? void 0 : roleName.trim().toLowerCase()) !== null && _a !== void 0 ? _a : syntax.trim().toLowerCase(),
|
|
30
36
|
version,
|
|
31
37
|
};
|
|
32
38
|
}
|
|
@@ -4,7 +4,9 @@ exports.contentModelPseudoClass = void 0;
|
|
|
4
4
|
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
5
|
const create_selector_1 = require("../create-selector");
|
|
6
6
|
function contentModelPseudoClass(specs) {
|
|
7
|
-
return (category) => (
|
|
7
|
+
return (category) => (
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
9
|
+
el) => {
|
|
8
10
|
category = category.trim().toLowerCase();
|
|
9
11
|
const selectors = (0, ml_spec_1.contentModelCategoryToTagNames)(`#${category}`, specs.def);
|
|
10
12
|
const matched = selectors
|
|
@@ -40,7 +42,7 @@ function contentModelPseudoClass(specs) {
|
|
|
40
42
|
})
|
|
41
43
|
.flat()
|
|
42
44
|
.filter((m) => m.matched);
|
|
43
|
-
if (matched.length) {
|
|
45
|
+
if (matched.length > 0) {
|
|
44
46
|
return {
|
|
45
47
|
specificity: [0, 1, 0],
|
|
46
48
|
matched: true,
|
package/lib/is.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isPureHTMLElement = exports.isNonDocumentTypeChildNode = exports.isElement = void 0;
|
|
4
|
-
function isElement(
|
|
4
|
+
function isElement(
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
6
|
+
node) {
|
|
5
7
|
return node.nodeType === node.ELEMENT_NODE;
|
|
6
8
|
}
|
|
7
9
|
exports.isElement = isElement;
|
|
8
|
-
function isNonDocumentTypeChildNode(
|
|
10
|
+
function isNonDocumentTypeChildNode(
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
12
|
+
node) {
|
|
9
13
|
return 'previousElementSibling' in node && 'nextElementSibling' in node;
|
|
10
14
|
}
|
|
11
15
|
exports.isNonDocumentTypeChildNode = isNonDocumentTypeChildNode;
|
|
12
|
-
function isPureHTMLElement(
|
|
16
|
+
function isPureHTMLElement(
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
18
|
+
el) {
|
|
13
19
|
return el.localName !== el.nodeName;
|
|
14
20
|
}
|
|
15
21
|
exports.isPureHTMLElement = isPureHTMLElement;
|
package/lib/match-selector.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Specificity, RegexSelector } from './types';
|
|
2
2
|
export type SelectorMatches = SelectorMatched | SelectorUnmatched;
|
|
3
3
|
type SelectorMatched = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
readonly matched: true;
|
|
5
|
+
readonly selector: string;
|
|
6
|
+
readonly specificity: Specificity;
|
|
7
|
+
readonly data?: Readonly<Record<string, string>>;
|
|
8
8
|
};
|
|
9
9
|
type SelectorUnmatched = {
|
|
10
|
-
|
|
10
|
+
readonly matched: false;
|
|
11
11
|
};
|
|
12
12
|
export declare function matchSelector(el: Node, selector: string | RegexSelector | undefined): SelectorMatches;
|
|
13
13
|
export {};
|
package/lib/match-selector.js
CHANGED
|
@@ -6,8 +6,10 @@ const tslib_1 = require("tslib");
|
|
|
6
6
|
const is_1 = require("./is");
|
|
7
7
|
const regex_selector_matches_1 = require("./regex-selector-matches");
|
|
8
8
|
const selector_1 = require("./selector");
|
|
9
|
-
function matchSelector(
|
|
10
|
-
|
|
9
|
+
function matchSelector(
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
11
|
+
el, selector) {
|
|
12
|
+
if (selector == null || selector === '') {
|
|
11
13
|
return {
|
|
12
14
|
matched: false,
|
|
13
15
|
};
|
|
@@ -15,7 +17,7 @@ function matchSelector(el, selector) {
|
|
|
15
17
|
if (typeof selector === 'string') {
|
|
16
18
|
const sel = new selector_1.Selector(selector);
|
|
17
19
|
const specificity = sel.match(el);
|
|
18
|
-
if (specificity) {
|
|
20
|
+
if (specificity !== false) {
|
|
19
21
|
return {
|
|
20
22
|
matched: true,
|
|
21
23
|
selector,
|
|
@@ -29,7 +31,9 @@ function matchSelector(el, selector) {
|
|
|
29
31
|
return regexSelect(el, selector);
|
|
30
32
|
}
|
|
31
33
|
exports.matchSelector = matchSelector;
|
|
32
|
-
function regexSelect(
|
|
34
|
+
function regexSelect(
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
36
|
+
el, selector) {
|
|
33
37
|
let edge = new SelectorTarget(selector);
|
|
34
38
|
let edgeSelector = selector.combination;
|
|
35
39
|
while (edgeSelector) {
|
|
@@ -49,7 +53,9 @@ class SelectorTarget {
|
|
|
49
53
|
from(target, combinator) {
|
|
50
54
|
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_combinedFrom, { target, combinator }, "f");
|
|
51
55
|
}
|
|
52
|
-
match(
|
|
56
|
+
match(
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
58
|
+
el) {
|
|
53
59
|
const unitCheck = this._matchWithoutCombineChecking(el);
|
|
54
60
|
if (!unitCheck.matched) {
|
|
55
61
|
return unitCheck;
|
|
@@ -139,12 +145,16 @@ class SelectorTarget {
|
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
|
-
_matchWithoutCombineChecking(
|
|
148
|
+
_matchWithoutCombineChecking(
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
150
|
+
el) {
|
|
143
151
|
return uncombinedRegexSelect(el, tslib_1.__classPrivateFieldGet(this, _SelectorTarget_selector, "f"));
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
154
|
_SelectorTarget_combinedFrom = new WeakMap(), _SelectorTarget_selector = new WeakMap();
|
|
147
|
-
function uncombinedRegexSelect(
|
|
155
|
+
function uncombinedRegexSelect(
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
157
|
+
el, selector) {
|
|
148
158
|
if (!(0, is_1.isElement)(el)) {
|
|
149
159
|
return {
|
|
150
160
|
matched: false,
|
|
@@ -18,7 +18,7 @@ function regexSelectorMatches(reg, raw, ignoreCase) {
|
|
|
18
18
|
exports.regexSelectorMatches = regexSelectorMatches;
|
|
19
19
|
function toRegexp(pattern) {
|
|
20
20
|
const matched = pattern.match(/^\/(.+)\/([ig]*)$/i);
|
|
21
|
-
if (matched) {
|
|
21
|
+
if (matched && matched[1]) {
|
|
22
22
|
return new RegExp(matched[1], matched[2]);
|
|
23
23
|
}
|
|
24
24
|
return pattern;
|
package/lib/selector.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { SelectorResult, Specificity } from './types';
|
|
2
|
-
type ExtendedPseudoClass = Record<string, (content: string) => (el: Element) => SelectorResult
|
|
2
|
+
type ExtendedPseudoClass = Readonly<Record<string, (content: string) => (el: Element) => SelectorResult>>;
|
|
3
3
|
export declare class Selector {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
#private;
|
|
5
|
+
constructor(selector: string, extended?: ExtendedPseudoClass);
|
|
6
|
+
match(el: Node, scope?: ParentNode | null): Specificity | false;
|
|
7
|
+
search(el: Node, scope?: ParentNode | null): SelectorResult[];
|
|
8
8
|
}
|
|
9
9
|
export {};
|
package/lib/selector.js
CHANGED
|
@@ -16,7 +16,12 @@ class Selector {
|
|
|
16
16
|
_Selector_ruleset.set(this, void 0);
|
|
17
17
|
tslib_1.__classPrivateFieldSet(this, _Selector_ruleset, Ruleset.parse(selector, extended), "f");
|
|
18
18
|
}
|
|
19
|
-
match(
|
|
19
|
+
match(
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
21
|
+
el,
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
23
|
+
scope) {
|
|
24
|
+
scope = (0, is_1.isElement)(el) ? el : null;
|
|
20
25
|
const results = this.search(el, scope);
|
|
21
26
|
for (const result of results) {
|
|
22
27
|
if (result.matched) {
|
|
@@ -25,7 +30,12 @@ class Selector {
|
|
|
25
30
|
}
|
|
26
31
|
return false;
|
|
27
32
|
}
|
|
28
|
-
search(
|
|
33
|
+
search(
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
35
|
+
el,
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
37
|
+
scope) {
|
|
38
|
+
scope = (0, is_1.isElement)(el) ? el : null;
|
|
29
39
|
return tslib_1.__classPrivateFieldGet(this, _Selector_ruleset, "f").match(el, scope);
|
|
30
40
|
}
|
|
31
41
|
}
|
|
@@ -48,17 +58,22 @@ class Ruleset {
|
|
|
48
58
|
return new Ruleset(selectors, extended, 0);
|
|
49
59
|
}
|
|
50
60
|
constructor(selectors, extended, depth) {
|
|
61
|
+
var _a, _b;
|
|
51
62
|
_Ruleset_selectorGroup.set(this, []);
|
|
52
63
|
tslib_1.__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector, depth, extended)));
|
|
53
64
|
const head = tslib_1.__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0];
|
|
54
|
-
this.headCombinator = (head === null || head === void 0 ? void 0 : head.headCombinator)
|
|
65
|
+
this.headCombinator = (_a = head === null || head === void 0 ? void 0 : head.headCombinator) !== null && _a !== void 0 ? _a : null;
|
|
55
66
|
if (this.headCombinator) {
|
|
56
67
|
if (depth <= 0) {
|
|
57
|
-
throw new invalid_selector_error_1.InvalidSelectorError(`'${tslib_1.__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0].selector}' is not a valid selector`);
|
|
68
|
+
throw new invalid_selector_error_1.InvalidSelectorError(`'${(_b = tslib_1.__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0]) === null || _b === void 0 ? void 0 : _b.selector}' is not a valid selector`);
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
71
|
}
|
|
61
|
-
match(
|
|
72
|
+
match(
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
74
|
+
el,
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
76
|
+
scope) {
|
|
62
77
|
(0, debug_1.log)('<%s> (%s)', (0, is_1.isElement)(el) ? el.localName : el.nodeName, scope ? ((0, is_1.isElement)(scope) ? scope.localName : scope.nodeName) : null);
|
|
63
78
|
return tslib_1.__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f").map(selector => {
|
|
64
79
|
selLog('"%s"', selector.selector);
|
|
@@ -71,16 +86,18 @@ class Ruleset {
|
|
|
71
86
|
_Ruleset_selectorGroup = new WeakMap();
|
|
72
87
|
class StructuredSelector {
|
|
73
88
|
constructor(selector, depth, extended) {
|
|
89
|
+
var _a, _b;
|
|
74
90
|
_StructuredSelector_edge.set(this, void 0);
|
|
75
91
|
_StructuredSelector_selector.set(this, void 0);
|
|
76
92
|
tslib_1.__classPrivateFieldSet(this, _StructuredSelector_selector, selector, "f");
|
|
77
93
|
tslib_1.__classPrivateFieldSet(this, _StructuredSelector_edge, new SelectorTarget(extended, depth), "f");
|
|
78
94
|
this.headCombinator =
|
|
79
|
-
tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0].type === 'combinator' ? tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0].value
|
|
95
|
+
((_a = tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0]) === null || _a === void 0 ? void 0 : _a.type) === 'combinator' ? (_b = tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0].value) !== null && _b !== void 0 ? _b : null : null;
|
|
96
|
+
const nodes = tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes.slice();
|
|
80
97
|
if (0 < depth && this.headCombinator) {
|
|
81
|
-
|
|
98
|
+
nodes.unshift((0, postcss_selector_parser_1.pseudo)({ value: ':scope' }));
|
|
82
99
|
}
|
|
83
|
-
|
|
100
|
+
nodes.forEach(node => {
|
|
84
101
|
switch (node.type) {
|
|
85
102
|
case 'combinator': {
|
|
86
103
|
const combinedTarget = new SelectorTarget(extended, depth);
|
|
@@ -107,7 +124,11 @@ class StructuredSelector {
|
|
|
107
124
|
get selector() {
|
|
108
125
|
return tslib_1.__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes.join('');
|
|
109
126
|
}
|
|
110
|
-
match(
|
|
127
|
+
match(
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
129
|
+
el,
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
131
|
+
scope) {
|
|
111
132
|
return tslib_1.__classPrivateFieldGet(this, _StructuredSelector_edge, "f").match(el, scope, 0);
|
|
112
133
|
}
|
|
113
134
|
}
|
|
@@ -154,16 +175,20 @@ class SelectorTarget {
|
|
|
154
175
|
from(target, combinator) {
|
|
155
176
|
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_combinedFrom, { target, combinator }, "f");
|
|
156
177
|
}
|
|
157
|
-
match(
|
|
158
|
-
|
|
178
|
+
match(
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
180
|
+
el,
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
182
|
+
scope, count) {
|
|
183
|
+
var _a, _b, _c;
|
|
159
184
|
const result = this._match(el, scope, count);
|
|
160
185
|
if (selLog.enabled) {
|
|
161
186
|
const nodeName = el.nodeName;
|
|
162
|
-
const selector = ((_a = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f")) === null || _a === void 0 ? void 0 : _a.target.toString())
|
|
187
|
+
const selector = (_b = (_a = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f")) === null || _a === void 0 ? void 0 : _a.target.toString()) !== null && _b !== void 0 ? _b : this.toString();
|
|
163
188
|
const combinator = result.combinator ? ` ${result.combinator}` : '';
|
|
164
189
|
selLog('The %s element by "%s" => %s (%d)', nodeName, `${selector}${combinator}`, result.matched, count);
|
|
165
190
|
if (selector === ':scope') {
|
|
166
|
-
selLog(`† Scope is the ${(scope === null || scope === void 0 ? void 0 : scope.nodeName)
|
|
191
|
+
selLog(`† Scope is the ${(_c = scope === null || scope === void 0 ? void 0 : scope.nodeName) !== null && _c !== void 0 ? _c : null}`);
|
|
167
192
|
}
|
|
168
193
|
}
|
|
169
194
|
delete result.combinator;
|
|
@@ -179,7 +204,11 @@ class SelectorTarget {
|
|
|
179
204
|
this.pseudo.map(pseudo => pseudo.value).join(''),
|
|
180
205
|
].join('');
|
|
181
206
|
}
|
|
182
|
-
_match(
|
|
207
|
+
_match(
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
209
|
+
el,
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
211
|
+
scope, count) {
|
|
183
212
|
const unitCheck = this._matchWithoutCombineChecking(el, scope);
|
|
184
213
|
if (!unitCheck.matched) {
|
|
185
214
|
return unitCheck;
|
|
@@ -227,7 +256,7 @@ class SelectorTarget {
|
|
|
227
256
|
unitCheck.specificity[2] + res.specificity[2],
|
|
228
257
|
];
|
|
229
258
|
}
|
|
230
|
-
if (matchedNodes.length) {
|
|
259
|
+
if (matchedNodes.length > 0) {
|
|
231
260
|
return {
|
|
232
261
|
combinator: '␣',
|
|
233
262
|
specificity,
|
|
@@ -248,7 +277,7 @@ class SelectorTarget {
|
|
|
248
277
|
const matchedNodes = [];
|
|
249
278
|
const has = [];
|
|
250
279
|
const not = [];
|
|
251
|
-
const specificity = unitCheck.specificity;
|
|
280
|
+
const specificity = [...unitCheck.specificity];
|
|
252
281
|
const parentNode = el.parentElement;
|
|
253
282
|
if (parentNode) {
|
|
254
283
|
const res = target.match(parentNode, scope, count + 1);
|
|
@@ -271,7 +300,7 @@ class SelectorTarget {
|
|
|
271
300
|
specificity[1] += res.specificity[1];
|
|
272
301
|
specificity[2] += res.specificity[2];
|
|
273
302
|
}
|
|
274
|
-
if (matchedNodes.length) {
|
|
303
|
+
if (matchedNodes.length > 0) {
|
|
275
304
|
return {
|
|
276
305
|
combinator: '>',
|
|
277
306
|
specificity,
|
|
@@ -292,7 +321,7 @@ class SelectorTarget {
|
|
|
292
321
|
const matchedNodes = [];
|
|
293
322
|
const has = [];
|
|
294
323
|
const not = [];
|
|
295
|
-
const specificity = unitCheck.specificity;
|
|
324
|
+
const specificity = [...unitCheck.specificity];
|
|
296
325
|
if (el.previousElementSibling) {
|
|
297
326
|
const res = target.match(el.previousElementSibling, scope, count + 1);
|
|
298
327
|
specificity[0] += res.specificity[0];
|
|
@@ -314,7 +343,7 @@ class SelectorTarget {
|
|
|
314
343
|
specificity[1] += res.specificity[1];
|
|
315
344
|
specificity[2] += res.specificity[2];
|
|
316
345
|
}
|
|
317
|
-
if (matchedNodes.length) {
|
|
346
|
+
if (matchedNodes.length > 0) {
|
|
318
347
|
return {
|
|
319
348
|
combinator: '+',
|
|
320
349
|
specificity,
|
|
@@ -365,7 +394,7 @@ class SelectorTarget {
|
|
|
365
394
|
unitCheck.specificity[2] + res.specificity[2],
|
|
366
395
|
];
|
|
367
396
|
}
|
|
368
|
-
if (matchedNodes.length) {
|
|
397
|
+
if (matchedNodes.length > 0) {
|
|
369
398
|
return {
|
|
370
399
|
combinator: '~',
|
|
371
400
|
specificity,
|
|
@@ -390,7 +419,11 @@ class SelectorTarget {
|
|
|
390
419
|
}
|
|
391
420
|
}
|
|
392
421
|
}
|
|
393
|
-
_matchWithoutCombineChecking(
|
|
422
|
+
_matchWithoutCombineChecking(
|
|
423
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
424
|
+
el,
|
|
425
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
426
|
+
scope) {
|
|
394
427
|
var _a;
|
|
395
428
|
const specificity = [0, 0, 0];
|
|
396
429
|
if (!(0, is_1.isElement)(el)) {
|
|
@@ -481,7 +514,9 @@ class SelectorTarget {
|
|
|
481
514
|
}
|
|
482
515
|
}
|
|
483
516
|
_SelectorTarget_combinedFrom = new WeakMap(), _SelectorTarget_extended = new WeakMap(), _SelectorTarget_isAdded = new WeakMap();
|
|
484
|
-
function attrMatch(attr,
|
|
517
|
+
function attrMatch(attr,
|
|
518
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
519
|
+
el) {
|
|
485
520
|
return Array.from(el.attributes).some(attrOfEl => {
|
|
486
521
|
if (attr.attribute !== attrOfEl.localName) {
|
|
487
522
|
return false;
|
|
@@ -519,7 +554,7 @@ function attrMatch(attr, el) {
|
|
|
519
554
|
break;
|
|
520
555
|
}
|
|
521
556
|
case '*=': {
|
|
522
|
-
if (valueOfEl.
|
|
557
|
+
if (!valueOfEl.includes(value)) {
|
|
523
558
|
return false;
|
|
524
559
|
}
|
|
525
560
|
break;
|
|
@@ -541,7 +576,11 @@ function attrMatch(attr, el) {
|
|
|
541
576
|
return true;
|
|
542
577
|
});
|
|
543
578
|
}
|
|
544
|
-
function pseudoMatch(pseudo,
|
|
579
|
+
function pseudoMatch(pseudo,
|
|
580
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
581
|
+
el,
|
|
582
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
583
|
+
scope, extended, depth) {
|
|
545
584
|
switch (pseudo.value) {
|
|
546
585
|
//
|
|
547
586
|
/**
|
|
@@ -553,7 +592,7 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
553
592
|
let parent = el.parentElement;
|
|
554
593
|
while (parent) {
|
|
555
594
|
const matched = ruleset.match(parent, scope).filter((r) => r.matched);
|
|
556
|
-
if (matched.length) {
|
|
595
|
+
if (matched.length > 0) {
|
|
557
596
|
return {
|
|
558
597
|
specificity,
|
|
559
598
|
matched: true,
|
|
@@ -597,7 +636,7 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
597
636
|
const matched = resList.filter((r) => r.matched);
|
|
598
637
|
return {
|
|
599
638
|
specificity,
|
|
600
|
-
matched:
|
|
639
|
+
matched: matched.length > 0,
|
|
601
640
|
nodes: matched.map(m => m.nodes).flat(),
|
|
602
641
|
has: matched.map(m => m.has).flat(),
|
|
603
642
|
};
|
|
@@ -611,7 +650,7 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
611
650
|
const has = getSiblings(el)
|
|
612
651
|
.map(sib => ruleset.match(sib, el).filter((m) => m.matched))
|
|
613
652
|
.flat();
|
|
614
|
-
if (has.length) {
|
|
653
|
+
if (has.length > 0) {
|
|
615
654
|
return {
|
|
616
655
|
specificity,
|
|
617
656
|
matched: true,
|
|
@@ -628,7 +667,7 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
628
667
|
const has = getDescendants(el)
|
|
629
668
|
.map(sib => ruleset.match(sib, el).filter((m) => m.matched))
|
|
630
669
|
.flat();
|
|
631
|
-
if (has.length) {
|
|
670
|
+
if (has.length > 0) {
|
|
632
671
|
return {
|
|
633
672
|
specificity,
|
|
634
673
|
matched: true,
|
|
@@ -649,7 +688,7 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
649
688
|
const matched = resList.filter((r) => r.matched);
|
|
650
689
|
return {
|
|
651
690
|
specificity: [0, 0, 0],
|
|
652
|
-
matched:
|
|
691
|
+
matched: matched.length > 0,
|
|
653
692
|
nodes: matched.map(m => m.nodes).flat(),
|
|
654
693
|
has: matched.map(m => m.has).flat(),
|
|
655
694
|
};
|
|
@@ -738,6 +777,9 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
738
777
|
}
|
|
739
778
|
const content = pseudo.nodes.map(node => node.toString()).join('');
|
|
740
779
|
const hook = extended[ext];
|
|
780
|
+
if (!hook) {
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
741
783
|
const matcher = hook(content);
|
|
742
784
|
return matcher(el);
|
|
743
785
|
}
|
|
@@ -745,10 +787,17 @@ function pseudoMatch(pseudo, el, scope, extended, depth) {
|
|
|
745
787
|
}
|
|
746
788
|
}
|
|
747
789
|
}
|
|
748
|
-
function isScope(
|
|
749
|
-
|
|
790
|
+
function isScope(
|
|
791
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
792
|
+
el,
|
|
793
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
794
|
+
scope) {
|
|
795
|
+
var _a;
|
|
796
|
+
return (_a = el === scope) !== null && _a !== void 0 ? _a : el.parentNode === null;
|
|
750
797
|
}
|
|
751
|
-
function getDescendants(
|
|
798
|
+
function getDescendants(
|
|
799
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
800
|
+
el, includeSelf = false) {
|
|
752
801
|
return [
|
|
753
802
|
...Array.from(el.children)
|
|
754
803
|
.map(child => getDescendants(child, true))
|
|
@@ -756,11 +805,15 @@ function getDescendants(el, includeSelf = false) {
|
|
|
756
805
|
...(includeSelf ? [el] : []),
|
|
757
806
|
];
|
|
758
807
|
}
|
|
759
|
-
function getSiblings(
|
|
760
|
-
|
|
761
|
-
|
|
808
|
+
function getSiblings(
|
|
809
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
810
|
+
el) {
|
|
811
|
+
var _a, _b;
|
|
812
|
+
return Array.from((_b = (_a = el.parentElement) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : []);
|
|
762
813
|
}
|
|
763
|
-
function getSpecificity(
|
|
814
|
+
function getSpecificity(
|
|
815
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
816
|
+
results) {
|
|
764
817
|
let specificity;
|
|
765
818
|
for (const result of results) {
|
|
766
819
|
if (specificity) {
|
package/lib/types.d.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
export type Specificity = [number, number, number];
|
|
1
|
+
export type Specificity = readonly [number, number, number];
|
|
2
2
|
export type SelectorResult = SelectorMatchedResult | SelectorUnmatchedResult;
|
|
3
3
|
export type SelectorMatchedResult = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
readonly specificity: Specificity;
|
|
5
|
+
readonly matched: true;
|
|
6
|
+
readonly nodes: readonly (Element | Text)[];
|
|
7
|
+
readonly has: readonly SelectorMatchedResult[];
|
|
8
8
|
};
|
|
9
9
|
export type SelectorUnmatchedResult = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
readonly specificity: Specificity;
|
|
11
|
+
readonly matched: false;
|
|
12
|
+
readonly not?: readonly SelectorMatchedResult[];
|
|
13
13
|
};
|
|
14
14
|
export type RegexSelector = RegexSelectorWithoutCombination & {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
readonly combination?: {
|
|
16
|
+
readonly combinator: RegexSelectorCombinator;
|
|
17
|
+
} & RegexSelector;
|
|
18
18
|
};
|
|
19
19
|
export type RegexSelectorCombinator = ' ' | '>' | '+' | '~' | ':has(+)' | ':has(~)';
|
|
20
20
|
export type RegexSelectorWithoutCombination = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
readonly nodeName?: string;
|
|
22
|
+
readonly attrName?: string;
|
|
23
|
+
readonly attrValue?: string;
|
|
24
24
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/selector",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-dev.177+e94f3601",
|
|
4
4
|
"description": "Extended W3C Selectors matcher",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -11,21 +11,25 @@
|
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
|
+
"typedoc": {
|
|
15
|
+
"entryPoint": "./src/index.ts"
|
|
16
|
+
},
|
|
14
17
|
"scripts": {
|
|
15
18
|
"build": "tsc",
|
|
16
19
|
"dev": "tsc --build --watch",
|
|
17
20
|
"clean": "tsc --build --clean"
|
|
18
21
|
},
|
|
19
22
|
"dependencies": {
|
|
23
|
+
"@markuplint/ml-spec": "3.0.0-dev.177+e94f3601",
|
|
24
|
+
"@types/debug": "^4.1.7",
|
|
20
25
|
"debug": "^4.3.4",
|
|
21
|
-
"postcss-selector-parser": "^6.0.
|
|
22
|
-
"tslib": "^2.4.
|
|
26
|
+
"postcss-selector-parser": "^6.0.11",
|
|
27
|
+
"tslib": "^2.4.1",
|
|
28
|
+
"type-fest": "^3.8.0"
|
|
23
29
|
},
|
|
24
30
|
"devDependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"
|
|
27
|
-
"@types/jsdom": "16",
|
|
28
|
-
"jsdom": "19"
|
|
31
|
+
"@types/jsdom": "21.1.1",
|
|
32
|
+
"jsdom": "21.1.1"
|
|
29
33
|
},
|
|
30
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "e94f3601bf93366d1a2c7385ff7235817d82f7c9"
|
|
31
35
|
}
|