@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,23 +1,25 @@
1
- import { NodeType, NAME, PARENT, CHILD, PREV, NEXT, IS_CONNECTED, HOOKS, OWNER_DOCUMENT, NamespaceURI } from './constants.mjs';
1
+ import { NODE_TYPE_NODE, NAME, PARENT, HOST, CHILD, PREV, NEXT, IS_CONNECTED, HOOKS, OWNER_DOCUMENT, HOOKS_DISPATCH, NODE_TYPE_ATTRIBUTE, NODE_TYPE_DOCUMENT_FRAGMENT, NODE_TYPE_DOCUMENT_TYPE, NODE_TYPE_DOCUMENT, NODE_TYPE_ELEMENT, XMLNS_NAMESPACE } from './constants.mjs';
2
2
  import { EventTarget } from './EventTarget.mjs';
3
+ import { normalizeNamespace } from './names.mjs';
3
4
  import { isCharacterData, descendants, isTextNode, isParentNode, cloneNode } from './shared.mjs';
4
5
 
5
6
  class Node extends EventTarget {
6
- nodeType = (() => NodeType.NODE)();
7
+ nodeType = NODE_TYPE_NODE;
7
8
  [NAME] = '';
8
9
  [PARENT] = null;
10
+ [HOST] = null;
9
11
  [CHILD] = null;
10
12
  [PREV] = null;
11
13
  [NEXT] = null;
12
14
  [IS_CONNECTED] = false;
13
15
  get [HOOKS]() {
14
- return this[OWNER_DOCUMENT].defaultView[HOOKS];
16
+ return this[OWNER_DOCUMENT].defaultView[HOOKS_DISPATCH];
15
17
  }
16
18
  get localName() {
17
19
  return this[NAME];
18
20
  }
19
21
  get nodeName() {
20
- return this[NAME].toUpperCase();
22
+ return this[NAME];
21
23
  }
22
24
  get ownerDocument() {
23
25
  return this[OWNER_DOCUMENT];
@@ -26,7 +28,8 @@ class Node extends EventTarget {
26
28
  return this[IS_CONNECTED];
27
29
  }
28
30
  isDefaultNamespace(namespace) {
29
- return namespace === NamespaceURI.XHTML;
31
+ const normalizedNamespace = normalizeNamespace(namespace);
32
+ return locateNamespace(this) === normalizedNamespace;
30
33
  }
31
34
  get parentNode() {
32
35
  return this[PARENT];
@@ -93,11 +96,12 @@ class Node extends EventTarget {
93
96
  if (isCharacterData(this)) {
94
97
  this.data = data;
95
98
  } else if (isParentNode(this)) {
96
- let child;
97
- while (child = this[CHILD]) {
98
- this.removeChild(child);
99
+ const text = data == null ? '' : String(data);
100
+ if (text === '') {
101
+ this.replaceChildren();
102
+ } else {
103
+ this.replaceChildren(text);
99
104
  }
100
- this.append(data);
101
105
  }
102
106
  }
103
107
  cloneNode(deep) {
@@ -105,12 +109,44 @@ class Node extends EventTarget {
105
109
  }
106
110
  contains(node) {
107
111
  let currentNode = node;
108
- while (true) {
109
- if (currentNode == null) return false;
112
+ while (currentNode != null) {
110
113
  if (currentNode === this) return true;
111
- currentNode = node.parentNode;
114
+ currentNode = currentNode.parentNode;
115
+ }
116
+ return false;
117
+ }
118
+ }
119
+ function locateNamespace(node) {
120
+ let current = node;
121
+ while (current) {
122
+ switch (current.nodeType) {
123
+ case NODE_TYPE_ELEMENT:
124
+ {
125
+ const element = current;
126
+ if (element.prefix == null && element.namespaceURI != null) {
127
+ return element.namespaceURI;
128
+ }
129
+ const namespace = element.attributes.getNamedItemNS(XMLNS_NAMESPACE, 'xmlns');
130
+ if (namespace != null && namespace.prefix == null) {
131
+ return normalizeNamespace(namespace.value);
132
+ }
133
+ current = element.parentElement;
134
+ break;
135
+ }
136
+ case NODE_TYPE_DOCUMENT:
137
+ current = current.documentElement;
138
+ break;
139
+ case NODE_TYPE_DOCUMENT_TYPE:
140
+ case NODE_TYPE_DOCUMENT_FRAGMENT:
141
+ return null;
142
+ case NODE_TYPE_ATTRIBUTE:
143
+ current = current.ownerElement;
144
+ break;
145
+ default:
146
+ current = current.parentElement;
112
147
  }
113
148
  }
149
+ return null;
114
150
  }
115
151
 
116
152
  export { Node };
@@ -1,6 +1,14 @@
1
+ // Performance note (2026-09-02): Benchmarks on an Apple M4 Pro with Node.js
2
+ // 24.19.0 (V8 13.6.233.17-node.51) and Chromium 152 showed indexed access and
3
+ // `for...of` iteration at parity with Array. Construction, `push()`, and some
4
+ // inherited methods (`forEach()`, `includes()`, `map()`, `filter()`, and
5
+ // `slice()`) were slower, but the measured end-to-end `querySelectorAll()`
6
+ // overhead was 0–12% (up to about 1 µs in the tested 100–1,000-element trees)
7
+ // and decreased as selector traversal dominated. Keep this direct subclass
8
+ // while indexed access and iteration remain the primary usage patterns.
1
9
  class NodeList extends Array {
2
10
  item(index) {
3
- return this[index];
11
+ return this[index] ?? null;
4
12
  }
5
13
  }
6
14
 
@@ -1,71 +1,114 @@
1
- import { PREV, NEXT, CHILD, PARENT, IS_CONNECTED, NodeType, HOOKS, OWNER_DOCUMENT } from './constants.mjs';
2
- import { ChildNode, toNode } from './ChildNode.mjs';
1
+ import { IS_CONNECTED, PREV, NEXT, NODE_TYPE_DOCUMENT_FRAGMENT, CHILD, OWNER_DOCUMENT, PARENT, NODE_TYPE_ELEMENT, HOOKS } from './constants.mjs';
2
+ import { ChildNode, REPLACE_NODE, validateInsertionNodes, INSERT_NODE, PREFLIGHT_INSERTIONS, stageNodes, toNode } from './ChildNode.mjs';
3
3
  import { NodeList } from './NodeList.mjs';
4
4
  import { querySelectorAll, querySelector } from './selectors.mjs';
5
- import { selfAndDescendants } from './shared.mjs';
5
+ import { selfAndDescendants, collectAdoptionSnapshot, adoptNodes, isElementNode } from './shared.mjs';
6
+ import { childListObserversActive, queueMutationRecord, mutationNodeList } from './MutationObserver.mjs';
7
+ import { performWithCustomElementReactions, enqueueCustomElementReaction } from './custom-element-reactions.mjs';
8
+ import { performHookEffects, isCoveredByPendingPublication } from './hook-effects.mjs';
9
+ import { createDOMException } from './dom-exception.mjs';
6
10
 
7
11
  class ParentNode extends ChildNode {
8
- childNodes = (() => new NodeList())();
9
- children = (() => new NodeList())();
12
+ childNodes = new NodeList();
13
+ children = new NodeList();
10
14
  appendChild(child) {
11
- this.insertInto(child, null);
15
+ return performWithCustomElementReactions(() => this[INSERT_NODE](child, null));
12
16
  }
13
17
  insertBefore(child, ref) {
14
- this.insertInto(child, ref || null);
18
+ return performWithCustomElementReactions(() => this[INSERT_NODE](child, ref || null));
15
19
  }
16
20
  append(...nodes) {
17
- for (const child of nodes) {
18
- if (child == null) continue;
19
- this.appendChild(toNode(this, child));
20
- }
21
+ return performWithCustomElementReactions(() => {
22
+ const staged = stageNodes(nodes.filter(node => node != null));
23
+ if (staged.length > 1) validateInsertionNodes(this, staged);
24
+ for (const child of staged) {
25
+ this[INSERT_NODE](toNode(this, child), null);
26
+ }
27
+ });
21
28
  }
22
29
  prepend(...nodes) {
23
- const before = this.firstChild;
24
- for (const child of nodes) {
25
- if (child == null) continue;
26
- this.insertBefore(toNode(this, child), before);
27
- }
30
+ return performWithCustomElementReactions(() => {
31
+ const staged = stageNodes(nodes.filter(node => node != null));
32
+ if (staged.length > 1) validateInsertionNodes(this, staged);
33
+ const before = this.firstChild;
34
+ for (const child of staged) {
35
+ this[INSERT_NODE](toNode(this, child), before);
36
+ }
37
+ });
28
38
  }
29
39
  replaceChildren(...nodes) {
30
- let child;
31
- while (child = this.firstChild) {
32
- this.removeChild(child);
33
- }
34
- this.append(...nodes);
40
+ return performWithCustomElementReactions(() => {
41
+ const staged = stageNodes(nodes.filter(node => node != null));
42
+ validateInsertionNodes(this, staged);
43
+ let child;
44
+ while (child = this.firstChild) {
45
+ this.removeChildImmediately(child);
46
+ }
47
+ for (const node of staged) {
48
+ this[INSERT_NODE](toNode(this, node), null);
49
+ }
50
+ });
35
51
  }
36
52
  removeChild(child) {
37
- if (child.parentNode !== this) throw Error(`not a child of this node`);
38
- const prev = child[PREV];
39
- const next = child[NEXT];
40
- if (prev) prev[NEXT] = next;else this[CHILD] = next;
41
- if (next) next[PREV] = prev;
42
- const childNodes = this.childNodes;
43
- const childNodesIndex = childNodes.indexOf(child);
44
- childNodes.splice(childNodesIndex, 1);
45
- if (child.nodeType === 1) {
46
- const children = this.children;
47
- children.splice(children.indexOf(child), 1);
48
- }
49
- child[PARENT] = null;
50
- child[NEXT] = null;
51
- child[PREV] = null;
52
- if (this[IS_CONNECTED]) {
53
- for (const node of selfAndDescendants(child)) {
54
- node[IS_CONNECTED] = false;
55
- node.disconnectedCallback?.();
56
- }
53
+ return performWithCustomElementReactions(() => {
54
+ this.removeChildImmediately(child);
55
+ return child;
56
+ });
57
+ }
58
+ removeChildImmediately(child) {
59
+ if (child.parentNode !== this) {
60
+ throw createDOMException('The node is not a child of this node', 'NotFoundError');
61
+ }
62
+ const disconnectedNodes = this[IS_CONNECTED] ? selfAndDescendants(child) : undefined;
63
+ const previousSibling = child[PREV];
64
+ const nextSibling = child[NEXT];
65
+ const childNodesIndex = detachChild(this, child);
66
+ if (disconnectedNodes) {
67
+ for (const node of disconnectedNodes) node[IS_CONNECTED] = false;
57
68
  }
58
- if (this.nodeType === NodeType.ELEMENT_NODE) {
59
- this[HOOKS].removeChild?.(this, child, childNodesIndex);
69
+ this.queueRemovalMutationRecord(this, child, previousSibling, nextSibling);
70
+ if (disconnectedNodes) {
71
+ this.enqueueTreeReactions(disconnectedNodes, 'disconnectedCallback');
60
72
  }
73
+ performHookEffects(this.collectRemovalHookEffects(child, childNodesIndex));
61
74
  }
62
75
  replaceChild(newChild, oldChild) {
76
+ return performWithCustomElementReactions(() => this[REPLACE_NODE](newChild, oldChild));
77
+ }
78
+ [REPLACE_NODE](newChild, oldChild, hookEffects) {
79
+ validateInsertionNodes(this, [newChild]);
63
80
  if (oldChild.parentNode !== this) {
64
- throw Error('reference node is not a child of this parent');
81
+ throw createDOMException('The reference node is not a child of this parent', 'NotFoundError');
65
82
  }
83
+ const previous = oldChild[PREV];
66
84
  const next = oldChild[NEXT];
67
- this.removeChild(oldChild);
68
- this.insertInto(newChild, next);
85
+ const insertion = this.prepareInsertion(newChild);
86
+ const removedNodes = this[IS_CONNECTED] ? selfAndDescendants(oldChild) : undefined;
87
+ const insertionRoots = new Set(insertion.map(({
88
+ node
89
+ }) => node));
90
+ let before = next;
91
+ while (before && insertionRoots.has(before)) before = before[NEXT];
92
+ const oldChildIndex = detachChild(this, oldChild);
93
+ if (removedNodes) {
94
+ for (const node of removedNodes) node[IS_CONNECTED] = false;
95
+ const removedNodeSet = new Set(removedNodes);
96
+ for (const prepared of insertion) {
97
+ if (removedNodeSet.has(prepared.node)) {
98
+ prepared.shouldDisconnect = false;
99
+ }
100
+ }
101
+ }
102
+ this.commitInsertion(insertion, before);
103
+ const destinationIsConnected = this[IS_CONNECTED];
104
+ this.queueRemovalMutationRecord(this, oldChild, previous, next);
105
+ this.queueInsertionMutationRecords(insertion);
106
+ if (removedNodes) {
107
+ this.enqueueTreeReactions(removedNodes, 'disconnectedCallback');
108
+ }
109
+ this.enqueueInsertionReactions(insertion, destinationIsConnected);
110
+ this.performOrCollectHookEffects([...this.collectRemovalHookEffects(oldChild, oldChildIndex), ...this.collectInsertionHookEffects(insertion)], hookEffects);
111
+ return oldChild;
69
112
  }
70
113
  querySelectorAll(selector) {
71
114
  return querySelectorAll(this, selector);
@@ -73,27 +116,111 @@ class ParentNode extends ChildNode {
73
116
  querySelector(selector) {
74
117
  return querySelector(this, selector);
75
118
  }
76
- insertInto(child, before) {
77
- // append the children of a DocumentFragment:
78
- if (child.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE) {
119
+ [INSERT_NODE](child, before, hookEffects) {
120
+ this.validateInsertion(child, before);
121
+ this.insertIntoValidated(child, before, hookEffects);
122
+ return child;
123
+ }
124
+ [PREFLIGHT_INSERTIONS](children) {
125
+ for (const child of children) {
126
+ this.validateInsertion(child, null);
127
+ this.prepareInsertion(child);
128
+ }
129
+ }
130
+ validateInsertion(child, before) {
131
+ validateInsertionNodes(this, [child]);
132
+ if (before && before.parentNode !== this) {
133
+ throw createDOMException('The reference node is not a child of this parent', 'NotFoundError');
134
+ }
135
+ }
136
+ insertIntoValidated(child, before, hookEffects) {
137
+ if (child === before) before = child[NEXT];
138
+ const insertion = this.prepareInsertion(child);
139
+ this.commitInsertion(insertion, before);
140
+ const destinationIsConnected = this[IS_CONNECTED];
141
+ this.queueInsertionMutationRecords(insertion);
142
+ this.enqueueInsertionReactions(insertion, destinationIsConnected);
143
+ this.performOrCollectHookEffects(this.collectInsertionHookEffects(insertion), hookEffects);
144
+ }
145
+ performOrCollectHookEffects(effects, hookEffects) {
146
+ if (hookEffects) hookEffects.push(...effects);else performHookEffects(effects);
147
+ }
148
+ prepareInsertion(child) {
149
+ const roots = [];
150
+ if (child.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT) {
79
151
  let node = child[CHILD];
80
152
  while (node) {
81
- const next = node[NEXT];
82
- this.insertInto(node, before);
83
- node = next;
153
+ roots.push(node);
154
+ node = node[NEXT];
84
155
  }
85
- return;
156
+ } else {
157
+ roots.push(child);
86
158
  }
87
- if (child.parentNode !== null) {
88
- child.parentNode.removeChild(child);
159
+ const destinationIsConnected = this[IS_CONNECTED];
160
+ const ownerDocument = this[OWNER_DOCUMENT];
161
+ const insertion = [];
162
+ for (const node of roots) {
163
+ const wasConnected = node[IS_CONNECTED];
164
+ const shouldTraverse = wasConnected || destinationIsConnected;
165
+ let nodes;
166
+ let adoption;
167
+ if (node[OWNER_DOCUMENT] === ownerDocument) {
168
+ if (shouldTraverse) nodes = selfAndDescendants(node);
169
+ } else {
170
+ const snapshot = collectAdoptionSnapshot(node);
171
+ adoption = snapshot.nodes;
172
+ if (shouldTraverse) nodes = snapshot.treeNodes;
173
+ }
174
+ insertion.push({
175
+ node,
176
+ nodes,
177
+ adoption,
178
+ shouldDisconnect: wasConnected
179
+ });
89
180
  }
90
- if (before) {
91
- if (before.parentNode !== this) {
92
- throw Error('reference node is not a child of this parent');
181
+ return insertion;
182
+ }
183
+ commitInsertion(insertion, before) {
184
+ for (const prepared of insertion) {
185
+ const sourceParent = prepared.node[PARENT];
186
+ if (sourceParent) {
187
+ const previousSibling = prepared.node[PREV];
188
+ const nextSibling = prepared.node[NEXT];
189
+ prepared.source = {
190
+ parent: sourceParent,
191
+ index: detachChild(sourceParent, prepared.node),
192
+ previousSibling,
193
+ nextSibling
194
+ };
93
195
  }
196
+ }
197
+ for (const prepared of insertion) {
198
+ const attached = this.attachChild(prepared.node, before);
199
+ prepared.insertIndex = attached.index;
200
+ prepared.previousSibling = attached.previousSibling;
201
+ prepared.nextSibling = attached.nextSibling;
202
+ }
203
+ const ownerDocument = this[OWNER_DOCUMENT];
204
+ for (const {
205
+ adoption
206
+ } of insertion) {
207
+ if (adoption) adoptNodes(adoption, ownerDocument);
208
+ }
209
+ const isConnected = this[IS_CONNECTED];
210
+ for (const {
211
+ nodes
212
+ } of insertion) {
213
+ if (nodes) {
214
+ for (const node of nodes) node[IS_CONNECTED] = isConnected;
215
+ }
216
+ }
217
+ }
218
+ attachChild(child, before) {
219
+ if (before) {
220
+ const previous = before[PREV];
94
221
  child[NEXT] = before;
95
- child[PREV] = before[PREV];
96
- if (before[PREV] === null) this[CHILD] = child;
222
+ child[PREV] = previous;
223
+ if (previous) previous[NEXT] = child;else this[CHILD] = child;
97
224
  before[PREV] = child;
98
225
  } else {
99
226
  child[NEXT] = null;
@@ -108,40 +235,154 @@ class ParentNode extends ChildNode {
108
235
  child[PREV] = null;
109
236
  }
110
237
  }
111
- const ownerDocument = this[OWNER_DOCUMENT];
112
- const isElement = child.nodeType === NodeType.ELEMENT_NODE;
238
+ const isElement = isElementNode(child);
113
239
  child[PARENT] = this;
114
- child[OWNER_DOCUMENT] = ownerDocument;
115
- const childNodes = this.childNodes;
116
240
  let insertIndex;
117
241
  if (before) {
118
- insertIndex = childNodes.indexOf(before);
119
- childNodes.splice(insertIndex, 0, child);
242
+ insertIndex = this.childNodes.indexOf(before);
243
+ this.childNodes.splice(insertIndex, 0, child);
120
244
  if (isElement) {
121
- const children = this.children;
122
- let ref = before;
123
- while (ref && ref.nodeType !== 1) ref = ref[NEXT];
124
- if (ref) {
125
- children.splice(children.indexOf(ref), 0, child);
245
+ let reference = before;
246
+ while (reference && !isElementNode(reference)) {
247
+ reference = reference[NEXT];
248
+ }
249
+ if (reference) {
250
+ this.children.splice(this.children.indexOf(reference), 0, child);
126
251
  } else {
127
- children.push(child);
252
+ this.children.push(child);
128
253
  }
129
254
  }
130
255
  } else {
131
- insertIndex = childNodes.length;
132
- childNodes.push(child);
256
+ insertIndex = this.childNodes.length;
257
+ this.childNodes.push(child);
133
258
  if (isElement) this.children.push(child);
134
259
  }
135
- if (this[IS_CONNECTED]) {
136
- for (const node of selfAndDescendants(child)) {
137
- node[IS_CONNECTED] = true;
138
- node.connectedCallback?.();
260
+ return {
261
+ index: insertIndex,
262
+ previousSibling: child[PREV],
263
+ nextSibling: child[NEXT]
264
+ };
265
+ }
266
+ queueRemovalMutationRecord(parent, child, previousSibling, nextSibling) {
267
+ if (!childListObserversActive) return;
268
+ queueMutationRecord({
269
+ type: 'childList',
270
+ target: parent,
271
+ removedNodes: mutationNodeList(child),
272
+ previousSibling,
273
+ nextSibling
274
+ });
275
+ }
276
+ queueInsertionMutationRecords(insertion) {
277
+ if (!childListObserversActive) return;
278
+ for (const prepared of insertion) {
279
+ const {
280
+ node,
281
+ source
282
+ } = prepared;
283
+ if (source) {
284
+ this.queueRemovalMutationRecord(source.parent, node, source.previousSibling, source.nextSibling);
285
+ }
286
+ queueMutationRecord({
287
+ type: 'childList',
288
+ target: this,
289
+ addedNodes: mutationNodeList(node),
290
+ previousSibling: prepared.previousSibling,
291
+ nextSibling: prepared.nextSibling
292
+ });
293
+ }
294
+ }
295
+ collectRemovalHookEffects(child, childNodesIndex) {
296
+ if (this.nodeType !== NODE_TYPE_ELEMENT || isCoveredByPendingPublication(this)) {
297
+ return [];
298
+ }
299
+ return [[() => this[HOOKS].removeChild?.(this, child, childNodesIndex)]];
300
+ }
301
+ collectInsertionHookEffects(insertion) {
302
+ const effects = [];
303
+ for (const prepared of insertion) {
304
+ const {
305
+ node,
306
+ source
307
+ } = prepared;
308
+ if (source?.parent.nodeType === NODE_TYPE_ELEMENT && !isCoveredByPendingPublication(source.parent)) {
309
+ effects.push([() => source.parent[HOOKS].removeChild?.(source.parent, node, source.index)]);
310
+ }
311
+ if (this.nodeType === NODE_TYPE_ELEMENT && !isCoveredByPendingPublication(this)) {
312
+ effects.push([() => this[HOOKS].insertChild?.(this, node, prepared.insertIndex), node]);
313
+ }
314
+ }
315
+ return effects;
316
+ }
317
+ enqueueInsertionReactions(insertion, destinationIsConnected) {
318
+ for (const prepared of insertion) {
319
+ const {
320
+ nodes
321
+ } = prepared;
322
+ if (nodes) {
323
+ if (prepared.shouldDisconnect) {
324
+ this.enqueueTreeReactions(nodes, 'disconnectedCallback');
325
+ }
326
+ if (destinationIsConnected) {
327
+ this.enqueueTreeReactions(nodes, 'connectedCallback');
328
+ }
139
329
  }
140
330
  }
141
- if (this.nodeType === NodeType.ELEMENT_NODE) {
142
- this[HOOKS].insertChild?.(this, child, insertIndex);
331
+ }
332
+ enqueueTreeReactions(nodes, callbackName) {
333
+ enqueueTreeReactions(nodes, callbackName);
334
+ }
335
+ }
336
+ function removeChildForAdoption(parent, child, adoption, destination) {
337
+ if (child.parentNode !== parent) throw Error(`not a child of this node`);
338
+ const disconnectedNodes = parent[IS_CONNECTED] ? adoption.treeNodes : undefined;
339
+ const previousSibling = child[PREV];
340
+ const nextSibling = child[NEXT];
341
+ const childNodesIndex = detachChild(parent, child);
342
+ if (disconnectedNodes) {
343
+ for (const node of disconnectedNodes) node[IS_CONNECTED] = false;
344
+ }
345
+ adoptNodes(adoption.nodes, destination);
346
+ if (childListObserversActive) {
347
+ queueMutationRecord({
348
+ type: 'childList',
349
+ target: parent,
350
+ removedNodes: mutationNodeList(child),
351
+ previousSibling,
352
+ nextSibling
353
+ });
354
+ }
355
+ if (disconnectedNodes) {
356
+ enqueueTreeReactions(disconnectedNodes, 'disconnectedCallback');
357
+ }
358
+ const effects = [];
359
+ if (parent.nodeType === NODE_TYPE_ELEMENT && !isCoveredByPendingPublication(parent)) {
360
+ effects.push([() => parent[HOOKS].removeChild?.(parent, child, childNodesIndex)]);
361
+ }
362
+ performHookEffects(effects);
363
+ }
364
+ function detachChild(parent, child) {
365
+ const previous = child[PREV];
366
+ const next = child[NEXT];
367
+ if (previous) previous[NEXT] = next;else parent[CHILD] = next;
368
+ if (next) next[PREV] = previous;
369
+ const childNodesIndex = parent.childNodes.indexOf(child);
370
+ parent.childNodes.splice(childNodesIndex, 1);
371
+ if (isElementNode(child)) {
372
+ parent.children.splice(parent.children.indexOf(child), 1);
373
+ }
374
+ child[PARENT] = null;
375
+ child[NEXT] = null;
376
+ child[PREV] = null;
377
+ return childNodesIndex;
378
+ }
379
+ function enqueueTreeReactions(nodes, callbackName) {
380
+ for (const node of nodes) {
381
+ const callback = node[callbackName];
382
+ if (typeof callback === 'function') {
383
+ enqueueCustomElementReaction(node, () => callback.call(node));
143
384
  }
144
385
  }
145
386
  }
146
387
 
147
- export { ParentNode };
388
+ export { ParentNode, removeChildForAdoption };
@@ -1,8 +1,8 @@
1
- import { NS, NamespaceURI } from './constants.mjs';
1
+ import { SVG_NAMESPACE, NS } from './constants.mjs';
2
2
  import { Element } from './Element.mjs';
3
3
 
4
4
  class SVGElement extends Element {
5
- [NS] = (() => NamespaceURI.SVG)();
5
+ [NS] = SVG_NAMESPACE;
6
6
  get ownerSVGElement() {
7
7
  let root = null;
8
8
  let parent = this.parentNode;
@@ -1,8 +1,8 @@
1
- import { NodeType, NAME } from './constants.mjs';
1
+ import { NODE_TYPE_TEXT, NAME } from './constants.mjs';
2
2
  import { CharacterData } from './CharacterData.mjs';
3
3
 
4
4
  class Text extends CharacterData {
5
- nodeType = (() => NodeType.TEXT_NODE)();
5
+ nodeType = NODE_TYPE_TEXT;
6
6
  [NAME] = '#text';
7
7
  }
8
8