@remote-dom/polyfill 1.4.6 → 1.5.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/cjs/ClipboardEvent.cjs +15 -0
  3. package/build/cjs/FocusEvent.cjs +15 -0
  4. package/build/cjs/ToggleEvent.cjs +16 -0
  5. package/build/cjs/Window.cjs +6 -0
  6. package/build/cjs/selectors.cjs +48 -13
  7. package/build/esm/ClipboardEvent.mjs +11 -0
  8. package/build/esm/FocusEvent.mjs +11 -0
  9. package/build/esm/ToggleEvent.mjs +12 -0
  10. package/build/esm/Window.mjs +6 -0
  11. package/build/esm/selectors.mjs +48 -13
  12. package/build/esnext/ClipboardEvent.esnext +11 -0
  13. package/build/esnext/FocusEvent.esnext +11 -0
  14. package/build/esnext/ToggleEvent.esnext +13 -0
  15. package/build/esnext/Window.esnext +6 -0
  16. package/build/esnext/selectors.esnext +43 -13
  17. package/build/tsconfig.tsbuildinfo +1 -1
  18. package/build/typescript/ClipboardEvent.d.ts +6 -0
  19. package/build/typescript/ClipboardEvent.d.ts.map +1 -0
  20. package/build/typescript/FocusEvent.d.ts +6 -0
  21. package/build/typescript/FocusEvent.d.ts.map +1 -0
  22. package/build/typescript/ToggleEvent.d.ts +7 -0
  23. package/build/typescript/ToggleEvent.d.ts.map +1 -0
  24. package/build/typescript/Window.d.ts +6 -0
  25. package/build/typescript/Window.d.ts.map +1 -1
  26. package/build/typescript/selectors.d.ts.map +1 -1
  27. package/build/typescript/tests/selectors.test.d.ts +2 -0
  28. package/build/typescript/tests/selectors.test.d.ts.map +1 -0
  29. package/package.json +1 -1
  30. package/source/ClipboardEvent.ts +12 -0
  31. package/source/FocusEvent.ts +12 -0
  32. package/source/ToggleEvent.ts +14 -0
  33. package/source/Window.ts +6 -0
  34. package/source/selectors.ts +52 -13
  35. package/source/tests/selectors.test.ts +280 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @remote-dom/polyfill
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#593](https://github.com/Shopify/remote-dom/pull/593) [`61f5cba`](https://github.com/Shopify/remote-dom/commit/61f5cbaa9965f7befbea3d3dfc2d2b2a0798c958) Thanks [@developit](https://github.com/developit)! - Add support for `not` in query-selectors
8
+
9
+ ## 1.4.7
10
+
11
+ ### Patch Changes
12
+
13
+ - [#594](https://github.com/Shopify/remote-dom/pull/594) [`789a7c7`](https://github.com/Shopify/remote-dom/commit/789a7c7480a445d1e5973bd6e2aa4e8889ec6f85) Thanks [@robin-drexler](https://github.com/robin-drexler)! - add `FocusEvent`, `ClipboardEvent` and `ToggleEvent` to polyfill
14
+
3
15
  ## 1.4.6
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const Event = require('./Event.cjs');
6
+
7
+ // https://w3c.github.io/clipboard-apis/#clipboardevent-interface
8
+ class ClipboardEvent extends Event.Event {
9
+ constructor(type, eventInitDict = {}) {
10
+ super(type, eventInitDict);
11
+ this.clipboardData = eventInitDict.clipboardData ?? null;
12
+ }
13
+ }
14
+
15
+ exports.ClipboardEvent = ClipboardEvent;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const Event = require('./Event.cjs');
6
+
7
+ // https://w3c.github.io/uievents/#interface-focusevent
8
+ class FocusEvent extends Event.Event {
9
+ constructor(type, eventInitDict = {}) {
10
+ super(type, eventInitDict);
11
+ this.relatedTarget = eventInitDict.relatedTarget ?? null;
12
+ }
13
+ }
14
+
15
+ exports.FocusEvent = FocusEvent;
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const Event = require('./Event.cjs');
6
+
7
+ // https://html.spec.whatwg.org/multipage/popover.html#toggleevent
8
+ class ToggleEvent extends Event.Event {
9
+ constructor(type, eventInitDict) {
10
+ super(type, eventInitDict);
11
+ this.oldState = eventInitDict.oldState;
12
+ this.newState = eventInitDict.newState;
13
+ }
14
+ }
15
+
16
+ exports.ToggleEvent = ToggleEvent;
@@ -8,6 +8,9 @@ const EventTarget = require('./EventTarget.cjs');
8
8
  const CustomEvent = require('./CustomEvent.cjs');
9
9
  const ErrorEvent = require('./ErrorEvent.cjs');
10
10
  const PromiseRejectionEvent = require('./PromiseRejectionEvent.cjs');
11
+ const ToggleEvent = require('./ToggleEvent.cjs');
12
+ const FocusEvent = require('./FocusEvent.cjs');
13
+ const ClipboardEvent = require('./ClipboardEvent.cjs');
11
14
  const Node = require('./Node.cjs');
12
15
  const ParentNode = require('./ParentNode.cjs');
13
16
  const ChildNode = require('./ChildNode.cjs');
@@ -37,6 +40,9 @@ class Window extends EventTarget.EventTarget {
37
40
  Event = (() => Event.Event)();
38
41
  ErrorEvent = (() => ErrorEvent.ErrorEvent)();
39
42
  PromiseRejectionEvent = (() => PromiseRejectionEvent.PromiseRejectionEvent)();
43
+ ToggleEvent = (() => ToggleEvent.ToggleEvent)();
44
+ FocusEvent = (() => FocusEvent.FocusEvent)();
45
+ ClipboardEvent = (() => ClipboardEvent.ClipboardEvent)();
40
46
  EventTarget = (() => EventTarget.EventTarget)();
41
47
  CustomEvent = (() => CustomEvent.CustomEvent)();
42
48
  Node = (() => Node.Node)();
@@ -53,7 +53,7 @@ function parseSelector(selector) {
53
53
  matchers: []
54
54
  };
55
55
  const parts = [part];
56
- const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:]+)|:(\w+)(?:\((.*?)\))?)/gi;
56
+ const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:+~]+)|:(\w+)(?:\((.*?)\))?)/gi;
57
57
  let token;
