@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.
@@ -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 IDENTIFIER = 'Identifier';
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 PSEUDO_CLASSES =
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 REG_ANCHOR = /^a(?:rea)?$/;
99
- export const REG_COMPLEX = new RegExp(`${COMBO}${COMPOUND_I}`, 'i');
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
- BIT_01, COMBINATOR, DOCUMENT_FRAGMENT_NODE, DOCUMENT_NODE, ELEMENT_NODE,
18
- EMPTY, NOT_SUPPORTED_ERR, REG_ANCHOR, REG_FORM, REG_FORM_CTRL,
19
- REG_FORM_VALID, REG_INTERACT, REG_LOGICAL_PSEUDO, REG_SHADOW_HOST,
20
- REG_TYPE_CHECK, REG_TYPE_INPUT, REG_TYPE_RANGE, REG_TYPE_RESET,
21
- REG_TYPE_SUBMIT, REG_TYPE_TEXT, SELECTOR_ATTR, SELECTOR_CLASS, SELECTOR_ID,
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 (REG_LOGICAL_PSEUDO.test(astName)) {
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 || REG_TYPE_INPUT.test(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 || REG_TYPE_INPUT.test(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
- REG_TYPE_INPUT.test(inputType)) {
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
- REG_TYPE_INPUT.test(inputType)) {
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 SELECTOR_PSEUDO_ELEMENT: {
1780
+ case PS_ELEMENT_SELECTOR: {
1771
1781
  this.#matcher.matchPseudoElementSelector(astName, opt);
1772
1782
  break;
1773
1783
  }
1774
- case SELECTOR_ID: {
1784
+ case ID_SELECTOR: {
1775
1785
  if (node.id === astName) {
1776
1786
  matched.add(node);
1777
1787
  }
1778
1788
  break;
1779
1789
  }
1780
- case SELECTOR_CLASS: {
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 SELECTOR_PSEUDO_CLASS: {
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 === SELECTOR_PSEUDO_CLASS &&
1807
+ } else if (this.#shadow && astType === PS_CLASS_SELECTOR &&
1798
1808
  node.nodeType === DOCUMENT_FRAGMENT_NODE) {
1799
- if (astName !== 'has' && REG_LOGICAL_PSEUDO.test(astName)) {
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 && REG_FORM.test(node.localName)) {
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 SELECTOR_ATTR:
1840
- case SELECTOR_ID: {
1850
+ case ATTR_SELECTOR:
1851
+ case ID_SELECTOR: {
1841
1852
  cacheable = false;
1842
1853
  break;
1843
1854
  }
1844
- case SELECTOR_PSEUDO_CLASS: {
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 SELECTOR_PSEUDO_ELEMENT: {
1935
+ case PS_ELEMENT_SELECTOR: {
1925
1936
  this.#matcher.matchPseudoElementSelector(leafName, opt);
1926
1937
  break;
1927
1938
  }
1928
- case SELECTOR_ID: {
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 SELECTOR_CLASS: {
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 SELECTOR_TYPE: {
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 SELECTOR_PSEUDO_ELEMENT: {
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 SELECTOR_ID: {
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 SELECTOR_CLASS: {
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 SELECTOR_TYPE: {
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 === SELECTOR_PSEUDO_ELEMENT ||
2477
- lastType === SELECTOR_ID) {
2487
+ if (lastType === PS_ELEMENT_SELECTOR ||
2488
+ lastType === ID_SELECTOR) {
2478
2489
  dir = DIR_PREV;
2479
2490
  twig = lastTwig;
2480
- } else if (firstType === SELECTOR_PSEUDO_ELEMENT ||
2481
- firstType === SELECTOR_ID) {
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 === SELECTOR_TYPE) {
2496
+ if (firstName === '*' && firstType === TYPE_SELECTOR) {
2486
2497
  dir = DIR_PREV;
2487
2498
  twig = lastTwig;
2488
- } else if (lastName === '*' && lastType === SELECTOR_TYPE) {
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 === SELECTOR_TYPE) {
2515
+ } else if (lastName === '*' && lastType === TYPE_SELECTOR) {
2505
2516
  dir = DIR_NEXT;
2506
2517
  twig = firstTwig;
2507
- } else if (firstName === '*' && firstType === SELECTOR_TYPE) {
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 === SELECTOR_PSEUDO_CLASS && leafName === 'dir') {
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, REG_LANG,
12
- REG_TAG_NAME, SELECTOR_ATTR, SELECTOR_TYPE, SYNTAX_ERR
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
- REG_TAG_NAME.test(localName)) {
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
- if (REG_LANG.test(astName)) {
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 SELECTOR_ATTR: {
466
+ case ATTR_SELECTOR: {
466
467
  matched = this._matchAttributeSelector(ast, node);
467
468
  break;
468
469
  }
469
- case SELECTOR_TYPE: {
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, BIT_HYPHEN,
12
- DUO, EMPTY, HEX, NTH, REG_HEX, REG_INVALID_SELECTOR, REG_LANG_QUOTED,
13
- REG_LOGICAL_EMPTY, REG_LOGICAL_PSEUDO, REG_SHADOW_PSEUDO, SELECTOR,
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 = REG_HEX.exec(item);
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 === BIT_HYPHEN) {
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 (REG_INVALID_SELECTOR.test(selector)) {
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 SELECTOR_PSEUDO_CLASS: {
195
- if (REG_LOGICAL_PSEUDO.test(node.name)) {
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 SELECTOR_PSEUDO_ELEMENT: {
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 === SELECTOR_PSEUDO_CLASS &&
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 === SELECTOR_PSEUDO_CLASS && REG_LOGICAL_PSEUDO.test(name);
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 === SELECTOR_PSEUDO_ELEMENT &&
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 === SELECTOR_PSEUDO_ELEMENT && REG_SHADOW_PSEUDO.test(name);
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
- [SELECTOR_PSEUDO_ELEMENT, BIT_01],
294
- [SELECTOR_ID, BIT_02],
295
- [SELECTOR_CLASS, BIT_04],
296
- [SELECTOR_TYPE, BIT_08],
297
- [SELECTOR_ATTR, BIT_16],
298
- [SELECTOR_PSEUDO_CLASS, BIT_32]
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, REG_DIR, REG_FILTER_COMPLEX,
14
- REG_FILTER_COMPOUND, REG_FILTER_SIMPLE, REG_SHADOW_MODE, REG_TYPE_INPUT,
15
- TEXT_NODE, TYPE_FROM, TYPE_TO, WALKER_FILTER
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
- REG_SHADOW_MODE.test(mode)) {
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 (REG_DIR.test(nodeDir)) {
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 || !REG_DIR.test(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 || REG_TYPE_INPUT.test(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
- reg = REG_FILTER_COMPLEX;
606
+ return !REG_LOGICAL_COMPLEX.test(selector);
603
607
  } else {
604
- reg = REG_FILTER_COMPOUND;
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;