@markuplint/selector 4.0.0-alpha.1 → 4.0.0-alpha.10
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/LICENSE
CHANGED
|
@@ -7,7 +7,7 @@ export function contentModelPseudoClass(specs) {
|
|
|
7
7
|
category = category.trim().toLowerCase();
|
|
8
8
|
const selectors = contentModelCategoryToTagNames(`#${category}`, specs.def);
|
|
9
9
|
const matched = selectors
|
|
10
|
-
.
|
|
10
|
+
.flatMap(selector => {
|
|
11
11
|
if (selector === '#custom') {
|
|
12
12
|
// @ts-ignore
|
|
13
13
|
if (el.isCustomElement) {
|
|
@@ -37,14 +37,13 @@ export function contentModelPseudoClass(specs) {
|
|
|
37
37
|
}
|
|
38
38
|
return createSelector(selector, specs).search(el);
|
|
39
39
|
})
|
|
40
|
-
.flat()
|
|
41
40
|
.filter((m) => m.matched);
|
|
42
41
|
if (matched.length > 0) {
|
|
43
42
|
return {
|
|
44
43
|
specificity: [0, 1, 0],
|
|
45
44
|
matched: true,
|
|
46
|
-
nodes: matched.
|
|
47
|
-
has: matched.
|
|
45
|
+
nodes: matched.flatMap(m => (m.matched ? m.nodes : [])),
|
|
46
|
+
has: matched.flatMap(m => (m.matched ? m.has : [])),
|
|
48
47
|
};
|
|
49
48
|
}
|
|
50
49
|
return {
|
package/lib/match-selector.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
1
12
|
var _SelectorTarget_combinedFrom, _SelectorTarget_selector;
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
13
|
import { isElement, isNonDocumentTypeChildNode, isPureHTMLElement } from './is.js';
|
|
4
14
|
import { regexSelectorMatches } from './regex-selector-matches.js';
|
|
5
15
|
import { Selector } from './selector.js';
|
|
@@ -176,46 +186,38 @@ el, selector) {
|
|
|
176
186
|
tagSelector = el.localName;
|
|
177
187
|
specificity[2] = 1;
|
|
178
188
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const matchedAttrName = regexSelectorMatches(
|
|
189
|
+
const isPure = isPureHTMLElement(el);
|
|
190
|
+
if (selector.attrName || selector.attrValue) {
|
|
191
|
+
const matchedAttrList = [...el.attributes]
|
|
192
|
+
.map(attr => {
|
|
193
|
+
const matchedAttrName = regexSelectorMatches(selector.attrName, attr.name, isPure);
|
|
194
|
+
if (selector.attrName && !matchedAttrName) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const matchedAttrValue = regexSelectorMatches(selector.attrValue, attr.value, isPure);
|
|
198
|
+
if (selector.attrValue && !matchedAttrValue) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
184
201
|
if (matchedAttrName) {
|
|
185
202
|
delete matchedAttrName.$0;
|
|
186
|
-
data = {
|
|
187
|
-
...data,
|
|
188
|
-
...matchedAttrName,
|
|
189
|
-
};
|
|
190
|
-
specifiedAttr.set(attrName, '');
|
|
191
203
|
}
|
|
192
|
-
return matchedAttrName;
|
|
193
|
-
});
|
|
194
|
-
if (!matchedAttrNameList.some(_ => !!_)) {
|
|
195
|
-
matched = false;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (selector.attrValue) {
|
|
199
|
-
const selectorAttrValue = selector.attrValue;
|
|
200
|
-
const matchedAttrValueList = Array.from(el.attributes).map(attr => {
|
|
201
|
-
const attrName = attr.name;
|
|
202
|
-
const attrValue = attr.value;
|
|
203
|
-
const matchedAttrValue = regexSelectorMatches(selectorAttrValue, attrValue, isPureHTMLElement(el));
|
|
204
204
|
if (matchedAttrValue) {
|
|
205
205
|
delete matchedAttrValue.$0;
|
|
206
|
-
data = {
|
|
207
|
-
...data,
|
|
208
|
-
...matchedAttrValue,
|
|
209
|
-
};
|
|
210
|
-
specifiedAttr.set(attrName, attrValue);
|
|
211
206
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
207
|
+
data = {
|
|
208
|
+
...data,
|
|
209
|
+
...matchedAttrName,
|
|
210
|
+
...matchedAttrValue,
|
|
211
|
+
};
|
|
212
|
+
specifiedAttr.set(attr.name, matchedAttrValue ? attr.value : '');
|
|
213
|
+
return matchedAttrValue ?? matchedAttrName ?? null;
|
|
214
|
+
})
|
|
215
|
+
.filter((a) => !!a);
|
|
216
|
+
if (matchedAttrList.length === 0) {
|
|
215
217
|
matched = false;
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
|
-
const attrSelector =
|
|
220
|
+
const attrSelector = [...specifiedAttr.entries()]
|
|
219
221
|
.map(([name, value]) => {
|
|
220
222
|
return `[${name}${value ? `="${value}"` : ''}]`;
|
|
221
223
|
})
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export function regexSelectorMatches(reg, raw, ignoreCase) {
|
|
2
|
+
if (!reg) {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
2
5
|
const res = {};
|
|
3
6
|
const pattern = toRegexp(reg);
|
|
4
7
|
const regex = new RegExp(pattern instanceof RegExp ? pattern : `^${pattern.trim()}$`, ignoreCase ? 'i' : undefined);
|
|
@@ -6,14 +9,15 @@ export function regexSelectorMatches(reg, raw, ignoreCase) {
|
|
|
6
9
|
if (!matched) {
|
|
7
10
|
return null;
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
for (const [i, val] of matched.entries())
|
|
13
|
+
res[`$${i}`] = val;
|
|
10
14
|
return {
|
|
11
15
|
...res,
|
|
12
16
|
...matched.groups,
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
19
|
function toRegexp(pattern) {
|
|
16
|
-
const matched = pattern.match(/^\/(.+)\/([
|
|
20
|
+
const matched = pattern.match(/^\/(.+)\/([gi]*)$/i);
|
|
17
21
|
if (matched && matched[1]) {
|
|
18
22
|
return new RegExp(matched[1], matched[2]);
|
|
19
23
|
}
|
package/lib/selector.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
1
12
|
var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_combinedFrom, _SelectorTarget_extended, _SelectorTarget_isAdded;
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
13
|
import { resolveNamespace } from '@markuplint/ml-spec';
|
|
4
14
|
import parser from 'postcss-selector-parser';
|
|
5
15
|
import { compareSpecificity } from './compare-specificity.js';
|
|
@@ -45,11 +55,11 @@ class Ruleset {
|
|
|
45
55
|
selectors.push(...root.nodes);
|
|
46
56
|
}).processSync(selector);
|
|
47
57
|
}
|
|
48
|
-
catch (
|
|
49
|
-
if (
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error instanceof Error) {
|
|
50
60
|
throw new InvalidSelectorError(selector);
|
|
51
61
|
}
|
|
52
|
-
throw
|
|
62
|
+
throw error;
|
|
53
63
|
}
|
|
54
64
|
return new Ruleset(selectors, extended, 0);
|
|
55
65
|
}
|
|
@@ -58,13 +68,11 @@ class Ruleset {
|
|
|
58
68
|
__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector, depth, extended)));
|
|
59
69
|
const head = __classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0];
|
|
60
70
|
this.headCombinator = head?.headCombinator ?? null;
|
|
61
|
-
if (this.headCombinator) {
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
throw new InvalidSelectorError(__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0]?.selector);
|
|
65
|
-
}
|
|
66
|
-
throw new Error('Combinated selector depth is not expected');
|
|
71
|
+
if (this.headCombinator && depth <= 0) {
|
|
72
|
+
if (__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0]?.selector) {
|
|
73
|
+
throw new InvalidSelectorError(__classPrivateFieldGet(this, _Ruleset_selectorGroup, "f")[0]?.selector);
|
|
67
74
|
}
|
|
75
|
+
throw new Error('Combinated selector depth is not expected');
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
match(
|
|
@@ -90,12 +98,12 @@ class StructuredSelector {
|
|
|
90
98
|
__classPrivateFieldSet(this, _StructuredSelector_edge, new SelectorTarget(extended, depth), "f");
|
|
91
99
|
this.headCombinator =
|
|
92
100
|
__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0]?.type === 'combinator' ? __classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes[0].value ?? null : null;
|
|
93
|
-
const nodes = __classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes
|
|
101
|
+
const nodes = [...__classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes];
|
|
94
102
|
if (0 < depth && this.headCombinator) {
|
|
95
103
|
// eslint-disable-next-line import/no-named-as-default-member
|
|
96
104
|
nodes.unshift(parser.pseudo({ value: ':scope' }));
|
|
97
105
|
}
|
|
98
|
-
|
|
106
|
+
for (const node of nodes) {
|
|
99
107
|
switch (node.type) {
|
|
100
108
|
case 'combinator': {
|
|
101
109
|
const combinedTarget = new SelectorTarget(extended, depth);
|
|
@@ -117,7 +125,7 @@ class StructuredSelector {
|
|
|
117
125
|
__classPrivateFieldGet(this, _StructuredSelector_edge, "f").add(node);
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
|
-
}
|
|
128
|
+
}
|
|
121
129
|
}
|
|
122
130
|
get selector() {
|
|
123
131
|
return __classPrivateFieldGet(this, _StructuredSelector_selector, "f").nodes.join('');
|
|
@@ -512,7 +520,7 @@ _SelectorTarget_combinedFrom = new WeakMap(), _SelectorTarget_extended = new Wea
|
|
|
512
520
|
function attrMatch(attr,
|
|
513
521
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
514
522
|
el) {
|
|
515
|
-
return
|
|
523
|
+
return [...el.attributes].some(attrOfEl => {
|
|
516
524
|
if (attr.attribute !== attrOfEl.localName) {
|
|
517
525
|
return false;
|
|
518
526
|
}
|
|
@@ -632,8 +640,8 @@ scope, extended, depth) {
|
|
|
632
640
|
return {
|
|
633
641
|
specificity,
|
|
634
642
|
matched: matched.length > 0,
|
|
635
|
-
nodes: matched.
|
|
636
|
-
has: matched.
|
|
643
|
+
nodes: matched.flatMap(m => m.nodes),
|
|
644
|
+
has: matched.flatMap(m => m.has),
|
|
637
645
|
};
|
|
638
646
|
}
|
|
639
647
|
case ':has': {
|
|
@@ -642,9 +650,7 @@ scope, extended, depth) {
|
|
|
642
650
|
switch (ruleset.headCombinator) {
|
|
643
651
|
case '+':
|
|
644
652
|
case '~': {
|
|
645
|
-
const has = getSiblings(el)
|
|
646
|
-
.map(sib => ruleset.match(sib, el).filter((m) => m.matched))
|
|
647
|
-
.flat();
|
|
653
|
+
const has = getSiblings(el).flatMap(sib => ruleset.match(sib, el).filter((m) => m.matched));
|
|
648
654
|
if (has.length > 0) {
|
|
649
655
|
return {
|
|
650
656
|
specificity,
|
|
@@ -659,9 +665,7 @@ scope, extended, depth) {
|
|
|
659
665
|
};
|
|
660
666
|
}
|
|
661
667
|
default: {
|
|
662
|
-
const has = getDescendants(el)
|
|
663
|
-
.map(sib => ruleset.match(sib, el).filter((m) => m.matched))
|
|
664
|
-
.flat();
|
|
668
|
+
const has = getDescendants(el).flatMap(sib => ruleset.match(sib, el).filter((m) => m.matched));
|
|
665
669
|
if (has.length > 0) {
|
|
666
670
|
return {
|
|
667
671
|
specificity,
|
|
@@ -684,8 +688,8 @@ scope, extended, depth) {
|
|
|
684
688
|
return {
|
|
685
689
|
specificity: [0, 0, 0],
|
|
686
690
|
matched: matched.length > 0,
|
|
687
|
-
nodes: matched.
|
|
688
|
-
has: matched.
|
|
691
|
+
nodes: matched.flatMap(m => m.nodes),
|
|
692
|
+
has: matched.flatMap(m => m.has),
|
|
689
693
|
};
|
|
690
694
|
}
|
|
691
695
|
case ':scope': {
|
|
@@ -747,6 +751,7 @@ scope, extended, depth) {
|
|
|
747
751
|
case ':nth-col': {
|
|
748
752
|
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).`);
|
|
749
753
|
}
|
|
754
|
+
/* eslint-disable unicorn/no-useless-switch-case */
|
|
750
755
|
case ':dir':
|
|
751
756
|
case ':lang':
|
|
752
757
|
case ':any-link':
|
|
@@ -780,6 +785,7 @@ scope, extended, depth) {
|
|
|
780
785
|
}
|
|
781
786
|
throw new Error(`Unsupported pseudo ${pseudo.toString()} selector.`);
|
|
782
787
|
}
|
|
788
|
+
/* eslint-enable unicorn/no-useless-switch-case */
|
|
783
789
|
}
|
|
784
790
|
}
|
|
785
791
|
function isScope(
|
|
@@ -792,22 +798,17 @@ scope) {
|
|
|
792
798
|
function getDescendants(
|
|
793
799
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
794
800
|
el, includeSelf = false) {
|
|
795
|
-
return [
|
|
796
|
-
...Array.from(el.children)
|
|
797
|
-
.map(child => getDescendants(child, true))
|
|
798
|
-
.flat(),
|
|
799
|
-
...(includeSelf ? [el] : []),
|
|
800
|
-
];
|
|
801
|
+
return [...[...el.children].flatMap(child => getDescendants(child, true)), ...(includeSelf ? [el] : [])];
|
|
801
802
|
}
|
|
802
803
|
function getSiblings(
|
|
803
804
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
804
805
|
el) {
|
|
805
|
-
return
|
|
806
|
+
return [...(el.parentElement?.children ?? [])];
|
|
806
807
|
}
|
|
807
808
|
function getSpecificity(
|
|
808
809
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
809
810
|
results) {
|
|
810
|
-
let specificity
|
|
811
|
+
let specificity;
|
|
811
812
|
for (const result of results) {
|
|
812
813
|
if (specificity) {
|
|
813
814
|
const order = compareSpecificity(specificity, result.specificity);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/selector",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.10",
|
|
4
4
|
"description": "Extended W3C Selectors matcher",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -25,16 +25,15 @@
|
|
|
25
25
|
"clean": "tsc --build --clean"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@markuplint/ml-spec": "4.0.0-alpha.
|
|
29
|
-
"@types/debug": "^4.1.
|
|
28
|
+
"@markuplint/ml-spec": "4.0.0-alpha.10",
|
|
29
|
+
"@types/debug": "^4.1.12",
|
|
30
30
|
"debug": "^4.3.4",
|
|
31
|
-
"postcss-selector-parser": "^6.0.
|
|
32
|
-
"
|
|
33
|
-
"type-fest": "^4.1.0"
|
|
31
|
+
"postcss-selector-parser": "^6.0.15",
|
|
32
|
+
"type-fest": "^4.10.1"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
|
-
"@types/jsdom": "21.1.
|
|
37
|
-
"jsdom": "
|
|
35
|
+
"@types/jsdom": "21.1.6",
|
|
36
|
+
"jsdom": "24.0.0"
|
|
38
37
|
},
|
|
39
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "b41153ea665aa8f091daf6114a06047f4ccb8350"
|
|
40
39
|
}
|