58
58
  while (token = tokenizer.exec(selector)) {
59
59
  // [1]: ancestor/parent/sibling/adjacent
@@ -80,8 +80,12 @@ function parseSelector(selector) {
80
80
  type = token[5] === '#' ? MatcherType.Id : MatcherType.Class;
81
81
  } else if (token[7]) {
82
82
  type = token[8] == null ? MatcherType.Pseudo : MatcherType.Function;
83
- } else if (token[6] && ELEMENT_SELECTOR_TEST.test(token[6])) {
84
- type = MatcherType.Element;
83
+ } else if (token[6]) {
84
+ if (token[6] === '*') {
85
+ type = MatcherType.Unknown; // Universal selector matches all
86
+ } else if (ELEMENT_SELECTOR_TEST.test(token[6])) {
87
+ type = MatcherType.Element;
88
+ }
85
89
  }
86
90
  part.matchers.push({
87
91
  type,
@@ -127,19 +131,34 @@ function matchesSelectorRecursive(element, parts) {
127
131
  }
128
132
  const link = combinator === Combinator.Child || combinator === Combinator.Descendant ? constants.PARENT : constants.PREV;
129
133
  let ref = element[link];
130
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
131
- return false;
132
- }
134
+ if (!ref) return false;
133
135
  if (combinator === Combinator.Descendant || combinator === Combinator.Sibling) {
134
- while (ref = ref[link]) {
135
- if (matchesSelectorMatcher(ref, matchers)) {
136
+ // For descendant/sibling combinators, search through all ancestors/siblings
137
+ while (ref) {
138
+ if (shared.isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) {
136
139
  const pp = parts.slice(0, -1);
137
140
  if (pp.length === 0) return true;
138
141
  if (matchesSelectorRecursive(element, pp)) return true;
139
142
  }
143
+ ref = ref[link];
144
+ }
145
+ return false;
146
+ } else {
147
+ // For child/adjacent combinators, check only the immediate parent/sibling
148
+ // For sibling combinators, skip non-element siblings
149
+ if (combinator === Combinator.Adjacent && !shared.isElementNode(ref)) {
150
+ // Skip to next element sibling
151
+ while (ref && !shared.isElementNode(ref)) {
152
+ ref = ref[link];
153
+ }
154
+ if (!ref) return false;
155
+ }
156
+ if (!shared.isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
157
+ return false;
140
158
  }
159
+ const pp = parts.slice(0, -1);
160
+ return pp.length === 0 || matchesSelectorRecursive(element, pp);
141
161
  }
142
- return false;
143
162
  }
144
163
  function matchesSelectorPart(element, {
145
164
  combinator,
@@ -150,15 +169,24 @@ function matchesSelectorPart(element, {
150
169
  }
151
170
  const link = combinator === Combinator.Child || combinator === Combinator.Descendant ? constants.PARENT : constants.PREV;
152
171
  let ref = element[link];
153
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
172
+ if (!ref) return false;
173
+
174
+ // For sibling combinators, skip non-element siblings
175
+ if (combinator === Combinator.Adjacent && !shared.isElementNode(ref)) {
176
+ while (ref && !shared.isElementNode(ref)) {
177
+ ref = ref[link];
178
+ }
179
+ if (!ref) return false;
180
+ }
181
+ if (!shared.isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
154
182
  return false;
155
183
  }
156
184
  if (combinator === Combinator.Descendant || combinator === Combinator.Sibling) {
157
185
  while (ref = ref[link]) {
158
- if (matchesSelectorMatcher(ref, matchers)) return true;
186
+ if (shared.isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) return true;
159
187
  }
160
188
  }
161
- return false;
189
+ return true;
162
190
  }
163
191
  function matchesSelectorMatcher(element, matcher) {
164
192
  if (!element) return false;
@@ -174,12 +202,17 @@ function matchesSelectorMatcher(element, matcher) {
174
202
  value
175
203
  } = matcher;
176
204
  switch (type) {
205
+ case MatcherType.Unknown:
206
+ return name === '*';
207
+ // Universal selector
177
208
  case MatcherType.Element:
178
209
  return element.localName === name;
179
210
  case MatcherType.Id:
180
211
  return element.getAttribute('id') === name;
181
212
  case MatcherType.Class:
182
- return element.getAttribute('class') === name;
213
+ const classAttr = element.getAttribute('class');
214
+ if (!classAttr) return false;
215
+ return classAttr.split(/\s+/).includes(name);
183
216
  case MatcherType.Attribute:
184
217
  return value == null ? element.hasAttribute(name) : element.getAttribute(name) === value;
185
218
  case MatcherType.Pseudo:
@@ -191,6 +224,8 @@ function matchesSelectorMatcher(element, matcher) {
191
224
  switch (name) {
192
225
  case 'has':
193
226
  return matchesSelector(element, value || '');
227
+ case 'not':
228
+ return !matchesSelector(element, value || '');
194
229
  default:
195
230
  throw Error(`Function :${name}(${value}) not implemented`);
196
231
  }
@@ -0,0 +1,11 @@
1
+ import { Event } from './Event.mjs';
2
+
3
+ // https://w3c.github.io/clipboard-apis/#clipboardevent-interface
4
+ class ClipboardEvent extends Event {
5
+ constructor(type, eventInitDict = {}) {
6
+ super(type, eventInitDict);
7
+ this.clipboardData = eventInitDict.clipboardData ?? null;
8
+ }
9
+ }
10
+
11
+ export { ClipboardEvent };
@@ -0,0 +1,11 @@
1
+ import { Event } from './Event.mjs';
2
+
3
+ // https://w3c.github.io/uievents/#interface-focusevent
4
+ class FocusEvent extends Event {
5
+ constructor(type, eventInitDict = {}) {
6
+ super(type, eventInitDict);
7
+ this.relatedTarget = eventInitDict.relatedTarget ?? null;
8
+ }
9
+ }
10
+
11
+ export { FocusEvent };
@@ -0,0 +1,12 @@
1
+ import { Event } from './Event.mjs';
2
+
3
+ // https://html.spec.whatwg.org/multipage/popover.html#toggleevent
4
+ class ToggleEvent extends Event {
5
+ constructor(type, eventInitDict) {
6
+ super(type, eventInitDict);
7
+ this.oldState = eventInitDict.oldState;
8
+ this.newState = eventInitDict.newState;
9
+ }
10
+ }
11
+
12
+ export { ToggleEvent };
@@ -4,6 +4,9 @@ import { EventTarget } from './EventTarget.mjs';
4
4
  import { CustomEvent } from './CustomEvent.mjs';
5
5
  import { ErrorEvent } from './ErrorEvent.mjs';
6
6
  import { PromiseRejectionEvent } from './PromiseRejectionEvent.mjs';
7
+ import { ToggleEvent } from './ToggleEvent.mjs';
8
+ import { FocusEvent } from './FocusEvent.mjs';
9
+ import { ClipboardEvent } from './ClipboardEvent.mjs';
7
10
  import { Node } from './Node.mjs';
8
11
  import { ParentNode } from './ParentNode.mjs';
9
12
  import { ChildNode } from './ChildNode.mjs';
@@ -33,6 +36,9 @@ class Window extends EventTarget {
33
36
  Event = (() => Event)();
34
37
  ErrorEvent = (() => ErrorEvent)();
35
38
  PromiseRejectionEvent = (() => PromiseRejectionEvent)();
39
+ ToggleEvent = (() => ToggleEvent)();
40
+ FocusEvent = (() => FocusEvent)();
41
+ ClipboardEvent = (() => ClipboardEvent)();
36
42
  EventTarget = (() => EventTarget)();
37
43
  CustomEvent = (() => CustomEvent)();
38
44
  Node = (() => Node)();
@@ -49,7 +49,7 @@ function parseSelector(selector) {
49
49
  matchers: []
50
50
  };
51
51
  const parts = [part];
52
- const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:]+)|:(\w+)(?:\((.*?)\))?)/gi;
52
+ const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:+~]+)|:(\w+)(?:\((.*?)\))?)/gi;
53
53
  let token;
54
54
  while (token = tokenizer.exec(selector)) {
55
55
  // [1]: ancestor/parent/sibling/adjacent
@@ -76,8 +76,12 @@ function parseSelector(selector) {
76
76
  type = token[5] === '#' ? MatcherType.Id : MatcherType.Class;
77
77
  } else if (token[7]) {
78
78
  type = token[8] == null ? MatcherType.Pseudo : MatcherType.Function;
79
- } else if (token[6] && ELEMENT_SELECTOR_TEST.test(token[6])) {
80
- type = MatcherType.Element;
79
+ } else if (token[6]) {
80
+ if (token[6] === '*') {
81
+ type = MatcherType.Unknown; // Universal selector matches all
82
+ } else if (ELEMENT_SELECTOR_TEST.test(token[6])) {
83
+ type = MatcherType.Element;
84
+ }
81
85
  }
82
86
  part.matchers.push({
83
87
  type,
@@ -123,19 +127,34 @@ function matchesSelectorRecursive(element, parts) {
123
127
  }
124
128
  const link = combinator === Combinator.Child || combinator === Combinator.Descendant ? PARENT : PREV;
125
129
  let ref = element[link];
126
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
127
- return false;
128
- }
130
+ if (!ref) return false;
129
131
  if (combinator === Combinator.Descendant || combinator === Combinator.Sibling) {
130
- while (ref = ref[link]) {
131
- if (matchesSelectorMatcher(ref, matchers)) {
132
+ // For descendant/sibling combinators, search through all ancestors/siblings
133
+ while (ref) {
134
+ if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) {
132
135
  const pp = parts.slice(0, -1);
133
136
  if (pp.length === 0) return true;
134
137
  if (matchesSelectorRecursive(element, pp)) return true;
135
138
  }
139
+ ref = ref[link];
140
+ }
141
+ return false;
142
+ } else {
143
+ // For child/adjacent combinators, check only the immediate parent/sibling
144
+ // For sibling combinators, skip non-element siblings
145
+ if (combinator === Combinator.Adjacent && !isElementNode(ref)) {
146
+ // Skip to next element sibling
147
+ while (ref && !isElementNode(ref)) {
148
+ ref = ref[link];
149
+ }
150
+ if (!ref) return false;
151
+ }
152
+ if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
153
+ return false;
136
154
  }
155
+ const pp = parts.slice(0, -1);
156
+ return pp.length === 0 || matchesSelectorRecursive(element, pp);
137
157
  }
138
- return false;
139
158
  }
140
159
  function matchesSelectorPart(element, {
141
160
  combinator,
@@ -146,15 +165,24 @@ function matchesSelectorPart(element, {
146
165
  }
147
166
  const link = combinator === Combinator.Child || combinator === Combinator.Descendant ? PARENT : PREV;
148
167
  let ref = element[link];
149
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
168
+ if (!ref) return false;
169
+
170
+ // For sibling combinators, skip non-element siblings
171
+ if (combinator === Combinator.Adjacent && !isElementNode(ref)) {
172
+ while (ref && !isElementNode(ref)) {
173
+ ref = ref[link];
174
+ }
175
+ if (!ref) return false;
176
+ }
177
+ if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
150
178
  return false;
151
179
  }
152
180
  if (combinator === Combinator.Descendant || combinator === Combinator.Sibling) {
153
181
  while (ref = ref[link]) {
154
- if (matchesSelectorMatcher(ref, matchers)) return true;
182
+ if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) return true;
155
183
  }
156
184
  }
157
- return false;
185
+ return true;
158
186
  }
159
187
  function matchesSelectorMatcher(element, matcher) {
160
188
  if (!element) return false;
@@ -170,12 +198,17 @@ function matchesSelectorMatcher(element, matcher) {
170
198
  value
171
199
  } = matcher;
172
200
  switch (type) {
201
+ case MatcherType.Unknown:
202
+ return name === '*';
203
+ // Universal selector
173
204
  case MatcherType.Element:
174
205
  return element.localName === name;
175
206
  case MatcherType.Id:
176
207
  return element.getAttribute('id') === name;
177
208
  case MatcherType.Class:
178
- return element.getAttribute('class') === name;
209
+ const classAttr = element.getAttribute('class');
210
+ if (!classAttr) return false;
211
+ return classAttr.split(/\s+/).includes(name);
179
212
  case MatcherType.Attribute:
180
213
  return value == null ? element.hasAttribute(name) : element.getAttribute(name) === value;
181
214
  case MatcherType.Pseudo:
@@ -187,6 +220,8 @@ function matchesSelectorMatcher(element, matcher) {
187
220
  switch (name) {
188
221
  case 'has':
189
222
  return matchesSelector(element, value || '');
223
+ case 'not':
224
+ return !matchesSelector(element, value || '');
190
225
  default:
191
226
  throw Error(`Function :${name}(${value}) not implemented`);
192
227
  }
@@ -0,0 +1,11 @@
1
+ import { Event } from './Event.esnext';
2
+
3
+ class ClipboardEvent extends Event {
4
+ clipboardData;
5
+ constructor(type, eventInitDict = {}) {
6
+ super(type, eventInitDict);
7
+ this.clipboardData = eventInitDict.clipboardData ?? null;
8
+ }
9
+ }
10
+
11
+ export { ClipboardEvent };
@@ -0,0 +1,11 @@
1
+ import { Event } from './Event.esnext';
2
+
3
+ class FocusEvent extends Event {
4
+ relatedTarget;
5
+ constructor(type, eventInitDict = {}) {
6
+ super(type, eventInitDict);
7
+ this.relatedTarget = eventInitDict.relatedTarget ?? null;
8
+ }
9
+ }
10
+
11
+ export { FocusEvent };
@@ -0,0 +1,13 @@
1
+ import { Event } from './Event.esnext';
2
+
3
+ class ToggleEvent extends Event {
4
+ oldState;
5
+ newState;
6
+ constructor(type, eventInitDict) {
7
+ super(type, eventInitDict);
8
+ this.oldState = eventInitDict.oldState;
9
+ this.newState = eventInitDict.newState;
10
+ }
11
+ }
12
+
13
+ export { ToggleEvent };
@@ -4,6 +4,9 @@ import { EventTarget } from './EventTarget.esnext';
4
4
  import { CustomEvent } from './CustomEvent.esnext';
5
5
  import { ErrorEvent } from './ErrorEvent.esnext';
6
6
  import { PromiseRejectionEvent } from './PromiseRejectionEvent.esnext';
7
+ import { ToggleEvent } from './ToggleEvent.esnext';
8
+ import { FocusEvent } from './FocusEvent.esnext';
9
+ import { ClipboardEvent } from './ClipboardEvent.esnext';
7
10
  import { Node } from './Node.esnext';
8
11
  import { ParentNode } from './ParentNode.esnext';
9
12
  import { ChildNode } from './ChildNode.esnext';
@@ -33,6 +36,9 @@ class Window extends EventTarget {
33
36
  Event = Event;
34
37
  ErrorEvent = ErrorEvent;
35
38
  PromiseRejectionEvent = PromiseRejectionEvent;
39
+ ToggleEvent = ToggleEvent;
40
+ FocusEvent = FocusEvent;
41
+ ClipboardEvent = ClipboardEvent;
36
42
  EventTarget = EventTarget;
37
43
  CustomEvent = CustomEvent;
38
44
  Node = Node;
@@ -28,7 +28,7 @@ function querySelectorAll(within, selector) {
28
28
  function parseSelector(selector) {
29
29
  let part = { combinator: 4 /* Inner */, matchers: [] };
30
30
  const parts = [part];
31
- const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:]+)|:(\w+)(?:\((.*?)\))?)/gi;
31
+ const tokenizer = /\s*?([>\s+~]?)\s*?(?:(?:\[\s*([^\]=]+)(?:=(['"])(.*?)\3)?\s*\])|([#.]?)([^\s#.[>:+~]+)|:(\w+)(?:\((.*?)\))?)/gi;
32
32
  let token;
33
33
  while (token = tokenizer.exec(selector)) {
34
34
  if (token[1]) {
@@ -46,8 +46,12 @@ function parseSelector(selector) {
46
46
  type = token[5] === "#" ? 2 /* Id */ : 3 /* Class */;
47
47
  } else if (token[7]) {
48
48
  type = token[8] == null ? 5 /* Pseudo */ : 6 /* Function */;
49
- } else if (token[6] && ELEMENT_SELECTOR_TEST.test(token[6])) {
50
- type = 1 /* Element */;
49
+ } else if (token[6]) {
50
+ if (token[6] === "*") {
51
+ type = 0 /* Unknown */;
52
+ } else if (ELEMENT_SELECTOR_TEST.test(token[6])) {
53
+ type = 1 /* Element */;
54
+ }
51
55
  }
52
56
  part.matchers.push({
53
57
  type,
@@ -90,19 +94,30 @@ function matchesSelectorRecursive(element, parts) {
90
94
  }
91
95
  const link = combinator === 1 /* Child */ || combinator === 0 /* Descendant */ ? PARENT : PREV;
92
96
  let ref = element[link];
93
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
94
- return false;
95
- }
97
+ if (!ref) return false;
96
98
  if (combinator === 0 /* Descendant */ || combinator === 2 /* Sibling */) {
97
- while (ref = ref[link]) {
98
- if (matchesSelectorMatcher(ref, matchers)) {
99
+ while (ref) {
100
+ if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) {
99
101
  const pp = parts.slice(0, -1);
100
102
  if (pp.length === 0) return true;
101
103
  if (matchesSelectorRecursive(element, pp)) return true;
102
104
  }
105
+ ref = ref[link];
106
+ }
107
+ return false;
108
+ } else {
109
+ if (combinator === 3 /* Adjacent */ && !isElementNode(ref)) {
110
+ while (ref && !isElementNode(ref)) {
111
+ ref = ref[link];
112
+ }
113
+ if (!ref) return false;
114
+ }
115
+ if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
116
+ return false;
103
117
  }
118
+ const pp = parts.slice(0, -1);
119
+ return pp.length === 0 || matchesSelectorRecursive(element, pp);
104
120
  }
105
- return false;
106
121
  }
107
122
  function matchesSelectorPart(element, { combinator, matchers }) {
108
123
  if (combinator === 4 /* Inner */) {
@@ -110,15 +125,23 @@ function matchesSelectorPart(element, { combinator, matchers }) {
110
125
  }
111
126
  const link = combinator === 1 /* Child */ || combinator === 0 /* Descendant */ ? PARENT : PREV;
112
127
  let ref = element[link];
113
- if (!ref || !matchesSelectorMatcher(ref, matchers)) {
128
+ if (!ref) return false;
129
+ if (combinator === 3 /* Adjacent */ && !isElementNode(ref)) {
130
+ while (ref && !isElementNode(ref)) {
131
+ ref = ref[link];
132
+ }
133
+ if (!ref) return false;
134
+ }
135
+ if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
114
136
  return false;
115
137
  }
116
138
  if (combinator === 0 /* Descendant */ || combinator === 2 /* Sibling */) {
117
139
  while (ref = ref[link]) {
118
- if (matchesSelectorMatcher(ref, matchers)) return true;
140
+ if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers))
141
+ return true;
119
142
  }
120
143
  }
121
- return false;
144
+ return true;
122
145
  }
123
146
  function matchesSelectorMatcher(element, matcher) {
124
147
  if (!element) return false;
@@ -130,12 +153,17 @@ function matchesSelectorMatcher(element, matcher) {
130
153
  }
131
154
  const { type, name, value } = matcher;
132
155
  switch (type) {
156
+ case 0 /* Unknown */:
157
+ return name === "*";
158
+ // Universal selector
133
159
  case 1 /* Element */:
134
160
  return element.localName === name;
135
161
  case 2 /* Id */:
136
162
  return element.getAttribute("id") === name;
137
163
  case 3 /* Class */:
138
- return element.getAttribute("class") === name;
164
+ const classAttr = element.getAttribute("class");
165
+ if (!classAttr) return false;
166
+ return classAttr.split(/\s+/).includes(name);
139
167
  case 4 /* Attribute */:
140
168
  return value == null ? element.hasAttribute(name) : element.getAttribute(name) === value;
141
169
  case 5 /* Pseudo */:
@@ -147,6 +175,8 @@ function matchesSelectorMatcher(element, matcher) {
147
175
  switch (name) {
148
176
  case "has":
149
177
  return matchesSelector(element, value || "");
178
+ case "not":
179
+ return !matchesSelector(element, value || "");
150
180
  default:
151
181
  throw Error(`Function :${name}(${value}) not implemented`);
152
182
  }