@remote-dom/polyfill 1.5.0 → 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 +94 -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 +7 -3
  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 +15 -3
  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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-set-global.test.d.ts","sourceRoot":"","sources":["../../../source/tests/window-set-global.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "access": "public",
8
8
  "@remote-dom/registry": "https://registry.npmjs.org"
9
9
  },
10
- "version": "1.5.0",
10
+ "version": "1.6.0",
11
11
  "engines": {
12
12
  "node": ">=14.0.0"
13
13
  },
package/source/Attr.ts CHANGED
@@ -4,21 +4,28 @@ import {
4
4
  VALUE,
5
5
  OWNER_ELEMENT,
6
6
  NAME,
7
- NamespaceURI,
8
- NodeType,
7
+ NODE_TYPE_ATTRIBUTE,
8
+ type NamespaceURI,
9
+ type NodeType,
9
10
  HOOKS,
10
11
  } from './constants.ts';
11
12
  import {Node} from './Node.ts';
12
13
  import type {Element} from './Element.ts';
14
+ import {
15
+ attributeObserversActive,
16
+ queueMutationRecord,
17
+ } from './MutationObserver.ts';
18
+ import {enqueueAttributeReaction} from './attribute-reactions.ts';
19
+ import {performWithCustomElementReactions} from './custom-element-reactions.ts';
13
20
 
