@asamuzakjp/dom-selector 5.2.2 → 5.3.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/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +3 -3
- package/dist/cjs/js/constant.js +1 -1
- package/dist/cjs/js/constant.js.map +3 -3
- package/dist/cjs/js/finder.js +1 -1
- package/dist/cjs/js/finder.js.map +3 -3
- package/dist/cjs/js/matcher.js +1 -1
- package/dist/cjs/js/matcher.js.map +2 -2
- package/dist/cjs/js/parser.js +2 -2
- package/dist/cjs/js/parser.js.map +3 -3
- package/dist/cjs/js/utility.js +1 -1
- package/dist/cjs/js/utility.js.map +3 -3
- package/package.json +1 -1
- package/src/index.js +3 -1
- package/src/js/constant.js +11 -40
- package/src/js/finder.js +51 -40
- package/src/js/matcher.js +7 -6
- package/src/js/parser.js +22 -22
- package/src/js/utility.js +17 -17
- package/types/js/constant.d.ts +11 -36
package/src/js/constant.js
CHANGED
|
@@ -4,26 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
/* string */
|
|
6
6
|
export const AN_PLUS_B = 'AnPlusB';
|
|
7
|
+
export const ATTR_SELECTOR = 'AttributeSelector';
|
|
8
|
+
export const CLASS_SELECTOR = 'ClassSelector';
|
|
7
9
|
export const COMBINATOR = 'Combinator';
|
|
8
10
|
export const EMPTY = '__EMPTY__';
|
|
9
|
-
export const
|
|
11
|
+
export const IDENT = 'Identifier';
|
|
12
|
+
export const ID_SELECTOR = 'IdSelector';
|
|
10
13
|
export const NOT_SUPPORTED_ERR = 'NotSupportedError';
|
|
11
14
|
export const NTH = 'Nth';
|
|
15
|
+
export const PS_CLASS_SELECTOR = 'PseudoClassSelector';
|
|
16
|
+
export const PS_ELEMENT_SELECTOR = 'PseudoElementSelector';
|
|
12
17
|
export const RAW = 'Raw';
|
|
13
18
|
export const SELECTOR = 'Selector';
|
|
14
|
-
export const SELECTOR_ATTR = 'AttributeSelector';
|
|
15
|
-
export const SELECTOR_CLASS = 'ClassSelector';
|
|
16
|
-
export const SELECTOR_ID = 'IdSelector';
|
|
17
19
|
export const SELECTOR_LIST = 'SelectorList';
|
|
18
|
-
export const SELECTOR_PSEUDO_CLASS = 'PseudoClassSelector';
|
|
19
|
-
export const SELECTOR_PSEUDO_ELEMENT = 'PseudoElementSelector';
|
|
20
|
-
export const SELECTOR_TYPE = 'TypeSelector';
|
|
21
20
|
export const STRING = 'String';
|
|
22
21
|
export const SYNTAX_ERR = 'SyntaxError';
|
|
23
22
|
export const TARGET_ALL = 'all';
|
|
24
23
|
export const TARGET_FIRST = 'first';
|
|
25
24
|
export const TARGET_LINEAL = 'lineal';
|
|
26
25
|
export const TARGET_SELF = 'self';
|
|
26
|
+
export const TYPE_SELECTOR = 'TypeSelector';
|
|
27
27
|
export const U_FFFD = '\uFFFD';
|
|
28
28
|
|
|
29
29
|
/* numeric */
|
|
@@ -34,9 +34,9 @@ export const BIT_08 = 8;
|
|
|
34
34
|
export const BIT_16 = 0x10;
|
|
35
35
|
export const BIT_32 = 0x20;
|
|
36
36
|
export const BIT_FFFF = 0xFFFF;
|
|
37
|
-
export const BIT_HYPHEN = 0x2D;
|
|
38
37
|
export const DUO = 2;
|
|
39
38
|
export const HEX = 16;
|
|
39
|
+
export const HYPHEN = 0x2D;
|
|
40
40
|
export const TYPE_FROM = 8;
|
|
41
41
|
export const TYPE_TO = -1;
|
|
42
42
|
|
|
@@ -61,7 +61,7 @@ export const ALPHA_NUM = '[A-Z\\d]+';
|
|
|
61
61
|
export const CHILD_IDX = '(?:first|last|only)-(?:child|of-type)';
|
|
62
62
|
export const DIGIT = '(?:0|[1-9]\\d*)';
|
|
63
63
|
export const LANG_PART = `(?:-${ALPHA_NUM})*`;
|
|
64
|
-
export const
|
|
64
|
+
export const PSEUDO_CLASS =
|
|
65
65
|
`(?:any-)?link|${CHILD_IDX}|checked|empty|indeterminate|root|target|visited`;
|
|
66
66
|
export const ANB =
|
|
67
67
|
`[+-]?(?:${DIGIT}n?|n)|(?:[+-]?${DIGIT})?n\\s*[+-]\\s*${DIGIT}`;
|
|
@@ -95,35 +95,6 @@ export const LOGICAL_COMPOUND =
|
|
|
95
95
|
`${KEY_IS_NOT}\\(\\s*${COMPOUND_A}(?:\\s*,\\s*${COMPOUND_A})*\\s*\\)`;
|
|
96
96
|
|
|
97
97
|
/* regexp */
|
|
98
|
-
export const
|
|
99
|
-
export const
|
|
100
|
-
export const REG_DESCEND = new RegExp(`${DESCEND}${COMPOUND_I}`, 'i');
|
|
101
|
-
export const REG_DIR = /^(?:ltr|rtl)$/;
|
|
102
|
-
export const REG_FILTER_COMPLEX =
|
|
103
|
-
new RegExp(`:(?!${PSEUDO_CLASSES}|${N_TH}|${LOGICAL_COMPLEX})`);
|
|
104
|
-
export const REG_FILTER_COMPOUND =
|
|
105
|
-
new RegExp(`:(?!${PSEUDO_CLASSES}|${N_TH}|${LOGICAL_COMPOUND})`);
|
|
106
|
-
export const REG_FILTER_SIMPLE = new RegExp(`:(?!${PSEUDO_CLASSES}|${N_TH})`);
|
|
107
|
-
export const REG_FORM = /^(?:button|fieldset|form|input|select|textarea)$/;
|
|
108
|
-
export const REG_FORM_CTRL =
|
|
109
|
-
/^(?:button|fieldset|input|optgroup|option|select|textarea)$/;
|
|
110
|
-
export const REG_FORM_VALID = /^(?:button|form|input|select|textarea)$/;
|
|
111
|
-
export const REG_HEX = /^([\da-f]{1,6}\s?)/i;
|
|
112
|
-
export const REG_INTERACT = /^(?:details|dialog)$/;
|
|
113
|
-
export const REG_INVALID_SELECTOR = /^$|^\s*>|,\s*$/;
|
|
114
|
-
export const REG_LANG = new RegExp(`^(?:\\*-)?${ALPHA_NUM}${LANG_PART}$`, 'i');
|
|
115
|
-
export const REG_LANG_QUOTED = /(:lang\(\s*("[A-Za-z\d\-*]*")\s*\))/;
|
|
116
|
-
export const REG_LOGICAL_EMPTY = /(:(is|where)\(\s*\))/;
|
|
117
|
-
export const REG_LOGICAL_PSEUDO = /^(?:has|is|not|where)$/;
|
|
118
|
-
export const REG_SHADOW_HOST = /^host(?:-context)?$/;
|
|
119
|
-
export const REG_SHADOW_MODE = /^(?:close|open)$/;
|
|
120
|
-
export const REG_SHADOW_PSEUDO = /^part|slotted$/;
|
|
121
|
-
export const REG_TAG_NAME = /[A-Z][\\w-]*/i;
|
|
122
|
-
export const REG_TYPE_CHECK = /^(?:checkbox|radio)$/;
|
|
123
|
-
export const REG_TYPE_INPUT =
|
|
98
|
+
export const REG_LOGICAL = /^(?:has|is|not|where)$/;
|
|
99
|
+
export const REG_INPUT_TYPE =
|
|
124
100
|
/^(?:date(?:time-local)?|email|month|number|password|search|tel|text|time|url|week)$/;
|
|
125
|
-
export const REG_TYPE_RANGE =
|
|
126
|
-
/^(?:date(?:time-local)?|month|number|range|time|week)$/;
|
|
127
|
-
export const REG_TYPE_RESET = /^(?:button|reset)$/;
|
|
128
|
-
export const REG_TYPE_SUBMIT = /^(?:image|submit)$/;
|
|
129
|
-
export const REG_TYPE_TEXT = /^(?:email|number|password|search|tel|text|url)$/;
|
package/src/js/finder.js
CHANGED
|
@@ -14,18 +14,26 @@ import {
|
|
|
14
14
|
|
|
15
15
|
/* constants */
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
SELECTOR_PSEUDO_CLASS, SELECTOR_PSEUDO_ELEMENT, SELECTOR_TYPE, SHOW_ALL,
|
|
23
|
-
SYNTAX_ERR, TARGET_ALL, TARGET_FIRST, TARGET_LINEAL, TARGET_SELF, TEXT_NODE,
|
|
24
|
-
WALKER_FILTER
|
|
17
|
+
ATTR_SELECTOR, BIT_01, CLASS_SELECTOR, COMBINATOR, DOCUMENT_FRAGMENT_NODE,
|
|
18
|
+
DOCUMENT_NODE, ELEMENT_NODE, EMPTY, ID_SELECTOR, NOT_SUPPORTED_ERR,
|
|
19
|
+
PS_CLASS_SELECTOR, PS_ELEMENT_SELECTOR, REG_INPUT_TYPE, REG_LOGICAL,
|
|
20
|
+
SHOW_ALL, SYNTAX_ERR, TARGET_ALL, TARGET_FIRST, TARGET_LINEAL, TARGET_SELF,
|
|
21
|
+
TEXT_NODE, TYPE_SELECTOR, WALKER_FILTER
|
|
25
22
|
} from './constant.js';
|
|
26
23
|
const DIR_NEXT = 'next';
|
|
27
24
|
const DIR_PREV = 'prev';
|
|
28
25
|
const KEY_TAB = 'Tab';
|
|
26
|
+
const REG_ANCHOR = /^a(?:rea)?$/;
|
|
27
|
+
const REG_FORM_CTRL =
|
|
28
|
+
/^(?:button|fieldset|input|optgroup|option|select|textarea)$/;
|
|
29
|
+
const REG_FORM_VALID = /^(?:button|form|input|select|textarea)$/;
|
|
30
|
+
const REG_INTERACT = /^(?:details|dialog)$/;
|
|
31
|
+
const REG_SHADOW_HOST = /^host(?:-context)?$/;
|
|
32
|
+
const REG_TYPE_CHECK = /^(?:checkbox|radio)$/;
|
|
33
|
+
const REG_TYPE_RANGE = /^(?:date(?:time-local)?|month|number|range|time|week)$/;
|
|
34
|
+
const REG_TYPE_RESET = /^(?:button|reset)$/;
|
|
35
|
+
const REG_TYPE_SUBMIT = /^(?:image|submit)$/;
|
|
36
|
+
const REG_TYPE_TEXT = /^(?:email|number|password|search|tel|text|url)$/;
|
|
29
37
|
|
|
30
38
|
/**
|
|
31
39
|
* Finder
|
|
@@ -110,6 +118,8 @@ export class Finder {
|
|
|
110
118
|
} else {
|
|
111
119
|
throw new this.#window.DOMException(e.message, e.name);
|
|
112
120
|
}
|
|
121
|
+
} else if (e.name in this.#window) {
|
|
122
|
+
throw new this.#window[e.name](e.message);
|
|
113
123
|
} else {
|
|
114
124
|
throw e;
|
|
115
125
|
}
|
|
@@ -828,7 +838,7 @@ export class Finder {
|
|
|
828
838
|
} = opt;
|
|
829
839
|
const matched = new Set();
|
|
830
840
|
// :has(), :is(), :not(), :where()
|
|
831
|
-
if (
|
|
841
|
+
if (REG_LOGICAL.test(astName)) {
|
|
832
842
|
let astData;
|
|
833
843
|
if (this.#astCache.has(ast)) {
|
|
834
844
|
astData = this.#astCache.get(ast);
|
|
@@ -1194,7 +1204,7 @@ export class Finder {
|
|
|
1194
1204
|
break;
|
|
1195
1205
|
}
|
|
1196
1206
|
case 'input': {
|
|
1197
|
-
if ((!node.type ||
|
|
1207
|
+
if ((!node.type || REG_INPUT_TYPE.test(node.type)) &&
|
|
1198
1208
|
(node.readonly || node.hasAttribute('readonly') ||
|
|
1199
1209
|
node.disabled || node.hasAttribute('disabled'))) {
|
|
1200
1210
|
matched.add(node);
|
|
@@ -1219,7 +1229,7 @@ export class Finder {
|
|
|
1219
1229
|
break;
|
|
1220
1230
|
}
|
|
1221
1231
|
case 'input': {
|
|
1222
|
-
if ((!node.type ||
|
|
1232
|
+
if ((!node.type || REG_INPUT_TYPE.test(node.type)) &&
|
|
1223
1233
|
!(node.readonly || node.hasAttribute('readonly') ||
|
|
1224
1234
|
node.disabled || node.hasAttribute('disabled'))) {
|
|
1225
1235
|
matched.add(node);
|
|
@@ -1476,7 +1486,7 @@ export class Finder {
|
|
|
1476
1486
|
if (node.hasAttribute('type')) {
|
|
1477
1487
|
const inputType = node.getAttribute('type');
|
|
1478
1488
|
if (inputType === 'file' || REG_TYPE_CHECK.test(inputType) ||
|
|
1479
|
-
|
|
1489
|
+
REG_INPUT_TYPE.test(inputType)) {
|
|
1480
1490
|
targetNode = node;
|
|
1481
1491
|
}
|
|
1482
1492
|
} else {
|
|
@@ -1497,7 +1507,7 @@ export class Finder {
|
|
|
1497
1507
|
if (node.hasAttribute('type')) {
|
|
1498
1508
|
const inputType = node.getAttribute('type');
|
|
1499
1509
|
if (inputType === 'file' || REG_TYPE_CHECK.test(inputType) ||
|
|
1500
|
-
|
|
1510
|
+
REG_INPUT_TYPE.test(inputType)) {
|
|
1501
1511
|
targetNode = node;
|
|
1502
1512
|
}
|
|
1503
1513
|
} else {
|
|
@@ -1767,23 +1777,23 @@ export class Finder {
|
|
|
1767
1777
|
}
|
|
1768
1778
|
if (node.nodeType === ELEMENT_NODE) {
|
|
1769
1779
|
switch (astType) {
|
|
1770
|
-
case
|
|
1780
|
+
case PS_ELEMENT_SELECTOR: {
|
|
1771
1781
|
this.#matcher.matchPseudoElementSelector(astName, opt);
|
|
1772
1782
|
break;
|
|
1773
1783
|
}
|
|
1774
|
-
case
|
|
1784
|
+
case ID_SELECTOR: {
|
|
1775
1785
|
if (node.id === astName) {
|
|
1776
1786
|
matched.add(node);
|
|
1777
1787
|
}
|
|
1778
1788
|
break;
|
|
1779
1789
|
}
|
|
1780
|
-
case
|
|
1790
|
+
case CLASS_SELECTOR: {
|
|
1781
1791
|
if (node.classList.contains(astName)) {
|
|
1782
1792
|
matched.add(node);
|
|
1783
1793
|
}
|
|
1784
1794
|
break;
|
|
1785
1795
|
}
|
|
1786
|
-
case
|
|
1796
|
+
case PS_CLASS_SELECTOR: {
|
|
1787
1797
|
const nodes = this._matchPseudoClassSelector(ast, node, opt);
|
|
1788
1798
|
return nodes;
|
|
1789
1799
|
}
|
|
@@ -1794,9 +1804,9 @@ export class Finder {
|
|
|
1794
1804
|
}
|
|
1795
1805
|
}
|
|
1796
1806
|
}
|
|
1797
|
-
} else if (this.#shadow && astType ===
|
|
1807
|
+
} else if (this.#shadow && astType === PS_CLASS_SELECTOR &&
|
|
1798
1808
|
node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
1799
|
-
if (astName !== 'has' &&
|
|
1809
|
+
if (astName !== 'has' && REG_LOGICAL.test(astName)) {
|
|
1800
1810
|
const nodes = this._matchPseudoClassSelector(ast, node, opt);
|
|
1801
1811
|
return nodes;
|
|
1802
1812
|
} else if (REG_SHADOW_HOST.test(astName)) {
|
|
@@ -1831,17 +1841,18 @@ export class Finder {
|
|
|
1831
1841
|
}
|
|
1832
1842
|
if (typeof bool !== 'boolean') {
|
|
1833
1843
|
let cacheable = true;
|
|
1834
|
-
if (node.nodeType === ELEMENT_NODE &&
|
|
1844
|
+
if (node.nodeType === ELEMENT_NODE &&
|
|
1845
|
+
/^(?:button|fieldset|form|input|select|textarea)$/.test(node.localName)) {
|
|
1835
1846
|
cacheable = false;
|
|
1836
1847
|
}
|
|
1837
1848
|
for (const leaf of leaves) {
|
|
1838
1849
|
switch (leaf.type) {
|
|
1839
|
-
case
|
|
1840
|
-
case
|
|
1850
|
+
case ATTR_SELECTOR:
|
|
1851
|
+
case ID_SELECTOR: {
|
|
1841
1852
|
cacheable = false;
|
|
1842
1853
|
break;
|
|
1843
1854
|
}
|
|
1844
|
-
case
|
|
1855
|
+
case PS_CLASS_SELECTOR: {
|
|
1845
1856
|
if (/^(?:(?:any-)?link|defined|dir)$/.test(leaf.name)) {
|
|
1846
1857
|
cacheable = false;
|
|
1847
1858
|
}
|
|
@@ -1921,11 +1932,11 @@ export class Finder {
|
|
|
1921
1932
|
pending = true;
|
|
1922
1933
|
} else {
|
|
1923
1934
|
switch (leafType) {
|
|
1924
|
-
case
|
|
1935
|
+
case PS_ELEMENT_SELECTOR: {
|
|
1925
1936
|
this.#matcher.matchPseudoElementSelector(leafName, opt);
|
|
1926
1937
|
break;
|
|
1927
1938
|
}
|
|
1928
|
-
case
|
|
1939
|
+
case ID_SELECTOR: {
|
|
1929
1940
|
if (this.#root.nodeType === ELEMENT_NODE) {
|
|
1930
1941
|
pending = true;
|
|
1931
1942
|
} else {
|
|
@@ -1943,7 +1954,7 @@ export class Finder {
|
|
|
1943
1954
|
}
|
|
1944
1955
|
break;
|
|
1945
1956
|
}
|
|
1946
|
-
case
|
|
1957
|
+
case CLASS_SELECTOR: {
|
|
1947
1958
|
const items = baseNode.getElementsByClassName(leafName);
|
|
1948
1959
|
nodes = this._matchHTMLCollection(items, {
|
|
1949
1960
|
compound,
|
|
@@ -1951,7 +1962,7 @@ export class Finder {
|
|
|
1951
1962
|
});
|
|
1952
1963
|
break;
|
|
1953
1964
|
}
|
|
1954
|
-
case
|
|
1965
|
+
case TYPE_SELECTOR: {
|
|
1955
1966
|
if (this.#document.contentType === 'text/html' &&
|
|
1956
1967
|
!/[*|]/.test(leafName)) {
|
|
1957
1968
|
const items = baseNode.getElementsByTagName(leafName);
|
|
@@ -2322,13 +2333,13 @@ export class Finder {
|
|
|
2322
2333
|
let filtered = false;
|
|
2323
2334
|
let pending = false;
|
|
2324
2335
|
switch (leafType) {
|
|
2325
|
-
case
|
|
2336
|
+
case PS_ELEMENT_SELECTOR: {
|
|
2326
2337
|
this.#matcher.matchPseudoElementSelector(leafName, {
|
|
2327
2338
|
warn: this.#warn
|
|
2328
2339
|
});
|
|
2329
2340
|
break;
|
|
2330
2341
|
}
|
|
2331
|
-
case
|
|
2342
|
+
case ID_SELECTOR: {
|
|
2332
2343
|
if (targetType === TARGET_SELF) {
|
|
2333
2344
|
[nodes, filtered] = this._matchSelf(leaves);
|
|
2334
2345
|
} else if (targetType === TARGET_LINEAL) {
|
|
@@ -2359,7 +2370,7 @@ export class Finder {
|
|
|
2359
2370
|
}
|
|
2360
2371
|
break;
|
|
2361
2372
|
}
|
|
2362
|
-
case
|
|
2373
|
+
case CLASS_SELECTOR: {
|
|
2363
2374
|
if (targetType === TARGET_SELF) {
|
|
2364
2375
|
[nodes, filtered] = this._matchSelf(leaves);
|
|
2365
2376
|
} else if (targetType === TARGET_LINEAL) {
|
|
@@ -2383,7 +2394,7 @@ export class Finder {
|
|
|
2383
2394
|
}
|
|
2384
2395
|
break;
|
|
2385
2396
|
}
|
|
2386
|
-
case
|
|
2397
|
+
case TYPE_SELECTOR: {
|
|
2387
2398
|
if (targetType === TARGET_SELF) {
|
|
2388
2399
|
[nodes, filtered] = this._matchSelf(leaves);
|
|
2389
2400
|
} else if (targetType === TARGET_LINEAL) {
|
|
@@ -2473,19 +2484,19 @@ export class Finder {
|
|
|
2473
2484
|
type: lastType
|
|
2474
2485
|
}]
|
|
2475
2486
|
} = lastTwig;
|
|
2476
|
-
if (lastType ===
|
|
2477
|
-
lastType ===
|
|
2487
|
+
if (lastType === PS_ELEMENT_SELECTOR ||
|
|
2488
|
+
lastType === ID_SELECTOR) {
|
|
2478
2489
|
dir = DIR_PREV;
|
|
2479
2490
|
twig = lastTwig;
|
|
2480
|
-
} else if (firstType ===
|
|
2481
|
-
firstType ===
|
|
2491
|
+
} else if (firstType === PS_ELEMENT_SELECTOR ||
|
|
2492
|
+
firstType === ID_SELECTOR) {
|
|
2482
2493
|
dir = DIR_NEXT;
|
|
2483
2494
|
twig = firstTwig;
|
|
2484
2495
|
} else if (targetType === TARGET_ALL) {
|
|
2485
|
-
if (firstName === '*' && firstType ===
|
|
2496
|
+
if (firstName === '*' && firstType === TYPE_SELECTOR) {
|
|
2486
2497
|
dir = DIR_PREV;
|
|
2487
2498
|
twig = lastTwig;
|
|
2488
|
-
} else if (lastName === '*' && lastType ===
|
|
2499
|
+
} else if (lastName === '*' && lastType === TYPE_SELECTOR) {
|
|
2489
2500
|
dir = DIR_NEXT;
|
|
2490
2501
|
twig = firstTwig;
|
|
2491
2502
|
} else if (branchLen === 2) {
|
|
@@ -2501,17 +2512,17 @@ export class Finder {
|
|
|
2501
2512
|
dir = DIR_NEXT;
|
|
2502
2513
|
twig = firstTwig;
|
|
2503
2514
|
}
|
|
2504
|
-
} else if (lastName === '*' && lastType ===
|
|
2515
|
+
} else if (lastName === '*' && lastType === TYPE_SELECTOR) {
|
|
2505
2516
|
dir = DIR_NEXT;
|
|
2506
2517
|
twig = firstTwig;
|
|
2507
|
-
} else if (firstName === '*' && firstType ===
|
|
2518
|
+
} else if (firstName === '*' && firstType === TYPE_SELECTOR) {
|
|
2508
2519
|
dir = DIR_PREV;
|
|
2509
2520
|
twig = lastTwig;
|
|
2510
2521
|
} else {
|
|
2511
2522
|
let bool;
|
|
2512
2523
|
for (const { combo, leaves: [leaf] } of branch) {
|
|
2513
2524
|
const { name: leafName, type: leafType } = leaf;
|
|
2514
|
-
if (leafType ===
|
|
2525
|
+
if (leafType === PS_CLASS_SELECTOR && leafName === 'dir') {
|
|
2515
2526
|
bool = false;
|
|
2516
2527
|
break;
|
|
2517
2528
|
}
|
package/src/js/matcher.js
CHANGED
|
@@ -8,8 +8,8 @@ import { getDirectionality, getType, isNamespaceDeclared } from './utility.js';
|
|
|
8
8
|
|
|
9
9
|
/* constants */
|
|
10
10
|
import {
|
|
11
|
-
ALPHA_NUM, ELEMENT_NODE, EMPTY, LANG_PART, NOT_SUPPORTED_ERR,
|
|
12
|
-
|
|
11
|
+
ALPHA_NUM, ATTR_SELECTOR, ELEMENT_NODE, EMPTY, LANG_PART, NOT_SUPPORTED_ERR,
|
|
12
|
+
SYNTAX_ERR, TYPE_SELECTOR
|
|
13
13
|
} from './constant.js';
|
|
14
14
|
|
|
15
15
|
/* Matcher */
|
|
@@ -294,7 +294,7 @@ export class Matcher {
|
|
|
294
294
|
prefix: astPrefix, localName: astLocalName
|
|
295
295
|
} = parseAstName(astName, node);
|
|
296
296
|
if (node.ownerDocument.contentType === 'text/html' &&
|
|
297
|
-
|
|
297
|
+
/[A-Z][\\w-]*/i.test(localName)) {
|
|
298
298
|
astPrefix = astPrefix.toLowerCase();
|
|
299
299
|
astLocalName = astLocalName.toLowerCase();
|
|
300
300
|
}
|
|
@@ -393,7 +393,8 @@ export class Matcher {
|
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
} else if (astName) {
|
|
396
|
-
|
|
396
|
+
const reg = new RegExp(`^(?:\\*-)?${ALPHA_NUM}${LANG_PART}$`, 'i');
|
|
397
|
+
if (reg.test(astName)) {
|
|
397
398
|
let regExtendedLang;
|
|
398
399
|
if (astName.indexOf('-') > -1) {
|
|
399
400
|
const [langMain, langSub, ...langRest] = astName.split('-');
|
|
@@ -462,11 +463,11 @@ export class Matcher {
|
|
|
462
463
|
}
|
|
463
464
|
let matched;
|
|
464
465
|
switch (ast.type) {
|
|
465
|
-
case
|
|
466
|
+
case ATTR_SELECTOR: {
|
|
466
467
|
matched = this._matchAttributeSelector(ast, node);
|
|
467
468
|
break;
|
|
468
469
|
}
|
|
469
|
-
case
|
|
470
|
+
case TYPE_SELECTOR: {
|
|
470
471
|
matched = this._matchTypeSelector(ast, node, opt ?? {});
|
|
471
472
|
break;
|
|
472
473
|
}
|
package/src/js/parser.js
CHANGED
|
@@ -8,12 +8,13 @@ import { getType } from './utility.js';
|
|
|
8
8
|
|
|
9
9
|
/* constants */
|
|
10
10
|
import {
|
|
11
|
-
BIT_01, BIT_02, BIT_04, BIT_08, BIT_16, BIT_32, BIT_FFFF,
|
|
12
|
-
DUO, EMPTY, HEX,
|
|
13
|
-
|
|
14
|
-
SELECTOR_ATTR, SELECTOR_CLASS, SELECTOR_ID, SELECTOR_PSEUDO_CLASS,
|
|
15
|
-
SELECTOR_PSEUDO_ELEMENT, SELECTOR_TYPE, SYNTAX_ERR, U_FFFD
|
|
11
|
+
ATTR_SELECTOR, BIT_01, BIT_02, BIT_04, BIT_08, BIT_16, BIT_32, BIT_FFFF,
|
|
12
|
+
CLASS_SELECTOR, DUO, EMPTY, HEX, HYPHEN, ID_SELECTOR, NTH, PS_CLASS_SELECTOR,
|
|
13
|
+
PS_ELEMENT_SELECTOR, REG_LOGICAL, SELECTOR, SYNTAX_ERR, TYPE_SELECTOR, U_FFFD
|
|
16
14
|
} from './constant.js';
|
|
15
|
+
const REG_LANG_QUOTED = /(:lang\(\s*("[A-Za-z\d\-*]*")\s*\))/;
|
|
16
|
+
const REG_LOGICAL_EMPTY = /(:(is|where)\(\s*\))/;
|
|
17
|
+
const REG_SHADOW_PSEUDO = /^part|slotted$/;
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* unescape selector
|
|
@@ -29,7 +30,7 @@ export const unescapeSelector = (selector = '') => {
|
|
|
29
30
|
if (item === '' && i === l - 1) {
|
|
30
31
|
item = U_FFFD;
|
|
31
32
|
} else {
|
|
32
|
-
const hexExists =
|
|
33
|
+
const hexExists = /^([\da-f]{1,6}\s?)/i.exec(item);
|
|
33
34
|
if (hexExists) {
|
|
34
35
|
const [, hex] = hexExists;
|
|
35
36
|
let str;
|
|
@@ -88,7 +89,7 @@ export const preprocess = (...args) => {
|
|
|
88
89
|
throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);
|
|
89
90
|
}
|
|
90
91
|
const codePoint = postHash.codePointAt(0);
|
|
91
|
-
if (codePoint ===
|
|
92
|
+
if (codePoint === HYPHEN) {
|
|
92
93
|
if (/^\d$/.test(postHash.substring(1, 2))) {
|
|
93
94
|
throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);
|
|
94
95
|
}
|
|
@@ -126,7 +127,7 @@ export const preprocess = (...args) => {
|
|
|
126
127
|
export const parseSelector = selector => {
|
|
127
128
|
selector = preprocess(selector);
|
|
128
129
|
// invalid selectors
|
|
129
|
-
if (
|
|
130
|
+
if (/^$|^\s*>|,\s*$/.test(selector)) {
|
|
130
131
|
throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);
|
|
131
132
|
}
|
|
132
133
|
let res;
|
|
@@ -191,8 +192,8 @@ export const walkAST = (ast = {}) => {
|
|
|
191
192
|
branches.add(node.children);
|
|
192
193
|
break;
|
|
193
194
|
}
|
|
194
|
-
case
|
|
195
|
-
if (
|
|
195
|
+
case PS_CLASS_SELECTOR: {
|
|
196
|
+
if (REG_LOGICAL.test(node.name)) {
|
|
196
197
|
info.set('hasNestedSelector', true);
|
|
197
198
|
info.set('hasLogicalPseudoFunc', true);
|
|
198
199
|
if (node.name === 'has') {
|
|
@@ -201,7 +202,7 @@ export const walkAST = (ast = {}) => {
|
|
|
201
202
|
}
|
|
202
203
|
break;
|
|
203
204
|
}
|
|
204
|
-
case
|
|
205
|
+
case PS_ELEMENT_SELECTOR: {
|
|
205
206
|
if (REG_SHADOW_PSEUDO.test(node.name)) {
|
|
206
207
|
info.set('hasNestedSelector', true);
|
|
207
208
|
}
|
|
@@ -221,12 +222,11 @@ export const walkAST = (ast = {}) => {
|
|
|
221
222
|
if (info.get('hasNestedSelector')) {
|
|
222
223
|
findAll(ast, (node, item, list) => {
|
|
223
224
|
if (list) {
|
|
224
|
-
if (node.type ===
|
|
225
|
-
REG_LOGICAL_PSEUDO.test(node.name)) {
|
|
225
|
+
if (node.type === PS_CLASS_SELECTOR && REG_LOGICAL.test(node.name)) {
|
|
226
226
|
const itemList = list.filter(i => {
|
|
227
227
|
const { name, type } = i;
|
|
228
228
|
const res =
|
|
229
|
-
type ===
|
|
229
|
+
type === PS_CLASS_SELECTOR && REG_LOGICAL.test(name);
|
|
230
230
|
return res;
|
|
231
231
|
});
|
|
232
232
|
for (const { children } of itemList) {
|
|
@@ -240,12 +240,12 @@ export const walkAST = (ast = {}) => {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
-
} else if (node.type ===
|
|
243
|
+
} else if (node.type === PS_ELEMENT_SELECTOR &&
|
|
244
244
|
REG_SHADOW_PSEUDO.test(node.name)) {
|
|
245
245
|
const itemList = list.filter(i => {
|
|
246
246
|
const { name, type } = i;
|
|
247
247
|
const res =
|
|
248
|
-
type ===
|
|
248
|
+
type === PS_ELEMENT_SELECTOR && REG_SHADOW_PSEUDO.test(name);
|
|
249
249
|
return res;
|
|
250
250
|
});
|
|
251
251
|
for (const { children } of itemList) {
|
|
@@ -290,12 +290,12 @@ export const sortAST = asts => {
|
|
|
290
290
|
const arr = [...asts];
|
|
291
291
|
if (arr.length > 1) {
|
|
292
292
|
const order = new Map([
|
|
293
|
-
[
|
|
294
|
-
[
|
|
295
|
-
[
|
|
296
|
-
[
|
|
297
|
-
[
|
|
298
|
-
[
|
|
293
|
+
[PS_ELEMENT_SELECTOR, BIT_01],
|
|
294
|
+
[ID_SELECTOR, BIT_02],
|
|
295
|
+
[CLASS_SELECTOR, BIT_04],
|
|
296
|
+
[TYPE_SELECTOR, BIT_08],
|
|
297
|
+
[ATTR_SELECTOR, BIT_16],
|
|
298
|
+
[PS_CLASS_SELECTOR, BIT_32]
|
|
299
299
|
]);
|
|
300
300
|
arr.sort((a, b) => {
|
|
301
301
|
const { type: typeA } = a;
|
package/src/js/utility.js
CHANGED
|
@@ -10,10 +10,15 @@ import isCustomElementName from 'is-potential-custom-element-name';
|
|
|
10
10
|
/* constants */
|
|
11
11
|
import {
|
|
12
12
|
DOCUMENT_FRAGMENT_NODE, DOCUMENT_NODE, DOCUMENT_POSITION_CONTAINS,
|
|
13
|
-
DOCUMENT_POSITION_PRECEDING, ELEMENT_NODE,
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
DOCUMENT_POSITION_PRECEDING, ELEMENT_NODE, N_TH, LOGICAL_COMPLEX,
|
|
14
|
+
LOGICAL_COMPOUND, PSEUDO_CLASS, REG_INPUT_TYPE, TEXT_NODE, TYPE_FROM,
|
|
15
|
+
TYPE_TO, WALKER_FILTER
|
|
16
16
|
} from './constant.js';
|
|
17
|
+
const REG_LOGICAL_COMPLEX =
|
|
18
|
+
new RegExp(`:(?!${PSEUDO_CLASS}|${N_TH}|${LOGICAL_COMPLEX})`);
|
|
19
|
+
const REG_LOGICAL_COMPOUND =
|
|
20
|
+
new RegExp(`:(?!${PSEUDO_CLASS}|${N_TH}|${LOGICAL_COMPOUND})`);
|
|
21
|
+
const REG_WO_LOGICAL = new RegExp(`:(?!${PSEUDO_CLASS}|${N_TH})`);
|
|
17
22
|
|
|
18
23
|
/**
|
|
19
24
|
* get type
|
|
@@ -171,7 +176,7 @@ export const isInShadowTree = node => {
|
|
|
171
176
|
while (refNode) {
|
|
172
177
|
const { host, mode, nodeType, parentNode } = refNode;
|
|
173
178
|
if (host && mode && nodeType === DOCUMENT_FRAGMENT_NODE &&
|
|
174
|
-
|
|
179
|
+
/^(?:close|open)$/.test(mode)) {
|
|
175
180
|
bool = true;
|
|
176
181
|
break;
|
|
177
182
|
}
|
|
@@ -221,7 +226,7 @@ export const getDirectionality = node => {
|
|
|
221
226
|
if (node.nodeType === ELEMENT_NODE) {
|
|
222
227
|
const { dir: nodeDir, localName, parentNode } = node;
|
|
223
228
|
const { getEmbeddingLevels } = bidiFactory();
|
|
224
|
-
if (
|
|
229
|
+
if (/^(?:ltr|rtl)$/.test(nodeDir)) {
|
|
225
230
|
res = nodeDir;
|
|
226
231
|
} else if (nodeDir === 'auto') {
|
|
227
232
|
let text;
|
|
@@ -253,7 +258,7 @@ export const getDirectionality = node => {
|
|
|
253
258
|
text = itemTextContent.trim();
|
|
254
259
|
} else if (itemNodeType === ELEMENT_NODE) {
|
|
255
260
|
if (!/^(?:bdi|script|style|textarea)$/.test(itemLocalName) &&
|
|
256
|
-
(!itemDir ||
|
|
261
|
+
(!itemDir || !/^(?:ltr|rtl)$/.test(itemDir))) {
|
|
257
262
|
if (itemLocalName === 'slot') {
|
|
258
263
|
text = getSlottedTextContent(item);
|
|
259
264
|
} else {
|
|
@@ -394,7 +399,7 @@ export const isFocusVisible = node => {
|
|
|
394
399
|
const { localName, type } = node;
|
|
395
400
|
switch (localName) {
|
|
396
401
|
case 'input': {
|
|
397
|
-
if (!type ||
|
|
402
|
+
if (!type || REG_INPUT_TYPE.test(type)) {
|
|
398
403
|
res = true;
|
|
399
404
|
}
|
|
400
405
|
break;
|
|
@@ -596,21 +601,16 @@ export const filterSelector = (selector, opt = {}) => {
|
|
|
596
601
|
// filter pseudo-classes
|
|
597
602
|
if (selector.includes(':')) {
|
|
598
603
|
const { complex, descend } = opt;
|
|
599
|
-
let reg;
|
|
600
604
|
if (/:(?:is|not)\(/.test(selector)) {
|
|
601
605
|
if (complex) {
|
|
602
|
-
|
|
606
|
+
return !REG_LOGICAL_COMPLEX.test(selector);
|
|
603
607
|
} else {
|
|
604
|
-
|
|
608
|
+
return !REG_LOGICAL_COMPOUND.test(selector);
|
|
605
609
|
}
|
|
606
|
-
} else {
|
|
607
|
-
if (descend) {
|
|
608
|
-
return false;
|
|
609
|
-
}
|
|
610
|
-
reg = REG_FILTER_SIMPLE;
|
|
611
|
-
}
|
|
612
|
-
if (reg.test(selector)) {
|
|
610
|
+
} else if (descend) {
|
|
613
611
|
return false;
|
|
612
|
+
} else {
|
|
613
|
+
return !REG_WO_LOGICAL.test(selector);
|
|
614
614
|
}
|
|
615
615
|
}
|
|
616
616
|
return true;
|