@asamuzakjp/dom-selector 1.2.2 → 1.2.4
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 +32 -32
- package/dist/cjs/js/constant.js +1 -1
- package/dist/cjs/js/constant.js.map +3 -3
- package/dist/cjs/js/matcher.js +1 -1
- package/dist/cjs/js/matcher.js.map +3 -3
- package/package.json +3 -3
- package/src/js/constant.js +2 -0
- package/src/js/matcher.js +393 -145
- package/types/js/constant.d.ts +2 -0
- package/types/js/matcher.d.ts +9 -3
package/src/js/matcher.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
DOCUMENT_FRAGMENT_NODE, DOCUMENT_NODE, ELEMENT_NODE, NOT_SUPPORTED_ERR,
|
|
19
19
|
REG_LOGICAL_PSEUDO, REG_SHADOW_HOST, SELECTOR_ATTR, SELECTOR_CLASS,
|
|
20
20
|
SELECTOR_ID, SELECTOR_PSEUDO_CLASS, SELECTOR_PSEUDO_ELEMENT, SELECTOR_TYPE,
|
|
21
|
-
SHOW_ELEMENT, SYNTAX_ERR, TEXT_NODE
|
|
21
|
+
SHOW_DOCUMENT, SHOW_DOCUMENT_FRAGMENT, SHOW_ELEMENT, SYNTAX_ERR, TEXT_NODE
|
|
22
22
|
} from './constant.js';
|
|
23
23
|
const FIND_NEXT = 'next';
|
|
24
24
|
const FIND_PREV = 'prev';
|
|
@@ -62,10 +62,13 @@ export class Matcher {
|
|
|
62
62
|
#ast;
|
|
63
63
|
#bit;
|
|
64
64
|
#cache;
|
|
65
|
+
#document;
|
|
65
66
|
#node;
|
|
66
67
|
#nodes;
|
|
67
68
|
#root;
|
|
68
|
-
#
|
|
69
|
+
#shadow;
|
|
70
|
+
#subtree;
|
|
71
|
+
#tree;
|
|
69
72
|
#warn;
|
|
70
73
|
|
|
71
74
|
/**
|
|
@@ -86,11 +89,11 @@ export class Matcher {
|
|
|
86
89
|
[SELECTOR_PSEUDO_CLASS, BIT_32]
|
|
87
90
|
]);
|
|
88
91
|
this.#cache = new WeakMap();
|
|
89
|
-
this.#
|
|
92
|
+
[this.#ast, this.#nodes] = this._prepare(selector);
|
|
90
93
|
this.#node = node;
|
|
94
|
+
[this.#document, this.#root, this.#tree] = this._setup(node);
|
|
95
|
+
this.#shadow = isInShadowTree(node);
|
|
91
96
|
this.#warn = !!warn;
|
|
92
|
-
[this.#ast, this.#nodes] = this._prepare(selector);
|
|
93
|
-
this.#root = this._getRoot(node);
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
/**
|
|
@@ -110,11 +113,11 @@ export class Matcher {
|
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
/**
|
|
113
|
-
*
|
|
116
|
+
* set up document, root, walker
|
|
114
117
|
* @param {object} node - Document, DocumentFragment, Element node
|
|
115
|
-
* @returns {object} - root
|
|
118
|
+
* @returns {Array.<object>} - document, root, walker
|
|
116
119
|
*/
|
|
117
|
-
|
|
120
|
+
_setup(node) {
|
|
118
121
|
let document;
|
|
119
122
|
let root;
|
|
120
123
|
switch (node.nodeType) {
|
|
@@ -150,12 +153,13 @@ export class Matcher {
|
|
|
150
153
|
throw new TypeError(`Unexpected node ${node.nodeName}`);
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
|
-
const
|
|
154
|
-
|
|
156
|
+
const filter = SHOW_DOCUMENT | SHOW_DOCUMENT_FRAGMENT | SHOW_ELEMENT;
|
|
157
|
+
const walker = document.createTreeWalker(root, filter);
|
|
158
|
+
return [
|
|
155
159
|
document,
|
|
156
160
|
root,
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
walker
|
|
162
|
+
];
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
/**
|
|
@@ -190,7 +194,7 @@ export class Matcher {
|
|
|
190
194
|
* @param {string} selector - CSS selector
|
|
191
195
|
* @returns {Array.<Array.<object|undefined>>} - array of ast and nodes
|
|
192
196
|
*/
|
|
193
|
-
_prepare(selector
|
|
197
|
+
_prepare(selector) {
|
|
194
198
|
const ast = parseSelector(selector);
|
|
195
199
|
const branches = walkAST(ast);
|
|
196
200
|
const tree = [];
|
|
@@ -243,6 +247,42 @@ export class Matcher {
|
|
|
243
247
|
];
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
/**
|
|
251
|
+
* traverse tree walker
|
|
252
|
+
* @param {object} [node] - Element node
|
|
253
|
+
* @param {object} [tree] - tree walker
|
|
254
|
+
* @returns {?object} - node
|
|
255
|
+
*/
|
|
256
|
+
_traverse(node = {}, tree = this.#tree) {
|
|
257
|
+
let current;
|
|
258
|
+
let refNode = tree.currentNode;
|
|
259
|
+
if (node.nodeType === ELEMENT_NODE && refNode === node) {
|
|
260
|
+
current = refNode;
|
|
261
|
+
} else {
|
|
262
|
+
if (refNode !== tree.root) {
|
|
263
|
+
while (refNode) {
|
|
264
|
+
if (refNode === tree.root ||
|
|
265
|
+
(node.nodeType === ELEMENT_NODE && refNode === node)) {
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
refNode = tree.parentNode();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (node.nodeType === ELEMENT_NODE) {
|
|
272
|
+
while (refNode) {
|
|
273
|
+
if (refNode === node) {
|
|
274
|
+
current = refNode;
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
refNode = tree.nextNode();
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
current = refNode;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return current ?? null;
|
|
284
|
+
}
|
|
285
|
+
|
|
246
286
|
/**
|
|
247
287
|
* collect nth child
|
|
248
288
|
* @param {object} anb - An+B options
|
|
@@ -267,16 +307,15 @@ export class Matcher {
|
|
|
267
307
|
}
|
|
268
308
|
}
|
|
269
309
|
if (parentNode) {
|
|
270
|
-
const arr = [].slice.call(parentNode.
|
|
310
|
+
const arr = [].slice.call(parentNode.childNodes)
|
|
311
|
+
.filter(n => n.nodeType === ELEMENT_NODE);
|
|
271
312
|
const l = arr.length;
|
|
272
313
|
if (l) {
|
|
273
314
|
const selectorNodes = new Set();
|
|
274
315
|
if (selectorBranches) {
|
|
275
|
-
const branchesLen = selectorBranches.length;
|
|
276
316
|
for (const refNode of arr) {
|
|
277
317
|
let bool;
|
|
278
|
-
for (
|
|
279
|
-
const leaves = selectorBranches[i];
|
|
318
|
+
for (const leaves of selectorBranches) {
|
|
280
319
|
bool = this._matchLeaves(leaves, refNode);
|
|
281
320
|
if (!bool) {
|
|
282
321
|
break;
|
|
@@ -294,8 +333,7 @@ export class Matcher {
|
|
|
294
333
|
if (a === 0) {
|
|
295
334
|
if (b > 0 && b <= l) {
|
|
296
335
|
if (selectorNodes.size) {
|
|
297
|
-
for (
|
|
298
|
-
const current = arr[i];
|
|
336
|
+
for (const current of arr) {
|
|
299
337
|
if (selectorNodes.has(current)) {
|
|
300
338
|
matched.add(current);
|
|
301
339
|
break;
|
|
@@ -341,13 +379,11 @@ export class Matcher {
|
|
|
341
379
|
}
|
|
342
380
|
}
|
|
343
381
|
} else {
|
|
344
|
-
|
|
345
|
-
|
|
382
|
+
if (node === this.#root && this.#root.nodeType === ELEMENT_NODE &&
|
|
383
|
+
(a + b) === 1) {
|
|
346
384
|
if (selectorBranches) {
|
|
347
|
-
const branchesLen = selectorBranches.length;
|
|
348
385
|
let bool;
|
|
349
|
-
for (
|
|
350
|
-
const leaves = selectorBranches[i];
|
|
386
|
+
for (const leaves of selectorBranches) {
|
|
351
387
|
bool = this._matchLeaves(leaves, node);
|
|
352
388
|
if (bool) {
|
|
353
389
|
break;
|
|
@@ -378,7 +414,8 @@ export class Matcher {
|
|
|
378
414
|
const { localName, parentNode, prefix } = node;
|
|
379
415
|
const matched = new Set();
|
|
380
416
|
if (parentNode) {
|
|
381
|
-
const arr = [].slice.call(parentNode.
|
|
417
|
+
const arr = [].slice.call(parentNode.childNodes)
|
|
418
|
+
.filter(n => n.nodeType === ELEMENT_NODE);
|
|
382
419
|
const l = arr.length;
|
|
383
420
|
if (l) {
|
|
384
421
|
if (reverse) {
|
|
@@ -388,8 +425,7 @@ export class Matcher {
|
|
|
388
425
|
if (a === 0) {
|
|
389
426
|
if (b > 0 && b <= l) {
|
|
390
427
|
let j = 0;
|
|
391
|
-
for (
|
|
392
|
-
const current = arr[i];
|
|
428
|
+
for (const current of arr) {
|
|
393
429
|
const { localName: itemLocalName, prefix: itemPrefix } = current;
|
|
394
430
|
if (itemLocalName === localName && itemPrefix === prefix) {
|
|
395
431
|
if (j === b - 1) {
|
|
@@ -410,8 +446,7 @@ export class Matcher {
|
|
|
410
446
|
}
|
|
411
447
|
if (nth >= 0 && nth < l) {
|
|
412
448
|
let j = a > 0 ? 0 : b - 1;
|
|
413
|
-
for (
|
|
414
|
-
const current = arr[i];
|
|
449
|
+
for (const current of arr) {
|
|
415
450
|
const { localName: itemLocalName, prefix: itemPrefix } = current;
|
|
416
451
|
if (itemLocalName === localName && itemPrefix === prefix) {
|
|
417
452
|
if (j === nth) {
|
|
@@ -431,8 +466,8 @@ export class Matcher {
|
|
|
431
466
|
}
|
|
432
467
|
}
|
|
433
468
|
} else {
|
|
434
|
-
|
|
435
|
-
|
|
469
|
+
if (node === this.#root && this.#root.nodeType === ELEMENT_NODE &&
|
|
470
|
+
(a + b) === 1) {
|
|
436
471
|
matched.add(node);
|
|
437
472
|
}
|
|
438
473
|
}
|
|
@@ -900,7 +935,6 @@ export class Matcher {
|
|
|
900
935
|
}
|
|
901
936
|
}
|
|
902
937
|
} else {
|
|
903
|
-
const { document, root } = this.#root;
|
|
904
938
|
const regAnchor = /^a(?:rea)?$/;
|
|
905
939
|
const regFormCtrl =
|
|
906
940
|
/^(?:(?:fieldse|inpu|selec)t|button|opt(?:group|ion)|textarea)$/;
|
|
@@ -921,7 +955,7 @@ export class Matcher {
|
|
|
921
955
|
}
|
|
922
956
|
case 'local-link': {
|
|
923
957
|
if (regAnchor.test(localName) && node.hasAttribute('href')) {
|
|
924
|
-
const { href, origin, pathname } = new URL(document.URL);
|
|
958
|
+
const { href, origin, pathname } = new URL(this.#document.URL);
|
|
925
959
|
const attrURL = new URL(node.getAttribute('href'), href);
|
|
926
960
|
if (attrURL.origin === origin && attrURL.pathname === pathname) {
|
|
927
961
|
matched.add(node);
|
|
@@ -934,17 +968,18 @@ export class Matcher {
|
|
|
934
968
|
break;
|
|
935
969
|
}
|
|
936
970
|
case 'target': {
|
|
937
|
-
const { hash } = new URL(document.URL);
|
|
938
|
-
if (node.id && hash === `#${node.id}` &&
|
|
971
|
+
const { hash } = new URL(this.#document.URL);
|
|
972
|
+
if (node.id && hash === `#${node.id}` &&
|
|
973
|
+
this.#document.contains(node)) {
|
|
939
974
|
matched.add(node);
|
|
940
975
|
}
|
|
941
976
|
break;
|
|
942
977
|
}
|
|
943
978
|
case 'target-within': {
|
|
944
|
-
const { hash } = new URL(document.URL);
|
|
979
|
+
const { hash } = new URL(this.#document.URL);
|
|
945
980
|
if (hash) {
|
|
946
981
|
const id = hash.replace(/^#/, '');
|
|
947
|
-
let current = document.getElementById(id);
|
|
982
|
+
let current = this.#document.getElementById(id);
|
|
948
983
|
while (current) {
|
|
949
984
|
if (current === node) {
|
|
950
985
|
matched.add(node);
|
|
@@ -960,19 +995,19 @@ export class Matcher {
|
|
|
960
995
|
if (node === this.#node) {
|
|
961
996
|
matched.add(node);
|
|
962
997
|
}
|
|
963
|
-
} else if (node === document.documentElement) {
|
|
998
|
+
} else if (node === this.#document.documentElement) {
|
|
964
999
|
matched.add(node);
|
|
965
1000
|
}
|
|
966
1001
|
break;
|
|
967
1002
|
}
|
|
968
1003
|
case 'focus': {
|
|
969
|
-
if (node === document.activeElement) {
|
|
1004
|
+
if (node === this.#document.activeElement) {
|
|
970
1005
|
matched.add(node);
|
|
971
1006
|
}
|
|
972
1007
|
break;
|
|
973
1008
|
}
|
|
974
1009
|
case 'focus-within': {
|
|
975
|
-
let current = document.activeElement;
|
|
1010
|
+
let current = this.#document.activeElement;
|
|
976
1011
|
while (current) {
|
|
977
1012
|
if (current === node) {
|
|
978
1013
|
matched.add(node);
|
|
@@ -1118,7 +1153,7 @@ export class Matcher {
|
|
|
1118
1153
|
parent = parent.parentNode;
|
|
1119
1154
|
}
|
|
1120
1155
|
if (!parent) {
|
|
1121
|
-
parent = document.documentElement;
|
|
1156
|
+
parent = this.#document.documentElement;
|
|
1122
1157
|
}
|
|
1123
1158
|
const nodes = [].slice.call(parent.getElementsByTagName('input'));
|
|
1124
1159
|
let checked;
|
|
@@ -1159,7 +1194,8 @@ export class Matcher {
|
|
|
1159
1194
|
form = form.parentNode;
|
|
1160
1195
|
}
|
|
1161
1196
|
if (form) {
|
|
1162
|
-
const iterator =
|
|
1197
|
+
const iterator =
|
|
1198
|
+
this.#document.createNodeIterator(form, SHOW_ELEMENT);
|
|
1163
1199
|
let nextNode = iterator.nextNode();
|
|
1164
1200
|
while (nextNode) {
|
|
1165
1201
|
const nodeName = nextNode.localName;
|
|
@@ -1231,10 +1267,9 @@ export class Matcher {
|
|
|
1231
1267
|
matched.add(node);
|
|
1232
1268
|
}
|
|
1233
1269
|
} else if (localName === 'fieldset') {
|
|
1234
|
-
|
|
1235
|
-
let refNode = iterator.nextNode();
|
|
1270
|
+
let refNode = this._traverse(node);
|
|
1236
1271
|
if (refNode === node) {
|
|
1237
|
-
refNode =
|
|
1272
|
+
refNode = this.#tree.nextNode();
|
|
1238
1273
|
}
|
|
1239
1274
|
let bool;
|
|
1240
1275
|
while (refNode) {
|
|
@@ -1244,7 +1279,7 @@ export class Matcher {
|
|
|
1244
1279
|
break;
|
|
1245
1280
|
}
|
|
1246
1281
|
}
|
|
1247
|
-
refNode =
|
|
1282
|
+
refNode = this.#tree.nextNode();
|
|
1248
1283
|
}
|
|
1249
1284
|
if (bool) {
|
|
1250
1285
|
matched.add(node);
|
|
@@ -1258,10 +1293,9 @@ export class Matcher {
|
|
|
1258
1293
|
matched.add(node);
|
|
1259
1294
|
}
|
|
1260
1295
|
} else if (localName === 'fieldset') {
|
|
1261
|
-
|
|
1262
|
-
let refNode = iterator.nextNode();
|
|
1296
|
+
let refNode = this._traverse(node);
|
|
1263
1297
|
if (refNode === node) {
|
|
1264
|
-
refNode =
|
|
1298
|
+
refNode = this.#tree.nextNode();
|
|
1265
1299
|
}
|
|
1266
1300
|
let bool;
|
|
1267
1301
|
while (refNode) {
|
|
@@ -1271,7 +1305,7 @@ export class Matcher {
|
|
|
1271
1305
|
break;
|
|
1272
1306
|
}
|
|
1273
1307
|
}
|
|
1274
|
-
refNode =
|
|
1308
|
+
refNode = this.#tree.nextNode();
|
|
1275
1309
|
}
|
|
1276
1310
|
if (!bool) {
|
|
1277
1311
|
matched.add(node);
|
|
@@ -1347,7 +1381,7 @@ export class Matcher {
|
|
|
1347
1381
|
break;
|
|
1348
1382
|
}
|
|
1349
1383
|
case 'root': {
|
|
1350
|
-
if (node === document.documentElement) {
|
|
1384
|
+
if (node === this.#document.documentElement) {
|
|
1351
1385
|
matched.add(node);
|
|
1352
1386
|
}
|
|
1353
1387
|
break;
|
|
@@ -1373,14 +1407,14 @@ export class Matcher {
|
|
|
1373
1407
|
}
|
|
1374
1408
|
case 'first-child': {
|
|
1375
1409
|
if ((parentNode && node === parentNode.firstElementChild) ||
|
|
1376
|
-
(node === root && root.nodeType === ELEMENT_NODE)) {
|
|
1410
|
+
(node === this.#root && this.#root.nodeType === ELEMENT_NODE)) {
|
|
1377
1411
|
matched.add(node);
|
|
1378
1412
|
}
|
|
1379
1413
|
break;
|
|
1380
1414
|
}
|
|
1381
1415
|
case 'last-child': {
|
|
1382
1416
|
if ((parentNode && node === parentNode.lastElementChild) ||
|
|
1383
|
-
(node === root && root.nodeType === ELEMENT_NODE)) {
|
|
1417
|
+
(node === this.#root && this.#root.nodeType === ELEMENT_NODE)) {
|
|
1384
1418
|
matched.add(node);
|
|
1385
1419
|
}
|
|
1386
1420
|
break;
|
|
@@ -1389,7 +1423,7 @@ export class Matcher {
|
|
|
1389
1423
|
if ((parentNode &&
|
|
1390
1424
|
node === parentNode.firstElementChild &&
|
|
1391
1425
|
node === parentNode.lastElementChild) ||
|
|
1392
|
-
(node === root && root.nodeType === ELEMENT_NODE)) {
|
|
1426
|
+
(node === this.#root && this.#root.nodeType === ELEMENT_NODE)) {
|
|
1393
1427
|
matched.add(node);
|
|
1394
1428
|
}
|
|
1395
1429
|
break;
|
|
@@ -1403,7 +1437,8 @@ export class Matcher {
|
|
|
1403
1437
|
if (node1) {
|
|
1404
1438
|
matched.add(node1);
|
|
1405
1439
|
}
|
|
1406
|
-
} else if (node === root &&
|
|
1440
|
+
} else if (node === this.#root &&
|
|
1441
|
+
this.#root.nodeType === ELEMENT_NODE) {
|
|
1407
1442
|
matched.add(node);
|
|
1408
1443
|
}
|
|
1409
1444
|
break;
|
|
@@ -1418,7 +1453,8 @@ export class Matcher {
|
|
|
1418
1453
|
if (node1) {
|
|
1419
1454
|
matched.add(node1);
|
|
1420
1455
|
}
|
|
1421
|
-
} else if (node === root &&
|
|
1456
|
+
} else if (node === this.#root &&
|
|
1457
|
+
this.#root.nodeType === ELEMENT_NODE) {
|
|
1422
1458
|
matched.add(node);
|
|
1423
1459
|
}
|
|
1424
1460
|
break;
|
|
@@ -1439,7 +1475,8 @@ export class Matcher {
|
|
|
1439
1475
|
matched.add(node);
|
|
1440
1476
|
}
|
|
1441
1477
|
}
|
|
1442
|
-
} else if (node === root &&
|
|
1478
|
+
} else if (node === this.#root &&
|
|
1479
|
+
this.#root.nodeType === ELEMENT_NODE) {
|
|
1443
1480
|
matched.add(node);
|
|
1444
1481
|
}
|
|
1445
1482
|
break;
|
|
@@ -1520,9 +1557,8 @@ export class Matcher {
|
|
|
1520
1557
|
const { attributes } = node;
|
|
1521
1558
|
let res;
|
|
1522
1559
|
if (attributes && attributes.length) {
|
|
1523
|
-
const { document } = this.#root;
|
|
1524
1560
|
let caseInsensitive;
|
|
1525
|
-
if (document.contentType === 'text/html') {
|
|
1561
|
+
if (this.#document.contentType === 'text/html') {
|
|
1526
1562
|
if (typeof astFlags === 'string' && /^s$/i.test(astFlags)) {
|
|
1527
1563
|
caseInsensitive = false;
|
|
1528
1564
|
} else {
|
|
@@ -1748,11 +1784,10 @@ export class Matcher {
|
|
|
1748
1784
|
const astName = unescapeSelector(ast.name);
|
|
1749
1785
|
const { localName, prefix } = node;
|
|
1750
1786
|
const { forgive } = opt;
|
|
1751
|
-
const { document } = this.#root;
|
|
1752
1787
|
let {
|
|
1753
1788
|
prefix: astPrefix, tagName: astNodeName
|
|
1754
1789
|
} = selectorToNodeProps(astName, node);
|
|
1755
|
-
if (document.contentType === 'text/html') {
|
|
1790
|
+
if (this.#document.contentType === 'text/html') {
|
|
1756
1791
|
astPrefix = astPrefix.toLowerCase();
|
|
1757
1792
|
astNodeName = astNodeName.toLowerCase();
|
|
1758
1793
|
}
|
|
@@ -1862,7 +1897,6 @@ export class Matcher {
|
|
|
1862
1897
|
_matchSelector(ast, node, opt) {
|
|
1863
1898
|
const { type: astType } = ast;
|
|
1864
1899
|
const astName = unescapeSelector(ast.name);
|
|
1865
|
-
const { shadow } = this.#root;
|
|
1866
1900
|
let matched = new Set();
|
|
1867
1901
|
if (node.nodeType === ELEMENT_NODE) {
|
|
1868
1902
|
switch (astType) {
|
|
@@ -1906,7 +1940,7 @@ export class Matcher {
|
|
|
1906
1940
|
}
|
|
1907
1941
|
}
|
|
1908
1942
|
}
|
|
1909
|
-
} else if (shadow && astType === SELECTOR_PSEUDO_CLASS &&
|
|
1943
|
+
} else if (this.#shadow && astType === SELECTOR_PSEUDO_CLASS &&
|
|
1910
1944
|
node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
1911
1945
|
if (astName !== 'has' && REG_LOGICAL_PSEUDO.test(astName)) {
|
|
1912
1946
|
const nodes = this._matchPseudoClassSelector(ast, node, opt);
|
|
@@ -1952,18 +1986,17 @@ export class Matcher {
|
|
|
1952
1986
|
const { type: leafType } = leaf;
|
|
1953
1987
|
const leafName = unescapeSelector(leaf.name);
|
|
1954
1988
|
const matchItems = items.length > 0;
|
|
1955
|
-
const { document, root, shadow } = this.#root;
|
|
1956
1989
|
let nodes = new Set();
|
|
1957
1990
|
let pending = false;
|
|
1958
|
-
if (shadow) {
|
|
1991
|
+
if (this.#shadow) {
|
|
1959
1992
|
pending = true;
|
|
1960
1993
|
} else {
|
|
1961
1994
|
switch (leafType) {
|
|
1962
1995
|
case SELECTOR_ID: {
|
|
1963
|
-
if (root.nodeType === ELEMENT_NODE) {
|
|
1996
|
+
if (this.#root.nodeType === ELEMENT_NODE) {
|
|
1964
1997
|
pending = true;
|
|
1965
1998
|
} else {
|
|
1966
|
-
const node = root.getElementById(leafName);
|
|
1999
|
+
const node = this.#root.getElementById(leafName);
|
|
1967
2000
|
if (node && node !== baseNode && baseNode.contains(node)) {
|
|
1968
2001
|
if (matchItems) {
|
|
1969
2002
|
const bool = this._matchLeaves(items, node);
|
|
@@ -1994,7 +2027,8 @@ export class Matcher {
|
|
|
1994
2027
|
break;
|
|
1995
2028
|
}
|
|
1996
2029
|
case SELECTOR_TYPE: {
|
|
1997
|
-
if (document.contentType === 'text/html' &&
|
|
2030
|
+
if (this.#document.contentType === 'text/html' &&
|
|
2031
|
+
!/[*|]/.test(leafName)) {
|
|
1998
2032
|
const arr = [].slice.call(baseNode.getElementsByTagName(leafName));
|
|
1999
2033
|
if (arr.length) {
|
|
2000
2034
|
if (matchItems) {
|
|
@@ -2066,11 +2100,13 @@ export class Matcher {
|
|
|
2066
2100
|
break;
|
|
2067
2101
|
}
|
|
2068
2102
|
case '>': {
|
|
2069
|
-
const childNodes =
|
|
2103
|
+
const childNodes = node.childNodes.values();
|
|
2070
2104
|
for (const refNode of childNodes) {
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2105
|
+
if (refNode.nodeType === ELEMENT_NODE) {
|
|
2106
|
+
const bool = this._matchLeaves(leaves, refNode, { forgive });
|
|
2107
|
+
if (bool) {
|
|
2108
|
+
matched.add(refNode);
|
|
2109
|
+
}
|
|
2074
2110
|
}
|
|
2075
2111
|
}
|
|
2076
2112
|
break;
|
|
@@ -2081,18 +2117,16 @@ export class Matcher {
|
|
|
2081
2117
|
if (nodes.size) {
|
|
2082
2118
|
matched = nodes;
|
|
2083
2119
|
} else if (pending) {
|
|
2084
|
-
|
|
2085
|
-
const iterator = document.createNodeIterator(node, SHOW_ELEMENT);
|
|
2086
|
-
let refNode = iterator.nextNode();
|
|
2120
|
+
let refNode = this._traverse(node);
|
|
2087
2121
|
if (refNode === node) {
|
|
2088
|
-
refNode =
|
|
2122
|
+
refNode = this.#tree.nextNode();
|
|
2089
2123
|
}
|
|
2090
2124
|
while (refNode) {
|
|
2091
2125
|
const bool = this._matchLeaves(leaves, refNode, { forgive });
|
|
2092
2126
|
if (bool) {
|
|
2093
2127
|
matched.add(refNode);
|
|
2094
2128
|
}
|
|
2095
|
-
refNode =
|
|
2129
|
+
refNode = this.#tree.nextNode();
|
|
2096
2130
|
}
|
|
2097
2131
|
}
|
|
2098
2132
|
}
|
|
@@ -2155,42 +2189,92 @@ export class Matcher {
|
|
|
2155
2189
|
}
|
|
2156
2190
|
|
|
2157
2191
|
/**
|
|
2158
|
-
* find
|
|
2192
|
+
* find matched node from tree walker
|
|
2193
|
+
* @param {Array.<object>} leaves - AST leaves
|
|
2194
|
+
* @param {object} [opt] - options
|
|
2195
|
+
* @param {object} [opt.node] - node to start from
|
|
2196
|
+
* @param {string} [opt.targetType] - target type
|
|
2197
|
+
* @param {object} [opt.tree] - tree walker
|
|
2198
|
+
* @returns {?object} - matched node
|
|
2199
|
+
*/
|
|
2200
|
+
_findNode(leaves, opt = {}) {
|
|
2201
|
+
let { node, targetType, tree } = opt;
|
|
2202
|
+
if (!tree) {
|
|
2203
|
+
tree = this.#tree;
|
|
2204
|
+
}
|
|
2205
|
+
let refNode = this._traverse(node);
|
|
2206
|
+
if (refNode.nodeType !== ELEMENT_NODE || refNode === node) {
|
|
2207
|
+
refNode = tree.nextNode();
|
|
2208
|
+
}
|
|
2209
|
+
let matchedNode;
|
|
2210
|
+
while (refNode) {
|
|
2211
|
+
let bool;
|
|
2212
|
+
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
2213
|
+
if (refNode === this.#node) {
|
|
2214
|
+
bool = true;
|
|
2215
|
+
} else {
|
|
2216
|
+
bool = this.#node.contains(refNode);
|
|
2217
|
+
}
|
|
2218
|
+
} else {
|
|
2219
|
+
bool = true;
|
|
2220
|
+
}
|
|
2221
|
+
if (bool) {
|
|
2222
|
+
const matched = this._matchLeaves(leaves, refNode);
|
|
2223
|
+
if (matched) {
|
|
2224
|
+
matchedNode = refNode;
|
|
2225
|
+
break;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
if (targetType === TARGET_LINEAL) {
|
|
2229
|
+
refNode = tree.parentNode();
|
|
2230
|
+
} else {
|
|
2231
|
+
refNode = tree.nextNode();
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
return matchedNode ?? null;
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
/**
|
|
2238
|
+
* find entry nodes
|
|
2159
2239
|
* @param {object} twig - twig
|
|
2160
2240
|
* @param {string} targetType - target type
|
|
2161
2241
|
* @returns {object} - collection of nodes etc.
|
|
2162
2242
|
*/
|
|
2163
|
-
|
|
2164
|
-
const { leaves
|
|
2243
|
+
_findEntryNodes(twig, targetType) {
|
|
2244
|
+
const { leaves } = twig;
|
|
2245
|
+
const [leaf, ...filterLeaves] = leaves;
|
|
2165
2246
|
const { type: leafType } = leaf;
|
|
2166
2247
|
const leafName = unescapeSelector(leaf.name);
|
|
2167
|
-
const
|
|
2248
|
+
const compound = filterLeaves.length > 0;
|
|
2168
2249
|
let nodes = new Set();
|
|
2250
|
+
let filtered = false;
|
|
2169
2251
|
let pending = false;
|
|
2170
2252
|
switch (leafType) {
|
|
2171
2253
|
case SELECTOR_ID: {
|
|
2172
2254
|
if (targetType === TARGET_SELF) {
|
|
2173
|
-
const bool = this._matchLeaves(
|
|
2255
|
+
const bool = this._matchLeaves(leaves, this.#node);
|
|
2174
2256
|
if (bool) {
|
|
2175
2257
|
nodes.add(this.#node);
|
|
2258
|
+
filtered = true;
|
|
2176
2259
|
}
|
|
2177
2260
|
} else if (targetType === TARGET_LINEAL) {
|
|
2178
2261
|
let refNode = this.#node;
|
|
2179
2262
|
while (refNode) {
|
|
2180
|
-
const bool = this._matchLeaves(
|
|
2263
|
+
const bool = this._matchLeaves(leaves, refNode);
|
|
2181
2264
|
if (bool) {
|
|
2182
2265
|
nodes.add(refNode);
|
|
2183
|
-
|
|
2266
|
+
filtered = true;
|
|
2184
2267
|
}
|
|
2185
2268
|
refNode = refNode.parentNode;
|
|
2186
2269
|
}
|
|
2187
2270
|
} else if (targetType === TARGET_ALL ||
|
|
2188
|
-
root.nodeType === ELEMENT_NODE) {
|
|
2271
|
+
this.#root.nodeType === ELEMENT_NODE) {
|
|
2189
2272
|
pending = true;
|
|
2190
2273
|
} else {
|
|
2191
|
-
const node = root.getElementById(leafName);
|
|
2274
|
+
const node = this.#root.getElementById(leafName);
|
|
2192
2275
|
if (node) {
|
|
2193
2276
|
nodes.add(node);
|
|
2277
|
+
filtered = true;
|
|
2194
2278
|
}
|
|
2195
2279
|
}
|
|
2196
2280
|
break;
|
|
@@ -2213,21 +2297,35 @@ export class Matcher {
|
|
|
2213
2297
|
break;
|
|
2214
2298
|
}
|
|
2215
2299
|
}
|
|
2216
|
-
} else if (
|
|
2217
|
-
const
|
|
2300
|
+
} else if (targetType === TARGET_FIRST) {
|
|
2301
|
+
const node = this._findNode(leaves, {
|
|
2302
|
+
node: this.#node,
|
|
2303
|
+
targetType,
|
|
2304
|
+
tree: this.#subtree
|
|
2305
|
+
});
|
|
2306
|
+
if (node) {
|
|
2307
|
+
nodes.add(node);
|
|
2308
|
+
filtered = true;
|
|
2309
|
+
break;
|
|
2310
|
+
}
|
|
2311
|
+
} else if (this.#root.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
2312
|
+
const childNodes = this.#root.childNodes.values();
|
|
2218
2313
|
const arr = [];
|
|
2219
2314
|
for (const node of childNodes) {
|
|
2220
|
-
if (node.
|
|
2221
|
-
|
|
2315
|
+
if (node.nodeType === ELEMENT_NODE) {
|
|
2316
|
+
if (node.classList.contains(leafName)) {
|
|
2317
|
+
arr.push(node);
|
|
2318
|
+
}
|
|
2319
|
+
const a = [].slice.call(node.getElementsByClassName(leafName));
|
|
2320
|
+
arr.push(...a);
|
|
2222
2321
|
}
|
|
2223
|
-
const a = [].slice.call(node.getElementsByClassName(leafName));
|
|
2224
|
-
arr.push(...a);
|
|
2225
2322
|
}
|
|
2226
2323
|
if (arr.length) {
|
|
2227
2324
|
nodes = new Set(arr);
|
|
2228
2325
|
}
|
|
2229
2326
|
} else {
|
|
2230
|
-
const arr =
|
|
2327
|
+
const arr =
|
|
2328
|
+
[].slice.call(this.#root.getElementsByClassName(leafName));
|
|
2231
2329
|
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
2232
2330
|
for (const node of arr) {
|
|
2233
2331
|
if (node === this.#node || isInclusive(node, this.#node)) {
|
|
@@ -2243,43 +2341,58 @@ export class Matcher {
|
|
|
2243
2341
|
case SELECTOR_TYPE: {
|
|
2244
2342
|
if (targetType === TARGET_SELF) {
|
|
2245
2343
|
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
2246
|
-
const bool = this._matchLeaves(
|
|
2344
|
+
const bool = this._matchLeaves(leaves, this.#node);
|
|
2247
2345
|
if (bool) {
|
|
2248
2346
|
nodes.add(this.#node);
|
|
2347
|
+
filtered = true;
|
|
2249
2348
|
}
|
|
2250
2349
|
}
|
|
2251
2350
|
} else if (targetType === TARGET_LINEAL) {
|
|
2252
2351
|
let refNode = this.#node;
|
|
2253
2352
|
while (refNode) {
|
|
2254
2353
|
if (refNode.nodeType === ELEMENT_NODE) {
|
|
2255
|
-
const bool = this._matchLeaves(
|
|
2354
|
+
const bool = this._matchLeaves(leaves, refNode);
|
|
2256
2355
|
if (bool) {
|
|
2257
2356
|
nodes.add(refNode);
|
|
2357
|
+
filtered = true;
|
|
2258
2358
|
}
|
|
2259
2359
|
refNode = refNode.parentNode;
|
|
2260
2360
|
} else {
|
|
2261
2361
|
break;
|
|
2262
2362
|
}
|
|
2263
2363
|
}
|
|
2264
|
-
} else if (
|
|
2364
|
+
} else if (targetType === TARGET_FIRST) {
|
|
2365
|
+
const node = this._findNode(leaves, {
|
|
2366
|
+
node: this.#node,
|
|
2367
|
+
targetType,
|
|
2368
|
+
tree: this.#subtree
|
|
2369
|
+
});
|
|
2370
|
+
if (node) {
|
|
2371
|
+
nodes.add(node);
|
|
2372
|
+
filtered = true;
|
|
2373
|
+
break;
|
|
2374
|
+
}
|
|
2375
|
+
} else if (this.#document.contentType !== 'text/html' ||
|
|
2265
2376
|
/[*|]/.test(leafName)) {
|
|
2266
2377
|
pending = true;
|
|
2267
|
-
} else if (root.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
2378
|
+
} else if (this.#root.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
2268
2379
|
const tagName = leafName.toLowerCase();
|
|
2269
|
-
const childNodes =
|
|
2380
|
+
const childNodes = this.#root.childNodes.values();
|
|
2270
2381
|
const arr = [];
|
|
2271
2382
|
for (const node of childNodes) {
|
|
2272
|
-
if (node.
|
|
2273
|
-
|
|
2383
|
+
if (node.nodeType === ELEMENT_NODE) {
|
|
2384
|
+
if (node.localName === tagName) {
|
|
2385
|
+
arr.push(node);
|
|
2386
|
+
}
|
|
2387
|
+
const a = [].slice.call(node.getElementsByTagName(leafName));
|
|
2388
|
+
arr.push(...a);
|
|
2274
2389
|
}
|
|
2275
|
-
const a = [].slice.call(node.getElementsByTagName(leafName));
|
|
2276
|
-
arr.push(...a);
|
|
2277
2390
|
}
|
|
2278
2391
|
if (arr.length) {
|
|
2279
2392
|
nodes = new Set(arr);
|
|
2280
2393
|
}
|
|
2281
2394
|
} else {
|
|
2282
|
-
const arr = [].slice.call(root.getElementsByTagName(leafName));
|
|
2395
|
+
const arr = [].slice.call(this.#root.getElementsByTagName(leafName));
|
|
2283
2396
|
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
2284
2397
|
for (const node of arr) {
|
|
2285
2398
|
if (node === this.#node || isInclusive(node, this.#node)) {
|
|
@@ -2299,49 +2412,62 @@ export class Matcher {
|
|
|
2299
2412
|
}
|
|
2300
2413
|
default: {
|
|
2301
2414
|
if (targetType !== TARGET_LINEAL && REG_SHADOW_HOST.test(leafName)) {
|
|
2302
|
-
if (shadow && this.#node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
2415
|
+
if (this.#shadow && this.#node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
2303
2416
|
const node = this._matchShadowHostPseudoClass(leaf, this.#node);
|
|
2304
2417
|
if (node) {
|
|
2305
2418
|
nodes.add(node);
|
|
2306
2419
|
}
|
|
2307
2420
|
}
|
|
2308
2421
|
} else if (targetType === TARGET_SELF) {
|
|
2309
|
-
const bool = this._matchLeaves(
|
|
2422
|
+
const bool = this._matchLeaves(leaves, this.#node);
|
|
2310
2423
|
if (bool) {
|
|
2311
2424
|
nodes.add(this.#node);
|
|
2425
|
+
filtered = true;
|
|
2312
2426
|
}
|
|
2313
2427
|
} else if (targetType === TARGET_LINEAL) {
|
|
2314
2428
|
let refNode = this.#node;
|
|
2315
2429
|
while (refNode) {
|
|
2316
|
-
const bool = this._matchLeaves(
|
|
2430
|
+
const bool = this._matchLeaves(leaves, refNode);
|
|
2317
2431
|
if (bool) {
|
|
2318
2432
|
nodes.add(refNode);
|
|
2433
|
+
filtered = true;
|
|
2319
2434
|
}
|
|
2320
2435
|
refNode = refNode.parentNode;
|
|
2321
2436
|
}
|
|
2437
|
+
} else if (targetType === TARGET_FIRST) {
|
|
2438
|
+
const node = this._findNode(leaves, {
|
|
2439
|
+
node: this.#node,
|
|
2440
|
+
targetType,
|
|
2441
|
+
tree: this.#subtree
|
|
2442
|
+
});
|
|
2443
|
+
if (node) {
|
|
2444
|
+
nodes.add(node);
|
|
2445
|
+
filtered = true;
|
|
2446
|
+
break;
|
|
2447
|
+
}
|
|
2322
2448
|
} else {
|
|
2323
2449
|
pending = true;
|
|
2324
2450
|
}
|
|
2325
2451
|
}
|
|
2326
2452
|
}
|
|
2327
|
-
const itemsLen = items.length;
|
|
2328
2453
|
// check last leaf if node not found, not pending and leaves left
|
|
2329
|
-
if (!nodes.size && !pending &&
|
|
2330
|
-
const lastLeaf =
|
|
2454
|
+
if (!nodes.size && !pending && compound) {
|
|
2455
|
+
const lastLeaf = filterLeaves[filterLeaves.length - 1];
|
|
2331
2456
|
const { type: lastLeafType } = lastLeaf;
|
|
2332
2457
|
if (lastLeafType === SELECTOR_PSEUDO_CLASS) {
|
|
2333
2458
|
let node;
|
|
2334
|
-
if (root.nodeType === ELEMENT_NODE) {
|
|
2335
|
-
node = root;
|
|
2459
|
+
if (this.#root.nodeType === ELEMENT_NODE) {
|
|
2460
|
+
node = this.#root;
|
|
2336
2461
|
} else {
|
|
2337
|
-
node = root.firstElementChild;
|
|
2462
|
+
node = this.#root.firstElementChild;
|
|
2338
2463
|
}
|
|
2339
2464
|
// throws if unknown pseudo-class
|
|
2340
2465
|
this._matchPseudoClassSelector(lastLeaf, node);
|
|
2341
2466
|
}
|
|
2342
2467
|
}
|
|
2343
2468
|
return {
|
|
2344
|
-
compound
|
|
2469
|
+
compound,
|
|
2470
|
+
filtered,
|
|
2345
2471
|
nodes,
|
|
2346
2472
|
pending
|
|
2347
2473
|
};
|
|
@@ -2355,32 +2481,54 @@ export class Matcher {
|
|
|
2355
2481
|
*/
|
|
2356
2482
|
_getEntryTwig(branch, targetType) {
|
|
2357
2483
|
const branchLen = branch.length;
|
|
2484
|
+
const complex = branchLen > 1;
|
|
2358
2485
|
const firstTwig = branch[0];
|
|
2359
2486
|
let find;
|
|
2360
2487
|
let twig;
|
|
2361
|
-
if (
|
|
2488
|
+
if (complex) {
|
|
2362
2489
|
const { leaves: [{ type: firstType }] } = firstTwig;
|
|
2363
2490
|
const lastTwig = branch[branchLen - 1];
|
|
2364
2491
|
const { leaves: [{ type: lastType }] } = lastTwig;
|
|
2365
|
-
if (lastType === SELECTOR_PSEUDO_ELEMENT ||
|
|
2492
|
+
if (lastType === SELECTOR_PSEUDO_ELEMENT ||
|
|
2493
|
+
lastType === SELECTOR_ID) {
|
|
2366
2494
|
find = FIND_PREV;
|
|
2367
2495
|
twig = lastTwig;
|
|
2368
2496
|
} else if (firstType === SELECTOR_PSEUDO_ELEMENT ||
|
|
2369
|
-
firstType === SELECTOR_ID
|
|
2497
|
+
firstType === SELECTOR_ID ||
|
|
2498
|
+
targetType === TARGET_ALL) {
|
|
2370
2499
|
find = FIND_NEXT;
|
|
2371
2500
|
twig = firstTwig;
|
|
2372
|
-
} else if (targetType === TARGET_FIRST && branchLen < BIT_04) {
|
|
2373
|
-
find = FIND_PREV;
|
|
2374
|
-
twig = lastTwig;
|
|
2375
2501
|
} else {
|
|
2376
|
-
|
|
2377
|
-
|
|
2502
|
+
let bool;
|
|
2503
|
+
for (const { combo, leaves: [leaf] } of branch) {
|
|
2504
|
+
const { type: leafType } = leaf;
|
|
2505
|
+
const leafName = unescapeSelector(leaf.name);
|
|
2506
|
+
if (leafType === SELECTOR_PSEUDO_CLASS && leafName === 'dir') {
|
|
2507
|
+
bool = false;
|
|
2508
|
+
break;
|
|
2509
|
+
}
|
|
2510
|
+
if (combo) {
|
|
2511
|
+
const { name: comboName } = combo;
|
|
2512
|
+
if (/^[+~]$/.test(comboName)) {
|
|
2513
|
+
bool = true;
|
|
2514
|
+
break;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
if (bool) {
|
|
2519
|
+
find = FIND_NEXT;
|
|
2520
|
+
twig = firstTwig;
|
|
2521
|
+
} else {
|
|
2522
|
+
find = FIND_PREV;
|
|
2523
|
+
twig = lastTwig;
|
|
2524
|
+
}
|
|
2378
2525
|
}
|
|
2379
2526
|
} else {
|
|
2380
2527
|
find = FIND_PREV;
|
|
2381
2528
|
twig = firstTwig;
|
|
2382
2529
|
}
|
|
2383
2530
|
return {
|
|
2531
|
+
complex,
|
|
2384
2532
|
find,
|
|
2385
2533
|
twig
|
|
2386
2534
|
};
|
|
@@ -2394,11 +2542,21 @@ export class Matcher {
|
|
|
2394
2542
|
_collectNodes(targetType) {
|
|
2395
2543
|
const ast = this.#ast.values();
|
|
2396
2544
|
if (targetType === TARGET_ALL || targetType === TARGET_FIRST) {
|
|
2545
|
+
if (targetType === TARGET_FIRST) {
|
|
2546
|
+
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
2547
|
+
this.#subtree =
|
|
2548
|
+
this.#document.createTreeWalker(this.#node, SHOW_ELEMENT);
|
|
2549
|
+
} else {
|
|
2550
|
+
this.#subtree = this.#tree;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2397
2553
|
const pendingItems = new Set();
|
|
2398
2554
|
let i = 0;
|
|
2399
2555
|
for (const { branch } of ast) {
|
|
2400
2556
|
const { find, twig } = this._getEntryTwig(branch, targetType);
|
|
2401
|
-
const {
|
|
2557
|
+
const {
|
|
2558
|
+
compound, filtered, nodes, pending
|
|
2559
|
+
} = this._findEntryNodes(twig, targetType);
|
|
2402
2560
|
if (nodes.size) {
|
|
2403
2561
|
this.#nodes[i] = nodes;
|
|
2404
2562
|
} else if (pending) {
|
|
@@ -2409,14 +2567,12 @@ export class Matcher {
|
|
|
2409
2567
|
} else {
|
|
2410
2568
|
this.#ast[i].skip = true;
|
|
2411
2569
|
}
|
|
2412
|
-
this.#ast[i].filtered = !compound;
|
|
2570
|
+
this.#ast[i].filtered = filtered || !compound;
|
|
2413
2571
|
this.#ast[i].find = find;
|
|
2414
2572
|
i++;
|
|
2415
2573
|
}
|
|
2416
2574
|
if (pendingItems.size) {
|
|
2417
|
-
|
|
2418
|
-
const iterator = document.createNodeIterator(root, SHOW_ELEMENT);
|
|
2419
|
-
let nextNode = iterator.nextNode();
|
|
2575
|
+
let nextNode = this._traverse();
|
|
2420
2576
|
while (nextNode) {
|
|
2421
2577
|
let bool = false;
|
|
2422
2578
|
if (this.#node.nodeType === ELEMENT_NODE) {
|
|
@@ -2435,26 +2591,26 @@ export class Matcher {
|
|
|
2435
2591
|
if (matched) {
|
|
2436
2592
|
const index = pendingItem.get('index');
|
|
2437
2593
|
this.#nodes[index].add(nextNode);
|
|
2438
|
-
|
|
2439
|
-
this.#ast[index].filtered = true;
|
|
2440
|
-
}
|
|
2594
|
+
this.#ast[index].filtered = true;
|
|
2441
2595
|
}
|
|
2442
2596
|
}
|
|
2443
2597
|
}
|
|
2444
|
-
nextNode =
|
|
2598
|
+
nextNode = this.#tree.nextNode();
|
|
2445
2599
|
}
|
|
2446
2600
|
}
|
|
2447
2601
|
} else {
|
|
2448
2602
|
let i = 0;
|
|
2449
2603
|
for (const { branch } of ast) {
|
|
2450
2604
|
const twig = branch[branch.length - 1];
|
|
2451
|
-
const {
|
|
2605
|
+
const {
|
|
2606
|
+
compound, filtered, nodes
|
|
2607
|
+
} = this._findEntryNodes(twig, targetType);
|
|
2452
2608
|
if (nodes.size) {
|
|
2453
2609
|
this.#nodes[i] = nodes;
|
|
2454
2610
|
} else {
|
|
2455
2611
|
this.#ast[i].skip = true;
|
|
2456
2612
|
}
|
|
2457
|
-
this.#ast[i].filtered = !compound;
|
|
2613
|
+
this.#ast[i].filtered = filtered || !compound;
|
|
2458
2614
|
this.#ast[i].find = FIND_PREV;
|
|
2459
2615
|
i++;
|
|
2460
2616
|
}
|
|
@@ -2501,13 +2657,13 @@ export class Matcher {
|
|
|
2501
2657
|
if (skip) {
|
|
2502
2658
|
continue;
|
|
2503
2659
|
} else if (branchLen) {
|
|
2504
|
-
const
|
|
2660
|
+
const entryNodes = this.#nodes[i];
|
|
2505
2661
|
const lastIndex = branchLen - 1;
|
|
2506
2662
|
if (lastIndex === 0) {
|
|
2507
2663
|
const { leaves: [, ...filterLeaves] } = branch[0];
|
|
2508
2664
|
if ((targetType === TARGET_ALL || targetType === TARGET_FIRST) &&
|
|
2509
2665
|
this.#node.nodeType === ELEMENT_NODE) {
|
|
2510
|
-
for (const node of
|
|
2666
|
+
for (const node of entryNodes) {
|
|
2511
2667
|
const bool = filtered || this._matchLeaves(filterLeaves, node);
|
|
2512
2668
|
if (bool && node !== this.#node && this.#node.contains(node)) {
|
|
2513
2669
|
nodes.add(node);
|
|
@@ -2519,13 +2675,13 @@ export class Matcher {
|
|
|
2519
2675
|
} else if (!filterLeaves.length) {
|
|
2520
2676
|
if (targetType === TARGET_ALL) {
|
|
2521
2677
|
const n = [...nodes];
|
|
2522
|
-
nodes = new Set([...n, ...
|
|
2678
|
+
nodes = new Set([...n, ...entryNodes]);
|
|
2523
2679
|
} else {
|
|
2524
|
-
const [node] = [...
|
|
2680
|
+
const [node] = [...entryNodes];
|
|
2525
2681
|
nodes.add(node);
|
|
2526
2682
|
}
|
|
2527
2683
|
} else {
|
|
2528
|
-
for (const node of
|
|
2684
|
+
for (const node of entryNodes) {
|
|
2529
2685
|
const bool = filtered || this._matchLeaves(filterLeaves, node);
|
|
2530
2686
|
if (bool) {
|
|
2531
2687
|
nodes.add(node);
|
|
@@ -2536,10 +2692,11 @@ export class Matcher {
|
|
|
2536
2692
|
}
|
|
2537
2693
|
}
|
|
2538
2694
|
} else if (find === FIND_NEXT) {
|
|
2539
|
-
let { combo, leaves:
|
|
2540
|
-
|
|
2695
|
+
let { combo, leaves: entryLeaves } = branch[0];
|
|
2696
|
+
const [, ...filterLeaves] = entryLeaves;
|
|
2697
|
+
let matched;
|
|
2698
|
+
for (const node of entryNodes) {
|
|
2541
2699
|
const bool = filtered || this._matchLeaves(filterLeaves, node);
|
|
2542
|
-
let matched;
|
|
2543
2700
|
if (bool) {
|
|
2544
2701
|
let nextNodes = new Set([node]);
|
|
2545
2702
|
for (let j = 1; j < branchLen; j++) {
|
|
@@ -2583,11 +2740,61 @@ export class Matcher {
|
|
|
2583
2740
|
break;
|
|
2584
2741
|
}
|
|
2585
2742
|
}
|
|
2743
|
+
if (!matched && targetType === TARGET_FIRST) {
|
|
2744
|
+
const [entryNode] = [...entryNodes];
|
|
2745
|
+
let refNode = this._findNode(entryLeaves, {
|
|
2746
|
+
targetType,
|
|
2747
|
+
node: entryNode,
|
|
2748
|
+
tree: this.#subtree
|
|
2749
|
+
});
|
|
2750
|
+
while (refNode) {
|
|
2751
|
+
let nextNodes = new Set([refNode]);
|
|
2752
|
+
for (let j = 1; j < branchLen; j++) {
|
|
2753
|
+
const { combo: nextCombo, leaves } = branch[j];
|
|
2754
|
+
const arr = [];
|
|
2755
|
+
for (const nextNode of nextNodes) {
|
|
2756
|
+
const twig = {
|
|
2757
|
+
combo,
|
|
2758
|
+
leaves
|
|
2759
|
+
};
|
|
2760
|
+
const m = this._matchCombinator(twig, nextNode, { find });
|
|
2761
|
+
if (m.size) {
|
|
2762
|
+
arr.push(...m);
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
if (arr.length) {
|
|
2766
|
+
if (j === lastIndex) {
|
|
2767
|
+
const [node] = this._sortNodes(arr);
|
|
2768
|
+
nodes.add(node);
|
|
2769
|
+
matched = true;
|
|
2770
|
+
break;
|
|
2771
|
+
} else {
|
|
2772
|
+
matched = false;
|
|
2773
|
+
combo = nextCombo;
|
|
2774
|
+
nextNodes = new Set(arr);
|
|
2775
|
+
}
|
|
2776
|
+
} else {
|
|
2777
|
+
matched = false;
|
|
2778
|
+
break;
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
if (matched) {
|
|
2782
|
+
break;
|
|
2783
|
+
}
|
|
2784
|
+
refNode = this._findNode(entryLeaves, {
|
|
2785
|
+
targetType,
|
|
2786
|
+
node: refNode,
|
|
2787
|
+
tree: this.#subtree
|
|
2788
|
+
});
|
|
2789
|
+
nextNodes = new Set([refNode]);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2586
2792
|
} else {
|
|
2587
|
-
const { leaves:
|
|
2588
|
-
|
|
2793
|
+
const { leaves: entryLeaves } = branch[lastIndex];
|
|
2794
|
+
const [, ...filterLeaves] = entryLeaves;
|
|
2795
|
+
let matched;
|
|
2796
|
+
for (const node of entryNodes) {
|
|
2589
2797
|
const bool = filtered || this._matchLeaves(filterLeaves, node);
|
|
2590
|
-
let matched;
|
|
2591
2798
|
if (bool) {
|
|
2592
2799
|
let nextNodes = new Set([node]);
|
|
2593
2800
|
for (let j = lastIndex - 1; j >= 0; j--) {
|
|
@@ -2613,13 +2820,54 @@ export class Matcher {
|
|
|
2613
2820
|
break;
|
|
2614
2821
|
}
|
|
2615
2822
|
}
|
|
2616
|
-
} else {
|
|
2617
|
-
matched = false;
|
|
2618
2823
|
}
|
|
2619
2824
|
if (matched && targetType !== TARGET_ALL) {
|
|
2620
2825
|
break;
|
|
2621
2826
|
}
|
|
2622
2827
|
}
|
|
2828
|
+
if (!matched && targetType === TARGET_FIRST) {
|
|
2829
|
+
const [entryNode] = [...entryNodes];
|
|
2830
|
+
let refNode = this._findNode(entryLeaves, {
|
|
2831
|
+
targetType,
|
|
2832
|
+
node: entryNode,
|
|
2833
|
+
tree: this.#subtree
|
|
2834
|
+
});
|
|
2835
|
+
while (refNode) {
|
|
2836
|
+
let nextNodes = new Set([refNode]);
|
|
2837
|
+
for (let j = lastIndex - 1; j >= 0; j--) {
|
|
2838
|
+
const twig = branch[j];
|
|
2839
|
+
const arr = [];
|
|
2840
|
+
for (const nextNode of nextNodes) {
|
|
2841
|
+
const m = this._matchCombinator(twig, nextNode, { find });
|
|
2842
|
+
if (m.size) {
|
|
2843
|
+
arr.push(...m);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (arr.length) {
|
|
2847
|
+
if (j === 0) {
|
|
2848
|
+
nodes.add(refNode);
|
|
2849
|
+
matched = true;
|
|
2850
|
+
break;
|
|
2851
|
+
} else {
|
|
2852
|
+
matched = false;
|
|
2853
|
+
nextNodes = new Set(arr);
|
|
2854
|
+
}
|
|
2855
|
+
} else {
|
|
2856
|
+
matched = false;
|
|
2857
|
+
break;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
if (matched) {
|
|
2861
|
+
break;
|
|
2862
|
+
}
|
|
2863
|
+
refNode = this._findNode(entryLeaves, {
|
|
2864
|
+
targetType,
|
|
2865
|
+
node: refNode,
|
|
2866
|
+
tree: this.#subtree
|
|
2867
|
+
});
|
|
2868
|
+
nextNodes = new Set([refNode]);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2623
2871
|
}
|
|
2624
2872
|
}
|
|
2625
2873
|
}
|