@asamuzakjp/dom-selector 6.8.0 → 7.0.0

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 CHANGED
@@ -1,324 +1,324 @@
1
- # DOM Selector
2
-
3
- [![build](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
4
- [![CodeQL](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql)
5
- [![npm (scoped)](https://img.shields.io/npm/v/@asamuzakjp/dom-selector)](https://www.npmjs.com/package/@asamuzakjp/dom-selector)
6
-
7
- A CSS selector engine.
8
-
9
- ## Install
10
-
11
- ```console
12
- npm i @asamuzakjp/dom-selector
13
- ```
14
-
15
- ## Usage
16
-
17
- ```javascript
18
- import { DOMSelector } from '@asamuzakjp/dom-selector';
19
- import { JSDOM } from 'jsdom';
20
-
21
- const { window } = new JSDOM();
22
- const {
23
- closest, matches, querySelector, querySelectorAll
24
- } = new DOMSelector(window);
25
- ```
26
-
27
- <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
28
-
29
- ### matches(selector, node, opt)
30
-
31
- matches - equivalent to [Element.matches()][64]
32
-
33
- #### Parameters
34
-
35
- - `selector` **[string][59]** CSS selector
36
- - `node` **[object][60]** Element node
37
- - `opt` **[object][60]?** options
38
- - `opt.noexcept` **[boolean][61]?** no exception
39
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
40
-
41
- Returns **[boolean][61]** `true` if matched, `false` otherwise
42
-
43
-
44
- ### closest(selector, node, opt)
45
-
46
- closest - equivalent to [Element.closest()][65]
47
-
48
- #### Parameters
49
-
50
- - `selector` **[string][59]** CSS selector
51
- - `node` **[object][60]** Element node
52
- - `opt` **[object][60]?** options
53
- - `opt.noexcept` **[boolean][61]?** no exception
54
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
55
-
56
- Returns **[object][60]?** matched node
57
-
58
-
59
- ### querySelector(selector, node, opt)
60
-
61
- querySelector - equivalent to [Document.querySelector()][66], [DocumentFragment.querySelector()][67] and [Element.querySelector()][68]
62
-
63
- #### Parameters
64
-
65
- - `selector` **[string][59]** CSS selector
66
- - `node` **[object][60]** Document, DocumentFragment or Element node
67
- - `opt` **[object][60]?** options
68
- - `opt.noexcept` **[boolean][61]?** no exception
69
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
70
-
71
- Returns **[object][60]?** matched node
72
-
73
-
74
- ### querySelectorAll(selector, node, opt)
75
-
76
- querySelectorAll - equivalent to [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70] and [Element.querySelectorAll()][71]
77
- **NOTE**: returns Array, not NodeList
78
-
79
- #### Parameters
80
-
81
- - `selector` **[string][59]** CSS selector
82
- - `node` **[object][60]** Document, DocumentFragment or Element node
83
- - `opt` **[object][60]?** options
84
- - `opt.noexcept` **[boolean][61]?** no exception
85
- - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
86
-
87
- Returns **[Array][62]&lt;([object][60] \| [undefined][63])>** array of matched nodes
88
-
89
-
90
- ## Monkey patch jsdom
91
-
92
- ``` javascript
93
- import { DOMSelector } from '@asamuzakjp/dom-selector';
94
- import { JSDOM } from 'jsdom';
95
-
96
- const dom = new JSDOM('', {
97
- runScripts: 'dangerously',
98
- url: 'http://localhost/',
99
- beforeParse: window => {
100
- const domSelector = new DOMSelector(window);
101
-
102
- const matches = domSelector.matches.bind(domSelector);
103
- window.Element.prototype.matches = function (...args) {
104
- if (!args.length) {
105
- throw new window.TypeError('1 argument required, but only 0 present.');
106
- }
107
- const [selector] = args;
108
- return matches(selector, this);
109
- };
110
-
111
- const closest = domSelector.closest.bind(domSelector);
112
- window.Element.prototype.closest = function (...args) {
113
- if (!args.length) {
114
- throw new window.TypeError('1 argument required, but only 0 present.');
115
- }
116
- const [selector] = args;
117
- return closest(selector, this);
118
- };
119
-
120
- const querySelector = domSelector.querySelector.bind(domSelector);
121
- window.Document.prototype.querySelector = function (...args) {
122
- if (!args.length) {
123
- throw new window.TypeError('1 argument required, but only 0 present.');
124
- }
125
- const [selector] = args;
126
- return querySelector(selector, this);
127
- };
128
- window.DocumentFragment.prototype.querySelector = function (...args) {
129
- if (!args.length) {
130
- throw new window.TypeError('1 argument required, but only 0 present.');
131
- }
132
- const [selector] = args;
133
- return querySelector(selector, this);
134
- };
135
- window.Element.prototype.querySelector = function (...args) {
136
- if (!args.length) {
137
- throw new window.TypeError('1 argument required, but only 0 present.');
138
- }
139
- const [selector] = args;
140
- return querySelector(selector, this);
141
- };
142
-
143
- const querySelectorAll = domSelector.querySelectorAll.bind(domSelector);
144
- window.Document.prototype.querySelectorAll = function (...args) {
145
- if (!args.length) {
146
- throw new window.TypeError('1 argument required, but only 0 present.');
147
- }
148
- const [selector] = args;
149
- return querySelectorAll(selector, this);
150
- };
151
- window.DocumentFragment.prototype.querySelectorAll = function (...args) {
152
- if (!args.length) {
153
- throw new window.TypeError('1 argument required, but only 0 present.');
154
- }
155
- const [selector] = args;
156
- return querySelectorAll(selector, this);
157
- };
158
- window.Element.prototype.querySelectorAll = function (...args) {
159
- if (!args.length) {
160
- throw new window.TypeError('1 argument required, but only 0 present.');
161
- }
162
- const [selector] = args;
163
- return querySelectorAll(selector, this);
164
- };
165
- }
166
- });
167
- ```
168
-
169
-
170
- ## Supported CSS selectors
171
-
172
- |Pattern|Supported|Note|
173
- |:--------|:-------:|:--------|
174
- |\*|✓| |
175
- |E|✓| |
176
- |ns\|E|✓| |
177
- |\*\|E|✓| |
178
- |\|E|✓| |
179
- |E&nbsp;F|✓| |
180
- |E > F|✓| |
181
- |E + F|✓| |
182
- |E ~ F|✓| |
183
- |F \|\| E|Unsupported| |
184
- |E.warning|✓| |
185
- |E#myid|✓| |
186
- |E\[foo\]|✓| |
187
- |E\[foo="bar"\]|✓| |
188
- |E\[foo="bar"&nbsp;i\]|✓| |
189
- |E\[foo="bar"&nbsp;s\]|✓| |
190
- |E\[foo~="bar"\]|✓| |
191
- |E\[foo^="bar"\]|✓| |
192
- |E\[foo$="bar"\]|✓| |
193
- |E\[foo*="bar"\]|✓| |
194
- |E\[foo\|="en"\]|✓| |
195
- |E:is(s1, s2, …)|✓| |
196
- |E:not(s1, s2, …)|✓| |
197
- |E:where(s1, s2, …)|✓| |
198
- |E:has(rs1, rs2, …)|✓| |
199
- |E:defined|Partially supported|Matching with MathML is not yet supported.|
200
- |E:dir(ltr)|✓| |
201
- |E:lang(en)|✓| |
202
- |E:any&#8209;link|✓| |
203
- |E:link|✓| |
204
- |E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
205
- |E:local&#8209;link|✓| |
206
- |E:target|✓| |
207
- |E:target&#8209;within|✓| |
208
- |E:scope|✓| |
209
- |E:hover|✓| |
210
- |E:active|✓| |
211
- |E:focus|✓| |
212
- |E:focus&#8209;visible|✓| |
213
- |E:focus&#8209;within|✓| |
214
- |E:current|Unsupported| |
215
- |E:current(s)|Unsupported| |
216
- |E:past|Unsupported| |
217
- |E:future|Unsupported| |
218
- |E:open<br>E:closed|Partially supported|Matching with &lt;select&gt;, e.g. `select:open`, is not supported.|
219
- |E:popover-open|✓| |
220
- |E:enabled<br>E:disabled|✓| |
221
- |E:read&#8209;write<br>E:read&#8209;only|✓| |
222
- |E:placeholder&#8209;shown|✓| |
223
- |E:default|✓| |
224
- |E:checked|✓| |
225
- |E:indeterminate|✓| |
226
- |E:blank|Unsupported| |
227
- |E:valid<br>E:invalid|✓| |
228
- |E:in-range<br>E:out-of-range|✓| |
229
- |E:required<br>E:optional|✓| |
230
- |E:user&#8209;valid<br>E:user&#8209;invalid|Unsupported| |
231
- |E:root|✓| |
232
- |E:empty|✓| |
233
- |E:nth&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
234
- |E:nth&#8209;last&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
235
- |E:first&#8209;child|✓| |
236
- |E:last&#8209;child|✓| |
237
- |E:only&#8209;child|✓| |
238
- |E:nth&#8209;of&#8209;type(n)|✓| |
239
- |E:nth&#8209;last&#8209;of&#8209;type(n)|✓| |
240
- |E:first&#8209;of&#8209;type|✓| |
241
- |E:last&#8209;of&#8209;type|✓| |
242
- |E:only&#8209;of&#8209;type|✓| |
243
- |E:nth&#8209;col(n)|Unsupported| |
244
- |E:nth&#8209;last&#8209;col(n)|Unsupported| |
245
- |CE:state(v)|✓|*1|
246
- |:host|✓| |
247
- |:host(s)|✓| |
248
- |:host(:state(v))|✓|*1|
249
- |:host:has(rs1, rs2, ...)|✓| |
250
- |:host(s):has(rs1, rs2, ...)|✓| |
251
- |:host&#8209;context(s)|✓| |
252
- |:host&#8209;context(s):has(rs1, rs2, ...)|✓| |
253
- |&amp;|✓|Only supports outermost `&`, i.e. equivalent to `:scope`|
254
-
255
- *1: `ElementInternals.states`, i.e. `CustomStateSet`, is not implemented in jsdom, so you need to apply a patch in the custom element constructor.
256
-
257
- ``` javascript
258
- class LabeledCheckbox extends window.HTMLElement {
259
- #internals;
260
- constructor() {
261
- super();
262
- this.#internals = this.attachInternals();
263
- // patch CustomStateSet
264
- if (!this.#internals.states) {
265
- this.#internals.states = new Set();
266
- }
267
- this.addEventListener('click', this._onClick.bind(this));
268
- }
269
- get checked() {
270
- return this.#internals.states.has('checked');
271
- }
272
- set checked(flag) {
273
- if (flag) {
274
- this.#internals.states.add('checked');
275
- } else {
276
- this.#internals.states.delete('checked');
277
- }
278
- }
279
- _onClick(event) {
280
- this.checked = !this.checked;
281
- }
282
- }
283
- ```
284
-
285
-
286
- ## Performance
287
-
288
- See [benchmark](https://github.com/asamuzaK/domSelector/actions/workflows/benchmark.yml) for the latest results.
289
-
290
-
291
- ## Acknowledgments
292
-
293
- The following resources have been of great help in the development of the DOM Selector.
294
-
295
- - [CSSTree](https://github.com/csstree/csstree)
296
- - [selery](https://github.com/danburzo/selery)
297
- - [jsdom](https://github.com/jsdom/jsdom)
298
- - [nwsapi](https://github.com/dperini/nwsapi)
299
-
300
- ---
301
- Copyright (c) 2023 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
302
-
303
-
304
- [1]: #matches
305
- [2]: #parameters
306
- [3]: #closest
307
- [4]: #parameters-1
308
- [5]: #queryselector
309
- [6]: #parameters-2
310
- [7]: #queryselectorall
311
- [8]: #parameters-3
312
- [59]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
313
- [60]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
314
- [61]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
315
- [62]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
316
- [63]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
317
- [64]: https://developer.mozilla.org/docs/Web/API/Element/matches
318
- [65]: https://developer.mozilla.org/docs/Web/API/Element/closest
319
- [66]: https://developer.mozilla.org/docs/Web/API/Document/querySelector
320
- [67]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelector
321
- [68]: https://developer.mozilla.org/docs/Web/API/Element/querySelector
322
- [69]: https://developer.mozilla.org/docs/Web/API/Document/querySelectorAll
323
- [70]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelectorAll
324
- [71]: https://developer.mozilla.org/docs/Web/API/Element/querySelectorAll
1
+ # DOM Selector
2
+
3
+ [![build](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
4
+ [![CodeQL](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql)
5
+ [![npm (scoped)](https://img.shields.io/npm/v/@asamuzakjp/dom-selector)](https://www.npmjs.com/package/@asamuzakjp/dom-selector)
6
+
7
+ A CSS selector engine.
8
+
9
+ ## Install
10
+
11
+ ```console
12
+ npm i @asamuzakjp/dom-selector
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```javascript
18
+ import { DOMSelector } from '@asamuzakjp/dom-selector';
19
+ import { JSDOM } from 'jsdom';
20
+
21
+ const { window } = new JSDOM();
22
+ const {
23
+ closest, matches, querySelector, querySelectorAll
24
+ } = new DOMSelector(window);
25
+ ```
26
+
27
+ <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
28
+
29
+ ### matches(selector, node, opt)
30
+
31
+ matches - equivalent to [Element.matches()][64]
32
+
33
+ #### Parameters
34
+
35
+ - `selector` **[string][59]** CSS selector
36
+ - `node` **[object][60]** Element node
37
+ - `opt` **[object][60]?** options
38
+ - `opt.noexcept` **[boolean][61]?** no exception
39
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
40
+
41
+ Returns **[boolean][61]** `true` if matched, `false` otherwise
42
+
43
+
44
+ ### closest(selector, node, opt)
45
+
46
+ closest - equivalent to [Element.closest()][65]
47
+
48
+ #### Parameters
49
+
50
+ - `selector` **[string][59]** CSS selector
51
+ - `node` **[object][60]** Element node
52
+ - `opt` **[object][60]?** options
53
+ - `opt.noexcept` **[boolean][61]?** no exception
54
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
55
+
56
+ Returns **[object][60]?** matched node
57
+
58
+
59
+ ### querySelector(selector, node, opt)
60
+
61
+ querySelector - equivalent to [Document.querySelector()][66], [DocumentFragment.querySelector()][67] and [Element.querySelector()][68]
62
+
63
+ #### Parameters
64
+
65
+ - `selector` **[string][59]** CSS selector
66
+ - `node` **[object][60]** Document, DocumentFragment or Element node
67
+ - `opt` **[object][60]?** options
68
+ - `opt.noexcept` **[boolean][61]?** no exception
69
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
70
+
71
+ Returns **[object][60]?** matched node
72
+
73
+
74
+ ### querySelectorAll(selector, node, opt)
75
+
76
+ querySelectorAll - equivalent to [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70] and [Element.querySelectorAll()][71]
77
+ **NOTE**: returns Array, not NodeList
78
+
79
+ #### Parameters
80
+
81
+ - `selector` **[string][59]** CSS selector
82
+ - `node` **[object][60]** Document, DocumentFragment or Element node
83
+ - `opt` **[object][60]?** options
84
+ - `opt.noexcept` **[boolean][61]?** no exception
85
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
86
+
87
+ Returns **[Array][62]&lt;([object][60] \| [undefined][63])>** array of matched nodes
88
+
89
+
90
+ ## Monkey patch jsdom
91
+
92
+ ``` javascript
93
+ import { DOMSelector } from '@asamuzakjp/dom-selector';
94
+ import { JSDOM } from 'jsdom';
95
+
96
+ const dom = new JSDOM('', {
97
+ runScripts: 'dangerously',
98
+ url: 'http://localhost/',
99
+ beforeParse: window => {
100
+ const domSelector = new DOMSelector(window);
101
+
102
+ const matches = domSelector.matches.bind(domSelector);
103
+ window.Element.prototype.matches = function (...args) {
104
+ if (!args.length) {
105
+ throw new window.TypeError('1 argument required, but only 0 present.');
106
+ }
107
+ const [selector] = args;
108
+ return matches(selector, this);
109
+ };
110
+
111
+ const closest = domSelector.closest.bind(domSelector);
112
+ window.Element.prototype.closest = function (...args) {
113
+ if (!args.length) {
114
+ throw new window.TypeError('1 argument required, but only 0 present.');
115
+ }
116
+ const [selector] = args;
117
+ return closest(selector, this);
118
+ };
119
+
120
+ const querySelector = domSelector.querySelector.bind(domSelector);
121
+ window.Document.prototype.querySelector = function (...args) {
122
+ if (!args.length) {
123
+ throw new window.TypeError('1 argument required, but only 0 present.');
124
+ }
125
+ const [selector] = args;
126
+ return querySelector(selector, this);
127
+ };
128
+ window.DocumentFragment.prototype.querySelector = function (...args) {
129
+ if (!args.length) {
130
+ throw new window.TypeError('1 argument required, but only 0 present.');
131
+ }
132
+ const [selector] = args;
133
+ return querySelector(selector, this);
134
+ };
135
+ window.Element.prototype.querySelector = function (...args) {
136
+ if (!args.length) {
137
+ throw new window.TypeError('1 argument required, but only 0 present.');
138
+ }
139
+ const [selector] = args;
140
+ return querySelector(selector, this);
141
+ };
142
+
143
+ const querySelectorAll = domSelector.querySelectorAll.bind(domSelector);
144
+ window.Document.prototype.querySelectorAll = function (...args) {
145
+ if (!args.length) {
146
+ throw new window.TypeError('1 argument required, but only 0 present.');
147
+ }
148
+ const [selector] = args;
149
+ return querySelectorAll(selector, this);
150
+ };
151
+ window.DocumentFragment.prototype.querySelectorAll = function (...args) {
152
+ if (!args.length) {
153
+ throw new window.TypeError('1 argument required, but only 0 present.');
154
+ }
155
+ const [selector] = args;
156
+ return querySelectorAll(selector, this);
157
+ };
158
+ window.Element.prototype.querySelectorAll = function (...args) {
159
+ if (!args.length) {
160
+ throw new window.TypeError('1 argument required, but only 0 present.');
161
+ }
162
+ const [selector] = args;
163
+ return querySelectorAll(selector, this);
164
+ };
165
+ }
166
+ });
167
+ ```
168
+
169
+
170
+ ## Supported CSS selectors
171
+
172
+ |Pattern|Supported|Note|
173
+ |:--------|:-------:|:--------|
174
+ |\*|✓| |
175
+ |E|✓| |
176
+ |ns\|E|✓| |
177
+ |\*\|E|✓| |
178
+ |\|E|✓| |
179
+ |E&nbsp;F|✓| |
180
+ |E > F|✓| |
181
+ |E + F|✓| |
182
+ |E ~ F|✓| |
183
+ |F \|\| E|Unsupported| |
184
+ |E.warning|✓| |
185
+ |E#myid|✓| |
186
+ |E\[foo\]|✓| |
187
+ |E\[foo="bar"\]|✓| |
188
+ |E\[foo="bar"&nbsp;i\]|✓| |
189
+ |E\[foo="bar"&nbsp;s\]|✓| |
190
+ |E\[foo~="bar"\]|✓| |
191
+ |E\[foo^="bar"\]|✓| |
192
+ |E\[foo$="bar"\]|✓| |
193
+ |E\[foo*="bar"\]|✓| |
194
+ |E\[foo\|="en"\]|✓| |
195
+ |E:is(s1, s2, …)|✓| |
196
+ |E:not(s1, s2, …)|✓| |
197
+ |E:where(s1, s2, …)|✓| |
198
+ |E:has(rs1, rs2, …)|✓| |
199
+ |E:defined|Partially supported|Matching with MathML is not yet supported.|
200
+ |E:dir(ltr)|✓| |
201
+ |E:lang(en)|✓| |
202
+ |E:any&#8209;link|✓| |
203
+ |E:link|✓| |
204
+ |E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
205
+ |E:local&#8209;link|✓| |
206
+ |E:target|✓| |
207
+ |E:target&#8209;within|✓| |
208
+ |E:scope|✓| |
209
+ |E:hover|✓| |
210
+ |E:active|✓| |
211
+ |E:focus|✓| |
212
+ |E:focus&#8209;visible|✓| |
213
+ |E:focus&#8209;within|✓| |
214
+ |E:current|Unsupported| |
215
+ |E:current(s)|Unsupported| |
216
+ |E:past|Unsupported| |
217
+ |E:future|Unsupported| |
218
+ |E:open<br>E:closed|Partially supported|Matching with &lt;select&gt;, e.g. `select:open`, is not supported.|
219
+ |E:popover-open|Unsupported| |
220
+ |E:enabled<br>E:disabled|✓| |
221
+ |E:read&#8209;write<br>E:read&#8209;only|✓| |
222
+ |E:placeholder&#8209;shown|✓| |
223
+ |E:default|✓| |
224
+ |E:checked|✓| |
225
+ |E:indeterminate|✓| |
226
+ |E:blank|Unsupported| |
227
+ |E:valid<br>E:invalid|✓| |
228
+ |E:in-range<br>E:out-of-range|✓| |
229
+ |E:required<br>E:optional|✓| |
230
+ |E:user&#8209;valid<br>E:user&#8209;invalid|Unsupported| |
231
+ |E:root|✓| |
232
+ |E:empty|✓| |
233
+ |E:nth&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
234
+ |E:nth&#8209;last&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
235
+ |E:first&#8209;child|✓| |
236
+ |E:last&#8209;child|✓| |
237
+ |E:only&#8209;child|✓| |
238
+ |E:nth&#8209;of&#8209;type(n)|✓| |
239
+ |E:nth&#8209;last&#8209;of&#8209;type(n)|✓| |
240
+ |E:first&#8209;of&#8209;type|✓| |
241
+ |E:last&#8209;of&#8209;type|✓| |
242
+ |E:only&#8209;of&#8209;type|✓| |
243
+ |E:nth&#8209;col(n)|Unsupported| |
244
+ |E:nth&#8209;last&#8209;col(n)|Unsupported| |
245
+ |CE:state(v)|✓|*1|
246
+ |:host|✓| |
247
+ |:host(s)|✓| |
248
+ |:host(:state(v))|✓|*1|
249
+ |:host:has(rs1, rs2, ...)|✓| |
250
+ |:host(s):has(rs1, rs2, ...)|✓| |
251
+ |:host&#8209;context(s)|✓| |
252
+ |:host&#8209;context(s):has(rs1, rs2, ...)|✓| |
253
+ |&amp;|✓|Only supports outermost `&`, i.e. equivalent to `:scope`|
254
+
255
+ *1: `ElementInternals.states`, i.e. `CustomStateSet`, is not implemented in jsdom, so you need to apply a patch in the custom element constructor.
256
+
257
+ ``` javascript
258
+ class LabeledCheckbox extends window.HTMLElement {
259
+ #internals;
260
+ constructor() {
261
+ super();
262
+ this.#internals = this.attachInternals();
263
+ // patch CustomStateSet
264
+ if (!this.#internals.states) {
265
+ this.#internals.states = new Set();
266
+ }
267
+ this.addEventListener('click', this._onClick.bind(this));
268
+ }
269
+ get checked() {
270
+ return this.#internals.states.has('checked');
271
+ }
272
+ set checked(flag) {
273
+ if (flag) {
274
+ this.#internals.states.add('checked');
275
+ } else {
276
+ this.#internals.states.delete('checked');
277
+ }
278
+ }
279
+ _onClick(event) {
280
+ this.checked = !this.checked;
281
+ }
282
+ }
283
+ ```
284
+
285
+
286
+ ## Performance
287
+
288
+ See [benchmark](https://github.com/asamuzaK/domSelector/actions/workflows/benchmark.yml) for the latest results.
289
+
290
+
291
+ ## Acknowledgments
292
+
293
+ The following resources have been of great help in the development of the DOM Selector.
294
+
295
+ - [CSSTree](https://github.com/csstree/csstree)
296
+ - [selery](https://github.com/danburzo/selery)
297
+ - [jsdom](https://github.com/jsdom/jsdom)
298
+ - [nwsapi](https://github.com/dperini/nwsapi)
299
+
300
+ ---
301
+ Copyright (c) 2023 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
302
+
303
+
304
+ [1]: #matches
305
+ [2]: #parameters
306
+ [3]: #closest
307
+ [4]: #parameters-1
308
+ [5]: #queryselector
309
+ [6]: #parameters-2
310
+ [7]: #queryselectorall
311
+ [8]: #parameters-3
312
+ [59]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
313
+ [60]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
314
+ [61]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
315
+ [62]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
316
+ [63]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
317
+ [64]: https://developer.mozilla.org/docs/Web/API/Element/matches
318
+ [65]: https://developer.mozilla.org/docs/Web/API/Element/closest
319
+ [66]: https://developer.mozilla.org/docs/Web/API/Document/querySelector
320
+ [67]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelector
321
+ [68]: https://developer.mozilla.org/docs/Web/API/Element/querySelector
322
+ [69]: https://developer.mozilla.org/docs/Web/API/Document/querySelectorAll
323
+ [70]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelectorAll
324
+ [71]: https://developer.mozilla.org/docs/Web/API/Element/querySelectorAll