@remote-dom/polyfill 1.5.1 → 1.6.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 (304) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +51 -3
  3. package/build/cjs/Attr.cjs +33 -4
  4. package/build/cjs/CharacterData.cjs +10 -0
  5. package/build/cjs/ChildNode.cjs +79 -13
  6. package/build/cjs/Comment.cjs +1 -1
  7. package/build/cjs/CustomElementRegistry.cjs +27 -2
  8. package/build/cjs/CustomEvent.cjs +2 -2
  9. package/build/cjs/Document.cjs +56 -32
  10. package/build/cjs/DocumentFragment.cjs +6 -2
  11. package/build/cjs/Element.cjs +68 -8
  12. package/build/cjs/Event.cjs +29 -27
  13. package/build/cjs/EventTarget.cjs +128 -58
  14. package/build/cjs/HTMLTemplateElement.cjs +1 -0
  15. package/build/cjs/MutationObserver.cjs +167 -1
  16. package/build/cjs/NamedNodeMap.cjs +82 -45
  17. package/build/cjs/Node.cjs +47 -11
  18. package/build/cjs/NodeList.cjs +9 -1
  19. package/build/cjs/ParentNode.cjs +319 -77
  20. package/build/cjs/SVGElement.cjs +1 -1
  21. package/build/cjs/Text.cjs +1 -1
  22. package/build/cjs/Window.cjs +131 -38
  23. package/build/cjs/attribute-reactions.cjs +20 -0
  24. package/build/cjs/constants.cjs +48 -24
  25. package/build/cjs/custom-element-reactions.cjs +52 -0
  26. package/build/cjs/dom-exception.cjs +15 -0
  27. package/build/cjs/hook-effects.cjs +51 -0
  28. package/build/cjs/names.cjs +61 -0
  29. package/build/cjs/selectors.cjs +213 -122
  30. package/build/cjs/serialization.cjs +168 -65
  31. package/build/cjs/shared.cjs +177 -28
  32. package/build/esm/Attr.mjs +34 -5
  33. package/build/esm/CharacterData.mjs +10 -0
  34. package/build/esm/ChildNode.mjs +76 -15
  35. package/build/esm/Comment.mjs +2 -2
  36. package/build/esm/CustomElementRegistry.mjs +27 -2
  37. package/build/esm/CustomEvent.mjs +2 -2
  38. package/build/esm/Document.mjs +60 -35
  39. package/build/esm/DocumentFragment.mjs +7 -3
  40. package/build/esm/Element.mjs +69 -9
  41. package/build/esm/Event.mjs +27 -27
  42. package/build/esm/EventTarget.mjs +130 -60
  43. package/build/esm/HTMLTemplateElement.mjs +2 -1
  44. package/build/esm/MutationObserver.mjs +166 -2
  45. package/build/esm/NamedNodeMap.mjs +83 -46
  46. package/build/esm/Node.mjs +48 -12
  47. package/build/esm/NodeList.mjs +9 -1
  48. package/build/esm/ParentNode.mjs +322 -81
  49. package/build/esm/SVGElement.mjs +2 -2
  50. package/build/esm/Text.mjs +2 -2
  51. package/build/esm/Window.mjs +132 -39
  52. package/build/esm/attribute-reactions.mjs +16 -0
  53. package/build/esm/constants.mjs +28 -23
  54. package/build/esm/custom-element-reactions.mjs +47 -0
  55. package/build/esm/dom-exception.mjs +11 -0
  56. package/build/esm/hook-effects.mjs +46 -0
  57. package/build/esm/names.mjs +54 -0
  58. package/build/esm/selectors.mjs +202 -124
  59. package/build/esm/serialization.mjs +169 -66
  60. package/build/esm/shared.mjs +173 -30
  61. package/build/esnext/Attr.esnext +45 -5
  62. package/build/esnext/CharacterData.esnext +10 -0
  63. package/build/esnext/ChildNode.esnext +84 -15
  64. package/build/esnext/Comment.esnext +2 -2
  65. package/build/esnext/CustomElementRegistry.esnext +42 -0
  66. package/build/esnext/CustomEvent.esnext +2 -2
  67. package/build/esnext/Document.esnext +69 -32
  68. package/build/esnext/DocumentFragment.esnext +6 -2
  69. package/build/esnext/Element.esnext +78 -9
  70. package/build/esnext/Event.esnext +36 -37
  71. package/build/esnext/EventTarget.esnext +133 -61
  72. package/build/esnext/HTMLTemplateElement.esnext +3 -1
  73. package/build/esnext/MutationObserver.esnext +163 -2
  74. package/build/esnext/NamedNodeMap.esnext +110 -42
  75. package/build/esnext/Node.esnext +50 -12
  76. package/build/esnext/NodeList.esnext +1 -1
  77. package/build/esnext/ParentNode.esnext +352 -79
  78. package/build/esnext/SVGElement.esnext +2 -2
  79. package/build/esnext/Text.esnext +2 -2
  80. package/build/esnext/Window.esnext +120 -16
  81. package/build/esnext/attribute-reactions.esnext +21 -0
  82. package/build/esnext/constants.esnext +34 -21
  83. package/build/esnext/custom-element-reactions.esnext +49 -0
  84. package/build/esnext/dom-exception.esnext +11 -0
  85. package/build/esnext/hook-effects.esnext +46 -0
  86. package/build/esnext/names.esnext +61 -0
  87. package/build/esnext/selectors.esnext +202 -100
  88. package/build/esnext/serialization.esnext +171 -48
  89. package/build/esnext/shared.esnext +181 -34
  90. package/build/tsconfig.tsbuildinfo +1 -1
  91. package/build/typescript/Attr.d.ts +6 -4
  92. package/build/typescript/Attr.d.ts.map +1 -1
  93. package/build/typescript/CharacterData.d.ts.map +1 -1
  94. package/build/typescript/ChildNode.d.ts +5 -0
  95. package/build/typescript/ChildNode.d.ts.map +1 -1
  96. package/build/typescript/ClipboardEvent.d.ts.map +1 -1
  97. package/build/typescript/Comment.d.ts +2 -2
  98. package/build/typescript/Comment.d.ts.map +1 -1
  99. package/build/typescript/CustomElementRegistry.d.ts +1 -0
  100. package/build/typescript/CustomElementRegistry.d.ts.map +1 -1
  101. package/build/typescript/CustomEvent.d.ts.map +1 -1
  102. package/build/typescript/Document.d.ts +10 -5
  103. package/build/typescript/Document.d.ts.map +1 -1
  104. package/build/typescript/DocumentFragment.d.ts +2 -1
  105. package/build/typescript/DocumentFragment.d.ts.map +1 -1
  106. package/build/typescript/Element.d.ts +16 -7
  107. package/build/typescript/Element.d.ts.map +1 -1
  108. package/build/typescript/ErrorEvent.d.ts.map +1 -1
  109. package/build/typescript/Event.d.ts +9 -10
  110. package/build/typescript/Event.d.ts.map +1 -1
  111. package/build/typescript/EventTarget.d.ts +20 -3
  112. package/build/typescript/EventTarget.d.ts.map +1 -1
  113. package/build/typescript/FocusEvent.d.ts.map +1 -1
  114. package/build/typescript/HTMLTemplateElement.d.ts.map +1 -1
  115. package/build/typescript/MutationObserver.d.ts +42 -0
  116. package/build/typescript/MutationObserver.d.ts.map +1 -1
  117. package/build/typescript/NamedNodeMap.d.ts +5 -3
  118. package/build/typescript/NamedNodeMap.d.ts.map +1 -1
  119. package/build/typescript/Node.d.ts +4 -3
  120. package/build/typescript/Node.d.ts.map +1 -1
  121. package/build/typescript/NodeList.d.ts +3 -2
  122. package/build/typescript/NodeList.d.ts.map +1 -1
  123. package/build/typescript/ParentNode.d.ts +29 -10
  124. package/build/typescript/ParentNode.d.ts.map +1 -1
  125. package/build/typescript/PromiseRejectionEvent.d.ts.map +1 -1
  126. package/build/typescript/SVGElement.d.ts +1 -1
  127. package/build/typescript/SVGElement.d.ts.map +1 -1
  128. package/build/typescript/Text.d.ts +1 -1
  129. package/build/typescript/Text.d.ts.map +1 -1
  130. package/build/typescript/ToggleEvent.d.ts.map +1 -1
  131. package/build/typescript/Window.d.ts +5 -1
  132. package/build/typescript/Window.d.ts.map +1 -1
  133. package/build/typescript/attribute-reactions.d.ts +4 -0
  134. package/build/typescript/attribute-reactions.d.ts.map +1 -0
  135. package/build/typescript/constants.d.ts +27 -18
  136. package/build/typescript/constants.d.ts.map +1 -1
  137. package/build/typescript/custom-element-reactions.d.ts +6 -0
  138. package/build/typescript/custom-element-reactions.d.ts.map +1 -0
  139. package/build/typescript/dom-exception.d.ts +2 -0
  140. package/build/typescript/dom-exception.d.ts.map +1 -0
  141. package/build/typescript/extensions.d.ts +4 -0
  142. package/build/typescript/extensions.d.ts.map +1 -0
  143. package/build/typescript/hook-effects.d.ts +6 -0
  144. package/build/typescript/hook-effects.d.ts.map +1 -0
  145. package/build/typescript/hooks.d.ts +3 -3
  146. package/build/typescript/hooks.d.ts.map +1 -1
  147. package/build/typescript/index.d.ts +1 -0
  148. package/build/typescript/index.d.ts.map +1 -1
  149. package/build/typescript/names.d.ts +11 -0
  150. package/build/typescript/names.d.ts.map +1 -0
  151. package/build/typescript/selectors.d.ts +21 -22
  152. package/build/typescript/selectors.d.ts.map +1 -1
  153. package/build/typescript/serialization.d.ts.map +1 -1
  154. package/build/typescript/shared.d.ts +10 -0
  155. package/build/typescript/shared.d.ts.map +1 -1
  156. package/build/typescript/tests/ChildNode.test.d.ts +2 -0
  157. package/build/typescript/tests/ChildNode.test.d.ts.map +1 -0
  158. package/build/typescript/tests/MutationObserver.test.d.ts +2 -0
  159. package/build/typescript/tests/MutationObserver.test.d.ts.map +1 -0
  160. package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts +2 -0
  161. package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts.map +1 -0
  162. package/build/typescript/tests/attr-mutation.test.d.ts +2 -0
  163. package/build/typescript/tests/attr-mutation.test.d.ts.map +1 -0
  164. package/build/typescript/tests/child-node-before-after.test.d.ts +2 -0
  165. package/build/typescript/tests/child-node-before-after.test.d.ts.map +1 -0
  166. package/build/typescript/tests/child-node-replace-with.test.d.ts +2 -0
  167. package/build/typescript/tests/child-node-replace-with.test.d.ts.map +1 -0
  168. package/build/typescript/tests/clone-import-namespaces.test.d.ts +2 -0
  169. package/build/typescript/tests/clone-import-namespaces.test.d.ts.map +1 -0
  170. package/build/typescript/tests/constants.test.d.ts +2 -0
  171. package/build/typescript/tests/constants.test.d.ts.map +1 -0
  172. package/build/typescript/tests/create-element-namespaces.test.d.ts +2 -0
  173. package/build/typescript/tests/create-element-namespaces.test.d.ts.map +1 -0
  174. package/build/typescript/tests/create-text-node.test.d.ts +2 -0
  175. package/build/typescript/tests/create-text-node.test.d.ts.map +1 -0
  176. package/build/typescript/tests/custom-element-reactions.test.d.ts +2 -0
  177. package/build/typescript/tests/custom-element-reactions.test.d.ts.map +1 -0
  178. package/build/typescript/tests/custom-element-registry.test.d.ts +2 -0
  179. package/build/typescript/tests/custom-element-registry.test.d.ts.map +1 -0
  180. package/build/typescript/tests/custom-event.test.d.ts +2 -0
  181. package/build/typescript/tests/custom-event.test.d.ts.map +1 -0
  182. package/build/typescript/tests/document-clone-import-contract.test.d.ts +2 -0
  183. package/build/typescript/tests/document-clone-import-contract.test.d.ts.map +1 -0
  184. package/build/typescript/tests/document.test.d.ts +2 -0
  185. package/build/typescript/tests/document.test.d.ts.map +1 -0
  186. package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts +2 -0
  187. package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts.map +1 -0
  188. package/build/typescript/tests/event-dispatch.test.d.ts +2 -0
  189. package/build/typescript/tests/event-dispatch.test.d.ts.map +1 -0
  190. package/build/typescript/tests/event-target.test.d.ts +2 -0
  191. package/build/typescript/tests/event-target.test.d.ts.map +1 -0
  192. package/build/typescript/tests/event.test.d.ts +2 -0
  193. package/build/typescript/tests/event.test.d.ts.map +1 -0
  194. package/build/typescript/tests/extensions.test.d.ts +2 -0
  195. package/build/typescript/tests/extensions.test.d.ts.map +1 -0
  196. package/build/typescript/tests/get-elements-by-tag-name.test.d.ts +2 -0
  197. package/build/typescript/tests/get-elements-by-tag-name.test.d.ts.map +1 -0
  198. package/build/typescript/tests/getElementsByClassName.test.d.ts +2 -0
  199. package/build/typescript/tests/getElementsByClassName.test.d.ts.map +1 -0
  200. package/build/typescript/tests/hooks.test.d.ts +2 -0
  201. package/build/typescript/tests/hooks.test.d.ts.map +1 -0
  202. package/build/typescript/tests/inner-html-parsing.test.d.ts +2 -0
  203. package/build/typescript/tests/inner-html-parsing.test.d.ts.map +1 -0
  204. package/build/typescript/tests/is-default-namespace.test.d.ts +2 -0
  205. package/build/typescript/tests/is-default-namespace.test.d.ts.map +1 -0
  206. package/build/typescript/tests/name-and-namespace-normalization.test.d.ts +2 -0
  207. package/build/typescript/tests/name-and-namespace-normalization.test.d.ts.map +1 -0
  208. package/build/typescript/tests/named-node-map.test.d.ts +2 -0
  209. package/build/typescript/tests/named-node-map.test.d.ts.map +1 -0
  210. package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts +2 -0
  211. package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts.map +1 -0
  212. package/build/typescript/tests/node.test.d.ts +2 -0
  213. package/build/typescript/tests/node.test.d.ts.map +1 -0
  214. package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts +2 -0
  215. package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts.map +1 -0
  216. package/build/typescript/tests/parent-node-mutation-validation.test.d.ts +2 -0
  217. package/build/typescript/tests/parent-node-mutation-validation.test.d.ts.map +1 -0
  218. package/build/typescript/tests/parent-node.test.d.ts +2 -0
  219. package/build/typescript/tests/parent-node.test.d.ts.map +1 -0
  220. package/build/typescript/tests/serialization-template.test.d.ts +2 -0
  221. package/build/typescript/tests/serialization-template.test.d.ts.map +1 -0
  222. package/build/typescript/tests/slot-attribute.test.d.ts +2 -0
  223. package/build/typescript/tests/slot-attribute.test.d.ts.map +1 -0
  224. package/build/typescript/tests/text-content.test.d.ts +2 -0
  225. package/build/typescript/tests/text-content.test.d.ts.map +1 -0
  226. package/build/typescript/tests/toggle-attribute.test.d.ts +2 -0
  227. package/build/typescript/tests/toggle-attribute.test.d.ts.map +1 -0
  228. package/build/typescript/tests/wide-tree-traversal.test.d.ts +2 -0
  229. package/build/typescript/tests/wide-tree-traversal.test.d.ts.map +1 -0
  230. package/build/typescript/tests/window-set-global.test.d.ts +2 -0
  231. package/build/typescript/tests/window-set-global.test.d.ts.map +1 -0
  232. package/package.json +1 -1
  233. package/source/Attr.ts +60 -8
  234. package/source/CharacterData.ts +13 -0
  235. package/source/ChildNode.ts +107 -14
  236. package/source/Comment.ts +2 -2
  237. package/source/CustomElementRegistry.ts +56 -0
  238. package/source/CustomEvent.ts +2 -2
  239. package/source/Document.ts +104 -38
  240. package/source/DocumentFragment.ts +12 -2
  241. package/source/Element.ts +129 -14
  242. package/source/Event.ts +34 -32
  243. package/source/EventTarget.ts +203 -79
  244. package/source/HTMLTemplateElement.ts +2 -1
  245. package/source/MutationObserver.ts +279 -1
  246. package/source/NamedNodeMap.ts +141 -60
  247. package/source/Node.ts +70 -14
  248. package/source/NodeList.ts +13 -3
  249. package/source/ParentNode.ts +500 -88
  250. package/source/SVGElement.ts +2 -2
  251. package/source/Text.ts +2 -2
  252. package/source/Window.ts +156 -17
  253. package/source/attribute-reactions.ts +32 -0
  254. package/source/constants.ts +40 -17
  255. package/source/custom-element-reactions.ts +64 -0
  256. package/source/dom-exception.ts +14 -0
  257. package/source/extensions.ts +4 -0
  258. package/source/hook-effects.ts +56 -0
  259. package/source/hooks.ts +11 -3
  260. package/source/index.ts +1 -0
  261. package/source/names.ts +94 -0
  262. package/source/selectors.ts +301 -138
  263. package/source/serialization.ts +224 -66
  264. package/source/shared.ts +269 -40
  265. package/source/tests/ChildNode.test.ts +178 -0
  266. package/source/tests/MutationObserver.test.ts +303 -0
  267. package/source/tests/adopt-inserted-subtrees.test.ts +584 -0
  268. package/source/tests/attr-mutation.test.ts +112 -0
  269. package/source/tests/child-node-before-after.test.ts +421 -0
  270. package/source/tests/child-node-replace-with.test.ts +251 -0
  271. package/source/tests/clone-import-namespaces.test.ts +365 -0
  272. package/source/tests/constants.test.ts +46 -0
  273. package/source/tests/create-element-namespaces.test.ts +142 -0
  274. package/source/tests/create-text-node.test.ts +38 -0
  275. package/source/tests/custom-element-reactions.test.ts +600 -0
  276. package/source/tests/custom-element-registry.test.ts +137 -0
  277. package/source/tests/custom-event.test.ts +26 -0
  278. package/source/tests/document-clone-import-contract.test.ts +77 -0
  279. package/source/tests/document.test.ts +122 -0
  280. package/source/tests/dom-mutation-selector-errors.test.ts +484 -0
  281. package/source/tests/event-dispatch.test.ts +270 -0
  282. package/source/tests/event-target.test.ts +208 -0
  283. package/source/tests/event.test.ts +98 -0
  284. package/source/tests/extensions.test.ts +159 -0
  285. package/source/tests/get-elements-by-tag-name.test.ts +79 -0
  286. package/source/tests/getElementsByClassName.test.ts +109 -0
  287. package/source/tests/hooks.test.ts +43 -0
  288. package/source/tests/inner-html-parsing.test.ts +461 -0
  289. package/source/tests/is-default-namespace.test.ts +111 -0
  290. package/source/tests/name-and-namespace-normalization.test.ts +319 -0
  291. package/source/tests/named-node-map.test.ts +122 -0
  292. package/source/tests/namespaced-attribute-reactions.test.ts +141 -0
  293. package/source/tests/node.test.ts +56 -0
  294. package/source/tests/parent-node-mutation-return-values.test.ts +63 -0
  295. package/source/tests/parent-node-mutation-validation.test.ts +362 -0
  296. package/source/tests/parent-node.test.ts +169 -0
  297. package/source/tests/selectors.test.ts +533 -22
  298. package/source/tests/serialization-template.test.ts +232 -0
  299. package/source/tests/slot-attribute.test.ts +133 -0
  300. package/source/tests/text-content.test.ts +440 -0
  301. package/source/tests/toggle-attribute.test.ts +113 -0
  302. package/source/tests/wide-tree-traversal.test.ts +699 -0
  303. package/source/tests/window-set-global.test.ts +321 -0
  304. package/tsconfig.json +1 -1
