@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 +324 -324
- package/package.json +10 -19
- package/src/index.js +1 -0
- package/src/js/finder.js +17 -11
- package/src/js/parser.js +6 -3
- package/src/js/utility.js +2 -4
- package/types/index.d.ts +1 -0
- package/dist/cjs/index.cjs +0 -4649
- package/dist/cjs/index.cjs.map +0 -1
- package/dist/cjs/index.d.cts +0 -16
package/README.md
CHANGED
|
@@ -1,324 +1,324 @@
|
|
|
1
|
-
# DOM Selector
|
|
2
|
-
|
|
3
|
-
[](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
|
|
4
|
-
[](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql)
|
|
5
|
-
[](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]<([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 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" i\]|✓| |
|
|
189
|
-
|E\[foo="bar" 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‑link|✓| |
|
|
203
|
-
|E:link|✓| |
|
|
204
|
-
|E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
|
|
205
|
-
|E:local‑link|✓| |
|
|
206
|
-
|E:target|✓| |
|
|
207
|
-
|E:target‑within|✓| |
|
|
208
|
-
|E:scope|✓| |
|
|
209
|
-
|E:hover|✓| |
|
|
210
|
-
|E:active|✓| |
|
|
211
|
-
|E:focus|✓| |
|
|
212
|
-
|E:focus‑visible|✓| |
|
|
213
|
-
|E:focus‑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 <select>, e.g. `select:open`, is not supported.|
|
|
219
|
-
|E:popover-open
|
|
220
|
-
|E:enabled<br>E:disabled|✓| |
|
|
221
|
-
|E:read‑write<br>E:read‑only|✓| |
|
|
222
|
-
|E:placeholder‑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‑valid<br>E:user‑invalid|Unsupported| |
|
|
231
|
-
|E:root|✓| |
|
|
232
|
-
|E:empty|✓| |
|
|
233
|
-
|E:nth‑child(n [of S]?)|✓| |
|
|
234
|
-
|E:nth‑last‑child(n [of S]?)|✓| |
|
|
235
|
-
|E:first‑child|✓| |
|
|
236
|
-
|E:last‑child|✓| |
|
|
237
|
-
|E:only‑child|✓| |
|
|
238
|
-
|E:nth‑of‑type(n)|✓| |
|
|
239
|
-
|E:nth‑last‑of‑type(n)|✓| |
|
|
240
|
-
|E:first‑of‑type|✓| |
|
|
241
|
-
|E:last‑of‑type|✓| |
|
|
242
|
-
|E:only‑of‑type|✓| |
|
|
243
|
-
|E:nth‑col(n)|Unsupported| |
|
|
244
|
-
|E:nth‑last‑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‑context(s)|✓| |
|
|
252
|
-
|:host‑context(s):has(rs1, rs2, ...)|✓| |
|
|
253
|
-
|&|✓|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
|
+
[](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
|
|
4
|
+
[](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql)
|
|
5
|
+
[](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]<([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 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" i\]|✓| |
|
|
189
|
+
|E\[foo="bar" 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‑link|✓| |
|
|
203
|
+
|E:link|✓| |
|
|
204
|
+
|E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
|
|
205
|
+
|E:local‑link|✓| |
|
|
206
|
+
|E:target|✓| |
|
|
207
|
+
|E:target‑within|✓| |
|
|
208
|
+
|E:scope|✓| |
|
|
209
|
+
|E:hover|✓| |
|
|
210
|
+
|E:active|✓| |
|
|
211
|
+
|E:focus|✓| |
|
|
212
|
+
|E:focus‑visible|✓| |
|
|
213
|
+
|E:focus‑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 <select>, e.g. `select:open`, is not supported.|
|
|
219
|
+
|E:popover-open|Unsupported| |
|
|
220
|
+
|E:enabled<br>E:disabled|✓| |
|
|
221
|
+
|E:read‑write<br>E:read‑only|✓| |
|
|
222
|
+
|E:placeholder‑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‑valid<br>E:user‑invalid|Unsupported| |
|
|
231
|
+
|E:root|✓| |
|
|
232
|
+
|E:empty|✓| |
|
|
233
|
+
|E:nth‑child(n [of S]?)|✓| |
|
|
234
|
+
|E:nth‑last‑child(n [of S]?)|✓| |
|
|
235
|
+
|E:first‑child|✓| |
|
|
236
|
+
|E:last‑child|✓| |
|
|
237
|
+
|E:only‑child|✓| |
|
|
238
|
+
|E:nth‑of‑type(n)|✓| |
|
|
239
|
+
|E:nth‑last‑of‑type(n)|✓| |
|
|
240
|
+
|E:first‑of‑type|✓| |
|
|
241
|
+
|E:last‑of‑type|✓| |
|
|
242
|
+
|E:only‑of‑type|✓| |
|
|
243
|
+
|E:nth‑col(n)|Unsupported| |
|
|
244
|
+
|E:nth‑last‑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‑context(s)|✓| |
|
|
252
|
+
|:host‑context(s):has(rs1, rs2, ...)|✓| |
|
|
253
|
+
|&|✓|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
|