@asamuzakjp/dom-selector 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,21 +55,21 @@ closest - same functionality as [Element.closest()][65]
55
55
  Returns **[object][60]?** matched node
56
56
 
57
57
 
58
- ### querySelector(selector, refPoint, opt)
58
+ ### querySelector(selector, node, opt)
59
59
 
60
60
  querySelector - same functionality as [Document.querySelector()][66], [DocumentFragment.querySelector()][67], [Element.querySelector()][68]
61
61
 
62
62
  #### Parameters
63
63
 
64
64
  - `selector` **[string][59]** CSS selector
65
- - `refPoint` **[object][60]** Document, DocumentFragment or Element node
65
+ - `node` **[object][60]** Document, DocumentFragment or Element node
66
66
  - `opt` **[object][60]?** options
67
67
  - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
68
68
 
69
69
  Returns **[object][60]?** matched node
70
70
 
71
71
 
72
- ### querySelectorAll(selector, refPoint, opt)
72
+ ### querySelectorAll(selector, node, opt)
73
73
 
74
74
  querySelectorAll - same functionality as [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70], [Element.querySelectorAll()][71]
75
75
  **NOTE**: returns Array, not NodeList
@@ -77,7 +77,7 @@ querySelectorAll - same functionality as [Document.querySelectorAll()][69], [Doc
77
77
  #### Parameters
78
78
 
79
79
  - `selector` **[string][59]** CSS selector
80
- - `refPoint` **[object][60]** Document, DocumentFragment or Element node
80
+ - `node` **[object][60]** Document, DocumentFragment or Element node
81
81
  - `opt` **[object][60]?** options
82
82
  - `opt.sort` **[boolean][61]?** sort matched nodes
83
83
  - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
package/package.json CHANGED
@@ -50,5 +50,5 @@
50
50
  "update": "npm-run-all -s update-*",
51
51
  "update-wpt": "git submodule update --init --recursive"
52
52
  },
53
- "version": "0.21.1"
53
+ "version": "0.22.0"
54
54
  }
package/src/index.js CHANGED
@@ -33,23 +33,23 @@ export const closest = (selector, node, opt) =>
33
33
  /**
34
34
  * querySelector
35
35
  * @param {string} selector - CSS selector
36
- * @param {object} refPoint - Document, DocumentFragment or Element node
36
+ * @param {object} node - Document, DocumentFragment or Element node
37
37
  * @param {object} [opt] - options
38
38
  * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
39
39
  * @returns {?object} - matched node
40
40
  */
41
- export const querySelector = (selector, refPoint, opt) =>
42
- new Matcher(selector, refPoint, opt).querySelector();
41
+ export const querySelector = (selector, node, opt) =>
42
+ new Matcher(selector, node, opt).querySelector();
43
43
 
44
44
  /**
45
45
  * querySelectorAll
46
46
  * NOTE: returns Array, not NodeList
47
47
  * @param {string} selector - CSS selector
48
- * @param {object} refPoint - Document, DocumentFragment or Element node
48
+ * @param {object} node - Document, DocumentFragment or Element node
49
49
  * @param {object} [opt] - options
50
50
  * @param {boolean} [opt.sort] - sort matched nodes
51
51
  * @param {boolean} [opt.warn] - console warn e.g. unsupported pseudo-class
52
52
  * @returns {Array.<object|undefined>} - array of matched nodes
53
53
  */