@@ -1,3 +1,281 @@
1
+ import type {Node} from './Node.ts';
2
+ import {NodeList} from './NodeList.ts';
3
+
4
+ export interface MutationObserverInit {
5
+ attributes?: boolean;
6
+ attributeFilter?: string[];
7
+ attributeOldValue?: boolean;
8
+ characterData?: boolean;
9
+ characterDataOldValue?: boolean;
10
+ childList?: boolean;
11
+ subtree?: boolean;
12
+ }
13
+
14
+ export interface MutationRecord {
15
+ readonly addedNodes: NodeList;
16
+ readonly attributeName: string | null;
17
+ readonly attributeNamespace: string | null;
18
+ readonly nextSibling: Node | null;
19
+ readonly oldValue: string | null;
20
+ readonly previousSibling: Node | null;
21
+ readonly removedNodes: NodeList;
22
+ readonly target: Node;
23
+ readonly type: 'attributes' | 'characterData' | 'childList';
24
+ }
25
+
26
+ export type MutationCallback = (
27
+ mutations: MutationRecord[],
28
+ observer: MutationObserver,
29
+ ) => void;
30
+
31
+ interface NormalizedMutationObserverInit {
32
+ attributes: boolean;
33
+ attributeFilter?: Set<string>;
34
+ attributeOldValue: boolean;
35
+ characterData: boolean;
36
+ characterDataOldValue: boolean;
37
+ childList: boolean;
38
+ subtree: boolean;
39
+ }
40
+
41
+ type MutationRecordInit = Pick<MutationRecord, 'target' | 'type'> &
42
+ Partial<
43
+ Pick<
44
+ MutationRecord,
45
+ | 'addedNodes'
46
+ | 'attributeName'
47
+ | 'attributeNamespace'
48
+ | 'nextSibling'
49
+ | 'oldValue'
50
+ | 'previousSibling'
51
+ | 'removedNodes'
52
+ >
53
+ >;
54
+
55
+ type Registrations = WeakMap<
56
+ Node,
57
+ Map<MutationObserver, NormalizedMutationObserverInit>
58
+ >;
59
+
60
+ let registrations: Registrations | undefined;
61
+ let registrationCount = 0;
62
+ let attributeRegistrationCount = 0;
63
+ let characterDataRegistrationCount = 0;
64
+ let childListRegistrationCount = 0;
65
+
66
+ // Mutation sites read these live bindings before capturing old values or
67
+ // allocating record data. Keep them split so observing one mutation type does
68
+ // not add work to unrelated mutations.
69
+ /** @internal */
70
+ export let attributeObserversActive = false;
71
+ /** @internal */
72
+ export let characterDataObserversActive = false;
73
+ /** @internal */
74
+ export let childListObserversActive = false;
75
+
1
76
  export class MutationObserver {
2
- // stub implementation
77
+ readonly #callback: MutationCallback;
78
+ readonly #records: MutationRecord[] = [];
79
+ readonly #targets = new Set<Node>();
80
+ #scheduled = false;
81
+
82
+ constructor(callback: MutationCallback) {
83
+ if (typeof callback !== 'function') {
84
+ throw new TypeError('MutationObserver callback must be a function');
85
+ }
86
+
87
+ this.#callback = callback;
88
+ }
89
+
90
+ observe(target: Node, options: MutationObserverInit = {}) {
91
+ const normalizedOptions = normalizeOptions(options);
92
+ const currentRegistrations = (registrations ??= new WeakMap());
93
+ let targetRegistrations = currentRegistrations.get(target);
94
+
95
+ if (targetRegistrations == null) {
96
+ targetRegistrations = new Map();
97
+ currentRegistrations.set(target, targetRegistrations);
98
+ }
99
+
100
+ const previousOptions = targetRegistrations.get(this);
101
+ if (previousOptions == null) {
102
+ registrationCount++;
103
+ } else {
104
+ updateRegistrationCounts(previousOptions, -1);
105
+ }
106
+
107
+ targetRegistrations.set(this, normalizedOptions);
108
+ updateRegistrationCounts(normalizedOptions, 1);
109
+ this.#targets.add(target);
110
+ }
111
+
112
+ disconnect() {
113
+ const currentRegistrations = registrations;
114
+ if (currentRegistrations == null) return;
115
+
116
+ for (const target of this.#targets) {
117
+ const targetRegistrations = currentRegistrations.get(target);
118
+ const options = targetRegistrations?.get(this);
119
+ if (options != null) {
120
+ targetRegistrations!.delete(this);
121
+ registrationCount--;
122
+ updateRegistrationCounts(options, -1);
123
+ }
124
+
125
+ if (targetRegistrations?.size === 0) {
126
+ currentRegistrations.delete(target);
127
+ }
128
+ }
129
+
130
+ this.#targets.clear();
131
+ this.#records.length = 0;
132
+
133
+ if (registrationCount === 0) {
134
+ registrations = undefined;
135
+ }
136
+ }
137
+
138
+ takeRecords() {
139
+ return this.#records.splice(0);
140
+ }
141
+
142
+ /** @internal */
143
+ enqueue(record: MutationRecord) {
144
+ this.#records.push(record);
145
+
146
+ if (this.#scheduled) return;
147
+ this.#scheduled = true;
148
+
149
+ queueMicrotask(() => {
150
+ this.#scheduled = false;
151
+ const records = this.takeRecords();
152
+
153
+ if (records.length > 0) {
154
+ this.#callback.call(this, records, this);
155
+ }
156
+ });
157
+ }
158
+ }
159
+
160
+ /** @internal */
161
+ export function queueMutationRecord(init: MutationRecordInit) {
162
+ const currentRegistrations = registrations;
163
+ if (currentRegistrations == null) return;
164
+
165
+ const interestedObservers = new Map<MutationObserver, boolean>();
166
+ let node: Node | null = init.target;
167
+
168
+ while (node) {
169
+ const targetRegistrations = currentRegistrations.get(node);
170
+
171
+ if (targetRegistrations) {
172
+ for (const [observer, options] of targetRegistrations) {
173
+ if (node !== init.target && !options.subtree) continue;
174
+
175
+ let includeOldValue = false;
176
+
177
+ if (init.type === 'attributes') {
178
+ if (!options.attributes) continue;
179
+ if (
180
+ options.attributeFilter &&
181
+ !options.attributeFilter.has(init.attributeName ?? '')
182
+ ) {
183
+ continue;
184
+ }
185
+ includeOldValue = options.attributeOldValue;
186
+ } else if (init.type === 'characterData') {
187
+ if (!options.characterData) continue;
188
+ includeOldValue = options.characterDataOldValue;
189
+ } else if (!options.childList) {
190
+ continue;
191
+ }
192
+
193
+ interestedObservers.set(
194
+ observer,
195
+ interestedObservers.get(observer) === true || includeOldValue,
196
+ );
197
+ }
198
+ }
199
+
200
+ node = node.parentNode;
201
+ }
202
+
203
+ for (const [observer, includeOldValue] of interestedObservers) {
204
+ observer.enqueue({
205
+ addedNodes: init.addedNodes ?? new NodeList(),
206
+ attributeName: init.attributeName ?? null,
207
+ attributeNamespace: init.attributeNamespace ?? null,
208
+ nextSibling: init.nextSibling ?? null,
209
+ oldValue: includeOldValue ? (init.oldValue ?? null) : null,
210
+ previousSibling: init.previousSibling ?? null,
211
+ removedNodes: init.removedNodes ?? new NodeList(),
212
+ target: init.target,
213
+ type: init.type,
214
+ });
215
+ }
216
+ }
217
+
218
+ /** @internal */
219
+ export function mutationNodeList(...nodes: Node[]) {
220
+ const list = new NodeList();
221
+ list.push(...nodes);
222
+ return list;
223
+ }
224
+
225
+ function normalizeOptions(
226
+ options: MutationObserverInit,
227
+ ): NormalizedMutationObserverInit {
228
+ if (
229
+ options.attributes === false &&
230
+ (options.attributeOldValue || options.attributeFilter != null)
231
+ ) {
232
+ throw new TypeError(
233
+ 'attributeOldValue and attributeFilter require attributes to be enabled',
234
+ );
235
+ }
236
+
237
+ if (options.characterData === false && options.characterDataOldValue) {
238
+ throw new TypeError(
239
+ 'characterDataOldValue requires characterData to be enabled',
240
+ );
241
+ }
242
+
243
+ const attributes =
244
+ options.attributes ??
245
+ (options.attributeOldValue === true || options.attributeFilter != null);
246
+ const characterData =
247
+ options.characterData ?? options.characterDataOldValue === true;
248
+ const childList = options.childList === true;
249
+
250
+ if (!attributes && !characterData && !childList) {
251
+ throw new TypeError(
252
+ 'MutationObserver options must enable childList, attributes, or characterData',
253
+ );
254
+ }
255
+
256
+ return {
257
+ attributes,
258
+ attributeFilter:
259
+ options.attributeFilter == null
260
+ ? undefined
261
+ : new Set(options.attributeFilter.map(String)),
262
+ attributeOldValue: options.attributeOldValue === true,
263
+ characterData,
264
+ characterDataOldValue: options.characterDataOldValue === true,
265
+ childList,
266
+ subtree: options.subtree === true,
267
+ };
268
+ }
269
+
270
+ function updateRegistrationCounts(
271
+ options: NormalizedMutationObserverInit,
272
+ delta: 1 | -1,
273
+ ) {
274
+ if (options.attributes) attributeRegistrationCount += delta;
275
+ if (options.characterData) characterDataRegistrationCount += delta;
276
+ if (options.childList) childListRegistrationCount += delta;
277
+
278
+ attributeObserversActive = attributeRegistrationCount > 0;
279
+ characterDataObserversActive = characterDataRegistrationCount > 0;
280
+ childListObserversActive = childListRegistrationCount > 0;
3
281
  }
@@ -1,13 +1,24 @@
1
1
  import {
2
2
  CHILD,
3
3
  OWNER_ELEMENT,
4
+ OWNER_DOCUMENT,
4
5
  NS,
5
6
  NEXT,
6
- NamespaceURI,
7
+ type NamespaceURI,
7
8
  HOOKS,
9
+ HTML_NAMESPACE,
10
+ asciiLowercase,
8
11
  } from './constants.ts';
12
+ import {normalizeNamespace} from './names.ts';
9
13
  import type {Attr} from './Attr.ts';
10
14
  import type {Element} from './Element.ts';
15
+ import {
16
+ attributeObserversActive,
17
+ queueMutationRecord,
18
+ } from './MutationObserver.ts';
19
+ import {performWithCustomElementReactions} from './custom-element-reactions.ts';
20
+ import {enqueueAttributeReaction} from './attribute-reactions.ts';
21
+ import {createDOMException} from './dom-exception.ts';
11
22
 
12
23
  export class NamedNodeMap {
13
24
  [CHILD]: Attr | null = null;
@@ -18,13 +29,27 @@ export class NamedNodeMap {
18
29
  }
19
30
 
20
31
  getNamedItem(name: string) {
21
- return this.getNamedItemNS(null, name);
32
+ const qualifiedName = String(name);
33
+ const normalizedName =
34
+ this[OWNER_ELEMENT][NS] === HTML_NAMESPACE
35
+ ? asciiLowercase(qualifiedName)
36
+ : qualifiedName;
37
+
38
+ let attr = this[CHILD];
39
+ while (attr) {
40
+ if (attr.name === normalizedName) return attr;
41
+ attr = attr[NEXT];
42
+ }
43
+ return null;
22
44
  }
23
45
 
24
- getNamedItemNS(namespaceURI: NamespaceURI | null, name: string) {
46
+ getNamedItemNS(namespaceURI: NamespaceURI, localName: string) {
47
+ const namespace = normalizeNamespace(namespaceURI);
48
+ const normalizedLocalName = String(localName);
49
+
25
50
  let attr = this[CHILD];
26
51
  while (attr) {
27
- if (attr.name === name && attr[NS] == namespaceURI) {
52
+ if (attr.localName === normalizedLocalName && attr[NS] === namespace) {
28
53
  return attr;
29
54
  }
30
55
  attr = attr[NEXT];
@@ -53,23 +78,62 @@ export class NamedNodeMap {
53
78
  }
54
79
 
55
80
  removeNamedItem(name: string) {
56
- return this.removeNamedItemNS(null, name);
81
+ const qualifiedName = String(name);
82
+ const normalizedName =
83
+ this[OWNER_ELEMENT][NS] === HTML_NAMESPACE
84
+ ? asciiLowercase(qualifiedName)
85
+ : qualifiedName;
86
+
87
+ return performWithCustomElementReactions(() =>
88
+ this.removeNamedItemImmediately((attr) => attr.name === normalizedName),
89
+ );
90
+ }
91
+
92
+ removeNamedItemNS(namespaceURI: NamespaceURI, localName: string) {
93
+ const namespace = normalizeNamespace(namespaceURI);
94
+ const normalizedLocalName = String(localName);
95
+
96
+ return performWithCustomElementReactions(() =>
97
+ this.removeNamedItemImmediately(
98
+ (attr) =>
99
+ attr.localName === normalizedLocalName && attr[NS] === namespace,
100
+ ),
101
+ );
57
102
  }
58
103
 
59
- removeNamedItemNS(namespaceURI: NamespaceURI | null, name: string) {
104
+ private removeNamedItemImmediately(matches: (attr: Attr) => boolean) {
60
105
  const ownerElement = this[OWNER_ELEMENT];
61
106
  let attr = this[CHILD];
62
107
  let prev: typeof attr | null = null;
63
108
 
64
109
  while (attr != null) {
65
- if (attr.name === name && attr[NS] == namespaceURI) {
110
+ if (matches(attr)) {
66
111
  if (prev) prev[NEXT] = attr[NEXT];
67
112
  if (this[CHILD] === attr) this[CHILD] = attr[NEXT];
68
- updateElementAttribute(ownerElement, attr.name, attr.value, null);
113
+ const oldValue = attr.value;
114
+ attr[NEXT] = null;
115
+ attr[OWNER_ELEMENT] = null;
116
+
117
+ if (attributeObserversActive) {
118
+ queueMutationRecord({
119
+ type: 'attributes',
120
+ target: ownerElement,
121
+ attributeName: attr.name,
122
+ attributeNamespace: attr[NS],
123
+ oldValue,
124
+ });
125
+ }
69
126
  ownerElement[HOOKS].removeAttribute?.(
70
127
  ownerElement as any,
71
- name,
72
- namespaceURI,
128
+ attr.name,
129
+ attr[NS],
130
+ );
131
+ enqueueAttributeReaction(
132
+ ownerElement,
133
+ attr.localName,
134
+ oldValue,
135
+ null,
136
+ attr[NS],
73
137
  );
74
138
  return attr;
75
139
  }
@@ -82,42 +146,73 @@ export class NamedNodeMap {
82
146
  }
83
147
 
84
148
  setNamedItem(attr: Attr) {
149
+ return performWithCustomElementReactions(() =>
150
+ this.setNamedItemImmediately(attr),
151
+ );
152
+ }
153
+
154
+ private setNamedItemImmediately(attr: Attr) {
85
155
  const ownerElement = this[OWNER_ELEMENT];
156
+ const currentOwner = attr[OWNER_ELEMENT];
157
+
158
+ if (currentOwner != null && currentOwner !== ownerElement) {
159
+ throw createDOMException(
160
+ 'The attribute is already in use by another element.',
161
+ 'InUseAttributeError',
162
+ );
163
+ }
164
+
86
165
  let old = null;
87
166
  let child = this[CHILD];
88
- attr[OWNER_ELEMENT] = ownerElement;
89
- if (child == null) {
90
- this[CHILD] = attr;
91
- // return null;
92
- } else {
93
- let prev;
94
- while (child) {
95
- if (child.name === attr.name && child[NS] == attr[NS]) {
96
- if (prev) prev[NEXT] = attr;
97
- else this[CHILD] = attr;
98
- attr[NEXT] = child[NEXT];
99
- child[NEXT] = null;
100
- old = child;
101
- break;
102
- // return child;
103
- }
104
- prev = child;
105
- child = child[NEXT];
167
+ let prev: Attr | null = null;
168
+
169
+ while (child) {
170
+ if (child.localName === attr.localName && child[NS] === attr[NS]) {
171
+ if (child === attr) return child;
172
+
173
+ if (prev) prev[NEXT] = attr;
174
+ else this[CHILD] = attr;
175
+ attr[NEXT] = child[NEXT];
176
+ child[NEXT] = null;
177
+ old = child;
178
+ break;
106
179
  }
180
+
181
+ prev = child;
182
+ child = child[NEXT];
183
+ }
184
+
185
+ if (old == null) {
107
186
  if (prev) prev[NEXT] = attr;
108
187
  else this[CHILD] = attr;
109
- // return null;
110
188
  }
111
189
 
112
- // only invoke the protocol if the value changed
113
- if (!old || old.value !== attr.value) {
114
- updateElementAttribute(
115
- ownerElement,
116
- attr.name,
117
- old?.value ?? null,
118
- attr.value,
190
+ attr[OWNER_ELEMENT] = ownerElement;
191
+ attr[OWNER_DOCUMENT] = ownerElement[OWNER_DOCUMENT];
192
+ if (old) old[OWNER_ELEMENT] = null;
193
+
194
+ const valueChanged = old == null || old.value !== attr.value;
195
+ const qualifiedNameChanged = old != null && old.name !== attr.name;
196
+
197
+ if (valueChanged && attributeObserversActive) {
198
+ queueMutationRecord({
199
+ type: 'attributes',
200
+ target: ownerElement,
201
+ attributeName: attr.name,
202
+ attributeNamespace: attr[NS],
203
+ oldValue: old?.value ?? null,
204
+ });
205
+ }
206
+
207
+ if (qualifiedNameChanged) {
208
+ ownerElement[HOOKS].removeAttribute?.(
209
+ ownerElement as any,
210
+ old!.name,
211
+ old![NS],
119
212
  );
213
+ }
120
214
 
215
+ if (valueChanged || qualifiedNameChanged) {
121
216
  ownerElement[HOOKS].setAttribute?.(
122
217
  ownerElement as any,
123
218
  attr.name,
@@ -126,6 +221,16 @@ export class NamedNodeMap {
126
221
  );
127
222
  }
128
223
 
224
+ if (valueChanged) {
225
+ enqueueAttributeReaction(
226
+ ownerElement,
227
+ attr.localName,
228
+ old?.value ?? null,
229
+ attr.value,
230
+ attr[NS],
231
+ );
232
+ }
233
+
129
234
  return old;
130
235
  }
131
236
 
@@ -141,27 +246,3 @@ export class NamedNodeMap {
141
246
  }
142
247
  }
143
248
  }
144
-
145
- function updateElementAttribute(
146
- element: Element,
147
- name: string,
148
- oldValue: string | null,
149
- newValue: string | null,
150
- ) {
151
- const {observedAttributes} = element.constructor as typeof Element;
152
- const {attributeChangedCallback} = element;
153
-
154
- if (name === 'slot') {
155
- element.slot = newValue ?? '';
156
- }
157
-
158
- if (
159
- attributeChangedCallback == null ||
160
- observedAttributes == null ||
161
- !observedAttributes.includes(name)
162
- ) {
163
- return;
164
- }
165
-
166
- return attributeChangedCallback.call(element, name, oldValue, newValue);
167
- }
package/source/Node.ts CHANGED
@@ -2,17 +2,28 @@ import {
2
2
  OWNER_DOCUMENT,
3
3
  NAME,
4
4
  PARENT,
5
+ HOST,
5
6
  CHILD,
6
7
  PREV,
7
8
  NEXT,
8
- NamespaceURI,
9
- NodeType,
9
+ NODE_TYPE_ATTRIBUTE,
10
+ NODE_TYPE_DOCUMENT,
11
+ NODE_TYPE_DOCUMENT_FRAGMENT,
12
+ NODE_TYPE_DOCUMENT_TYPE,
13
+ NODE_TYPE_ELEMENT,
14
+ NODE_TYPE_NODE,
15
+ XMLNS_NAMESPACE,
16
+ type NodeType,
10
17
  HOOKS,
18
+ HOOKS_DISPATCH,
11
19
  IS_CONNECTED,
12
20
  } from './constants.ts';
21
+ import type {Attr} from './Attr.ts';
13
22
  import type {Document} from './Document.ts';
23
+ import type {Element} from './Element.ts';
14
24
  import type {ParentNode} from './ParentNode.ts';
15
25
  import {EventTarget} from './EventTarget.ts';
26
+ import {normalizeNamespace} from './names.ts';
16
27
  import {
17
28
  isCharacterData,
18
29
  isParentNode,
@@ -22,18 +33,19 @@ import {
22
33
  } from './shared.ts';
23
34
 
24
35
  export class Node extends EventTarget {
25
- nodeType = NodeType.NODE;
36
+ nodeType: NodeType = NODE_TYPE_NODE;
26
37
 
27
38
  [OWNER_DOCUMENT]!: Document;
28
39
  [NAME] = '';
29
40
  [PARENT]: ParentNode | null = null;
41
+ [HOST]: Node | null = null;
30
42
  [CHILD]: Node | null = null;
31
43
  [PREV]: Node | null = null;
32
44
  [NEXT]: Node | null = null;
33
45
  [IS_CONNECTED] = false;
34
46
 
35
47
  protected get [HOOKS]() {
36
- return this[OWNER_DOCUMENT].defaultView[HOOKS];
48
+ return this[OWNER_DOCUMENT].defaultView[HOOKS_DISPATCH];
37
49
  }
38
50
 
39
51
  get localName() {
@@ -41,7 +53,7 @@ export class Node extends EventTarget {
41
53
  }
42
54
 
43
55
  get nodeName() {
44
- return this[NAME].toUpperCase();
56
+ return this[NAME];
45
57
  }
46
58
 
47
59
  get ownerDocument() {
@@ -52,8 +64,9 @@ export class Node extends EventTarget {
52
64
  return this[IS_CONNECTED];
53
65
  }
54
66
 
55
- isDefaultNamespace(namespace: string) {
56
- return namespace === NamespaceURI.XHTML;
67
+ isDefaultNamespace(namespace: string | null): boolean {
68
+ const normalizedNamespace = normalizeNamespace(namespace);
69
+ return locateNamespace(this) === normalizedNamespace;
57
70
  }
58
71
 
59
72
  get parentNode() {
@@ -142,11 +155,12 @@ export class Node extends EventTarget {
142
155
  if (isCharacterData(this)) {
143
156
  this.data = data;
144
157
  } else if (isParentNode(this)) {
145
- let child;
146
- while ((child = this[CHILD])) {
147
- this.removeChild(child);
158
+ const text = data == null ? '' : String(data);
159
+ if (text === '') {
160
+ this.replaceChildren();
161
+ } else {
162
+ this.replaceChildren(text);
148
163
  }
149
- this.append(data);
150
164
  }
151
165
  }
152
166
 
@@ -157,10 +171,52 @@ export class Node extends EventTarget {
157
171
  contains(node: Node | null) {
158
172
  let currentNode: Node | null = node;
159
173
 
160
- while (true) {
161
- if (currentNode == null) return false;
174
+ while (currentNode != null) {
162
175
  if (currentNode === this) return true;
163
- currentNode = node!.parentNode;
176
+ currentNode = currentNode.parentNode;
164
177
  }
178
+
179
+ return false;
165
180
  }
166
181
  }
182
+
183
+ function locateNamespace(node: Node | null): string | null {
184
+ let current = node;
185
+
186
+ while (current) {
187
+ switch (current.nodeType) {
188
+ case NODE_TYPE_ELEMENT: {
189
+ const element = current as Element;
190
+
191
+ if (element.prefix == null && element.namespaceURI != null) {
192
+ return element.namespaceURI;
193
+ }
194
+
195
+ const namespace = element.attributes.getNamedItemNS(
196
+ XMLNS_NAMESPACE,
197
+ 'xmlns',
198
+ );
199
+
200
+ if (namespace != null && namespace.prefix == null) {
201
+ return normalizeNamespace(namespace.value);
202
+ }
203
+
204
+ current = element.parentElement;
205
+ break;
206
+ }
207
+ case NODE_TYPE_DOCUMENT:
208
+ current = (current as Document).documentElement;
209
+ break;
210
+ case NODE_TYPE_DOCUMENT_TYPE:
211
+ case NODE_TYPE_DOCUMENT_FRAGMENT:
212
+ return null;
213
+ case NODE_TYPE_ATTRIBUTE:
214
+ current = (current as Attr).ownerElement;
215
+ break;
216
+ default:
217
+ current = current.parentElement;
218
+ }
219
+ }
220
+
221
+ return null;
222
+ }