@asamuzakjp/dom-selector 0.18.1 → 0.19.2
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 +6 -5
- package/package.json +3 -3
- package/src/index.js +21 -36
- package/src/js/constant.js +14 -32
- package/src/js/matcher.js +89 -99
- package/src/js/parser.js +6 -13
- package/types/index.d.ts +7 -6
- package/types/js/matcher.d.ts +6 -5
- package/types/js/parser.d.ts +2 -3
- package/src/js/domexception.js +0 -13
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://github.com/asamuzaK/domSelector/releases)
|
|
9
9
|
-->
|
|
10
10
|
|
|
11
|
-
Retrieve DOM node from the given CSS selector.
|
|
11
|
+
Retrieve DOM node from the given CSS selector.
|
|
12
12
|
**Experimental**
|
|
13
13
|
|
|
14
14
|
## Install
|
|
@@ -20,9 +20,9 @@ npm i @asamuzakjp/dom-selector
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
22
|
```javascript
|
|
23
|
-
|
|
23
|
+
import {
|
|
24
24
|
matches, closest, querySelector, querySelectorAll
|
|
25
|
-
}
|
|
25
|
+
} from '@asamuzakjp/dom-selector';
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
|
@@ -38,7 +38,7 @@ matches - same functionality as [Element.matches()][64]
|
|
|
38
38
|
- `opt` **[object][60]?** options
|
|
39
39
|
- `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
|
|
40
40
|
|
|
41
|
-
Returns **[boolean][61]**
|
|
41
|
+
Returns **[boolean][61]** `true` if matched, `false` otherwise
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
### closest(selector, node, opt)
|
|
@@ -71,7 +71,7 @@ Returns **[object][60]?** matched node
|
|
|
71
71
|
|
|
72
72
|
### querySelectorAll(selector, refPoint, opt)
|
|
73
73
|
|
|
74
|
-
querySelectorAll - same functionality as [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70], [Element.querySelectorAll()][71]
|
|
74
|
+
querySelectorAll - same functionality as [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70], [Element.querySelectorAll()][71]
|
|
75
75
|
**NOTE**: returns Array, not NodeList
|
|
76
76
|
|
|
77
77
|
#### Parameters
|
|
@@ -79,6 +79,7 @@ querySelectorAll - same functionality as [Document.querySelectorAll()][69], [Doc
|
|
|
79
79
|
- `selector` **[string][59]** CSS selector
|
|
80
80
|
- `refPoint` **[object][60]** Document, DocumentFragment or Element node
|
|
81
81
|
- `opt` **[object][60]?** options
|
|
82
|
+
- `opt.sort` **[boolean][61]?** sort matched nodes
|
|
82
83
|
- `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
|
|
83
84
|
|
|
84
85
|
Returns **[Array][62]<([object][60] \| [undefined][63])>** array of matched nodes
|
package/package.json
CHANGED
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"types"
|
|
17
17
|
],
|
|
18
18
|
"main": "src/index.js",
|
|
19
|
+
"type": "module",
|
|
19
20
|
"types": "types/index.d.ts",
|
|
20
21
|
"dependencies": {
|
|
21
22
|
"css-tree": "^2.3.1",
|
|
22
|
-
"domexception": "^4.0.0",
|
|
23
23
|
"is-potential-custom-element-name": "^1.0.1"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"chai": "^4.3.7",
|
|
30
30
|
"eslint": "^8.43.0",
|
|
31
31
|
"eslint-config-standard": "^17.1.0",
|
|
32
|
-
"eslint-plugin-jsdoc": "^46.
|
|
32
|
+
"eslint-plugin-jsdoc": "^46.3.0",
|
|
33
33
|
"eslint-plugin-regexp": "^1.15.0",
|
|
34
34
|
"eslint-plugin-unicorn": "^47.0.0",
|
|
35
35
|
"jsdom": "^22.1.0",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"test": "c8 --reporter=text mocha --exit test/**/*.test.js",
|
|
47
47
|
"tsc": "npx tsc"
|
|
48
48
|
},
|
|
49
|
-
"version": "0.
|
|
49
|
+
"version": "0.19.2"
|
|
50
50
|
}
|
package/src/index.js
CHANGED
|
@@ -4,67 +4,52 @@
|
|
|
4
4
|
* @copyright asamuzaK (Kazz)
|
|
5
5
|
* @see {@link https://github.com/asamuzaK/domSelector/blob/main/LICENSE}
|
|
6
6
|
*/
|
|
7
|
-
'use strict';
|
|
8
7
|
|
|
9
8
|
/* import */
|
|
10
|
-
|
|
9
|
+
import { Matcher } from './js/matcher.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
|
-
* matches
|
|
12
|
+
* matches
|
|
14
13
|
* @param {string} selector - CSS selector
|
|
15
14
|
* @param {object} node - Element node
|
|
16
15
|
* @param {object} [opt] - options
|
|
17
|
-
* @param {
|
|
18
|
-
* @returns {boolean} -
|
|
16
|
+
* @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
|
|
17
|
+
* @returns {boolean} - `true` if matched `false` otherwise
|
|
19
18
|
*/
|
|
20
|
-
const matches = (selector, node, opt) =>
|
|
21
|
-
|
|
22
|
-
return matcher.matches();
|
|
23
|
-
};
|
|
19
|
+
export const matches = (selector, node, opt) =>
|
|
20
|
+
new Matcher(selector, node, opt).matches();
|
|
24
21
|
|
|
25
22
|
/**
|
|
26
|
-
* closest
|
|
23
|
+
* closest
|
|
27
24
|
* @param {string} selector - CSS selector
|
|
28
25
|
* @param {object} node - Element node
|
|
29
26
|
* @param {object} [opt] - options
|
|
30
|
-
* @param {
|
|
27
|
+
* @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
|
|
31
28
|
* @returns {?object} - matched node
|
|
32
29
|
*/
|
|
33
|
-
const closest = (selector, node, opt) =>
|
|
34
|
-
|
|
35
|
-
return matcher.closest();
|
|
36
|
-
};
|
|
30
|
+
export const closest = (selector, node, opt) =>
|
|
31
|
+
new Matcher(selector, node, opt).closest();
|
|
37
32
|
|
|
38
33
|
/**
|
|
39
|
-
* querySelector
|
|
34
|
+
* querySelector
|
|
40
35
|
* @param {string} selector - CSS selector
|
|
41
|
-
* @param {object} refPoint - Document or Element node
|
|
36
|
+
* @param {object} refPoint - Document, DocumentFragment or Element node
|
|
42
37
|
* @param {object} [opt] - options
|
|
43
|
-
* @param {
|
|
38
|
+
* @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
|
|
44
39
|
* @returns {?object} - matched node
|
|
45
40
|
*/
|
|
46
|
-
const querySelector = (selector, refPoint, opt) =>
|
|
47
|
-
|
|
48
|
-
return matcher.querySelector();
|
|
49
|
-
};
|
|
41
|
+
export const querySelector = (selector, refPoint, opt) =>
|
|
42
|
+
new Matcher(selector, refPoint, opt).querySelector();
|
|
50
43
|
|
|
51
44
|
/**
|
|
52
|
-
* querySelectorAll
|
|
45
|
+
* querySelectorAll
|
|
53
46
|
* NOTE: returns Array, not NodeList
|
|
54
47
|
* @param {string} selector - CSS selector
|
|
55
|
-
* @param {object} refPoint - Document or Element node
|
|
48
|
+
* @param {object} refPoint - Document, DocumentFragment or Element node
|
|
56
49
|
* @param {object} [opt] - options
|
|
57
|
-
* @param {
|
|
50
|
+
* @param {boolean} [opt.sort] - sort matched nodes
|
|
51
|
+
* @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
|
|
58
52
|
* @returns {Array.<object|undefined>} - array of matched nodes
|
|
59
53
|
*/
|
|
60
|
-
const querySelectorAll = (selector, refPoint, opt) =>
|
|
61
|
-
|
|
62
|
-
return matcher.querySelectorAll();
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
module.exports = {
|
|
66
|
-
closest,
|
|
67
|
-
matches,
|
|
68
|
-
querySelector,
|
|
69
|
-
querySelectorAll
|
|
70
|
-
};
|
|
54
|
+
export const querySelectorAll = (selector, refPoint, opt) =>
|
|
55
|
+
new Matcher(selector, refPoint, opt).querySelectorAll();
|
package/src/js/constant.js
CHANGED
|
@@ -1,36 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* constant.js
|
|
3
3
|
*/
|
|
4
|
-
'use strict';
|
|
5
4
|
|
|
6
|
-
const AN_PLUS_B = 'AnPlusB';
|
|
7
|
-
const ATTRIBUTE_SELECTOR = 'AttributeSelector';
|
|
8
|
-
const CLASS_SELECTOR = 'ClassSelector';
|
|
9
|
-
const COMBINATOR = 'Combinator';
|
|
10
|
-
const ID_SELECTOR = 'IdSelector';
|
|
11
|
-
const IDENTIFIER = 'Identifier';
|
|
12
|
-
const NTH = 'Nth';
|
|
13
|
-
const PSEUDO_CLASS_SELECTOR = 'PseudoClassSelector';
|
|
14
|
-
const PSEUDO_ELEMENT_SELECTOR = 'PseudoElementSelector';
|
|
15
|
-
const RAW = 'Raw';
|
|
16
|
-
const SELECTOR = 'Selector';
|
|
17
|
-
const SELECTOR_LIST = 'SelectorList';
|
|
18
|
-
const STRING = 'String';
|
|
19
|
-
const TYPE_SELECTOR = 'TypeSelector';
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
AN_PLUS_B,
|
|
23
|
-
ATTRIBUTE_SELECTOR,
|
|
24
|
-
CLASS_SELECTOR,
|
|
25
|
-
COMBINATOR,
|
|
26
|
-
ID_SELECTOR,
|
|
27
|
-
IDENTIFIER,
|
|
28
|
-
NTH,
|
|
29
|
-
PSEUDO_CLASS_SELECTOR,
|
|
30
|
-
PSEUDO_ELEMENT_SELECTOR,
|
|
31
|
-
RAW,
|
|
32
|
-
SELECTOR,
|
|
33
|
-
SELECTOR_LIST,
|
|
34
|
-
STRING,
|
|
35
|
-
TYPE_SELECTOR
|
|
36
|
-
};
|
|
5
|
+
export const AN_PLUS_B = 'AnPlusB';
|
|
6
|
+
export const ATTRIBUTE_SELECTOR = 'AttributeSelector';
|
|
7
|
+
export const CLASS_SELECTOR = 'ClassSelector';
|
|
8
|
+
export const COMBINATOR = 'Combinator';
|
|
9
|
+
export const ID_SELECTOR = 'IdSelector';
|
|
10
|
+
export const IDENTIFIER = 'Identifier';
|
|
11
|
+
export const NTH = 'Nth';
|
|
12
|
+
export const PSEUDO_CLASS_SELECTOR = 'PseudoClassSelector';
|
|
13
|
+
export const PSEUDO_ELEMENT_SELECTOR = 'PseudoElementSelector';
|
|
14
|
+
export const RAW = 'Raw';
|
|
15
|
+
export const SELECTOR = 'Selector';
|
|
16
|
+
export const SELECTOR_LIST = 'SelectorList';
|
|
17
|
+
export const STRING = 'String';
|
|
18
|
+
export const TYPE_SELECTOR = 'TypeSelector';
|
package/src/js/matcher.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* matcher.js
|
|
3
3
|
*/
|
|
4
|
-
'use strict';
|
|
5
4
|
|
|
6
5
|
/* import */
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const { generateCSS, parseSelector, walkAST } = require('./parser.js');
|
|
6
|
+
import isCustomElementName from 'is-potential-custom-element-name';
|
|
7
|
+
import { generateCSS, parseSelector, walkAST } from './parser.js';
|
|
10
8
|
|
|
11
9
|
/* constants */
|
|
12
|
-
|
|
10
|
+
import {
|
|
13
11
|
ATTRIBUTE_SELECTOR, CLASS_SELECTOR, COMBINATOR, ID_SELECTOR,
|
|
14
12
|
PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, TYPE_SELECTOR
|
|
15
|
-
}
|
|
13
|
+
} from './constant.js';
|
|
16
14
|
const BIT_ATTRIBUTE_SELECTOR = 16;
|
|
17
15
|
const BIT_CLASS_SELECTOR = 2;
|
|
18
16
|
const BIT_ID_SELECTOR = 4;
|
|
@@ -46,7 +44,7 @@ const WHITESPACE = /^[\n\r\f]/;
|
|
|
46
44
|
* @param {object} node - Element
|
|
47
45
|
* @returns {boolean} - result
|
|
48
46
|
*/
|
|
49
|
-
const isContentEditable = (node = {}) => {
|
|
47
|
+
export const isContentEditable = (node = {}) => {
|
|
50
48
|
let res;
|
|
51
49
|
if (node.nodeType === ELEMENT_NODE) {
|
|
52
50
|
if (node.ownerDocument.designMode === 'on') {
|
|
@@ -76,7 +74,7 @@ const isContentEditable = (node = {}) => {
|
|
|
76
74
|
* @param {object} node - Element node
|
|
77
75
|
* @returns {boolean} - result
|
|
78
76
|
*/
|
|
79
|
-
const isNamespaceDeclared = (ns = '', node = {}) => {
|
|
77
|
+
export const isNamespaceDeclared = (ns = '', node = {}) => {
|
|
80
78
|
let res;
|
|
81
79
|
if (ns && typeof ns === 'string' && node.nodeType === ELEMENT_NODE) {
|
|
82
80
|
const attr = `xmlns:${ns}`;
|
|
@@ -102,7 +100,7 @@ const isNamespaceDeclared = (ns = '', node = {}) => {
|
|
|
102
100
|
* @param {object} root - Document, DocumentFragment, Element node
|
|
103
101
|
* @returns {boolean} - result
|
|
104
102
|
*/
|
|
105
|
-
const isDescendant = (node = {}, root = {}) => {
|
|
103
|
+
export const isDescendant = (node = {}, root = {}) => {
|
|
106
104
|
const { nodeType, ownerDocument } = node;
|
|
107
105
|
let res;
|
|
108
106
|
if (nodeType === ELEMENT_NODE && ownerDocument) {
|
|
@@ -123,7 +121,7 @@ const isDescendant = (node = {}, root = {}) => {
|
|
|
123
121
|
* @param {string} selector - CSS selector
|
|
124
122
|
* @returns {?string} - unescaped selector
|
|
125
123
|
*/
|
|
126
|
-
const unescapeSelector = (selector = '') => {
|
|
124
|
+
export const unescapeSelector = (selector = '') => {
|
|
127
125
|
if (typeof selector === 'string' && selector.indexOf('\\', 0) >= 0) {
|
|
128
126
|
const arr = selector.split('\\');
|
|
129
127
|
const l = arr.length;
|
|
@@ -170,7 +168,7 @@ const unescapeSelector = (selector = '') => {
|
|
|
170
168
|
* @param {object} [node] - Element node
|
|
171
169
|
* @returns {object} - parsed AST name
|
|
172
170
|
*/
|
|
173
|
-
const parseASTName = (name, node) => {
|
|
171
|
+
export const parseASTName = (name, node) => {
|
|
174
172
|
let astPrefix, astNodeName;
|
|
175
173
|
if (name && typeof name === 'string') {
|
|
176
174
|
if (/\|/.test(name)) {
|
|
@@ -194,57 +192,63 @@ const parseASTName = (name, node) => {
|
|
|
194
192
|
|
|
195
193
|
/**
|
|
196
194
|
* Matcher
|
|
195
|
+
* NOTE: #list[i] corresponds to #matrix[i]
|
|
196
|
+
* #list: [
|
|
197
|
+
* {
|
|
198
|
+
* branch: branch[],
|
|
199
|
+
* skip: boolean
|
|
200
|
+
* },
|
|
201
|
+
* {
|
|
202
|
+
* branch: branch[],
|
|
203
|
+
* skip: boolean
|
|
204
|
+
* }
|
|
205
|
+
* ]
|
|
206
|
+
* #matrix: [
|
|
207
|
+
* [
|
|
208
|
+
* Set([node, node]),
|
|
209
|
+
* Set([node, node, node]
|
|
210
|
+
* Set([node, node])
|
|
211
|
+
* ],
|
|
212
|
+
* [
|
|
213
|
+
* Set([node, node, node]),
|
|
214
|
+
* Set([node, node])
|
|
215
|
+
* ]
|
|
216
|
+
* ]
|
|
217
|
+
* branch[]: [twig{}, twig{}]
|
|
218
|
+
* twig{}: {
|
|
219
|
+
* combo: leaf{}|null,
|
|
220
|
+
* leaves: leaves[]
|
|
221
|
+
* }
|
|
222
|
+
* leaves[]: [leaf{}, leaf{}, leaf{}]
|
|
223
|
+
* leaf{}: AST leaf
|
|
224
|
+
* node: Element node
|
|
197
225
|
*/
|
|
198
|
-
class Matcher {
|
|
226
|
+
export class Matcher {
|
|
199
227
|
/* private fields */
|
|
200
228
|
#list;
|
|
201
229
|
#matrix;
|
|
202
230
|
#node;
|
|
203
231
|
#root;
|
|
204
232
|
#selector;
|
|
233
|
+
#sort;
|
|
205
234
|
#warn;
|
|
206
235
|
|
|
207
|
-
/**
|
|
208
|
-
* NOTE: #list[i] corresponds to #matrix[i]
|
|
209
|
-
* #list: [
|
|
210
|
-
* { branch: branch[], skip: boolean },
|
|
211
|
-
* { branch: branch[], skip: boolean }
|
|
212
|
-
* ]
|
|
213
|
-
* branch[]: [twig{}, twig{}]
|
|
214
|
-
* twig{}: {
|
|
215
|
-
* combo: leaf{}|null,
|
|
216
|
-
* leaves: leaves[]
|
|
217
|
-
* }
|
|
218
|
-
* leaves[]: [leaf{}, leaf{}, leaf{}]
|
|
219
|
-
* leaf{}: AST leaf
|
|
220
|
-
* #matrix: [
|
|
221
|
-
* [
|
|
222
|
-
* Set([node, node]),
|
|
223
|
-
* Set([node, node, node]
|
|
224
|
-
* Set([node, node])
|
|
225
|
-
* ],
|
|
226
|
-
* [
|
|
227
|
-
* Set([node, node, node]),
|
|
228
|
-
* Set([node, node])
|
|
229
|
-
* ]
|
|
230
|
-
* ]
|
|
231
|
-
* node: Element node
|
|
232
|
-
*/
|
|
233
|
-
|
|
234
236
|
/**
|
|
235
237
|
* construct
|
|
236
238
|
* @param {string} selector - CSS selector
|
|
237
239
|
* @param {object} node - Document, DocumentFragment, Element node
|
|
238
240
|
* @param {object} [opt] - options
|
|
241
|
+
* @param {boolean} [opt.sort] - sort results of querySelectorAll()
|
|
239
242
|
* @param {boolean} [opt.warn] - console warn
|
|
240
243
|
*/
|
|
241
244
|
constructor(selector, node, opt = {}) {
|
|
242
|
-
const { warn } = opt;
|
|
243
|
-
[this.#list, this.#matrix] = this._prepare(selector);
|
|
245
|
+
const { sort, warn } = opt;
|
|
244
246
|
this.#node = node;
|
|
245
247
|
this.#root = this._getRoot(node);
|
|
246
248
|
this.#selector = selector;
|
|
249
|
+
this.#sort = !!sort;
|
|
247
250
|
this.#warn = !!warn;
|
|
251
|
+
this._prepare(selector);
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
/**
|
|
@@ -313,29 +317,31 @@ class Matcher {
|
|
|
313
317
|
*/
|
|
314
318
|
_sortLeaves(leaves) {
|
|
315
319
|
const arr = [...leaves];
|
|
316
|
-
|
|
317
|
-
[
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
320
|
+
if (arr.length > 1) {
|
|
321
|
+
const bitMap = new Map([
|
|
322
|
+
[ATTRIBUTE_SELECTOR, BIT_ATTRIBUTE_SELECTOR],
|
|
323
|
+
[CLASS_SELECTOR, BIT_CLASS_SELECTOR],
|
|
324
|
+
[ID_SELECTOR, BIT_ID_SELECTOR],
|
|
325
|
+
[PSEUDO_CLASS_SELECTOR, BIT_PSEUDO_CLASS_SELECTOR],
|
|
326
|
+
[PSEUDO_ELEMENT_SELECTOR, BIT_PSEUDO_ELEMENT_SELECTOR],
|
|
327
|
+
[TYPE_SELECTOR, BIT_TYPE_SELECTOR]
|
|
328
|
+
]);
|
|
329
|
+
arr.sort((a, b) => {
|
|
330
|
+
const { type: typeA } = a;
|
|
331
|
+
const { type: typeB } = b;
|
|
332
|
+
const bitA = bitMap.get(typeA);
|
|
333
|
+
const bitB = bitMap.get(typeB);
|
|
334
|
+
let res;
|
|
335
|
+
if (bitA === bitB) {
|
|
336
|
+
res = 0;
|
|
337
|
+
} else if (bitA > bitB) {
|
|
338
|
+
res = 1;
|
|
339
|
+
} else {
|
|
340
|
+
res = -1;
|
|
341
|
+
}
|
|
342
|
+
return res;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
339
345
|
return arr;
|
|
340
346
|
}
|
|
341
347
|
|
|
@@ -735,7 +741,7 @@ class Matcher {
|
|
|
735
741
|
}
|
|
736
742
|
|
|
737
743
|
/**
|
|
738
|
-
* match logical pseudo-class functions - :
|
|
744
|
+
* match logical pseudo-class functions - :has(), :is(), :not(), :where()
|
|
739
745
|
* @param {object} ast - AST
|
|
740
746
|
* @param {object} node - Element node
|
|
741
747
|
* @returns {?object} - matched node
|
|
@@ -2187,14 +2193,7 @@ class Matcher {
|
|
|
2187
2193
|
if (bool) {
|
|
2188
2194
|
for (const pendingItem of pendingItems) {
|
|
2189
2195
|
const { leaves } = pendingItem.get('twig');
|
|
2190
|
-
const
|
|
2191
|
-
let matched;
|
|
2192
|
-
for (const leaf of leafIterator) {
|
|
2193
|
-
matched = this._matchSelector(leaf, nextNode).has(nextNode);
|
|
2194
|
-
if (!matched) {
|
|
2195
|
-
break;
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2196
|
+
const matched = this._matchLeaves(leaves, nextNode);
|
|
2198
2197
|
if (matched) {
|
|
2199
2198
|
const indexI = pendingItem.get('i');
|
|
2200
2199
|
const indexJ = pendingItem.get('j');
|
|
@@ -2331,7 +2330,7 @@ class Matcher {
|
|
|
2331
2330
|
const twig = branch[j];
|
|
2332
2331
|
for (const nextNode of nextNodes) {
|
|
2333
2332
|
matched = this._matchTwig(twig, nextNode, {
|
|
2334
|
-
|
|
2333
|
+
find: 'prev'
|
|
2335
2334
|
});
|
|
2336
2335
|
}
|
|
2337
2336
|
if (matched.size) {
|
|
@@ -2381,23 +2380,25 @@ class Matcher {
|
|
|
2381
2380
|
*/
|
|
2382
2381
|
_sortNodes(nodes) {
|
|
2383
2382
|
const arr = [...nodes];
|
|
2384
|
-
arr.
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2383
|
+
if (arr.length > 1) {
|
|
2384
|
+
arr.sort((a, b) => {
|
|
2385
|
+
let res;
|
|
2386
|
+
const posBit = a.compareDocumentPosition(b);
|
|
2387
|
+
if (posBit & DOCUMENT_POSITION_PRECEDING ||
|
|
2388
|
+
posBit & DOCUMENT_POSITION_CONTAINS) {
|
|
2389
|
+
res = 1;
|
|
2390
|
+
} else {
|
|
2391
|
+
res = -1;
|
|
2392
|
+
}
|
|
2393
|
+
return res;
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2395
2396
|
return arr;
|
|
2396
2397
|
}
|
|
2397
2398
|
|
|
2398
2399
|
/**
|
|
2399
2400
|
* matches
|
|
2400
|
-
* @returns {boolean} - matched
|
|
2401
|
+
* @returns {boolean} - `true` if matched `false` otherwise
|
|
2401
2402
|
*/
|
|
2402
2403
|
matches() {
|
|
2403
2404
|
let res;
|
|
@@ -2441,10 +2442,8 @@ class Matcher {
|
|
|
2441
2442
|
try {
|
|
2442
2443
|
const nodes = this._find('first');
|
|
2443
2444
|
nodes.delete(this.#node);
|
|
2444
|
-
if (nodes.size
|
|
2445
|
+
if (nodes.size) {
|
|
2445
2446
|
[res] = this._sortNodes(nodes);
|
|
2446
|
-
} else if (nodes.size) {
|
|
2447
|
-
[res] = [...nodes];
|
|
2448
2447
|
}
|
|
2449
2448
|
} catch (e) {
|
|
2450
2449
|
this._onError(e);
|
|
@@ -2462,7 +2461,7 @@ class Matcher {
|
|
|
2462
2461
|
try {
|
|
2463
2462
|
const nodes = this._find('all');
|
|
2464
2463
|
nodes.delete(this.#node);
|
|
2465
|
-
if (nodes.size > 1) {
|
|
2464
|
+
if (nodes.size > 1 && this.#sort) {
|
|
2466
2465
|
res.push(...this._sortNodes(nodes));
|
|
2467
2466
|
} else if (nodes.size) {
|
|
2468
2467
|
res.push(...nodes);
|
|
@@ -2473,12 +2472,3 @@ class Matcher {
|
|
|
2473
2472
|
return res;
|
|
2474
2473
|
}
|
|
2475
2474
|
};
|
|
2476
|
-
|
|
2477
|
-
module.exports = {
|
|
2478
|
-
Matcher,
|
|
2479
|
-
isContentEditable,
|
|
2480
|
-
isDescendant,
|
|
2481
|
-
isNamespaceDeclared,
|
|
2482
|
-
parseASTName,
|
|
2483
|
-
unescapeSelector
|
|
2484
|
-
};
|
package/src/js/parser.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* parser.js
|
|
3
3
|
*/
|
|
4
|
-
'use strict';
|
|
5
4
|
|
|
6
5
|
/* import */
|
|
7
|
-
|
|
8
|
-
const DOMException = require('./domexception.js');
|
|
6
|
+
import { findAll, parse, toPlainObject, walk } from 'css-tree';
|
|
9
7
|
|
|
10
8
|
/* constants */
|
|
11
|
-
|
|
9
|
+
import { PSEUDO_CLASS_SELECTOR, SELECTOR } from './constant.js';
|
|
12
10
|
const CODE_POINT_UNIT = parseInt('10000', 16);
|
|
13
11
|
const HEX = 16;
|
|
14
12
|
const PAIR = 2;
|
|
@@ -24,7 +22,7 @@ const PSEUDO_FUNC = /^(?:(?:ha|i)s|not|where)$/;
|
|
|
24
22
|
* @param {...*} args - arguments
|
|
25
23
|
* @returns {string} - filtered selector string
|
|
26
24
|
*/
|
|
27
|
-
const preprocess = (...args) => {
|
|
25
|
+
export const preprocess = (...args) => {
|
|
28
26
|
if (!args.length) {
|
|
29
27
|
throw new TypeError('1 argument required, but only 0 present');
|
|
30
28
|
}
|
|
@@ -66,7 +64,7 @@ const preprocess = (...args) => {
|
|
|
66
64
|
* @param {string} selector - CSS selector
|
|
67
65
|
* @returns {object} - AST
|
|
68
66
|
*/
|
|
69
|
-
const parseSelector = selector => {
|
|
67
|
+
export const parseSelector = selector => {
|
|
70
68
|
selector = preprocess(selector);
|
|
71
69
|
// invalid selectors
|
|
72
70
|
if (selector === '' || /^\s*>/.test(selector) || /,\s*$/.test(selector)) {
|
|
@@ -96,7 +94,7 @@ const parseSelector = selector => {
|
|
|
96
94
|
* @param {object} ast - AST
|
|
97
95
|
* @returns {Array.<object|undefined>} - collection of AST branches
|
|
98
96
|
*/
|
|
99
|
-
const walkAST = (ast = {}) => {
|
|
97
|
+
export const walkAST = (ast = {}) => {
|
|
100
98
|
const branches = new Set();
|
|
101
99
|
let hasPseudoFunc;
|
|
102
100
|
const opt = {
|
|
@@ -139,9 +137,4 @@ const walkAST = (ast = {}) => {
|
|
|
139
137
|
};
|
|
140
138
|
|
|
141
139
|
/* export */
|
|
142
|
-
|
|
143
|
-
generateCSS: generate,
|
|
144
|
-
parseSelector,
|
|
145
|
-
preprocess,
|
|
146
|
-
walkAST
|
|
147
|
-
};
|
|
140
|
+
export { generate as generateCSS } from 'css-tree';
|
package/types/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
export function closest(selector: string, node: object, opt?: {
|
|
2
|
-
warn?: object;
|
|
3
|
-
}): object | null;
|
|
4
1
|
export function matches(selector: string, node: object, opt?: {
|
|
5
|
-
warn?:
|
|
2
|
+
warn?: boolean;
|
|
6
3
|
}): boolean;
|
|
4
|
+
export function closest(selector: string, node: object, opt?: {
|
|
5
|
+
warn?: boolean;
|
|
6
|
+
}): object | null;
|
|
7
7
|
export function querySelector(selector: string, refPoint: object, opt?: {
|
|
8
|
-
warn?:
|
|
8
|
+
warn?: boolean;
|
|
9
9
|
}): object | null;
|
|
10
10
|
export function querySelectorAll(selector: string, refPoint: object, opt?: {
|
|
11
|
-
|
|
11
|
+
sort?: boolean;
|
|
12
|
+
warn?: boolean;
|
|
12
13
|
}): Array<object | undefined>;
|
package/types/js/matcher.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
export function isContentEditable(node?: object): boolean;
|
|
2
|
+
export function isNamespaceDeclared(ns?: string, node?: object): boolean;
|
|
3
|
+
export function isDescendant(node?: object, root?: object): boolean;
|
|
4
|
+
export function unescapeSelector(selector?: string): string | null;
|
|
5
|
+
export function parseASTName(name: string, node?: object): object;
|
|
1
6
|
export class Matcher {
|
|
2
7
|
constructor(selector: string, node: object, opt?: {
|
|
8
|
+
sort?: boolean;
|
|
3
9
|
warn?: boolean;
|
|
4
10
|
});
|
|
5
11
|
_onError(e: Error): void;
|
|
@@ -44,8 +50,3 @@ export class Matcher {
|
|
|
44
50
|
querySelectorAll(): Array<object | undefined>;
|
|
45
51
|
#private;
|
|
46
52
|
}
|
|
47
|
-
export function isContentEditable(node?: object): boolean;
|
|
48
|
-
export function isDescendant(node?: object, root?: object): boolean;
|
|
49
|
-
export function isNamespaceDeclared(ns?: string, node?: object): boolean;
|
|
50
|
-
export function parseASTName(name: string, node?: object): object;
|
|
51
|
-
export function unescapeSelector(selector?: string): string | null;
|
package/types/js/parser.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { generate } from "css-tree";
|
|
2
|
-
export function parseSelector(selector: string): object;
|
|
3
1
|
export function preprocess(...args: any[]): string;
|
|
2
|
+
export function parseSelector(selector: string): object;
|
|
4
3
|
export function walkAST(ast?: object): Array<object | undefined>;
|
|
5
|
-
export { generate as generateCSS };
|
|
4
|
+
export { generate as generateCSS } from "css-tree";
|
package/src/js/domexception.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* domexception.js
|
|
3
|
-
*/
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
// NOTE: Node.js has DOMException global since v17.0.0
|
|
7
|
-
if (!globalThis.DOMException) {
|
|
8
|
-
/* import */
|
|
9
|
-
const DOMException = require('domexception');
|
|
10
|
-
globalThis.DOMException = DOMException;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
module.exports = globalThis.DOMException;
|