14
21
  export class Attr extends Node {
15
- nodeType = NodeType.ATTRIBUTE_NODE;
16
- [NS]: NamespaceURI | null = null;
22
+ nodeType: NodeType = NODE_TYPE_ATTRIBUTE;
23
+ [NS]: NamespaceURI = null;
17
24
  [NEXT]: Attr | null = null;
18
25
  [VALUE]: string;
19
26
  [OWNER_ELEMENT]: Element | null = null;
20
27
 
21
- constructor(name: string, value: string, namespace?: NamespaceURI | null) {
28
+ constructor(name: string, value: string, namespace?: NamespaceURI) {
22
29
  super();
23
30
  this[NAME] = name;
24
31
  this[VALUE] = value;
@@ -35,16 +42,61 @@ export class Attr extends Node {
35
42
  }
36
43
 
37
44
  set name(_readonly: string) {}
45
+
46
+ get localName() {
47
+ if (this[NS] == null) return this[NAME];
48
+
49
+ const separator = this[NAME].indexOf(':');
50
+ return separator < 0 ? this[NAME] : this[NAME].slice(separator + 1);
51
+ }
52
+
53
+ get prefix() {
54
+ if (this[NS] == null) return null;
55
+
56
+ const separator = this[NAME].indexOf(':');
57
+ return separator < 0 ? null : this[NAME].slice(0, separator);
58
+ }
38
59
  get value() {
39
60
  return this[VALUE];
40
61
  }
41
62
 
42
63
  set value(value: string) {
43
64
  const str = String(value);
44
- this[VALUE] = str;
45
65
  const ownerElement = this[OWNER_ELEMENT];
46
- if (!ownerElement) return;
47
- this[HOOKS].setAttribute?.(ownerElement as any, this[NAME], str, this[NS]);
66
+
67
+ if (!ownerElement) {
68
+ this[VALUE] = str;
69
+ return;
70
+ }
71
+
72
+ performWithCustomElementReactions(() => {
73
+ const oldValue = this[VALUE];
74
+ this[VALUE] = str;
75
+
76
+ if (attributeObserversActive && oldValue !== str) {
77
+ queueMutationRecord({
78
+ type: 'attributes',
79
+ target: ownerElement,
80
+ attributeName: this[NAME],
81
+ attributeNamespace: this[NS],
82
+ oldValue,
83
+ });
84
+ }
85
+
86
+ this[HOOKS].setAttribute?.(
87
+ ownerElement as any,
88
+ this[NAME],
89
+ str,
90
+ this[NS],
91
+ );
92
+ enqueueAttributeReaction(
93
+ ownerElement,
94
+ this.localName,
95
+ oldValue,
96
+ str,
97
+ this[NS],
98
+ );
99
+ });
48
100
  }
49
101
 
50
102
  get nodeValue() {
@@ -1,5 +1,9 @@
1
1
  import {DATA, HOOKS} from './constants.ts';
2
2
  import {ChildNode} from './ChildNode.ts';
3
+ import {
4
+ characterDataObserversActive,
5
+ queueMutationRecord,
6
+ } from './MutationObserver.ts';
3
7
 
4
8
  export class CharacterData extends ChildNode {
5
9
  [DATA] = '';
@@ -10,11 +14,20 @@ export class CharacterData extends ChildNode {
10
14
  }
11
15
 
12
16
  protected setData(data: any) {
17
+ const shouldQueueMutation = characterDataObserversActive;
18
+ const oldValue = shouldQueueMutation ? this[DATA] : null;
13
19
  let str = '';
14
20
  if (data != null) {
15
21
  str = typeof data === 'string' ? data : String(data);
16
22
  }
17
23
  this[DATA] = str;
24
+ if (shouldQueueMutation && oldValue !== str) {
25
+ queueMutationRecord({
26
+ type: 'characterData',
27
+ target: this,
28
+ oldValue,
29
+ });
30
+ }
18
31
  this[HOOKS].setText?.(this as any, str);
19
32
  }
20
33
 
@@ -1,7 +1,14 @@
1
- import {NEXT} from './constants.ts';
1
+ import {HOST, NEXT, PARENT, PREV} from './constants.ts';
2
+ import {performWithCustomElementReactions} from './custom-element-reactions.ts';
3
+ import {performHookEffects, type HookEffect} from './hook-effects.ts';
4
+ import {createDOMException} from './dom-exception.ts';
2
5
  import type {ParentNode} from './ParentNode.ts';
3
6
  import {Node} from './Node.ts';
4
7
 
8
+ export const INSERT_NODE = Symbol('insertNode');
9
+ export const PREFLIGHT_INSERTIONS = Symbol('preflightInsertions');
10
+ export const REPLACE_NODE = Symbol('replaceNode');
11
+
5
12
  export class ChildNode extends Node {
6
13
  remove() {
7
14
  const parent = this.parentNode;
@@ -10,36 +17,122 @@ export class ChildNode extends Node {
10
17
  }
11
18
 
12
19
  replaceWith(...nodes: (Node | string)[]) {
20
+ const staged = stageNodes(nodes);
13
21
  const parent = this.parentNode;
14
22
  if (!parent) return;
15
- const node = toNode(parent, nodes[0]);
16
- const next = node[NEXT];
17
- parent.replaceChild(this, node);
18
- for (let i = 1; i < nodes.length; i++) {
19
- parent.insertBefore(toNode(parent, nodes[i]), next);
20
- }
23
+
24
+ return performChildNodeMutation((hookEffects) => {
25
+ validateInsertionNodes(parent, staged);
26
+
27
+ let next = this[NEXT];
28
+ while (next && staged.includes(next)) next = next[NEXT];
29
+
30
+ const replacement = convertNodesIntoNode(parent, staged, hookEffects);
31
+ if (this.parentNode === parent) {
32
+ parent[REPLACE_NODE](replacement, this, hookEffects);
33
+ } else {
34
+ parent[INSERT_NODE](replacement, next, hookEffects);
35
+ }
36
+ });
21
37
  }
22
38
 
23
39
  before(...nodes: (Node | string)[]) {
40
+ const staged = stageNodes(nodes);
24
41
  const parent = this.parentNode;
25
42
  if (!parent) return;
26
- for (const node of nodes) {
27
- parent.insertBefore(toNode(parent, node), this);
28
- }
43
+
44
+ return performChildNodeMutation((hookEffects) => {
45
+ validateInsertionNodes(parent, staged);
46
+
47
+ let previous = this[PREV];
48
+ while (previous && staged.includes(previous)) previous = previous[PREV];
49
+
50
+ const node = convertNodesIntoNode(parent, staged, hookEffects);
51
+ parent[INSERT_NODE](
52
+ node,
53
+ previous ? previous[NEXT] : parent.firstChild,
54
+ hookEffects,
55
+ );
56
+ });
29
57
  }
30
58
 
31
59
  after(...nodes: (Node | string)[]) {
60
+ const staged = stageNodes(nodes);
32
61
  const parent = this.parentNode;
33
62
  if (!parent) return;
34
- const next = this[NEXT];
35
- for (const node of nodes) {
36
- parent.insertBefore(toNode(parent, node), next);
37
- }
63
+
64
+ return performChildNodeMutation((hookEffects) => {
65
+ validateInsertionNodes(parent, staged);
66
+
67
+ let next = this[NEXT];
68
+ while (next && staged.includes(next)) next = next[NEXT];
69
+
70
+ const node = convertNodesIntoNode(parent, staged, hookEffects);
71
+ parent[INSERT_NODE](node, next, hookEffects);
72
+ });
38
73
  }
39
74
  }
40
75
 
76
+ function performChildNodeMutation(
77
+ mutation: (hookEffects: HookEffect[]) => void,
78
+ ) {
79
+ return performWithCustomElementReactions(() => {
80
+ const hookEffects: HookEffect[] = [];
81
+ try {
82
+ mutation(hookEffects);
83
+ } catch (error) {
84
+ try {
85
+ performHookEffects(hookEffects);
86
+ } catch {}
87
+ throw error;
88
+ }
89
+ performHookEffects(hookEffects);
90
+ });
91
+ }
92
+
93
+ export function stageNodes(nodes: (Node | string)[]) {
94
+ return nodes.map((node) => (node instanceof Node ? node : String(node)));
95
+ }
96
+
41
97
  export function toNode(parent: ParentNode, node: Node | any) {
42
98
  if (node instanceof Node) return node;
43
99
  const ownerDocument = parent.ownerDocument;
44
100
  return ownerDocument.createTextNode(String(node));
45
101
  }
102
+
103
+ export function validateInsertionNodes(
104
+ parent: ParentNode,
105
+ nodes: (Node | string)[],
106
+ ) {
107
+ for (const node of nodes) {
108
+ if (!(node instanceof Node)) continue;
109
+
110
+ let ancestor: Node | null = parent;
111
+ while (ancestor) {
112
+ if (ancestor === node) {
113
+ throw createDOMException(
114
+ 'Cannot insert a node into itself or one of its descendants',
115
+ 'HierarchyRequestError',
116
+ );
117
+ }
118
+ ancestor = ancestor[PARENT] ?? ancestor[HOST];
119
+ }
120
+ }
121
+ }
122
+
123
+ function convertNodesIntoNode(
124
+ parent: ParentNode,
125
+ nodes: (Node | string)[],
126
+ hookEffects: HookEffect[],
127
+ ): Node {
128
+ const convertedNodes: Node[] = [];
129
+ for (const node of nodes) convertedNodes.push(toNode(parent, node));
130
+ if (convertedNodes.length === 1) return convertedNodes[0]!;
131
+
132
+ const fragment = parent.ownerDocument.createDocumentFragment();
133
+ fragment[PREFLIGHT_INSERTIONS](convertedNodes);
134
+ for (const node of convertedNodes) {
135
+ fragment[INSERT_NODE](node, null, hookEffects);
136
+ }
137
+ return fragment;
138
+ }
package/source/Comment.ts CHANGED
@@ -1,7 +1,7 @@
1
- import {NAME} from './constants.ts';
1
+ import {NAME, NODE_TYPE_COMMENT, type NodeType} from './constants.ts';
2
2
  import {CharacterData} from './CharacterData.ts';
3
3
 
4
4
  export class Comment extends CharacterData {
5
- nodeType = 8;
5
+ nodeType: NodeType = NODE_TYPE_COMMENT;
6
6
  [NAME] = '#comment';
7
7
  }
@@ -1,3 +1,33 @@
1
+ import {createDOMException} from './dom-exception.ts';
2
+
3
+ const VALID_CUSTOM_ELEMENT_NAME =
4
+ /^[a-z][^A-Z\u0000\t\n\f\r />]*-[^A-Z\u0000\t\n\f\r />]*$/u;
5
+
6
+ const RESERVED_CUSTOM_ELEMENT_NAMES = new Set([
7
+ 'annotation-xml',
8
+ 'color-profile',
9
+ 'font-face',
10
+ 'font-face-src',
11
+ 'font-face-uri',
12
+ 'font-face-format',
13
+ 'font-face-name',
14
+ 'missing-glyph',
15
+ ]);
16
+
17
+ function isValidCustomElementName(name: string) {
18
+ return (
19
+ VALID_CUSTOM_ELEMENT_NAME.test(name) &&
20
+ !RESERVED_CUSTOM_ELEMENT_NAMES.has(name)
21
+ );
22
+ }
23
+
24
+ function createInvalidCustomElementNameError(name: string) {
25
+ return createDOMException(
26
+ `Invalid custom element name: "${name}"`,
27
+ 'SyntaxError',
28
+ );
29
+ }
30
+
1
31
  export class CustomElementRegistryImplementation
2
32
  implements CustomElementRegistry
3
33
  {
@@ -12,6 +42,24 @@ export class CustomElementRegistryImplementation
12
42
  Constructor: CustomElementConstructor,
13
43
  _options?: ElementDefinitionOptions,
14
44
  ) {
45
+ if (!isValidCustomElementName(name)) {
46
+ throw createInvalidCustomElementNameError(name);
47
+ }
48
+
49
+ if (this.registry.has(name)) {
50
+ throw createDOMException(
51
+ `A custom element named "${name}" has already been defined`,
52
+ 'NotSupportedError',
53
+ );
54
+ }
55
+
56
+ if (this.getName(Constructor) != null) {
57
+ throw createDOMException(
58
+ 'This constructor has already been registered in this custom element registry',
59
+ 'NotSupportedError',
60
+ );
61
+ }
62
+
15
63
  this.registry.set(name, Constructor);
16
64
 
17
65
  const listeners = this.listenersByName.get(name);
@@ -38,6 +86,10 @@ export class CustomElementRegistryImplementation
38
86
  }
39
87
 
40
88
  whenDefined(name: string) {
89
+ if (!isValidCustomElementName(name)) {
90
+ return Promise.reject(createInvalidCustomElementNameError(name));
91
+ }
92
+
41
93
  const Constructor = this.registry.get(name);
42
94
 
43
95
  if (Constructor != null) return Promise.resolve(Constructor);
@@ -57,4 +109,8 @@ export class CustomElementRegistryImplementation
57
109
  upgrade(_root: Node) {
58
110
  // TODO
59
111
  }
112
+
113
+ initialize(_root: Node) {
114
+ // TODO
115
+ }
60
116
  }
@@ -10,7 +10,7 @@ export class CustomEvent<T = any> extends Event {
10
10
 
11
11
  constructor(type: string, eventInitDict?: CustomEventInit<T>) {
12
12
  super(type, eventInitDict);
13
- this.detail = eventInitDict?.detail as any;
13
+ this.detail = (eventInitDict?.detail ?? null) as any;
14
14
  }
15
15
 
16
16
  /**
@@ -25,6 +25,6 @@ export class CustomEvent<T = any> extends Event {
25
25
  detail?: T,
26
26
  ) {
27
27
  super.initEvent(type, bubbles, cancelable);
28
- (this as any).detail = detail;
28
+ (this as any).detail = detail ?? null;
29
29
  }
30
30
  }
@@ -1,29 +1,48 @@
1
1
  import {
2
2
  NS,
3
3
  NAME,
4
- NamespaceURI,
5
- NodeType,
4
+ PREFIX,
5
+ NODE_TYPE_DOCUMENT,
6
+ HTML_NAMESPACE,
7
+ SVG_NAMESPACE,
8
+ type NamespaceURI,
9
+ type NodeType,
6
10
  OWNER_DOCUMENT,
7
11
  HOOKS,
8
12
  IS_CONNECTED,
13
+ CREATE_ELEMENT,
14
+ asciiLowercase,
9
15
  } from './constants.ts';
16
+ import {
17
+ validateAndExtractQualifiedName,
18
+ validateElementLocalName,
19
+ } from './names.ts';
10
20
  import type {Window} from './Window.ts';
11
21
  import type {Node} from './Node.ts';
12
22
  import {Event} from './Event.ts';
13
- import {ParentNode} from './ParentNode.ts';
23
+ import {ParentNode, removeChildForAdoption} from './ParentNode.ts';
14
24
  import {Element} from './Element.ts';
15
25
  import {SVGElement} from './SVGElement.ts';
16
26
  import {Text} from './Text.ts';
17
27
  import {Comment} from './Comment.ts';
18
28
  import {DocumentFragment} from './DocumentFragment.ts';
19
29
  import {HTMLTemplateElement} from './HTMLTemplateElement.ts';
20
- import {isParentNode, cloneNode} from './shared.ts';
30
+ import {
31
+ adoptNodes,
32
+ cloneNode,
33
+ collectAdoptionSnapshot,
34
+ getElementById as findElementById,
35
+ getElementsByClassName as findElementsByClassName,
36
+ getElementsByTagName as findElementsByTagName,
37
+ } from './shared.ts';
21
38
  import {HTMLBodyElement} from './HTMLBodyElement.ts';
22
39
  import {HTMLHeadElement} from './HTMLHeadElement.ts';
23
40
  import {HTMLHtmlElement} from './HTMLHtmlElement.ts';
41
+ import {performWithCustomElementReactions} from './custom-element-reactions.ts';
42
+ import {createDOMException} from './dom-exception.ts';
24
43
 
25
44
  export class Document extends ParentNode {
26
- nodeType = NodeType.DOCUMENT_NODE;
45
+ nodeType: NodeType = NODE_TYPE_DOCUMENT;
27
46
  [NAME] = '#document';
28
47
  body: HTMLBodyElement;
29
48
  head: HTMLHeadElement;
@@ -44,17 +63,51 @@ export class Document extends ParentNode {
44
63
  this.documentElement.appendChild(this.body);
45
64
  }
46
65
 
66
+ get textContent(): string | null {
67
+ return null;
68
+ }
69
+
70
+ set textContent(data: any) {
71
+ if (data != null) void `${data}`;
72
+ }
73
+
74
+ getElementsByClassName(classNames: string) {
75
+ return findElementsByClassName(this, classNames);
76
+ }
77
+
47
78
  createElement(localName: string) {
48
- return createElement(this, localName);
79
+ const name = String(localName);
80
+ validateElementLocalName(name);
81
+ return createElement(this, asciiLowercase(name));
82
+ }
83
+
84
+ createElementNS(namespaceURI: NamespaceURI, qualifiedName: string) {
85
+ const name = validateAndExtractQualifiedName(
86
+ namespaceURI,
87
+ qualifiedName,
88
+ 'element',
89
+ );
90
+ return createElement(
91
+ this,
92
+ name.qualifiedName,
93
+ name.namespace,
94
+ name.prefix,
95
+ name.localName,
96
+ );
49
97
  }
50
98
 
51
- createElementNS(namespaceURI: NamespaceURI, localName: string) {
52
- return createElement(this, localName, namespaceURI);
99
+ [CREATE_ELEMENT](
100
+ qualifiedName: string,
101
+ namespace: NamespaceURI,
102
+ prefix: string | null,
103
+ localName: string,
104
+ ) {
105
+ return createElement(this, qualifiedName, namespace, prefix, localName);
53
106
  }
54
107
 
55
108
  createTextNode(data: any) {
56
109
  const text = createNode(new Text(data), this);
57
- this[HOOKS].createText?.(text as any, String(data));
110
+ this[HOOKS].createText?.(text as any, text.data);
58
111
  return text;
59
112
  }
60
113
 
@@ -70,17 +123,35 @@ export class Document extends ParentNode {
70
123
  return new Event('');
71
124
  }
72
125
 
126
+ getElementById(elementId: string) {
127
+ return findElementById(this, elementId);
128
+ }
129
+
130
+ getElementsByTagName(qualifiedName: string) {
131
+ return findElementsByTagName(this, qualifiedName);
132
+ }
133
+
73
134
  importNode(node: Node, deep?: boolean) {
135
+ if (node.nodeType === NODE_TYPE_DOCUMENT) {
136
+ throw createDOMException(
137
+ 'Cannot import a document node',
138
+ 'NotSupportedError',
139
+ );
140
+ }
141
+
74
142
  return cloneNode(node, deep, this);
75
143
  }
76
144
 
77
145
  adoptNode(node: Node) {
78
146
  if (node[OWNER_DOCUMENT] === this) return node;
79
147
 
80
- node.parentNode?.removeChild(node);
81
- adoptNode(node, this);
82
-
83
- return node;
148
+ const adoption = collectAdoptionSnapshot(node);
149
+ return performWithCustomElementReactions(() => {
150
+ const parent = node.parentNode;
151
+ if (parent) removeChildForAdoption(parent, node, adoption, this);
152
+ else adoptNodes(adoption.nodes, this);
153
+ return node;
154
+ });
84
155
  }
85
156
  }
86
157
 
@@ -96,49 +167,44 @@ export function createNode<T extends Node>(node: T, ownerDocument: Document) {
96
167
 
97
168
  export function createElement<T extends Element>(
98
169
  ownerDocument: Document,
99
- name: string,
100
- namespace?: NamespaceURI,
170
+ qualifiedName: string,
171
+ namespace: NamespaceURI = HTML_NAMESPACE,
172
+ prefix: string | null = null,
173
+ localName = qualifiedName,
101
174
  ) {
102
175
  let element: T;
103
- const lowerName = String(name).toLowerCase();
104
176
 
105
- if (namespace === NamespaceURI.SVG) {
177
+ if (namespace === SVG_NAMESPACE) {
106
178
  element = new SVGElement() as any;
107
- } else if (lowerName === 'template') {
179
+ } else if (namespace === HTML_NAMESPACE && localName === 'template') {
108
180
  element = new HTMLTemplateElement() as any;
109
- } else {
110
- const CustomElement = ownerDocument.defaultView.customElements.get(name);
181
+ } else if (namespace === HTML_NAMESPACE) {
182
+ const CustomElement =
183
+ ownerDocument.defaultView.customElements.get(localName);
111
184
  element = CustomElement ? (new CustomElement() as any) : new Element();
185
+ } else {
186
+ element = new Element() as any;
112
187
  }
113
188
 
114
- return setupElement(element, ownerDocument, name, namespace);
189
+ return setupElement(element, ownerDocument, qualifiedName, namespace, prefix);
115
190
  }
116
191
 
117
192
  export function setupElement<T extends Element>(
118
193
  element: T,
119
194
  ownerDocument: Document,
120
- name: string,
121
- namespace?: NamespaceURI,
195
+ qualifiedName: string,
196
+ namespace: NamespaceURI = HTML_NAMESPACE,
197
+ prefix: string | null = null,
122
198
  ) {
123
199
  createNode(element, ownerDocument);
124
200
 
125
- Object.defineProperty(element, NAME, {value: name});
126
-
127
- if (namespace) {
128
- Object.defineProperty(element, NS, {value: namespace});
129
- }
201
+ Object.defineProperties(element, {
202
+ [NAME]: {value: qualifiedName},
203
+ [NS]: {value: namespace},
204
+ [PREFIX]: {value: prefix},
205
+ });
130
206
 
131
207
  ownerDocument[HOOKS].createElement?.(element as any, namespace);
132
208
 
133
209
  return element;
134
210
  }
135
-
136
- export function adoptNode(node: Node, document: Document) {
137
- node[OWNER_DOCUMENT] = document;
138
-
139
- if (isParentNode(node)) {
140
- for (const child of node.childNodes) {
141
- adoptNode(child, document);
142
- }
143
- }
144
- }
@@ -1,8 +1,20 @@
1
- import {NAME, OWNER_DOCUMENT, NodeType} from './constants.ts';
1
+ import {
2
+ NAME,
3
+ OWNER_DOCUMENT,
4
+ NODE_TYPE_DOCUMENT_FRAGMENT,
5
+ type NodeType,
6
+ } from './constants.ts';
2
7
  import {ParentNode} from './ParentNode.ts';
8
+ import {getElementById as findElementById} from './shared.ts';
3
9
 
4
10
  export class DocumentFragment extends ParentNode {
5
- nodeType = NodeType.DOCUMENT_FRAGMENT_NODE;
11
+ nodeType: NodeType = NODE_TYPE_DOCUMENT_FRAGMENT;
6
12
  [NAME] = '#document-fragment';
7
- [OWNER_DOCUMENT] = window.document as any;
13
+ [OWNER_DOCUMENT] = (typeof window !== 'undefined'
14
+ ? window.document
15
+ : null) as any;
16
+
17
+ getElementById(elementId: string) {
18
+ return findElementById(this, elementId);
19
+ }
8
20
  }