54
- export const querySelectorAll = (selector, refPoint, opt) =>
55
- new Matcher(selector, refPoint, opt).querySelectorAll();
54
+ export const querySelectorAll = (selector, node, opt) =>
55
+ new Matcher(selector, node, opt).querySelectorAll();
@@ -98,10 +98,6 @@ export const selectorToNodeProps = (selector, node) => {
98
98
  if (selector && typeof selector === 'string') {
99
99
  if (/\|/.test(selector)) {
100
100
  [prefix, tagName] = selector.split('|');
101
- if (prefix && prefix !== '*' &&
102
- node && !isNamespaceDeclared(prefix, node)) {
103
- throw new DOMException(`invalid selector ${selector}`, SYNTAX_ERR);
104
- }
105
101
  } else {
106
102
  prefix = '*';
107
103
  tagName = selector;
package/src/js/matcher.js CHANGED
@@ -5,7 +5,8 @@
5
5
  /* import */
6
6
  import isCustomElementName from 'is-potential-custom-element-name';
7
7
  import {
8
- isContentEditable, isSameOrDescendant, selectorToNodeProps
8
+ isContentEditable, isNamespaceDeclared, isSameOrDescendant,
9
+ selectorToNodeProps
9
10
  } from './dom-util.js';
10
11
  import {
11
12
  generateCSS, parseSelector, unescapeSelector, walkAST
@@ -26,11 +27,16 @@ const TARGET_SELF = 'self';
26
27
 
27
28
  /* regexp */
28
29
  const DIR_VALUE = /^(?:auto|ltr|rtl)$/;
29
- const HTML_FORM_INPUT = /^(?:(?:inpu|selec)t|textarea)$/;
30
- const HTML_FORM_PARTS = /^(?:button|fieldset|opt(?:group|ion))$/;
31
- const HTML_FORM_VALIDITY = /^(?:(?:(?:in|out)pu|selec)t|button|form|textarea)$/;
30
+ const FORM_INPUT = /^(?:input|textarea)$/;
31
+ const FORM_PARTS =
32
+ /^(?:(?:fieldse|inpu|selec)t|button|opt(?:group|ion)|textarea)$/;
33
+ const FORM_VALIDITY = /^(?:(?:(?:in|out)pu|selec)t|button|form|textarea)$/;
34
+ const HTML_ANCHOR = /^a(?:rea)?$/;
32
35
  const HTML_INTERACT = /^d(?:etails|ialog)$/;
36
+ const INPUT_CHECK = /^(?:checkbox|radio)$/;
33
37
  const INPUT_RANGE = /(?:(?:rang|tim)e|date(?:time-local)?|month|number|week)$/;
38
+ const INPUT_RESET = /^(?:button|reset)$/;
39
+ const INPUT_SUBMIT = /^(?:image|submit)$/;
34
40
  const INPUT_TEXT = /^(?:(?:emai|te|ur)l|password|search|text)$/;
35
41
  const PSEUDO_FUNC = /^(?:(?:ha|i)s|not|where)$/;
36
42
  const PSEUDO_NTH = /^nth-(?:last-)?(?:child|of-type)$/;
@@ -145,7 +151,7 @@ export class Matcher {
145
151
  break;
146
152
  }
147
153
  default: {
148
- throw new TypeError(`Unexpected node type: ${node.nodeName}`);
154
+ throw new TypeError(`Unexpected node ${node.nodeName}`);
149
155
  }
150
156
  }
151
157
  return {
@@ -209,7 +215,7 @@ export class Matcher {
209
215
  if (item.type === COMBINATOR) {
210
216
  const [nextItem] = items;
211
217
  if (nextItem.type === COMBINATOR) {
212
- const msg = `invalid combinator ${item.name}${nextItem.name}`;
218
+ const msg = `Invalid combinator ${item.name}${nextItem.name}`;
213
219
  throw new DOMException(msg, SYNTAX_ERR);
214
220
  }
215
221
  branch.push({
@@ -245,42 +251,6 @@ export class Matcher {
245
251
  ];
246
252
  }
247
253
 
248
- /**
249
- * throw DOMExeption on pseudo element selector
250
- * @param {object} astName - AST name
251
- * @throws {DOMException}
252
- * @returns {void}
253
- */
254
- _throwOnPseudoElementSelector(astName) {
255
- let msg;
256
- let type;
257
- switch (astName) {
258
- case 'after':
259
- case 'backdrop':
260
- case 'before':
261
- case 'cue':
262
- case 'cue-region':
263
- case 'first-letter':
264
- case 'first-line':
265
- case 'file-selector-button':
266
- case 'marker':
267
- case 'part':
268
- case 'placeholder':
269
- case 'selection':
270
- case 'slotted':
271
- case 'target-text': {
272
- msg = `Unsupported pseudo-element ::${astName}`;
273
- type = NOT_SUPPORTED_ERR;
274
- break;
275
- }
276
- default: {
277
- msg = `Unknown pseudo-element ::${astName}`;
278
- type = SYNTAX_ERR;
279
- }
280
- }
281
- throw new DOMException(msg, type);
282
- }
283
-
284
254
  /**
285
255
  * collect nth child
286
256
  * @param {object} anb - An+B options
@@ -294,84 +264,109 @@ export class Matcher {
294
264
  _collectNthChild(anb, node) {
295
265
  const { a, b, reverse, selector } = anb;
296
266
  const { parentNode } = node;
297
- const selectorNodes = new Set();
267
+ const matched = new Set();
268
+ let selectorBranches;
298
269
  if (selector) {
299
- let branches;
300
270
  if (this.#cache.has(selector)) {
301
- branches = this.#cache.get(selector);
271
+ selectorBranches = this.#cache.get(selector);
302
272
  } else {
303
- branches = walkAST(selector);
304
- this.#cache.set(selector, branches);
273
+ selectorBranches = walkAST(selector);
274
+ this.#cache.set(selector, selectorBranches);
305
275
  }
306
- const branchLen = branches.length;
307
- const iterator = [...parentNode.children].values();
308
- for (const refNode of iterator) {
309
- let bool;
310
- for (let i = 0; i < branchLen; i++) {
311
- const leaves = branches[i];
312
- bool = this._matchLeaves(leaves, refNode);
313
- if (!bool) {
314
- break;
276
+ }
277
+ if (parentNode) {
278
+ const arr = [...parentNode.children];
279
+ const l = arr.length;
280
+ if (l) {
281
+ const selectorNodes = new Set();
282
+ if (selectorBranches) {
283
+ const branchesLen = selectorBranches.length;
284
+ for (const refNode of arr) {
285
+ let bool;
286
+ for (let i = 0; i < branchesLen; i++) {
287
+ const leaves = selectorBranches[i];
288
+ bool = this._matchLeaves(leaves, refNode);
289
+ if (!bool) {
290
+ break;
291
+ }
292
+ }
293
+ if (bool) {
294
+ selectorNodes.add(refNode);
295
+ }
315
296
  }
316
297
  }
317
- if (bool) {
318
- selectorNodes.add(refNode);
298
+ if (reverse) {
299
+ arr.reverse();
319
300
  }
320
- }
321
- }
322
- const arr = [...parentNode.children];
323
- if (reverse) {
324
- arr.reverse();
325
- }
326
- const l = arr.length;
327
- const matched = new Set();
328
- // :first-child, :last-child, :nth-child(0 of S)
329
- if (a === 0) {
330
- if (b > 0 && b <= l) {
331
- if (selectorNodes.size) {
332
- for (let i = 0; i < l; i++) {
333
- const current = arr[i];
334
- if (selectorNodes.has(current)) {
301
+ // :first-child, :last-child, :nth-child(0 of S)
302
+ if (a === 0) {
303
+ if (b > 0 && b <= l) {
304
+ if (selectorNodes.size) {
305
+ for (let i = 0; i < l; i++) {
306
+ const current = arr[i];
307
+ if (selectorNodes.has(current)) {
308
+ matched.add(current);
309
+ break;
310
+ }
311
+ }
312
+ } else if (!selector) {
313
+ const current = arr[b - 1];
335
314
  matched.add(current);
336
- break;
337
315
  }
338
316
  }
339
- } else if (!selector) {
340
- const current = arr[b - 1];
341
- matched.add(current);
342
- }
343
- }
344
- // :nth-child()
345
- } else {
346
- let n = 0;
347
- let nth = b - 1;
348
- if (a > 0) {
349
- while (nth < 0) {
350
- nth += (++n * a);
351
- }
352
- }
353
- if (nth >= 0 && nth < l) {
354
- let j = a > 0 ? 0 : b - 1;
355
- for (let i = 0; i < l && nth >= 0 && nth < l; i++) {
356
- const current = arr[i];
357
- if (selectorNodes.size) {
358
- if (selectorNodes.has(current)) {
359
- if (j === nth) {
360
- matched.add(current);
317
+ // :nth-child()
318
+ } else {
319
+ let n = 0;
320
+ let nth = b - 1;
321
+ if (a > 0) {
322
+ while (nth < 0) {
323
+ nth += (++n * a);
324
+ }
325
+ }
326
+ if (nth >= 0 && nth < l) {
327
+ let j = a > 0 ? 0 : b - 1;
328
+ for (let i = 0; i < l && nth >= 0 && nth < l; i++) {
329
+ const current = arr[i];
330
+ if (selectorNodes.size) {
331
+ if (selectorNodes.has(current)) {
332
+ if (j === nth) {
333
+ matched.add(current);
334
+ nth += a;
335
+ }
336
+ if (a > 0) {
337
+ j++;
338
+ } else {
339
+ j--;
340
+ }
341
+ }
342
+ } else if (i === nth) {
343
+ if (!selector) {
344
+ matched.add(current);
345
+ }
361
346
  nth += a;
362
347
  }
363
- if (a > 0) {
364
- j++;
365
- } else {
366
- j--;
367
- }
368
348
  }
369
- } else if (i === nth) {
370
- if (!selector) {
371
- matched.add(current);
349
+ }
350
+ }
351
+ }
352
+ } else {
353
+ const { root } = this.#root;
354
+ if (root.nodeType === ELEMENT_NODE && node === root && (a + b) === 1) {
355
+ if (selectorBranches) {
356
+ const branchesLen = selectorBranches.length;
357
+ let bool;
358
+ for (let i = 0; i < branchesLen; i++) {
359
+ const leaves = selectorBranches[i];
360
+ bool = this._matchLeaves(leaves, node);
361
+ if (bool) {
362
+ break;
372
363
  }
373
- nth += a;
374
364
  }
365
+ if (bool) {
366
+ matched.add(node);
367
+ }
368
+ } else {
369
+ matched.add(node);
375
370
  }
376
371
  }
377
372
  }
@@ -390,56 +385,65 @@ export class Matcher {
390
385
  _collectNthOfType(anb, node) {
391
386
  const { a, b, reverse } = anb;
392
387
  const { localName, parentNode, prefix } = node;
393
- const arr = [...parentNode.children];
394
- if (reverse) {
395
- arr.reverse();
396
- }
397
- const l = arr.length;
398
388
  const matched = new Set();
399
- // :first-of-type, :last-of-type
400
- if (a === 0) {
401
- if (b > 0 && b <= l) {
402
- let j = 0;
403
- for (let i = 0; i < l; i++) {
404
- const current = arr[i];
405
- const { localName: itemLocalName, prefix: itemPrefix } = current;
406
- if (itemLocalName === localName && itemPrefix === prefix) {
407
- if (j === b - 1) {
408
- matched.add(current);
409
- break;
389
+ if (parentNode) {
390
+ const arr = [...parentNode.children];
391
+ const l = arr.length;
392
+ if (l) {
393
+ if (reverse) {
394
+ arr.reverse();
395
+ }
396
+ // :first-of-type, :last-of-type
397
+ if (a === 0) {
398
+ if (b > 0 && b <= l) {
399
+ let j = 0;
400
+ for (let i = 0; i < l; i++) {
401
+ const current = arr[i];
402
+ const { localName: itemLocalName, prefix: itemPrefix } = current;
403
+ if (itemLocalName === localName && itemPrefix === prefix) {
404
+ if (j === b - 1) {
405
+ matched.add(current);
406
+ break;
407
+ }
408
+ j++;
409
+ }
410
410
  }
411
- j++;
412
411
  }
413
- }
414
- }
415
- // :nth-of-type()
416
- } else {
417
- let nth = b - 1;
418
- if (a > 0) {
419
- while (nth < 0) {
420
- nth += a;
421
- }
422
- }
423
- if (nth >= 0 && nth < l) {
424
- let j = a > 0 ? 0 : b - 1;
425
- for (let i = 0; i < l; i++) {
426
- const current = arr[i];
427
- const { localName: itemLocalName, prefix: itemPrefix } = current;
428
- if (itemLocalName === localName && itemPrefix === prefix) {
429
- if (j === nth) {
430
- matched.add(current);
412
+ // :nth-of-type()
413
+ } else {
414
+ let nth = b - 1;
415
+ if (a > 0) {
416
+ while (nth < 0) {
431
417
  nth += a;
432
418
  }
433
- if (nth < 0 || nth >= l) {
434
- break;
435
- } else if (a > 0) {
436
- j++;
437
- } else {
438
- j--;
419
+ }
420
+ if (nth >= 0 && nth < l) {
421
+ let j = a > 0 ? 0 : b - 1;
422
+ for (let i = 0; i < l; i++) {
423
+ const current = arr[i];
424
+ const { localName: itemLocalName, prefix: itemPrefix } = current;
425
+ if (itemLocalName === localName && itemPrefix === prefix) {
426
+ if (j === nth) {
427
+ matched.add(current);
428
+ nth += a;
429
+ }
430
+ if (nth < 0 || nth >= l) {
431
+ break;
432
+ } else if (a > 0) {
433
+ j++;
434
+ } else {
435
+ j--;
436
+ }
437
+ }
439
438
  }
440
439
  }
441
440
  }
442
441
  }
442
+ } else {
443
+ const { root } = this.#root;
444
+ if (root.nodeType === ELEMENT_NODE && node === root && (a + b) === 1) {
445
+ matched.add(node);
446
+ }
443
447
  }
444
448
  return matched;
445
449
  }
@@ -489,7 +493,7 @@ export class Matcher {
489
493
  }
490
494
  }
491
495
  let matched = new Set();
492
- if (anbMap.has('a') && anbMap.has('b') && node.parentNode) {
496
+ if (anbMap.has('a') && anbMap.has('b')) {
493
497
  if (/^nth-(?:last-)?child$/.test(nthName)) {
494
498
  if (selector) {
495
499
  anbMap.set('selector', selector);
@@ -510,6 +514,50 @@ export class Matcher {
510
514
  return matched;
511
515
  }
512
516
 
517
+ /**
518
+ * match pseudo element selector
519
+ * @param {string} astName - AST name
520
+ * @param {object} opt - options
521
+ * @throws {DOMException}
522
+ * @returns {void}
523
+ */
524
+ _matchPseudoElementSelector(astName, opt = {}) {
525
+ const { forgive } = opt;
526
+ switch (astName) {
527
+ case 'after':
528
+ case 'backdrop':
529
+ case 'before':
530
+ case 'cue':
531
+ case 'cue-region':
532
+ case 'first-letter':
533
+ case 'first-line':
534
+ case 'file-selector-button':
535
+ case 'marker':
536
+ case 'part':
537
+ case 'placeholder':
538
+ case 'selection':
539
+ case 'slotted':
540
+ case 'target-text': {
541
+ if (this.#warn) {
542
+ throw new DOMException(`Unsupported pseudo-element ::${astName}`,
543
+ NOT_SUPPORTED_ERR);
544
+ }
545
+ break;
546
+ }
547
+ default: {
548
+ if (astName.startsWith('-webkit-')) {
549
+ if (this.#warn) {
550
+ throw new DOMException(`Unsupported pseudo-element ::${astName}`,
551
+ NOT_SUPPORTED_ERR);
552
+ }
553
+ } else if (!forgive) {
554
+ throw new DOMException(`Unknown pseudo-element ::${astName}`,
555
+ SYNTAX_ERR);
556
+ }
557
+ }
558
+ }
559
+ }
560
+
513
561
  /**
514
562
  * match directionality pseudo-class - :dir()
515
563
  * @see https://html.spec.whatwg.org/multipage/dom.html#the-dir-attribute
@@ -534,14 +582,17 @@ export class Matcher {
534
582
  } else if (nodeDir === 'auto' &&
535
583
  (localName === 'textarea' ||
536
584
  (localName === 'input' &&
537
- (!inputType ||
538
- /^(?:(?:emai|te|ur)l|search|text)$/.test(inputType))))) {
539
- throw new DOMException('Unsupported pseudo-class :dir()',
540
- NOT_SUPPORTED_ERR);
585
+ (!inputType || INPUT_TEXT.test(inputType))))) {
586
+ if (this.#warn) {
587
+ throw new DOMException('Unsupported pseudo-class :dir()',
588
+ NOT_SUPPORTED_ERR);
589
+ }
541
590
  // FIXME:
542
591
  } else if (nodeDir === 'auto' || (localName === 'bdi' && !nodeDir)) {
543
- throw new DOMException('Unsupported pseudo-class :dir()',
544
- NOT_SUPPORTED_ERR);
592
+ if (this.#warn) {
593
+ throw new DOMException('Unsupported pseudo-class :dir()',
594
+ NOT_SUPPORTED_ERR);
595
+ }
545
596
  } else if (!nodeDir) {
546
597
  let parent = node.parentNode;
547
598
  while (parent) {
@@ -663,7 +714,8 @@ export class Matcher {
663
714
  if (nodes.size) {
664
715
  if (leaves.length) {
665
716
  for (const nextNode of nodes) {
666
- bool = this._matchHasPseudoFunc(leaves, nextNode);
717
+ bool =
718
+ this._matchHasPseudoFunc(Object.assign([], leaves), nextNode);
667
719
  if (bool) {
668
720
  break;
669
721
  }
@@ -678,20 +730,22 @@ export class Matcher {
678
730
 
679
731
  /**
680
732
  * match logical pseudo-class functions - :has(), :is(), :not(), :where()
681
- * @param {object} astOpt - AST options
733
+ * @param {object} astData - AST data
682
734
  * @param {object} node - Element node
683
735
  * @returns {?object} - matched node
684
736
  */
685
- _matchLogicalPseudoFunc(astOpt = {}, node) {
686
- const { astName = '', branches = [], selector = '' } = astOpt;
737
+ _matchLogicalPseudoFunc(astData, node) {
738
+ const {
739
+ astName = '', branches = [], selector = '', twigBranches = []
740
+ } = astData;
687
741
  let res;
688
- const branchLen = branches.length;
689
742
  if (astName === 'has') {
690
743
  if (selector.includes(':has(')) {
691
744
  res = null;
692
745
  } else {
693
746
  let bool;
694
- for (let i = 0; i < branchLen; i++) {
747
+ const l = branches.length;
748
+ for (let i = 0; i < l; i++) {
695
749
  const leaves = branches[i];
696
750
  bool = this._matchHasPseudoFunc(Object.assign([], leaves), node);
697
751
  if (bool) {
@@ -702,15 +756,45 @@ export class Matcher {
702
756
  res = node;
703
757
  }
704
758
  }
705
- // NOTE: according to MDN, :not() can not contain :not()
706
- // but spec says nothing about that?
707
- } else if (astName === 'not' && selector.includes(':not(')) {
708
- res = null;
709
759
  } else {
760
+ const forgive = /^(?:is|where)$/.test(astName);
710
761
  let bool;
711
- for (let i = 0; i < branchLen; i++) {
712
- const leaves = branches[i];
713
- bool = this._matchLeaves(leaves, node);
762
+ const l = twigBranches.length;
763
+ for (let i = 0; i < l; i++) {
764
+ const branch = twigBranches[i];
765
+ const lastIndex = branch.length - 1;
766
+ const { leaves } = branch[lastIndex];
767
+ bool = this._matchLeaves(leaves, node, {
768
+ forgive
769
+ });
770
+ if (bool && lastIndex > 0) {
771
+ let nextNodes = new Set([node]);
772
+ for (let j = lastIndex - 1; j >= 0; j--) {
773
+ const twig = branch[j];
774
+ const arr = [];
775
+ for (const nextNode of nextNodes) {
776
+ const m = this._matchCombinator(twig, nextNode, {
777
+ forgive,
778
+ find: 'prev'
779
+ });
780
+ if (m.size) {
781
+ arr.push(...m);
782
+ }
783
+ }
784
+ const matchedNodes = new Set(arr);
785
+ if (matchedNodes.size) {
786
+ if (j === 0) {
787
+ bool = true;
788
+ break;
789
+ } else {
790
+ nextNodes = matchedNodes;
791
+ }
792
+ } else {
793
+ bool = false;
794
+ break;
795
+ }
796
+ }
797
+ }
714
798
  if (bool) {
715
799
  break;
716
800
  }
@@ -731,38 +815,64 @@ export class Matcher {
731
815
  * @see https://html.spec.whatwg.org/#pseudo-classes
732
816
  * @param {object} ast - AST
733
817
  * @param {object} node - Element node
818
+ * @param {object} opt - options
734
819
  * @returns {object} - collection of matched nodes
735
820
  */
736
- _matchPseudoClassSelector(ast, node) {
821
+ _matchPseudoClassSelector(ast, node, opt = {}) {
737
822
  const { children: astChildren } = ast;
738
823
  const { localName, parentNode } = node;
824
+ const { forgive } = opt;
739
825
  const astName = unescapeSelector(ast.name);
740
826
  let matched = new Set();
741
827
  // :has(), :is(), :not(), :where()
742
828
  if (PSEUDO_FUNC.test(astName)) {
743
- let opt;
829
+ let astData;
744
830
  if (this.#cache.has(ast)) {
745
- opt = this.#cache.get(ast);
831
+ astData = this.#cache.get(ast);
746
832
  } else {
747
833
  const branches = walkAST(ast);
748
- const branchLen = branches.length;
749
- const branchSelectors = [];
750
- for (let i = 0; i < branchLen; i++) {
751
- const leaves = branches[i];
834
+ const selectors = [];
835
+ const twigBranches = [];
836
+ for (const [...leaves] of branches) {
752
837
  for (const leaf of leaves) {
753
838
  const css = generateCSS(leaf);
754
- branchSelectors.push(css);
839
+ selectors.push(css);
840
+ }
841
+ const branch = [];
842
+ const leavesSet = new Set();
843
+ let item = leaves.shift();
844
+ while (item) {
845
+ if (item.type === COMBINATOR) {
846
+ branch.push({
847
+ combo: item,
848
+ leaves: [...leavesSet]
849
+ });
850
+ leavesSet.clear();
851
+ } else if (item) {
852
+ leavesSet.add(item);
853
+ }
854
+ if (leaves.length) {
855
+ item = leaves.shift();
856
+ } else {
857
+ branch.push({
858
+ combo: null,
859
+ leaves: [...leavesSet]
860
+ });
861
+ leavesSet.clear();
862
+ break;
863
+ }
755
864
  }
865
+ twigBranches.push(branch);
756
866
  }
757
- const selector = branchSelectors.join(',');
758
- opt = {
867
+ astData = {
759
868
  astName,
760
869
  branches,
761
- selector
870
+ twigBranches,
871
+ selector: selectors.join(',')
762
872
  };
763
- this.#cache.set(ast, opt);
873
+ this.#cache.set(ast, astData);
764
874
  }
765
- const res = this._matchLogicalPseudoFunc(opt, node);
875
+ const res = this._matchLogicalPseudoFunc(astData, node);
766
876
  if (res) {
767
877
  matched.add(res);
768
878
  }
@@ -790,28 +900,35 @@ export class Matcher {
790
900
  switch (astName) {
791
901
  case 'current':
792
902
  case 'nth-col':
793
- case 'nth-last-col':
794
- throw new DOMException(`Unsupported pseudo-class :${astName}()`,
795
- NOT_SUPPORTED_ERR);
796
- default:
797
- throw new DOMException(`Unknown pseudo-class :${astName}()`,
798
- SYNTAX_ERR);
903
+ case 'nth-last-col': {
904
+ if (this.#warn) {
905
+ throw new DOMException(`Unsupported pseudo-class :${astName}()`,
906
+ NOT_SUPPORTED_ERR);
907
+ }
908
+ break;
909
+ }
910
+ default: {
911
+ if (!forgive) {
912
+ throw new DOMException(`Unknown pseudo-class :${astName}()`,
913
+ SYNTAX_ERR);
914
+ }
915
+ }
799
916
  }
800
917
  }
801
918
  } else {
802
- const { document } = this.#root;
803
- const root = document.documentElement;
919
+ const { document, root } = this.#root;
920
+ const { documentElement } = document;
804
921
  const docURL = new URL(document.URL);
805
922
  switch (astName) {
806
923
  case 'any-link':
807
924
  case 'link': {
808
- if (/^a(?:rea)?$/.test(localName) && node.hasAttribute('href')) {
925
+ if (HTML_ANCHOR.test(localName) && node.hasAttribute('href')) {
809
926
  matched.add(node);
810
927
  }
811
928
  break;
812
929
  }
813
930
  case 'local-link': {
814
- if (/^a(?:rea)?$/.test(localName) && node.hasAttribute('href')) {
931
+ if (HTML_ANCHOR.test(localName) && node.hasAttribute('href')) {
815
932
  const attrURL = new URL(node.getAttribute('href'), docURL.href);
816
933
  if (attrURL.origin === docURL.origin &&
817
934
  attrURL.pathname === docURL.pathname) {
@@ -850,7 +967,7 @@ export class Matcher {
850
967
  if (node === this.#node) {
851
968
  matched.add(node);
852
969
  }
853
- } else if (node === root) {
970
+ } else if (node === documentElement) {
854
971
  matched.add(node);
855
972
  }
856
973
  break;
@@ -885,9 +1002,7 @@ export class Matcher {
885
1002
  break;
886
1003
  }
887
1004
  case 'disabled': {
888
- if (HTML_FORM_INPUT.test(localName) ||
889
- HTML_FORM_PARTS.test(localName) ||
890
- isCustomElementName(localName)) {
1005
+ if (FORM_PARTS.test(localName) || isCustomElementName(localName)) {
891
1006
  if (node.disabled || node.hasAttribute('disabled')) {
892
1007
  matched.add(node);
893
1008
  } else {
@@ -907,16 +1022,14 @@ export class Matcher {
907
1022
  break;
908
1023
  }
909
1024
  case 'enabled': {
910
- if ((HTML_FORM_INPUT.test(localName) ||
911
- HTML_FORM_PARTS.test(localName) ||
912
- isCustomElementName(localName)) &&
1025
+ if ((FORM_PARTS.test(localName) || isCustomElementName(localName)) &&
913
1026
  !(node.disabled && node.hasAttribute('disabled'))) {
914
1027
  matched.add(node);
915
1028
  }
916
1029
  break;
917
1030
  }
918
1031
  case 'read-only': {
919
- if (/^(?:input|textarea)$/.test(localName)) {
1032
+ if (FORM_INPUT.test(localName)) {
920
1033
  let targetNode;
921
1034
  if (localName === 'input') {
922
1035
  if (node.hasAttribute('type')) {
@@ -930,7 +1043,7 @@ export class Matcher {
930
1043
  } else {
931
1044
  targetNode = node;
932
1045
  }
933
- } else if (localName === 'textarea') {
1046
+ } else {
934
1047
  targetNode = node;
935
1048
  }
936
1049
  if (targetNode) {
@@ -945,7 +1058,7 @@ export class Matcher {
945
1058
  break;
946
1059
  }
947
1060
  case 'read-write': {
948
- if (/^(?:input|textarea)$/.test(localName)) {
1061
+ if (FORM_INPUT.test(localName)) {
949
1062
  let targetNode;
950
1063
  if (localName === 'input') {
951
1064
  if (node.hasAttribute('type')) {
@@ -959,7 +1072,7 @@ export class Matcher {
959
1072
  } else {
960
1073
  targetNode = node;
961
1074
  }
962
- } else if (localName === 'textarea') {
1075
+ } else {
963
1076
  targetNode = node;
964
1077
  }
965
1078
  if (targetNode) {
@@ -996,7 +1109,7 @@ export class Matcher {
996
1109
  }
997
1110
  case 'checked': {
998
1111
  if ((localName === 'input' && node.hasAttribute('type') &&
999
- /^(?:checkbox|radio)$/.test(node.getAttribute('type')) &&
1112
+ INPUT_CHECK.test(node.getAttribute('type')) &&
1000
1113
  node.checked) ||
1001
1114
  (localName === 'option' && node.selected)) {
1002
1115
  matched.add(node);
@@ -1019,7 +1132,7 @@ export class Matcher {
1019
1132
  parent = parent.parentNode;
1020
1133
  }
1021
1134
  if (!parent) {
1022
- parent = root;
1135
+ parent = documentElement;
1023
1136
  }
1024
1137
  const nodes = [...parent.getElementsByTagName('input')];
1025
1138
  let checked;
@@ -1047,9 +1160,9 @@ export class Matcher {
1047
1160
  // button[type="submit"], input[type="submit"], input[type="image"]
1048
1161
  if ((localName === 'button' &&
1049
1162
  !(node.hasAttribute('type') &&
1050
- /^(?:button|reset)$/.test(node.getAttribute('type')))) ||
1163
+ INPUT_RESET.test(node.getAttribute('type')))) ||
1051
1164
  (localName === 'input' && node.hasAttribute('type') &&
1052
- /^(?:image|submit)$/.test(node.getAttribute('type')))) {
1165
+ INPUT_SUBMIT.test(node.getAttribute('type')))) {
1053
1166
  let form = node.parentNode;
1054
1167
  while (form) {
1055
1168
  if (form.localName === 'form') {
@@ -1065,10 +1178,10 @@ export class Matcher {
1065
1178
  let m;
1066
1179
  if (nodeName === 'button') {
1067
1180
  m = !(nextNode.hasAttribute('type') &&
1068
- /^(?:button|reset)$/.test(nextNode.getAttribute('type')));
1181
+ INPUT_RESET.test(nextNode.getAttribute('type')));
1069
1182
  } else if (nodeName === 'input') {
1070
1183
  m = nextNode.hasAttribute('type') &&
1071
- /^(?:image|submit)$/.test(nextNode.getAttribute('type'));
1184
+ INPUT_SUBMIT.test(nextNode.getAttribute('type'));
1072
1185
  }
1073
1186
  if (m) {
1074
1187
  if (nextNode === node) {
@@ -1081,7 +1194,7 @@ export class Matcher {
1081
1194
  }
1082
1195
  // input[type="checkbox"], input[type="radio"]
1083
1196
  } else if (localName === 'input' && node.hasAttribute('type') &&
1084
- /^(?:checkbox|radio)$/.test(node.getAttribute('type')) &&
1197
+ INPUT_CHECK.test(node.getAttribute('type')) &&
1085
1198
  node.hasAttribute('checked')) {
1086
1199
  matched.add(node);
1087
1200
  // option
@@ -1099,8 +1212,10 @@ export class Matcher {
1099
1212
  }
1100
1213
  // FIXME:
1101
1214
  if (isMultiple) {
1102
- throw new DOMException(`Unsupported pseudo-class :${astName}`,
1103
- NOT_SUPPORTED_ERR);
1215
+ if (this.#warn) {
1216
+ throw new DOMException(`Unsupported pseudo-class :${astName}`,
1217
+ NOT_SUPPORTED_ERR);
1218
+ }
1104
1219
  } else {
1105
1220
  const firstOpt = parentNode.firstElementChild;
1106
1221
  const defaultOpt = new Set();
@@ -1123,12 +1238,11 @@ export class Matcher {
1123
1238
  break;
1124
1239
  }
1125
1240
  case 'valid': {
1126
- if (HTML_FORM_VALIDITY.test(localName)) {
1241
+ if (FORM_VALIDITY.test(localName)) {
1127
1242
  if (node.checkValidity()) {
1128
1243
  matched.add(node);
1129
1244
  }
1130
1245
  } else if (/^fieldset$/.test(localName)) {
1131
- const { document } = this.#root;
1132
1246
  const iterator = document.createNodeIterator(node, SHOW_ELEMENT);
1133
1247
  let refNode = iterator.nextNode();
1134
1248
  if (refNode === node) {
@@ -1136,7 +1250,7 @@ export class Matcher {
1136
1250
  }
1137
1251
  let bool;
1138
1252
  while (refNode) {
1139
- if (HTML_FORM_VALIDITY.test(refNode.localName)) {
1253
+ if (FORM_VALIDITY.test(refNode.localName)) {
1140
1254
  bool = refNode.checkValidity();
1141
1255
  if (!bool) {
1142
1256
  break;
@@ -1151,12 +1265,11 @@ export class Matcher {
1151
1265
  break;
1152
1266
  }
1153
1267
  case 'invalid': {
1154
- if (HTML_FORM_VALIDITY.test(localName)) {
1268
+ if (FORM_VALIDITY.test(localName)) {
1155
1269
  if (!node.checkValidity()) {
1156
1270
  matched.add(node);
1157
1271
  }
1158
1272
  } else if (/^fieldset$/.test(localName)) {
1159
- const { document } = this.#root;
1160
1273
  const iterator = document.createNodeIterator(node, SHOW_ELEMENT);
1161
1274
  let refNode = iterator.nextNode();
1162
1275
  if (refNode === node) {
@@ -1164,7 +1277,7 @@ export class Matcher {
1164
1277
  }
1165
1278
  let bool;
1166
1279
  while (refNode) {
1167
- if (HTML_FORM_VALIDITY.test(refNode.localName)) {
1280
+ if (FORM_VALIDITY.test(refNode.localName)) {
1168
1281
  bool = refNode.checkValidity();
1169
1282
  if (!bool) {
1170
1283
  break;
@@ -1256,7 +1369,7 @@ export class Matcher {
1256
1369
  break;
1257
1370
  }
1258
1371
  case 'root': {
1259
- if (node === root) {
1372
+ if (node === documentElement) {
1260
1373
  matched.add(node);
1261
1374
  }
1262
1375
  break;
@@ -1281,20 +1394,24 @@ export class Matcher {
1281
1394
  break;
1282
1395
  }
1283
1396
  case 'first-child': {
1284
- if (parentNode && node === parentNode.firstElementChild) {
1397
+ if ((parentNode && node === parentNode.firstElementChild) ||
1398
+ (root.nodeType === ELEMENT_NODE && node === root)) {
1285
1399
  matched.add(node);
1286
1400
  }
1287
1401
  break;
1288
1402
  }
1289
1403
  case 'last-child': {
1290
- if (parentNode && node === parentNode.lastElementChild) {
1404
+ if ((parentNode && node === parentNode.lastElementChild) ||
1405
+ (root.nodeType === ELEMENT_NODE && node === root)) {
1291
1406
  matched.add(node);
1292
1407
  }
1293
1408
  break;
1294
1409
  }
1295
1410
  case 'only-child': {
1296
- if (parentNode && node === parentNode.firstElementChild &&
1297
- node === parentNode.lastElementChild) {
1411
+ if ((parentNode &&
1412
+ node === parentNode.firstElementChild &&
1413
+ node === parentNode.lastElementChild) ||
1414
+ (root.nodeType === ELEMENT_NODE && node === root)) {
1298
1415
  matched.add(node);
1299
1416
  }
1300
1417
  break;
@@ -1308,6 +1425,8 @@ export class Matcher {
1308
1425
  if (node1) {
1309
1426
  matched.add(node1);
1310
1427
  }
1428
+ } else if (root.nodeType === ELEMENT_NODE && node === root) {
1429
+ matched.add(node);
1311
1430
  }
1312
1431
  break;
1313
1432
  }
@@ -1321,6 +1440,8 @@ export class Matcher {
1321
1440
  if (node1) {
1322
1441
  matched.add(node1);
1323
1442
  }
1443
+ } else if (root.nodeType === ELEMENT_NODE && node === root) {
1444
+ matched.add(node);
1324
1445
  }
1325
1446
  break;
1326
1447
  }
@@ -1340,6 +1461,8 @@ export class Matcher {
1340
1461
  matched.add(node);
1341
1462
  }
1342
1463
  }
1464
+ } else if (root.nodeType === ELEMENT_NODE && node === root) {
1465
+ matched.add(node);
1343
1466
  }
1344
1467
  break;
1345
1468
  }
@@ -1348,8 +1471,11 @@ export class Matcher {
1348
1471
  case 'before':
1349
1472
  case 'first-letter':
1350
1473
  case 'first-line': {
1351
- throw new DOMException(`Unsupported pseudo-element ::${astName}`,
1352
- NOT_SUPPORTED_ERR);
1474
+ if (this.#warn) {
1475
+ throw new DOMException(`Unsupported pseudo-element ::${astName}`,
1476
+ NOT_SUPPORTED_ERR);
1477
+ }
1478
+ break;
1353
1479
  }
1354
1480
  case 'active':
1355
1481
  case 'autofill':
@@ -1372,12 +1498,22 @@ export class Matcher {
1372
1498
  case 'user-valid':
1373
1499
  case 'volume-locked':
1374
1500
  case '-webkit-autofill': {
1375
- throw new DOMException(`Unsupported pseudo-class :${astName}`,
1376
- NOT_SUPPORTED_ERR);
1501
+ if (this.#warn) {
1502
+ throw new DOMException(`Unsupported pseudo-class :${astName}`,
1503
+ NOT_SUPPORTED_ERR);
1504
+ }
1505
+ break;
1377
1506
  }
1378
1507
  default: {
1379
- throw new DOMException(`Unknown pseudo-class :${astName}`,
1380
- SYNTAX_ERR);
1508
+ if (astName.startsWith('-webkit-')) {
1509
+ if (this.#warn) {
1510
+ throw new DOMException(`Unsupported pseudo-class :${astName}`,
1511
+ NOT_SUPPORTED_ERR);
1512
+ }
1513
+ } else if (!forgive) {
1514
+ throw new DOMException(`Unknown pseudo-class :${astName}`,
1515
+ SYNTAX_ERR);
1516
+ }
1381
1517
  }
1382
1518
  }
1383
1519
  }
@@ -1395,7 +1531,7 @@ export class Matcher {
1395
1531
  flags: astFlags, matcher: astMatcher, name: astName, value: astValue
1396
1532
  } = ast;
1397
1533
  if (typeof astFlags === 'string' && !/^[is]$/i.test(astFlags)) {
1398
- throw new DOMException('invalid attribute selector', SYNTAX_ERR);
1534
+ throw new DOMException('Invalid attribute selector', SYNTAX_ERR);
1399
1535
  }
1400
1536
  const { attributes } = node;
1401
1537
  let res;
@@ -1450,7 +1586,8 @@ export class Matcher {
1450
1586
  if (/:/.test(itemName)) {
1451
1587
  const [itemNamePrefix, itemNameLocalName] = itemName.split(':');
1452
1588
  if (astAttrPrefix === itemNamePrefix &&
1453
- astAttrLocalName === itemNameLocalName) {
1589
+ astAttrLocalName === itemNameLocalName &&
1590
+ isNamespaceDeclared(astAttrPrefix, node)) {
1454
1591
  attrValues.add(itemValue);
1455
1592
  }
1456
1593
  }
@@ -1649,7 +1786,8 @@ export class Matcher {
1649
1786
  if (astNodeName === '*' || astNodeName === nodeName) {
1650
1787
  res = node;
1651
1788
  }
1652
- } else if (astPrefix === nodePrefix) {
1789
+ } else if (astPrefix === nodePrefix &&
1790
+ isNamespaceDeclared(astPrefix, node)) {
1653
1791
  if (astNodeName === '*' || astNodeName === nodeName) {
1654
1792
  res = node;
1655
1793
  }
@@ -1661,9 +1799,10 @@ export class Matcher {
1661
1799
  * match selector
1662
1800
  * @param {object} ast - AST
1663
1801
  * @param {object} node - Document, DocumentFragment, Element node
1802
+ * @param {object} opt - options
1664
1803
  * @returns {object} - collection of matched nodes
1665
1804
  */
1666
- _matchSelector(ast, node) {
1805
+ _matchSelector(ast, node, opt) {
1667
1806
  const { type } = ast;
1668
1807
  let matched = new Set();
1669
1808
  if (node.nodeType === ELEMENT_NODE) {
@@ -1690,7 +1829,7 @@ export class Matcher {
1690
1829
  break;
1691
1830
  }
1692
1831
  case PSEUDO_CLASS_SELECTOR: {
1693
- const nodes = this._matchPseudoClassSelector(ast, node);
1832
+ const nodes = this._matchPseudoClassSelector(ast, node, opt);
1694
1833
  if (nodes.size) {
1695
1834
  matched = nodes;
1696
1835
  }
@@ -1698,7 +1837,7 @@ export class Matcher {
1698
1837
  }
1699
1838
  case PSEUDO_ELEMENT_SELECTOR: {
1700
1839
  const astName = unescapeSelector(ast.name);
1701
- this._throwOnPseudoElementSelector(astName);
1840
+ this._matchPseudoElementSelector(astName, opt);
1702
1841
  break;
1703
1842
  }
1704
1843
  case TYPE_SELECTOR:
@@ -1717,12 +1856,13 @@ export class Matcher {
1717
1856
  * match leaves
1718
1857
  * @param {Array.<object>} leaves - AST leaves
1719
1858
  * @param {object} node - node
1859
+ * @param {object} opt - options
1720
1860
  * @returns {boolean} - result
1721
1861
  */
1722
- _matchLeaves(leaves, node) {
1862
+ _matchLeaves(leaves, node, opt) {
1723
1863
  let bool;
1724
1864
  for (const leaf of leaves) {
1725
- bool = this._matchSelector(leaf, node).has(node);
1865
+ bool = this._matchSelector(leaf, node, opt).has(node);
1726
1866
  if (!bool) {
1727
1867
  break;
1728
1868
  }
@@ -1807,7 +1947,7 @@ export class Matcher {
1807
1947
  break;
1808
1948
  }
1809
1949
  case PSEUDO_ELEMENT_SELECTOR: {
1810
- this._throwOnPseudoElementSelector(leafName);
1950
+ this._matchPseudoElementSelector(leafName);
1811
1951
  break;
1812
1952
  }
1813
1953
  default: {
@@ -1831,7 +1971,7 @@ export class Matcher {
1831
1971
  _matchCombinator(twig, node, opt = {}) {
1832
1972
  const { combo, leaves } = twig;
1833
1973
  const { name: comboName } = combo;
1834
- const { find } = opt;
1974
+ const { find, forgive } = opt;
1835
1975
  let matched = new Set();
1836
1976
  if (find === 'next') {
1837
1977
  switch (comboName) {
@@ -1893,7 +2033,9 @@ export class Matcher {
1893
2033
  case '+': {
1894
2034
  const refNode = node.previousElementSibling;
1895
2035
  if (refNode) {
1896
- const bool = this._matchLeaves(leaves, refNode);
2036
+ const bool = this._matchLeaves(leaves, refNode, {
2037
+ forgive
2038
+ });
1897
2039
  if (bool) {
1898
2040
  matched.add(refNode);
1899
2041
  }
@@ -1904,7 +2046,9 @@ export class Matcher {
1904
2046
  const arr = [];
1905
2047
  let refNode = node.previousElementSibling;
1906
2048
  while (refNode) {
1907
- const bool = this._matchLeaves(leaves, refNode);
2049
+ const bool = this._matchLeaves(leaves, refNode, {
2050
+ forgive
2051
+ });
1908
2052
  if (bool) {
1909
2053
  arr.push(refNode);
1910
2054
  }
@@ -1918,7 +2062,9 @@ export class Matcher {
1918
2062
  case '>': {
1919
2063
  const refNode = node.parentNode;
1920
2064
  if (refNode) {
1921
- const bool = this._matchLeaves(leaves, refNode);
2065
+ const bool = this._matchLeaves(leaves, refNode, {
2066
+ forgive
2067
+ });
1922
2068
  if (bool) {
1923
2069
  matched.add(refNode);
1924
2070
  }
@@ -1930,7 +2076,9 @@ export class Matcher {
1930
2076
  const arr = [];
1931
2077
  let refNode = node.parentNode;
1932
2078
  while (refNode) {
1933
- const bool = this._matchLeaves(leaves, refNode);
2079
+ const bool = this._matchLeaves(leaves, refNode, {
2080
+ forgive
2081
+ });
1934
2082
  if (bool) {
1935
2083
  arr.push(refNode);
1936
2084
  }
@@ -2105,7 +2253,7 @@ export class Matcher {
2105
2253
  break;
2106
2254
  }
2107
2255
  case PSEUDO_ELEMENT_SELECTOR: {
2108
- this._throwOnPseudoElementSelector(leafName);
2256
+ this._matchPseudoElementSelector(leafName);
2109
2257
  break;
2110
2258
  }
2111
2259
  default: {
@@ -2372,7 +2520,7 @@ export class Matcher {
2372
2520
  */
2373
2521
  matches() {
2374
2522
  if (this.#node.nodeType !== ELEMENT_NODE) {
2375
- throw new TypeError(`Unexpected node type: ${this.#node.nodeName}`);
2523
+ throw new TypeError(`Unexpected node ${this.#node.nodeName}`);
2376
2524
  }
2377
2525
  let res;
2378
2526
  try {
@@ -2390,7 +2538,7 @@ export class Matcher {
2390
2538
  */
2391
2539
  closest() {
2392
2540
  if (this.#node.nodeType !== ELEMENT_NODE) {
2393
- throw new TypeError(`Unexpected node type: ${this.#node.nodeName}`);
2541
+ throw new TypeError(`Unexpected node ${this.#node.nodeName}`);
2394
2542
  }
2395
2543
  let res;
2396
2544
  try {
package/src/js/parser.js CHANGED
@@ -102,7 +102,7 @@ export const preprocess = (...args) => {
102
102
  selector = Object.prototype.toString.call(selector)
103
103
  .slice(TYPE_FROM, TYPE_TO).toLowerCase();
104
104
  } else {
105
- throw new DOMException(`invalid selector ${selector}`, SYNTAX_ERR);
105
+ throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);
106
106
  }
107
107
  return selector;
108
108
  };
@@ -116,7 +116,7 @@ export const parseSelector = selector => {
116
116
  selector = preprocess(selector);
117
117
  // invalid selectors
118
118
  if (/^$|^\s*>|,\s*$/.test(selector)) {
119
- throw new DOMException(`invalid selector ${selector}`, SYNTAX_ERR);
119
+ throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);
120
120
  }
121
121
  let res;
122
122
  try {
package/types/index.d.ts CHANGED
@@ -4,10 +4,10 @@ export function matches(selector: string, node: object, opt?: {
4
4
  export function closest(selector: string, node: object, opt?: {
5
5
  warn?: boolean;
6
6
  }): object | null;
7
- export function querySelector(selector: string, refPoint: object, opt?: {
7
+ export function querySelector(selector: string, node: object, opt?: {
8
8
  warn?: boolean;
9
9
  }): object | null;
10
- export function querySelectorAll(selector: string, refPoint: object, opt?: {
10
+ export function querySelectorAll(selector: string, node: object, opt?: {
11
11
  sort?: boolean;
12
12
  warn?: boolean;
13
13
  }): Array<object | undefined>;
@@ -7,7 +7,6 @@ export class Matcher {
7
7
  _getRoot(node?: object): object;
8
8
  _sortLeaves(leaves: Array<object>): Array<object>;
9
9
  _prepare(selector?: string): Array<Array<object | undefined>>;
10
- _throwOnPseudoElementSelector(astName: object): void;
11
10
  _collectNthChild(anb: {
12
11
  a: number;
13
12
  b: number;
@@ -20,17 +19,18 @@ export class Matcher {
20
19
  reverse?: boolean;
21
20
  }, node: object): object;
22
21
  _matchAnPlusB(ast: object, node: object, nthName: string): object;
22
+ _matchPseudoElementSelector(astName: string, opt?: object): void;
23
23
  _matchDirectionPseudoClass(ast: object, node: object): object | null;
24
24
  _matchLanguagePseudoClass(ast: object, node: object): object | null;
25
25
  _matchHasPseudoFunc(leaves: Array<object>, node: object): boolean;
26
- _matchLogicalPseudoFunc(astOpt: object, node: object): object | null;
27
- _matchPseudoClassSelector(ast: object, node: object): object;
26
+ _matchLogicalPseudoFunc(astData: object, node: object): object | null;
27
+ _matchPseudoClassSelector(ast: object, node: object, opt?: object): object;
28
28
  _matchAttributeSelector(ast: object, node: object): object | null;
29
29
  _matchClassSelector(ast: object, node: object): object | null;
30
30
  _matchIDSelector(ast: object, node: object): object | null;
31
31
  _matchTypeSelector(ast: object, node: object): object | null;
32
- _matchSelector(ast: object, node: object): object;
33
- _matchLeaves(leaves: Array<object>, node: object): boolean;
32
+ _matchSelector(ast: object, node: object, opt: object): object;
33
+ _matchLeaves(leaves: Array<object>, node: object, opt: object): boolean;
34
34
  _findDescendantNodes(leaves: Array<object>, baseNode: object): object;
35
35
  _matchCombinator(twig: object, node: object, opt?: {
36
36
  find?: string;