@mml-io/observable-dom 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # Observable DOM
2
+ #### `@mml-io/observable-dom`
3
+
4
+ [![npm version](https://img.shields.io/npm/v/@mml-io/observable-dom.svg?style=flat)](https://www.npmjs.com/package/@mml-io/observable-dom)
5
+
6
+ This package is the core of the NetworkedDOM system. It provides classes that can execute HTML documents (including JavaScript) and emit messages that describe the changes to the DOM.
7
+
8
+ It is designed to be used in a message-passing system, where the messages are sent to a remote client that can apply the changes to a local DOM to keep it in sync with the remote DOM.
9
+
10
+ It is also capable of diffing the changes between the last state of a DOM and a current/new state of a DOM, and describing only necessary changes to make to reach the new state.
11
+
12
+ ## Classes
13
+
14
+ * `ObservableDOM`
15
+ * A class that can execute HTML documents using a provided `DOMRunnerInterface` / `DOMRunnerFactory` and emit messages that describe the changes to the DOM.
16
+ * Can apply events to the DOM.
17
+ * `JSDOMRunner` / `JSDOMRunnerFactory`
18
+ * A class that implements the `DOMRunnerInterface` / `DOMRunnerFactory` and uses `jsdom` to execute HTML documents.
@@ -1,4 +1,4 @@
1
- import { RemoteEvent } from "@mml-io/observable-dom-common";
1
+ import { ObservableDOMRemoteEvent } from "@mml-io/observable-dom-common";
2
2
  import { DOMWindow } from "jsdom";
3
3
  import { DOMRunnerFactory, DOMRunnerInterface, DOMRunnerMessage } from "./ObservableDOM";
4
4
  export declare const JSDOMRunnerFactory: DOMRunnerFactory;
@@ -28,6 +28,6 @@ export declare class JSDOMRunner implements DOMRunnerInterface {
28
28
  getWindow(): any;
29
29
  dispose(): void;
30
30
  getDocumentTime(): number;
31
- dispatchRemoteEventFromConnectionId(connectionId: number, domNode: Element, remoteEvent: RemoteEvent): void;
31
+ dispatchRemoteEventFromConnectionId(connectionId: number, domNode: Element, remoteEvent: ObservableDOMRemoteEvent): void;
32
32
  private createVirtualConsole;
33
33
  }
@@ -1,4 +1,4 @@
1
- import { LogMessage, ObservableDOMInterface, ObservableDOMMessage, ObservableDOMParameters, RemoteEvent, StaticVirtualDOMElement } from "@mml-io/observable-dom-common";
1
+ import { LogMessage, ObservableDOMInterface, ObservableDOMMessage, ObservableDOMParameters, ObservableDOMRemoteEvent, StaticVirtualDOMElement } from "@mml-io/observable-dom-common";
2
2
  export type DOMRunnerMessage = {
3
3
  loaded?: boolean;
4
4
  mutationList?: Array<MutationRecord>;
@@ -12,7 +12,7 @@ export type DOMRunnerInterface = {
12
12
  HTMLScriptElement: typeof HTMLScriptElement;
13
13
  Comment: typeof Comment;
14
14
  };
15
- dispatchRemoteEventFromConnectionId(connectionId: number, realElement: Element, remoteEvent: RemoteEvent): void;
15
+ dispatchRemoteEventFromConnectionId(connectionId: number, realElement: Element, remoteEvent: ObservableDOMRemoteEvent): void;
16
16
  dispose(): void;
17
17
  getDocumentTime(): number;
18
18
  };
@@ -42,13 +42,14 @@ export declare class ObservableDOM implements ObservableDOMInterface {
42
42
  addConnectedUserId(connectionId: number): void;
43
43
  removeConnectedUserId(connectionId: number): void;
44
44
  private processModificationList;
45
+ private createMutationRecord;
45
46
  private removeVirtualDOMElement;
46
47
  private createVirtualDOMElementWithChildren;
47
48
  private createVirtualDOMElement;
48
49
  private getVirtualDOMElementForRealElementOrThrow;
49
50
  private isIgnoredElement;
50
51
  private isIgnoredAttribute;
51
- dispatchRemoteEventFromConnectionId(connectionId: number, remoteEvent: RemoteEvent): void;
52
+ dispatchRemoteEventFromConnectionId(connectionId: number, remoteEvent: ObservableDOMRemoteEvent): void;
52
53
  dispose(): void;
53
54
  private getDocumentTime;
54
55
  }
package/build/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./ObservableDOM";
2
1
  export * from "./JSDOMRunner";
2
+ export * from "./ObservableDOM";
package/build/index.js CHANGED
@@ -1,9 +1,196 @@
1
+ // src/JSDOMRunner.ts
2
+ import {
3
+ JSDOM,
4
+ ResourceLoader,
5
+ VirtualConsole
6
+ } from "jsdom";
7
+ import * as nodeFetch from "node-fetch";
8
+ import nodeFetchFn from "node-fetch";
9
+ import vm from "vm";
10
+ var ErrDOMWindowNotInitialized = "DOMWindow not initialized";
11
+ var JSDOMRunnerFactory = (htmlPath, htmlContents, params, callback) => {
12
+ return new JSDOMRunner(htmlPath, htmlContents, params, callback);
13
+ };
14
+ var RejectionResourceLoader = class extends ResourceLoader {
15
+ fetch(url) {
16
+ console.error("RejectionResourceLoader.fetch", url);
17
+ return null;
18
+ }
19
+ };
20
+ var AllowListResourceLoader = class extends ResourceLoader {
21
+ constructor(urls, opts) {
22
+ super(opts);
23
+ this.urls = urls;
24
+ }
25
+ fetch(url, opts) {
26
+ const allow = this.urls.some((allowedURL) => {
27
+ return typeof allowedURL === "string" ? allowedURL === url : allowedURL.test(url);
28
+ });
29
+ if (allow) {
30
+ return super.fetch(url, opts ?? {});
31
+ }
32
+ console.error("AllowListResourceLoader.fetch: resource not allowed", url);
33
+ return null;
34
+ }
35
+ };
36
+ var JSDOMRunner = class {
37
+ constructor(htmlPath, htmlContents, params, callback, { allowResourceLoading } = { allowResourceLoading: false }) {
38
+ this.domWindow = null;
39
+ this.mutationObserver = null;
40
+ this.documentStartTime = Date.now();
41
+ this.isLoaded = false;
42
+ this.logBuffer = [];
43
+ this.htmlPath = htmlPath;
44
+ this.callback = callback;
45
+ const resources = Array.isArray(allowResourceLoading) ? new AllowListResourceLoader(allowResourceLoading) : allowResourceLoading ? "usable" : new RejectionResourceLoader();
46
+ this.jsdom = new JSDOM(htmlContents, {
47
+ runScripts: "dangerously",
48
+ resources,
49
+ url: this.htmlPath,
50
+ virtualConsole: this.createVirtualConsole(),
51
+ beforeParse: (window) => {
52
+ this.domWindow = window;
53
+ this.domWindow.fetch = nodeFetchFn;
54
+ this.domWindow.Headers = nodeFetch.Headers;
55
+ this.domWindow.Request = nodeFetch.Request;
56
+ this.domWindow.Response = nodeFetch.Response;
57
+ const timeline = {};
58
+ Object.defineProperty(timeline, "currentTime", {
59
+ get: () => {
60
+ return this.getDocumentTime();
61
+ }
62
+ });
63
+ window.document.timeline = timeline;
64
+ window.params = JSON.parse(JSON.stringify(params));
65
+ this.mutationObserver = new window.MutationObserver((mutationList) => {
66
+ this.callback({
67
+ mutationList
68
+ });
69
+ });
70
+ window.addEventListener("load", () => {
71
+ var _a;
72
+ (_a = this.mutationObserver) == null ? void 0 : _a.observe(window.document, {
73
+ attributes: true,
74
+ childList: true,
75
+ subtree: true,
76
+ characterData: true
77
+ });
78
+ this.isLoaded = true;
79
+ this.callback({
80
+ loaded: true
81
+ });
82
+ this.flushLogBuffer();
83
+ });
84
+ }
85
+ });
86
+ }
87
+ flushLogBuffer() {
88
+ for (const logMessage of this.logBuffer) {
89
+ this.callback({
90
+ logMessage
91
+ });
92
+ }
93
+ this.logBuffer = [];
94
+ }
95
+ log(message) {
96
+ if (!this.isLoaded) {
97
+ this.logBuffer.push(message);
98
+ return;
99
+ }
100
+ this.callback({
101
+ logMessage: message
102
+ });
103
+ }
104
+ getDocument() {
105
+ if (!this.domWindow) {
106
+ throw new Error(ErrDOMWindowNotInitialized);
107
+ }
108
+ return this.domWindow.document;
109
+ }
110
+ getWindow() {
111
+ return this.domWindow;
112
+ }
113
+ dispose() {
114
+ var _a, _b;
115
+ const records = (_a = this.mutationObserver) == null ? void 0 : _a.takeRecords();
116
+ this.callback({
117
+ mutationList: records
118
+ });
119
+ (_b = this.mutationObserver) == null ? void 0 : _b.disconnect();
120
+ this.jsdom.window.close();
121
+ }
122
+ getDocumentTime() {
123
+ return Date.now() - this.documentStartTime;
124
+ }
125
+ dispatchRemoteEventFromConnectionId(connectionId, domNode, remoteEvent) {
126
+ if (!this.domWindow) {
127
+ throw new Error(ErrDOMWindowNotInitialized);
128
+ }
129
+ const bubbles = remoteEvent.bubbles || false;
130
+ const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {
131
+ bubbles,
132
+ detail: { ...remoteEvent.params, connectionId }
133
+ });
134
+ const eventTypeLowerCase = remoteEvent.name.toLowerCase();
135
+ if (eventTypeLowerCase !== "click") {
136
+ const handlerAttributeName = "on" + eventTypeLowerCase;
137
+ const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);
138
+ if (handlerAttributeValue) {
139
+ const script = handlerAttributeValue;
140
+ const vmContext = this.jsdom.getInternalVMContext();
141
+ try {
142
+ const invoke = vm.runInContext(`(function(event){ ${script} })`, vmContext);
143
+ Reflect.apply(invoke, domNode, [remoteEventObject]);
144
+ } catch (e) {
145
+ console.error("Error running event handler:", e);
146
+ }
147
+ }
148
+ }
149
+ domNode.dispatchEvent(remoteEventObject);
150
+ }
151
+ createVirtualConsole() {
152
+ const virtualConsole = new VirtualConsole();
153
+ virtualConsole.on("jsdomError", (...args) => {
154
+ this.log({
155
+ level: "system",
156
+ content: args
157
+ });
158
+ });
159
+ virtualConsole.on("error", (...args) => {
160
+ this.log({
161
+ level: "error",
162
+ content: args
163
+ });
164
+ });
165
+ virtualConsole.on("warn", (...args) => {
166
+ this.log({
167
+ level: "warn",
168
+ content: args
169
+ });
170
+ });
171
+ virtualConsole.on("log", (...args) => {
172
+ this.log({
173
+ level: "log",
174
+ content: args
175
+ });
176
+ });
177
+ virtualConsole.on("info", (...args) => {
178
+ this.log({
179
+ level: "info",
180
+ content: args
181
+ });
182
+ });
183
+ return virtualConsole;
184
+ }
185
+ };
186
+
1
187
  // src/utils.ts
2
188
  function virtualDOMElementToStatic(el) {
3
189
  return {
4
190
  nodeId: el.nodeId,
5
191
  tag: el.tag,
6
- attributes: el.attributes,
192
+ attributes: Object.assign({}, el.attributes),
193
+ // Copy the attributes object - shallow copy is fine as the attributes are strings
7
194
  childNodes: el.childNodes.map((child) => virtualDOMElementToStatic(child)),
8
195
  textContent: el.textContent
9
196
  };
@@ -96,126 +283,147 @@ var ObservableDOM = class {
96
283
  );
97
284
  }
98
285
  processModificationList(mutationList) {
99
- const documentEl = this.domRunner.getDocument();
100
- const documentVirtualDOMElement = this.realElementToVirtualElement.get(documentEl);
101
- if (!documentVirtualDOMElement) {
102
- throw new Error(`document not created in processModificationList`);
103
- }
104
286
  if (mutationList.length > 1) {
105
287
  }
288
+ const allMutationRecords = [];
106
289
  for (const mutation of mutationList) {
107
- if (this.isIgnoredElement(mutation.target)) {
108
- continue;
290
+ const idsRecord = this.createMutationRecord(mutation);
291
+ if (idsRecord) {
292
+ allMutationRecords.push(idsRecord);
109
293
  }
110
- if (mutation.type === "attributes" && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
111
- this.isIgnoredAttribute(mutation.target, mutation.attributeName)) {
112
- continue;
113
- }
114
- const targetNode = mutation.target;
115
- const targetElement = this.realElementToVirtualElement.get(targetNode);
116
- if (!targetElement) {
117
- throw new Error("Unknown node:" + targetNode + "," + mutation.type);
118
- }
119
- let previousSiblingElement = null;
120
- let insertionIndex = 0;
121
- const toAdd = [];
122
- const removedNodeIds = [];
123
- if (mutation.type === "childList") {
124
- mutation.removedNodes.forEach((node) => {
125
- const asElementOrText = node;
126
- if (this.isIgnoredElement(asElementOrText)) {
127
- return;
128
- }
129
- const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);
130
- if (!childDOMElement) {
131
- return;
294
+ }
295
+ if (allMutationRecords.length > 0) {
296
+ this.callback(
297
+ {
298
+ mutations: allMutationRecords,
299
+ documentTime: this.getDocumentTime()
300
+ },
301
+ this
302
+ );
303
+ }
304
+ }
305
+ createMutationRecord(mutation) {
306
+ if (this.isIgnoredElement(mutation.target)) {
307
+ return null;
308
+ }
309
+ if (mutation.type === "attributes" && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
310
+ this.isIgnoredAttribute(mutation.target, mutation.attributeName)) {
311
+ return null;
312
+ }
313
+ const targetNode = mutation.target;
314
+ const targetElement = this.realElementToVirtualElement.get(targetNode);
315
+ if (!targetElement) {
316
+ return null;
317
+ }
318
+ let previousSiblingElement = null;
319
+ let insertionIndex = 0;
320
+ const toAdd = [];
321
+ const removedNodeIds = [];
322
+ if (mutation.type === "childList") {
323
+ mutation.removedNodes.forEach((node) => {
324
+ const asElementOrText = node;
325
+ if (this.isIgnoredElement(asElementOrText)) {
326
+ return;
327
+ }
328
+ const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);
329
+ if (!childDOMElement) {
330
+ return;
331
+ } else {
332
+ const index = targetElement.childNodes.indexOf(childDOMElement);
333
+ if (index === -1) {
132
334
  } else {
133
- const index = targetElement.childNodes.indexOf(childDOMElement);
134
- if (index === -1) {
335
+ this.removeVirtualDOMElement(childDOMElement);
336
+ removedNodeIds.push(childDOMElement.nodeId);
337
+ const removal = targetElement.childNodes.splice(index, 1);
338
+ if (removal.length !== 1) {
339
+ throw new Error("Removal length not 1");
135
340
  } else {
136
- this.removeVirtualDOMElement(childDOMElement);
137
- removedNodeIds.push(childDOMElement.nodeId);
138
- const removal = targetElement.childNodes.splice(index, 1);
139
- if (removal.length !== 1) {
140
- throw new Error("Removal length not 1");
141
- } else {
142
- if (removal[0].nodeId !== childDOMElement.nodeId) {
143
- throw new Error("Removal node id mismatch");
144
- }
341
+ if (removal[0].nodeId !== childDOMElement.nodeId) {
342
+ throw new Error("Removal node id mismatch");
145
343
  }
146
344
  }
147
345
  }
148
- });
149
- mutation.addedNodes.forEach((node) => {
150
- const asElementOrText = node;
151
- if (asElementOrText.parentNode !== targetNode) {
152
- } else {
153
- if (!previousSiblingElement) {
154
- let firstNonIgnoredPreviousSibling = asElementOrText.previousSibling;
155
- let virtualPreviousSibling;
156
- while (firstNonIgnoredPreviousSibling && !virtualPreviousSibling) {
157
- virtualPreviousSibling = this.realElementToVirtualElement.get(
158
- firstNonIgnoredPreviousSibling
159
- );
160
- if (virtualPreviousSibling && targetElement.childNodes.indexOf(virtualPreviousSibling) === -1) {
161
- virtualPreviousSibling = void 0;
162
- }
163
- firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling;
164
- }
165
- if (virtualPreviousSibling) {
166
- previousSiblingElement = virtualPreviousSibling;
167
- insertionIndex = targetElement.childNodes.indexOf(previousSiblingElement);
168
- if (insertionIndex === -1) {
169
- throw new Error(
170
- "Previous sibling is not currently a child of the parent element"
171
- );
172
- }
173
- insertionIndex += 1;
346
+ }
347
+ });
348
+ mutation.addedNodes.forEach((node) => {
349
+ const asElementOrText = node;
350
+ if (asElementOrText.parentNode !== targetNode) {
351
+ } else {
352
+ if (!previousSiblingElement) {
353
+ let firstNonIgnoredPreviousSibling = asElementOrText.previousSibling;
354
+ let virtualPreviousSibling;
355
+ while (firstNonIgnoredPreviousSibling && !virtualPreviousSibling) {
356
+ virtualPreviousSibling = this.realElementToVirtualElement.get(
357
+ firstNonIgnoredPreviousSibling
358
+ );
359
+ if (virtualPreviousSibling && targetElement.childNodes.indexOf(virtualPreviousSibling) === -1) {
360
+ virtualPreviousSibling = void 0;
174
361
  }
362
+ firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling;
175
363
  }
176
- const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(
177
- asElementOrText,
178
- targetElement
179
- );
180
- if (childVirtualDOMElement) {
181
- toAdd.push(childVirtualDOMElement);
364
+ if (virtualPreviousSibling) {
365
+ previousSiblingElement = virtualPreviousSibling;
366
+ insertionIndex = targetElement.childNodes.indexOf(previousSiblingElement);
367
+ if (insertionIndex === -1) {
368
+ throw new Error("Previous sibling is not currently a child of the parent element");
369
+ }
370
+ insertionIndex += 1;
182
371
  }
183
372
  }
184
- });
185
- targetElement.childNodes.splice(insertionIndex, 0, ...toAdd);
186
- } else if (mutation.type === "attributes") {
187
- const attributeName = mutation.attributeName;
188
- if (!this.isIgnoredAttribute(targetNode, attributeName)) {
189
- const attributeValue = targetNode.getAttribute(attributeName);
190
- if (attributeValue === null) {
191
- delete targetElement.attributes[attributeName];
192
- } else {
193
- targetElement.attributes[attributeName] = attributeValue;
373
+ const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(
374
+ asElementOrText,
375
+ targetElement
376
+ );
377
+ if (childVirtualDOMElement) {
378
+ toAdd.push(childVirtualDOMElement);
194
379
  }
195
380
  }
196
- } else if (mutation.type === "characterData") {
197
- targetElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
381
+ });
382
+ targetElement.childNodes.splice(insertionIndex, 0, ...toAdd);
383
+ if (toAdd.length === 0 && removedNodeIds.length === 0) {
384
+ return null;
198
385
  }
199
386
  const addedNodes = toAdd.map(virtualDOMElementToStatic);
200
- const mutationRecord = {
201
- type: mutation.type,
387
+ return {
388
+ type: "childList",
202
389
  targetId: targetElement.nodeId,
203
390
  addedNodes,
204
391
  removedNodeIds,
205
- previousSiblingId: previousSiblingElement ? previousSiblingElement.nodeId : null,
206
- attribute: mutation.attributeName ? {
207
- attributeName: mutation.attributeName,
208
- value: mutation.target.getAttribute(mutation.attributeName)
209
- } : null
392
+ previousSiblingId: previousSiblingElement ? previousSiblingElement.nodeId : null
393
+ };
394
+ } else if (mutation.type === "attributes") {
395
+ const attributeName = mutation.attributeName;
396
+ if (!this.isIgnoredAttribute(targetNode, attributeName)) {
397
+ const previousValue = targetElement.attributes[attributeName];
398
+ const attributeValue = targetNode.getAttribute(attributeName);
399
+ if (attributeValue === null) {
400
+ if (previousValue === void 0) {
401
+ return null;
402
+ }
403
+ delete targetElement.attributes[attributeName];
404
+ } else {
405
+ if (attributeValue === previousValue) {
406
+ return null;
407
+ }
408
+ targetElement.attributes[attributeName] = attributeValue;
409
+ }
410
+ return {
411
+ type: "attributes",
412
+ targetId: targetElement.nodeId,
413
+ attributes: {
414
+ [attributeName]: attributeValue
415
+ }
416
+ };
417
+ }
418
+ } else if (mutation.type === "characterData") {
419
+ targetElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
420
+ return {
421
+ type: "characterData",
422
+ targetId: targetElement.nodeId,
423
+ textContent: targetElement.textContent ? targetElement.textContent : ""
210
424
  };
211
- this.callback(
212
- {
213
- mutation: mutationRecord,
214
- documentTime: this.getDocumentTime()
215
- },
216
- this
217
- );
218
425
  }
426
+ throw new Error("Unknown mutation type: " + mutation.type);
219
427
  }
220
428
  removeVirtualDOMElement(virtualDOMElement) {
221
429
  this.nodeIdToNode.delete(virtualDOMElement.nodeId);
@@ -332,192 +540,6 @@ var ObservableDOM = class {
332
540
  return this.domRunner.getDocumentTime();
333
541
  }
334
542
  };
335
-
336
- // src/JSDOMRunner.ts
337
- import vm from "vm";
338
- import {
339
- JSDOM,
340
- ResourceLoader,
341
- VirtualConsole
342
- } from "jsdom";
343
- import * as nodeFetch from "node-fetch";
344
- import nodeFetchFn from "node-fetch";
345
- var ErrDOMWindowNotInitialized = "DOMWindow not initialized";
346
- var JSDOMRunnerFactory = (htmlPath, htmlContents, params, callback) => {
347
- return new JSDOMRunner(htmlPath, htmlContents, params, callback);
348
- };
349
- var RejectionResourceLoader = class extends ResourceLoader {
350
- fetch(url) {
351
- console.error("RejectionResourceLoader.fetch", url);
352
- return null;
353
- }
354
- };
355
- var AllowListResourceLoader = class extends ResourceLoader {
356
- constructor(urls, opts) {
357
- super(opts);
358
- this.urls = urls;
359
- }
360
- fetch(url, opts) {
361
- const allow = this.urls.some((allowedURL) => {
362
- return typeof allowedURL === "string" ? allowedURL === url : allowedURL.test(url);
363
- });
364
- if (allow) {
365
- return super.fetch(url, opts ?? {});
366
- }
367
- console.error("AllowListResourceLoader.fetch: resource not allowed", url);
368
- return null;
369
- }
370
- };
371
- var JSDOMRunner = class {
372
- constructor(htmlPath, htmlContents, params, callback, { allowResourceLoading } = { allowResourceLoading: false }) {
373
- this.domWindow = null;
374
- this.mutationObserver = null;
375
- this.documentStartTime = Date.now();
376
- this.isLoaded = false;
377
- this.logBuffer = [];
378
- this.htmlPath = htmlPath;
379
- this.callback = callback;
380
- const resources = Array.isArray(allowResourceLoading) ? new AllowListResourceLoader(allowResourceLoading) : allowResourceLoading ? "usable" : new RejectionResourceLoader();
381
- this.jsdom = new JSDOM(htmlContents, {
382
- runScripts: "dangerously",
383
- resources,
384
- url: this.htmlPath,
385
- virtualConsole: this.createVirtualConsole(),
386
- beforeParse: (window) => {
387
- this.domWindow = window;
388
- this.domWindow.fetch = nodeFetchFn;
389
- this.domWindow.Headers = nodeFetch.Headers;
390
- this.domWindow.Request = nodeFetch.Request;
391
- this.domWindow.Response = nodeFetch.Response;
392
- const timeline = {};
393
- Object.defineProperty(timeline, "currentTime", {
394
- get: () => {
395
- return this.getDocumentTime();
396
- }
397
- });
398
- window.document.timeline = timeline;
399
- window.params = JSON.parse(JSON.stringify(params));
400
- this.mutationObserver = new window.MutationObserver((mutationList) => {
401
- this.callback({
402
- mutationList
403
- });
404
- });
405
- window.addEventListener("load", () => {
406
- var _a;
407
- (_a = this.mutationObserver) == null ? void 0 : _a.observe(window.document, {
408
- attributes: true,
409
- childList: true,
410
- subtree: true,
411
- characterData: true
412
- });
413
- this.isLoaded = true;
414
- this.callback({
415
- loaded: true
416
- });
417
- this.flushLogBuffer();
418
- });
419
- }
420
- });
421
- }
422
- flushLogBuffer() {
423
- for (const logMessage of this.logBuffer) {
424
- this.callback({
425
- logMessage
426
- });
427
- }
428
- this.logBuffer = [];
429
- }
430
- log(message) {
431
- if (!this.isLoaded) {
432
- this.logBuffer.push(message);
433
- return;
434
- }
435
- this.callback({
436
- logMessage: message
437
- });
438
- }
439
- getDocument() {
440
- if (!this.domWindow) {
441
- throw new Error(ErrDOMWindowNotInitialized);
442
- }
443
- return this.domWindow.document;
444
- }
445
- getWindow() {
446
- return this.domWindow;
447
- }
448
- dispose() {
449
- var _a, _b;
450
- const records = (_a = this.mutationObserver) == null ? void 0 : _a.takeRecords();
451
- this.callback({
452
- mutationList: records
453
- });
454
- (_b = this.mutationObserver) == null ? void 0 : _b.disconnect();
455
- this.jsdom.window.close();
456
- }
457
- getDocumentTime() {
458
- return Date.now() - this.documentStartTime;
459
- }
460
- dispatchRemoteEventFromConnectionId(connectionId, domNode, remoteEvent) {
461
- if (!this.domWindow) {
462
- throw new Error(ErrDOMWindowNotInitialized);
463
- }
464
- const bubbles = remoteEvent.bubbles || false;
465
- const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {
466
- bubbles,
467
- detail: { ...remoteEvent.params, connectionId }
468
- });
469
- const eventTypeLowerCase = remoteEvent.name.toLowerCase();
470
- if (eventTypeLowerCase !== "click") {
471
- const handlerAttributeName = "on" + eventTypeLowerCase;
472
- const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);
473
- if (handlerAttributeValue) {
474
- const script = handlerAttributeValue;
475
- const vmContext = this.jsdom.getInternalVMContext();
476
- try {
477
- const invoke = vm.runInContext(`(function(event){ ${script} })`, vmContext);
478
- Reflect.apply(invoke, domNode, [remoteEventObject]);
479
- } catch (e) {
480
- console.error("Error running event handler:", e);
481
- }
482
- }
483
- }
484
- domNode.dispatchEvent(remoteEventObject);
485
- }
486
- createVirtualConsole() {
487
- const virtualConsole = new VirtualConsole();
488
- virtualConsole.on("jsdomError", (...args) => {
489
- this.log({
490
- level: "system",
491
- content: args
492
- });
493
- });
494
- virtualConsole.on("error", (...args) => {
495
- this.log({
496
- level: "error",
497
- content: args
498
- });
499
- });
500
- virtualConsole.on("warn", (...args) => {
501
- this.log({
502
- level: "warn",
503
- content: args
504
- });
505
- });
506
- virtualConsole.on("log", (...args) => {
507
- this.log({
508
- level: "log",
509
- content: args
510
- });
511
- });
512
- virtualConsole.on("info", (...args) => {
513
- this.log({
514
- level: "info",
515
- content: args
516
- });
517
- });
518
- return virtualConsole;
519
- }
520
- };
521
543
  export {
522
544
  JSDOMRunner,
523
545
  JSDOMRunnerFactory,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/utils.ts", "../src/ObservableDOM.ts", "../src/JSDOMRunner.ts"],
4
- "sourcesContent": ["import { StaticVirtualDOMElement } from \"@mml-io/observable-dom-common\";\n\nimport { LiveVirtualDOMElement } from \"./ObservableDOM\";\n\nexport function virtualDOMElementToStatic(el: LiveVirtualDOMElement): StaticVirtualDOMElement {\n return {\n nodeId: el.nodeId,\n tag: el.tag,\n attributes: el.attributes,\n childNodes: el.childNodes.map((child) => virtualDOMElementToStatic(child)),\n textContent: el.textContent,\n };\n}\n", "import {\n LogMessage,\n ObservableDOMInterface,\n ObservableDOMMessage,\n ObservableDOMParameters,\n RemoteEvent,\n StaticVirtualDOMElement,\n StaticVirtualDOMMutationIdsRecord,\n} from \"@mml-io/observable-dom-common\";\n\nimport { virtualDOMElementToStatic } from \"./utils\";\n\nexport type DOMRunnerMessage = {\n loaded?: boolean;\n mutationList?: Array<MutationRecord>;\n logMessage?: LogMessage;\n};\n\nexport type DOMRunnerInterface = {\n getDocument(): Document;\n getWindow(): Window & {\n CustomEvent: typeof CustomEvent;\n Text: typeof Text;\n HTMLScriptElement: typeof HTMLScriptElement;\n Comment: typeof Comment;\n }; // TODO - Define this without using JSDOM types\n dispatchRemoteEventFromConnectionId(\n connectionId: number,\n realElement: Element,\n remoteEvent: RemoteEvent,\n ): void;\n dispose(): void;\n getDocumentTime(): number;\n};\n\nexport type DOMRunnerFactory = (\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (domRunnerMessage: DOMRunnerMessage) => void,\n) => DOMRunnerInterface;\n\nexport type LiveVirtualDOMElement = Omit<StaticVirtualDOMElement, \"childNodes\"> & {\n realElement: Element | Text;\n childNodes: Array<LiveVirtualDOMElement>;\n parent: LiveVirtualDOMElement | null;\n};\n\n/**\n * The ObservableDOM class handles the running of an HTML document using a provided DOMRunnerFactory and converting the\n * mutations that are structured as references to live DOM elements into messages that refer to elements by nodeIds.\n */\nexport class ObservableDOM implements ObservableDOMInterface {\n private nodeToNodeId = new Map<LiveVirtualDOMElement, number>();\n private nodeIdToNode = new Map<number, LiveVirtualDOMElement>();\n private realElementToVirtualElement = new Map<Element | Text, LiveVirtualDOMElement>();\n private ignoreTextNodes = true;\n private callback: (message: ObservableDOMMessage, observableDOM: ObservableDOMInterface) => void;\n private nextNodeId = 1;\n private htmlPath: string;\n private domRunner: DOMRunnerInterface;\n private loaded = false;\n private preLoadLogMessages: Array<LogMessage> = [];\n\n private documentTimeIntervalTimer: NodeJS.Timeout;\n\n constructor(\n observableDOMParameters: ObservableDOMParameters,\n callback: (message: ObservableDOMMessage, observableDOM: ObservableDOMInterface) => void,\n runnerFactory: DOMRunnerFactory,\n ) {\n this.htmlPath = observableDOMParameters.htmlPath;\n this.ignoreTextNodes = observableDOMParameters.ignoreTextNodes;\n this.callback = callback;\n\n this.documentTimeIntervalTimer = setInterval(() => {\n this.callback(\n {\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }, observableDOMParameters.pingIntervalMilliseconds || 5000);\n\n this.domRunner = runnerFactory(\n observableDOMParameters.htmlPath,\n observableDOMParameters.htmlContents,\n observableDOMParameters.params,\n (domRunnerMessage: DOMRunnerMessage) => {\n if (domRunnerMessage.loaded) {\n this.loaded = true;\n this.createVirtualDOMElementWithChildren(\n this.domRunner.getDocument() as unknown as Element,\n null,\n );\n\n const snapshot = virtualDOMElementToStatic(\n this.getVirtualDOMElementForRealElementOrThrow(\n this.domRunner.getDocument() as unknown as Element,\n ),\n );\n\n this.callback(\n {\n snapshot,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n for (const logMessage of this.preLoadLogMessages) {\n this.callback(\n {\n logMessage,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n this.preLoadLogMessages = [];\n } else if (domRunnerMessage.mutationList) {\n this.processModificationList(domRunnerMessage.mutationList);\n } else if (domRunnerMessage.logMessage) {\n if (!this.loaded) {\n this.preLoadLogMessages.push(domRunnerMessage.logMessage);\n return;\n }\n this.callback(\n {\n logMessage: domRunnerMessage.logMessage,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n },\n );\n }\n\n public addConnectedUserId(connectionId: number): void {\n this.domRunner.getWindow().dispatchEvent(\n new (this.domRunner.getWindow().CustomEvent)(\"connected\", {\n detail: { connectionId },\n }),\n );\n }\n\n public removeConnectedUserId(connectionId: number): void {\n this.domRunner.getWindow().dispatchEvent(\n new (this.domRunner.getWindow().CustomEvent)(\"disconnected\", {\n detail: { connectionId },\n }),\n );\n }\n\n private processModificationList(mutationList: Array<MutationRecord>): void {\n const documentEl = this.domRunner.getDocument() as unknown as Element;\n const documentVirtualDOMElement = this.realElementToVirtualElement.get(documentEl);\n if (!documentVirtualDOMElement) {\n throw new Error(`document not created in processModificationList`);\n }\n\n if (mutationList.length > 1) {\n // TODO (https://github.com/mml-io/mml/issues/100) - walk back through the records to derive the intermediate\n // states (e.g. if an attribute is later added to an element created in an earlier record then it should not\n // have that attribute when the element is added. This is important as incorrect attribute sets can affect\n // visibility and expected client performance.\n }\n\n for (const mutation of mutationList) {\n if (this.isIgnoredElement(mutation.target as Element | Text)) {\n continue;\n }\n\n if (\n mutation.type === \"attributes\" &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.isIgnoredAttribute(mutation.target as Element | Text, mutation.attributeName!)\n ) {\n continue;\n }\n\n const targetNode = mutation.target as Element | Text;\n const targetElement = this.realElementToVirtualElement.get(targetNode);\n if (!targetElement) {\n throw new Error(\"Unknown node:\" + targetNode + \",\" + mutation.type);\n }\n\n let previousSiblingElement: LiveVirtualDOMElement | null = null;\n let insertionIndex = 0;\n const toAdd: Array<LiveVirtualDOMElement> = [];\n const removedNodeIds: Array<number> = [];\n\n if (mutation.type === \"childList\") {\n mutation.removedNodes.forEach((node: Node) => {\n const asElementOrText = node as Element | Text;\n if (this.isIgnoredElement(asElementOrText)) {\n return;\n }\n const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);\n if (!childDOMElement) {\n /*\n This can happen if element was a child of a parent element, but was moved to a new parent in the same batch of mutations.\n We can ignore this removal as the element will be in the correct place in the hierarchy already.\n */\n return;\n } else {\n const index = targetElement.childNodes.indexOf(childDOMElement);\n if (index === -1) {\n /*\n This can happen if element was a child of a parent element, but was moved to a new parent in the same batch of mutations.\n We can ignore this removal as the element will be in the correct place in the hierarchy already.\n */\n } else {\n this.removeVirtualDOMElement(childDOMElement);\n removedNodeIds.push(childDOMElement.nodeId);\n const removal = targetElement.childNodes.splice(index, 1);\n if (removal.length !== 1) {\n throw new Error(\"Removal length not 1\");\n } else {\n if (removal[0].nodeId !== childDOMElement.nodeId) {\n throw new Error(\"Removal node id mismatch\");\n }\n }\n }\n }\n });\n\n mutation.addedNodes.forEach((node: Node) => {\n const asElementOrText = node as Element | Text;\n if (asElementOrText.parentNode !== targetNode) {\n // Ignore this addition - it is likely overridden by an earlier addition of this element to its eventual node in this mutation batch\n } else {\n if (!previousSiblingElement) {\n /*\n Either there is no previous element (this is the first element)\n or the previous element has not yet been determined.\n\n Use the current previous sibling of this added node as the first\n choice for the previous sibling, but only use previous siblings\n that are not ignored (are tracked as virtual elements).\n */\n let firstNonIgnoredPreviousSibling: Element | Text | null =\n asElementOrText.previousSibling as Element | Text;\n let virtualPreviousSibling: LiveVirtualDOMElement | undefined;\n while (firstNonIgnoredPreviousSibling && !virtualPreviousSibling) {\n virtualPreviousSibling = this.realElementToVirtualElement.get(\n firstNonIgnoredPreviousSibling as Element | Text,\n );\n if (\n virtualPreviousSibling &&\n targetElement.childNodes.indexOf(virtualPreviousSibling) === -1\n ) {\n // This element is not a child of the parent element - it is not a valid previous sibling\n virtualPreviousSibling = undefined;\n }\n\n firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling as\n | Element\n | Text\n | null;\n }\n\n if (virtualPreviousSibling) {\n previousSiblingElement = virtualPreviousSibling;\n insertionIndex = targetElement.childNodes.indexOf(previousSiblingElement);\n if (insertionIndex === -1) {\n throw new Error(\n \"Previous sibling is not currently a child of the parent element\",\n );\n }\n insertionIndex += 1;\n }\n }\n const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(\n asElementOrText,\n targetElement,\n );\n if (childVirtualDOMElement) {\n toAdd.push(childVirtualDOMElement);\n }\n }\n });\n targetElement.childNodes.splice(insertionIndex, 0, ...toAdd);\n } else if (mutation.type === \"attributes\") {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const attributeName = mutation.attributeName!;\n if (!this.isIgnoredAttribute(targetNode, attributeName)) {\n const attributeValue = (targetNode as Element).getAttribute(attributeName);\n if (attributeValue === null) {\n delete targetElement.attributes[attributeName];\n } else {\n targetElement.attributes[attributeName] = attributeValue;\n }\n }\n } else if (mutation.type === \"characterData\") {\n targetElement.textContent = targetNode.textContent ? targetNode.textContent : undefined;\n }\n\n // Convert the \"real\" DOM MutationRecord into a \"virtual\" DOM MutationRecord that references the VirtualDOMElements\n // This is done so that the same process for handling mutations can be used for both changes to a live DOM and also\n // to diffs between DOM snapshots when reloading\n\n const addedNodes: Array<StaticVirtualDOMElement> = toAdd.map(virtualDOMElementToStatic);\n\n const mutationRecord: StaticVirtualDOMMutationIdsRecord = {\n type: mutation.type,\n targetId: targetElement.nodeId,\n addedNodes,\n removedNodeIds,\n previousSiblingId: previousSiblingElement\n ? (previousSiblingElement as LiveVirtualDOMElement).nodeId\n : null,\n attribute: mutation.attributeName\n ? {\n attributeName: mutation.attributeName,\n value: (mutation.target as Element).getAttribute(mutation.attributeName),\n }\n : null,\n };\n\n this.callback(\n {\n mutation: mutationRecord,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n }\n\n private removeVirtualDOMElement(virtualDOMElement: LiveVirtualDOMElement): void {\n this.nodeIdToNode.delete(virtualDOMElement.nodeId);\n this.nodeToNodeId.delete(virtualDOMElement);\n this.realElementToVirtualElement.delete(virtualDOMElement.realElement);\n for (const child of virtualDOMElement.childNodes) {\n this.removeVirtualDOMElement(child);\n }\n }\n\n private createVirtualDOMElementWithChildren(\n node: Element | Text,\n parent: LiveVirtualDOMElement | null,\n ): LiveVirtualDOMElement | null {\n const [virtualElement, existing] = this.createVirtualDOMElement(node, parent);\n if (!virtualElement) {\n return null;\n }\n if (existing) {\n return null;\n }\n if ((node as Element).childNodes) {\n for (let i = 0; i < (node as Element).childNodes.length; i++) {\n const child = (node as Element).childNodes[i];\n const childVirtualElement = this.createVirtualDOMElementWithChildren(\n child as Element | Text,\n virtualElement,\n );\n if (childVirtualElement) {\n virtualElement.childNodes.push(childVirtualElement);\n }\n }\n }\n\n return virtualElement;\n }\n\n private createVirtualDOMElement(\n node: Element | Text,\n parent: LiveVirtualDOMElement | null,\n ): [LiveVirtualDOMElement | null, boolean] {\n if (this.isIgnoredElement(node)) {\n return [null, false];\n }\n if (!node) {\n throw new Error(\"Cannot assign node id to null\");\n }\n\n const existingValue = this.realElementToVirtualElement.get(node);\n if (existingValue !== undefined) {\n /*\n This is undesirable, but the batching of mutations from MutationObserver means that\n this node could be being added in a mutation after a mutation of a parent that when\n handled resulting in adding this node early.\n */\n return [existingValue, true];\n }\n\n const attributes: { [key: string]: string } = {};\n if ((node as any).attributes) {\n const asHTMLElement = node as HTMLElement;\n for (const key of asHTMLElement.getAttributeNames()) {\n const value = asHTMLElement.getAttribute(key);\n if (value === null) {\n throw new Error(\"Null attribute value for key: \" + key);\n }\n if (!this.isIgnoredAttribute(node, key)) {\n attributes[key] = value;\n }\n }\n }\n\n const nodeId = this.nextNodeId++;\n const virtualElement: LiveVirtualDOMElement = {\n nodeId,\n tag: node.nodeName,\n attributes,\n childNodes: [],\n realElement: node,\n parent,\n };\n if (node instanceof this.domRunner.getWindow().Text && node.textContent) {\n virtualElement.textContent = node.textContent;\n }\n this.nodeToNodeId.set(virtualElement, nodeId);\n this.nodeIdToNode.set(nodeId, virtualElement);\n this.realElementToVirtualElement.set(node, virtualElement);\n return [virtualElement, false];\n }\n\n private getVirtualDOMElementForRealElementOrThrow(\n realElement: Element | Text,\n ): LiveVirtualDOMElement {\n const virtualElement = this.realElementToVirtualElement.get(realElement);\n if (!virtualElement) {\n throw new Error(`Virtual element not found for real element`);\n }\n return virtualElement;\n }\n\n private isIgnoredElement(node: Element | Text): boolean {\n if (this.ignoreTextNodes && node instanceof this.domRunner.getWindow().Text) {\n return true;\n } else if (node instanceof this.domRunner.getWindow().HTMLScriptElement) {\n return true;\n } else if (node instanceof this.domRunner.getWindow().Comment) {\n return true;\n }\n return false;\n }\n\n private isIgnoredAttribute(node: Element | Text, attributeName: string): boolean {\n return attributeName.startsWith(\"on\");\n }\n\n public dispatchRemoteEventFromConnectionId(connectionId: number, remoteEvent: RemoteEvent): void {\n const domNode = this.nodeIdToNode.get(remoteEvent.nodeId);\n if (!domNode) {\n console.error(\"Unknown node ID in remote event: \" + remoteEvent.nodeId);\n return;\n }\n\n if (domNode instanceof this.domRunner.getWindow().Text) {\n console.warn(\"Cannot dispatch remote event to text node\");\n return;\n }\n\n this.domRunner.dispatchRemoteEventFromConnectionId(\n connectionId,\n domNode.realElement as Element,\n remoteEvent,\n );\n }\n\n public dispose() {\n clearInterval(this.documentTimeIntervalTimer);\n this.domRunner.dispose();\n }\n\n private getDocumentTime() {\n return this.domRunner.getDocumentTime();\n }\n}\n", "import vm from \"vm\";\n\nimport { LogMessage, RemoteEvent } from \"@mml-io/observable-dom-common\";\nimport {\n AbortablePromise,\n DOMWindow,\n FetchOptions,\n JSDOM,\n ResourceLoader,\n ResourceLoaderConstructorOptions,\n VirtualConsole,\n} from \"jsdom\";\nimport * as nodeFetch from \"node-fetch\";\nimport nodeFetchFn from \"node-fetch\";\n\nimport { DOMRunnerFactory, DOMRunnerInterface, DOMRunnerMessage } from \"./ObservableDOM\";\n\nconst ErrDOMWindowNotInitialized = \"DOMWindow not initialized\";\n\nexport const JSDOMRunnerFactory: DOMRunnerFactory = (\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (mutationList: DOMRunnerMessage) => void,\n): DOMRunnerInterface => {\n return new JSDOMRunner(htmlPath, htmlContents, params, callback);\n};\n\n// This is used to stop JSDOM trying to load resources\nclass RejectionResourceLoader extends ResourceLoader {\n public fetch(url: string): AbortablePromise<Buffer> | null {\n console.error(\"RejectionResourceLoader.fetch\", url);\n return null;\n }\n}\n\nexport type ResourceURL = string | RegExp;\n\n// This allows JSDOM to load resources if their URLs are specified in the urls array.\nclass AllowListResourceLoader extends ResourceLoader {\n private urls: ResourceURL[];\n\n constructor(urls: ResourceURL[], opts?: ResourceLoaderConstructorOptions) {\n super(opts);\n this.urls = urls;\n }\n public fetch(url: string, opts?: FetchOptions): AbortablePromise<Buffer> | null {\n const allow = this.urls.some((allowedURL) => {\n return typeof allowedURL === \"string\" ? allowedURL === url : allowedURL.test(url);\n });\n\n if (allow) {\n return super.fetch(url, opts ?? {});\n }\n\n console.error(\"AllowListResourceLoader.fetch: resource not allowed\", url);\n return null;\n }\n}\n\nexport type JSDOMRunnerOptions = {\n allowResourceLoading: boolean | ResourceURL[];\n};\n\n/**\n * The JSDOMRunner class is used to run HTML Documents using JSDOM and emit DOMRunnerMessages for document events such\n * as mutations.\n *\n * It handles the receiving of remote events and the dispatching of them to the underlying DOM elements.\n */\nexport class JSDOMRunner implements DOMRunnerInterface {\n public domWindow: DOMWindow | null = null;\n private jsdom: JSDOM;\n\n private callback: (message: DOMRunnerMessage) => void;\n private mutationObserver: MutationObserver | null = null;\n private htmlPath: string;\n\n private documentStartTime = Date.now();\n\n private isLoaded = false;\n private logBuffer: LogMessage[] = [];\n\n constructor(\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (domRunnerMessage: DOMRunnerMessage) => void,\n { allowResourceLoading }: JSDOMRunnerOptions = { allowResourceLoading: false },\n ) {\n this.htmlPath = htmlPath;\n this.callback = callback;\n\n const resources = Array.isArray(allowResourceLoading)\n ? new AllowListResourceLoader(allowResourceLoading)\n : allowResourceLoading\n ? \"usable\"\n : new RejectionResourceLoader();\n\n this.jsdom = new JSDOM(htmlContents, {\n runScripts: \"dangerously\",\n resources,\n url: this.htmlPath,\n virtualConsole: this.createVirtualConsole(),\n beforeParse: (window) => {\n this.domWindow = window;\n\n this.domWindow.fetch = nodeFetchFn as unknown as typeof fetch;\n this.domWindow.Headers = nodeFetch.Headers as unknown as typeof Headers;\n this.domWindow.Request = nodeFetch.Request as unknown as typeof Request;\n this.domWindow.Response = nodeFetch.Response as unknown as typeof Response;\n\n // This is a polyfill for https://developer.mozilla.org/en-US/docs/Web/API/Document/timeline\n const timeline = {};\n Object.defineProperty(timeline, \"currentTime\", {\n get: () => {\n return this.getDocumentTime();\n },\n });\n (window.document as any).timeline = timeline;\n\n // JSON stringify and parse to avoid potential reference leaks from the params object\n window.params = JSON.parse(JSON.stringify(params));\n\n this.mutationObserver = new window.MutationObserver((mutationList) => {\n this.callback({\n mutationList,\n });\n });\n\n window.addEventListener(\"load\", () => {\n this.mutationObserver?.observe(window.document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n });\n\n this.isLoaded = true;\n\n this.callback({\n loaded: true,\n });\n\n this.flushLogBuffer();\n });\n },\n });\n }\n\n private flushLogBuffer() {\n for (const logMessage of this.logBuffer) {\n this.callback({\n logMessage,\n });\n }\n\n this.logBuffer = [];\n }\n\n private log(message: LogMessage) {\n if (!this.isLoaded) {\n this.logBuffer.push(message);\n return;\n }\n\n this.callback({\n logMessage: message,\n });\n }\n\n public getDocument(): Document {\n if (!this.domWindow) {\n throw new Error(ErrDOMWindowNotInitialized);\n }\n\n return this.domWindow.document;\n }\n\n public getWindow(): any {\n return this.domWindow;\n }\n\n public dispose() {\n const records = this.mutationObserver?.takeRecords();\n this.callback({\n mutationList: records,\n });\n this.mutationObserver?.disconnect();\n this.jsdom.window.close();\n }\n\n public getDocumentTime() {\n return Date.now() - this.documentStartTime;\n }\n\n public dispatchRemoteEventFromConnectionId(\n connectionId: number,\n domNode: Element,\n remoteEvent: RemoteEvent,\n ) {\n if (!this.domWindow) {\n throw new Error(ErrDOMWindowNotInitialized);\n }\n\n const bubbles = remoteEvent.bubbles || false;\n const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {\n bubbles,\n detail: { ...remoteEvent.params, connectionId },\n });\n\n const eventTypeLowerCase = remoteEvent.name.toLowerCase();\n\n // TODO - check if there are other events that automatically wire up similarly to click->onclick and avoid those too\n if (eventTypeLowerCase !== \"click\") {\n const handlerAttributeName = \"on\" + eventTypeLowerCase;\n const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);\n if (handlerAttributeValue) {\n // This event is defined as an HTML event attribute.\n const script = handlerAttributeValue;\n const vmContext = this.jsdom.getInternalVMContext();\n try {\n const invoke = vm.runInContext(`(function(event){ ${script} })`, vmContext);\n Reflect.apply(invoke, domNode, [remoteEventObject]);\n } catch (e) {\n console.error(\"Error running event handler:\", e);\n }\n }\n }\n\n // Dispatch the event via JavaScript.\n domNode.dispatchEvent(remoteEventObject);\n }\n\n private createVirtualConsole(): VirtualConsole {\n const virtualConsole = new VirtualConsole();\n virtualConsole.on(\"jsdomError\", (...args) => {\n this.log({\n level: \"system\",\n content: args,\n });\n });\n virtualConsole.on(\"error\", (...args) => {\n this.log({\n level: \"error\",\n content: args,\n });\n });\n virtualConsole.on(\"warn\", (...args) => {\n this.log({\n level: \"warn\",\n content: args,\n });\n });\n virtualConsole.on(\"log\", (...args) => {\n this.log({\n level: \"log\",\n content: args,\n });\n });\n virtualConsole.on(\"info\", (...args) => {\n this.log({\n level: \"info\",\n content: args,\n });\n });\n return virtualConsole;\n }\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/JSDOMRunner.ts", "../src/utils.ts", "../src/ObservableDOM.ts"],
4
+ "sourcesContent": ["import { LogMessage, ObservableDOMRemoteEvent } from \"@mml-io/observable-dom-common\";\nimport {\n AbortablePromise,\n DOMWindow,\n FetchOptions,\n JSDOM,\n ResourceLoader,\n ResourceLoaderConstructorOptions,\n VirtualConsole,\n} from \"jsdom\";\nimport * as nodeFetch from \"node-fetch\";\nimport nodeFetchFn from \"node-fetch\";\nimport vm from \"vm\";\n\nimport { DOMRunnerFactory, DOMRunnerInterface, DOMRunnerMessage } from \"./ObservableDOM\";\n\nconst ErrDOMWindowNotInitialized = \"DOMWindow not initialized\";\n\nexport const JSDOMRunnerFactory: DOMRunnerFactory = (\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (mutationList: DOMRunnerMessage) => void,\n): DOMRunnerInterface => {\n return new JSDOMRunner(htmlPath, htmlContents, params, callback);\n};\n\n// This is used to stop JSDOM trying to load resources\nclass RejectionResourceLoader extends ResourceLoader {\n public fetch(url: string): AbortablePromise<Buffer> | null {\n console.error(\"RejectionResourceLoader.fetch\", url);\n return null;\n }\n}\n\nexport type ResourceURL = string | RegExp;\n\n// This allows JSDOM to load resources if their URLs are specified in the urls array.\nclass AllowListResourceLoader extends ResourceLoader {\n private urls: ResourceURL[];\n\n constructor(urls: ResourceURL[], opts?: ResourceLoaderConstructorOptions) {\n super(opts);\n this.urls = urls;\n }\n public fetch(url: string, opts?: FetchOptions): AbortablePromise<Buffer> | null {\n const allow = this.urls.some((allowedURL) => {\n return typeof allowedURL === \"string\" ? allowedURL === url : allowedURL.test(url);\n });\n\n if (allow) {\n return super.fetch(url, opts ?? {});\n }\n\n console.error(\"AllowListResourceLoader.fetch: resource not allowed\", url);\n return null;\n }\n}\n\nexport type JSDOMRunnerOptions = {\n allowResourceLoading: boolean | ResourceURL[];\n};\n\n/**\n * The JSDOMRunner class is used to run HTML Documents using JSDOM and emit DOMRunnerMessages for document events such\n * as mutations.\n *\n * It handles the receiving of remote events and the dispatching of them to the underlying DOM elements.\n */\nexport class JSDOMRunner implements DOMRunnerInterface {\n public domWindow: DOMWindow | null = null;\n private jsdom: JSDOM;\n\n private callback: (message: DOMRunnerMessage) => void;\n private mutationObserver: MutationObserver | null = null;\n private htmlPath: string;\n\n private documentStartTime = Date.now();\n\n private isLoaded = false;\n private logBuffer: LogMessage[] = [];\n\n constructor(\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (domRunnerMessage: DOMRunnerMessage) => void,\n { allowResourceLoading }: JSDOMRunnerOptions = { allowResourceLoading: false },\n ) {\n this.htmlPath = htmlPath;\n this.callback = callback;\n\n const resources = Array.isArray(allowResourceLoading)\n ? new AllowListResourceLoader(allowResourceLoading)\n : allowResourceLoading\n ? \"usable\"\n : new RejectionResourceLoader();\n\n this.jsdom = new JSDOM(htmlContents, {\n runScripts: \"dangerously\",\n resources,\n url: this.htmlPath,\n virtualConsole: this.createVirtualConsole(),\n beforeParse: (window) => {\n this.domWindow = window;\n\n this.domWindow.fetch = nodeFetchFn as unknown as typeof fetch;\n this.domWindow.Headers = nodeFetch.Headers as unknown as typeof Headers;\n this.domWindow.Request = nodeFetch.Request as unknown as typeof Request;\n this.domWindow.Response = nodeFetch.Response as unknown as typeof Response;\n\n // This is a polyfill for https://developer.mozilla.org/en-US/docs/Web/API/Document/timeline\n const timeline = {};\n Object.defineProperty(timeline, \"currentTime\", {\n get: () => {\n return this.getDocumentTime();\n },\n });\n (window.document as any).timeline = timeline;\n\n // JSON stringify and parse to avoid potential reference leaks from the params object\n window.params = JSON.parse(JSON.stringify(params));\n\n this.mutationObserver = new window.MutationObserver((mutationList) => {\n this.callback({\n mutationList,\n });\n });\n\n window.addEventListener(\"load\", () => {\n this.mutationObserver?.observe(window.document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n });\n\n this.isLoaded = true;\n\n this.callback({\n loaded: true,\n });\n\n this.flushLogBuffer();\n });\n },\n });\n }\n\n private flushLogBuffer() {\n for (const logMessage of this.logBuffer) {\n this.callback({\n logMessage,\n });\n }\n\n this.logBuffer = [];\n }\n\n private log(message: LogMessage) {\n if (!this.isLoaded) {\n this.logBuffer.push(message);\n return;\n }\n\n this.callback({\n logMessage: message,\n });\n }\n\n public getDocument(): Document {\n if (!this.domWindow) {\n throw new Error(ErrDOMWindowNotInitialized);\n }\n\n return this.domWindow.document;\n }\n\n public getWindow(): any {\n return this.domWindow;\n }\n\n public dispose() {\n const records = this.mutationObserver?.takeRecords();\n this.callback({\n mutationList: records,\n });\n this.mutationObserver?.disconnect();\n this.jsdom.window.close();\n }\n\n public getDocumentTime() {\n return Date.now() - this.documentStartTime;\n }\n\n public dispatchRemoteEventFromConnectionId(\n connectionId: number,\n domNode: Element,\n remoteEvent: ObservableDOMRemoteEvent,\n ) {\n if (!this.domWindow) {\n throw new Error(ErrDOMWindowNotInitialized);\n }\n\n const bubbles = remoteEvent.bubbles || false;\n const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {\n bubbles,\n detail: { ...remoteEvent.params, connectionId },\n });\n\n const eventTypeLowerCase = remoteEvent.name.toLowerCase();\n\n // TODO - check if there are other events that automatically wire up similarly to click->onclick and avoid those too\n if (eventTypeLowerCase !== \"click\") {\n const handlerAttributeName = \"on\" + eventTypeLowerCase;\n const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);\n if (handlerAttributeValue) {\n // This event is defined as an HTML event attribute.\n const script = handlerAttributeValue;\n const vmContext = this.jsdom.getInternalVMContext();\n try {\n const invoke = vm.runInContext(`(function(event){ ${script} })`, vmContext);\n Reflect.apply(invoke, domNode, [remoteEventObject]);\n } catch (e) {\n console.error(\"Error running event handler:\", e);\n }\n }\n }\n\n // Dispatch the event via JavaScript.\n domNode.dispatchEvent(remoteEventObject);\n }\n\n private createVirtualConsole(): VirtualConsole {\n const virtualConsole = new VirtualConsole();\n virtualConsole.on(\"jsdomError\", (...args) => {\n this.log({\n level: \"system\",\n content: args,\n });\n });\n virtualConsole.on(\"error\", (...args) => {\n this.log({\n level: \"error\",\n content: args,\n });\n });\n virtualConsole.on(\"warn\", (...args) => {\n this.log({\n level: \"warn\",\n content: args,\n });\n });\n virtualConsole.on(\"log\", (...args) => {\n this.log({\n level: \"log\",\n content: args,\n });\n });\n virtualConsole.on(\"info\", (...args) => {\n this.log({\n level: \"info\",\n content: args,\n });\n });\n return virtualConsole;\n }\n}\n", "import { StaticVirtualDOMElement } from \"@mml-io/observable-dom-common\";\n\nimport { LiveVirtualDOMElement } from \"./ObservableDOM\";\n\nexport function virtualDOMElementToStatic(el: LiveVirtualDOMElement): StaticVirtualDOMElement {\n return {\n nodeId: el.nodeId,\n tag: el.tag,\n attributes: Object.assign({}, el.attributes), // Copy the attributes object - shallow copy is fine as the attributes are strings\n childNodes: el.childNodes.map((child) => virtualDOMElementToStatic(child)),\n textContent: el.textContent,\n };\n}\n", "import {\n LogMessage,\n ObservableDOMInterface,\n ObservableDOMMessage,\n ObservableDOMParameters,\n ObservableDOMRemoteEvent,\n StaticVirtualDOMElement,\n StaticVirtualDOMMutationIdsRecord,\n} from \"@mml-io/observable-dom-common\";\n\nimport { virtualDOMElementToStatic } from \"./utils\";\n\nexport type DOMRunnerMessage = {\n loaded?: boolean;\n mutationList?: Array<MutationRecord>;\n logMessage?: LogMessage;\n};\n\nexport type DOMRunnerInterface = {\n getDocument(): Document;\n getWindow(): Window & {\n CustomEvent: typeof CustomEvent;\n Text: typeof Text;\n HTMLScriptElement: typeof HTMLScriptElement;\n Comment: typeof Comment;\n }; // TODO - Define this without using JSDOM types\n dispatchRemoteEventFromConnectionId(\n connectionId: number,\n realElement: Element,\n remoteEvent: ObservableDOMRemoteEvent,\n ): void;\n dispose(): void;\n getDocumentTime(): number;\n};\n\nexport type DOMRunnerFactory = (\n htmlPath: string,\n htmlContents: string,\n params: object,\n callback: (domRunnerMessage: DOMRunnerMessage) => void,\n) => DOMRunnerInterface;\n\nexport type LiveVirtualDOMElement = Omit<StaticVirtualDOMElement, \"childNodes\"> & {\n realElement: Element | Text;\n childNodes: Array<LiveVirtualDOMElement>;\n parent: LiveVirtualDOMElement | null;\n};\n\n/**\n * The ObservableDOM class handles the running of an HTML document using a provided DOMRunnerFactory and converting the\n * mutations that are structured as references to live DOM elements into messages that refer to elements by nodeIds.\n */\nexport class ObservableDOM implements ObservableDOMInterface {\n private nodeToNodeId = new Map<LiveVirtualDOMElement, number>();\n private nodeIdToNode = new Map<number, LiveVirtualDOMElement>();\n private realElementToVirtualElement = new Map<Element | Text, LiveVirtualDOMElement>();\n private ignoreTextNodes = true;\n private callback: (message: ObservableDOMMessage, observableDOM: ObservableDOMInterface) => void;\n private nextNodeId = 1;\n private htmlPath: string;\n private domRunner: DOMRunnerInterface;\n private loaded = false;\n private preLoadLogMessages: Array<LogMessage> = [];\n\n private documentTimeIntervalTimer: NodeJS.Timeout;\n\n constructor(\n observableDOMParameters: ObservableDOMParameters,\n callback: (message: ObservableDOMMessage, observableDOM: ObservableDOMInterface) => void,\n runnerFactory: DOMRunnerFactory,\n ) {\n this.htmlPath = observableDOMParameters.htmlPath;\n this.ignoreTextNodes = observableDOMParameters.ignoreTextNodes;\n this.callback = callback;\n\n this.documentTimeIntervalTimer = setInterval(() => {\n this.callback(\n {\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }, observableDOMParameters.pingIntervalMilliseconds || 5000);\n\n this.domRunner = runnerFactory(\n observableDOMParameters.htmlPath,\n observableDOMParameters.htmlContents,\n observableDOMParameters.params,\n (domRunnerMessage: DOMRunnerMessage) => {\n if (domRunnerMessage.loaded) {\n this.loaded = true;\n this.createVirtualDOMElementWithChildren(\n this.domRunner.getDocument() as unknown as Element,\n null,\n );\n\n const snapshot = virtualDOMElementToStatic(\n this.getVirtualDOMElementForRealElementOrThrow(\n this.domRunner.getDocument() as unknown as Element,\n ),\n );\n\n this.callback(\n {\n snapshot,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n for (const logMessage of this.preLoadLogMessages) {\n this.callback(\n {\n logMessage,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n this.preLoadLogMessages = [];\n } else if (domRunnerMessage.mutationList) {\n this.processModificationList(domRunnerMessage.mutationList);\n } else if (domRunnerMessage.logMessage) {\n if (!this.loaded) {\n this.preLoadLogMessages.push(domRunnerMessage.logMessage);\n return;\n }\n this.callback(\n {\n logMessage: domRunnerMessage.logMessage,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n },\n );\n }\n\n public addConnectedUserId(connectionId: number): void {\n this.domRunner.getWindow().dispatchEvent(\n new (this.domRunner.getWindow().CustomEvent)(\"connected\", {\n detail: { connectionId },\n }),\n );\n }\n\n public removeConnectedUserId(connectionId: number): void {\n this.domRunner.getWindow().dispatchEvent(\n new (this.domRunner.getWindow().CustomEvent)(\"disconnected\", {\n detail: { connectionId },\n }),\n );\n }\n\n private processModificationList(mutationList: Array<MutationRecord>): void {\n if (mutationList.length > 1) {\n // TODO (https://github.com/mml-io/mml/issues/100) - walk back through the records to derive the intermediate\n // states (e.g. if an attribute is later added to an element created in an earlier record then it should not\n // have that attribute when the element is added. This is important as incorrect attribute sets can affect\n // visibility and expected client performance.\n }\n\n const allMutationRecords: Array<StaticVirtualDOMMutationIdsRecord> = [];\n for (const mutation of mutationList) {\n const idsRecord = this.createMutationRecord(mutation);\n if (idsRecord) {\n allMutationRecords.push(idsRecord);\n }\n }\n\n if (allMutationRecords.length > 0) {\n this.callback(\n {\n mutations: allMutationRecords,\n documentTime: this.getDocumentTime(),\n },\n this,\n );\n }\n }\n\n private createMutationRecord(mutation: MutationRecord): StaticVirtualDOMMutationIdsRecord | null {\n if (this.isIgnoredElement(mutation.target as Element | Text)) {\n return null;\n }\n\n if (\n mutation.type === \"attributes\" &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.isIgnoredAttribute(mutation.target as Element | Text, mutation.attributeName!)\n ) {\n return null;\n }\n\n const targetNode = mutation.target as Element | Text;\n const targetElement = this.realElementToVirtualElement.get(targetNode);\n if (!targetElement) {\n // This can happen if the target element for this mutation has been removed in a previous mutation\n return null;\n }\n\n let previousSiblingElement: LiveVirtualDOMElement | null = null;\n let insertionIndex = 0;\n const toAdd: Array<LiveVirtualDOMElement> = [];\n const removedNodeIds: Array<number> = [];\n\n if (mutation.type === \"childList\") {\n mutation.removedNodes.forEach((node: Node) => {\n const asElementOrText = node as Element | Text;\n if (this.isIgnoredElement(asElementOrText)) {\n return;\n }\n const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);\n if (!childDOMElement) {\n /*\n This can happen if element was a child of a parent element, but was moved to a new parent in the same batch of mutations.\n We can ignore this removal as the element will be in the correct place in the hierarchy already.\n */\n return;\n } else {\n const index = targetElement.childNodes.indexOf(childDOMElement);\n if (index === -1) {\n /*\n This can happen if element was a child of a parent element, but was moved to a new parent in the same batch of mutations.\n We can ignore this removal as the element will be in the correct place in the hierarchy already.\n */\n } else {\n this.removeVirtualDOMElement(childDOMElement);\n removedNodeIds.push(childDOMElement.nodeId);\n const removal = targetElement.childNodes.splice(index, 1);\n if (removal.length !== 1) {\n throw new Error(\"Removal length not 1\");\n } else {\n if (removal[0].nodeId !== childDOMElement.nodeId) {\n throw new Error(\"Removal node id mismatch\");\n }\n }\n }\n }\n });\n\n mutation.addedNodes.forEach((node: Node) => {\n const asElementOrText = node as Element | Text;\n if (asElementOrText.parentNode !== targetNode) {\n // Ignore this addition - it is likely overridden by an earlier addition of this element to its eventual node in this mutation batch\n } else {\n if (!previousSiblingElement) {\n /*\n Either there is no previous element (this is the first element)\n or the previous element has not yet been determined.\n\n Use the current previous sibling of this added node as the first\n choice for the previous sibling, but only use previous siblings\n that are not ignored (are tracked as virtual elements).\n */\n let firstNonIgnoredPreviousSibling: Element | Text | null =\n asElementOrText.previousSibling as Element | Text;\n let virtualPreviousSibling: LiveVirtualDOMElement | undefined;\n while (firstNonIgnoredPreviousSibling && !virtualPreviousSibling) {\n virtualPreviousSibling = this.realElementToVirtualElement.get(\n firstNonIgnoredPreviousSibling as Element | Text,\n );\n if (\n virtualPreviousSibling &&\n targetElement.childNodes.indexOf(virtualPreviousSibling) === -1\n ) {\n // This element is not a child of the parent element - it is not a valid previous sibling\n virtualPreviousSibling = undefined;\n }\n\n firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling as\n | Element\n | Text\n | null;\n }\n\n if (virtualPreviousSibling) {\n previousSiblingElement = virtualPreviousSibling;\n insertionIndex = targetElement.childNodes.indexOf(previousSiblingElement);\n if (insertionIndex === -1) {\n throw new Error(\"Previous sibling is not currently a child of the parent element\");\n }\n insertionIndex += 1;\n }\n }\n const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(\n asElementOrText,\n targetElement,\n );\n if (childVirtualDOMElement) {\n toAdd.push(childVirtualDOMElement);\n }\n }\n });\n targetElement.childNodes.splice(insertionIndex, 0, ...toAdd);\n\n if (toAdd.length === 0 && removedNodeIds.length === 0) {\n // This is a no-op mutation\n return null;\n }\n // Convert the \"real\" DOM MutationRecord into a \"virtual\" DOM MutationRecord that references the VirtualDOMElements\n // This is done so that the same process for handling mutations can be used for both changes to a live DOM and also\n // to diffs between DOM snapshots when reloading\n const addedNodes: Array<StaticVirtualDOMElement> = toAdd.map(virtualDOMElementToStatic);\n return {\n type: \"childList\",\n targetId: targetElement.nodeId,\n addedNodes,\n removedNodeIds,\n previousSiblingId: previousSiblingElement\n ? (previousSiblingElement as LiveVirtualDOMElement).nodeId\n : null,\n };\n } else if (mutation.type === \"attributes\") {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const attributeName = mutation.attributeName!;\n if (!this.isIgnoredAttribute(targetNode, attributeName)) {\n const previousValue = targetElement.attributes[attributeName];\n const attributeValue = (targetNode as Element).getAttribute(attributeName);\n if (attributeValue === null) {\n if (previousValue === undefined) {\n // This is a no-op mutation\n return null;\n }\n delete targetElement.attributes[attributeName];\n } else {\n if (attributeValue === previousValue) {\n // This is a no-op mutation\n return null;\n }\n targetElement.attributes[attributeName] = attributeValue;\n }\n return {\n type: \"attributes\",\n targetId: targetElement.nodeId,\n attributes: {\n [attributeName]: attributeValue,\n },\n };\n }\n } else if (mutation.type === \"characterData\") {\n targetElement.textContent = targetNode.textContent ? targetNode.textContent : undefined;\n return {\n type: \"characterData\",\n targetId: targetElement.nodeId,\n textContent: targetElement.textContent ? targetElement.textContent : \"\",\n };\n }\n\n throw new Error(\"Unknown mutation type: \" + mutation.type);\n }\n\n private removeVirtualDOMElement(virtualDOMElement: LiveVirtualDOMElement): void {\n this.nodeIdToNode.delete(virtualDOMElement.nodeId);\n this.nodeToNodeId.delete(virtualDOMElement);\n this.realElementToVirtualElement.delete(virtualDOMElement.realElement);\n for (const child of virtualDOMElement.childNodes) {\n this.removeVirtualDOMElement(child);\n }\n }\n\n private createVirtualDOMElementWithChildren(\n node: Element | Text,\n parent: LiveVirtualDOMElement | null,\n ): LiveVirtualDOMElement | null {\n const [virtualElement, existing] = this.createVirtualDOMElement(node, parent);\n if (!virtualElement) {\n return null;\n }\n if (existing) {\n return null;\n }\n if ((node as Element).childNodes) {\n for (let i = 0; i < (node as Element).childNodes.length; i++) {\n const child = (node as Element).childNodes[i];\n const childVirtualElement = this.createVirtualDOMElementWithChildren(\n child as Element | Text,\n virtualElement,\n );\n if (childVirtualElement) {\n virtualElement.childNodes.push(childVirtualElement);\n }\n }\n }\n\n return virtualElement;\n }\n\n private createVirtualDOMElement(\n node: Element | Text,\n parent: LiveVirtualDOMElement | null,\n ): [LiveVirtualDOMElement | null, boolean] {\n if (this.isIgnoredElement(node)) {\n return [null, false];\n }\n if (!node) {\n throw new Error(\"Cannot assign node id to null\");\n }\n\n const existingValue = this.realElementToVirtualElement.get(node);\n if (existingValue !== undefined) {\n /*\n This is undesirable, but the batching of mutations from MutationObserver means that\n this node could be being added in a mutation after a mutation of a parent that when\n handled resulting in adding this node early.\n */\n return [existingValue, true];\n }\n\n const attributes: { [key: string]: string } = {};\n if ((node as any).attributes) {\n const asHTMLElement = node as HTMLElement;\n for (const key of asHTMLElement.getAttributeNames()) {\n const value = asHTMLElement.getAttribute(key);\n if (value === null) {\n throw new Error(\"Null attribute value for key: \" + key);\n }\n if (!this.isIgnoredAttribute(node, key)) {\n attributes[key] = value;\n }\n }\n }\n\n const nodeId = this.nextNodeId++;\n const virtualElement: LiveVirtualDOMElement = {\n nodeId,\n tag: node.nodeName,\n attributes,\n childNodes: [],\n realElement: node,\n parent,\n };\n if (node instanceof this.domRunner.getWindow().Text && node.textContent) {\n virtualElement.textContent = node.textContent;\n }\n this.nodeToNodeId.set(virtualElement, nodeId);\n this.nodeIdToNode.set(nodeId, virtualElement);\n this.realElementToVirtualElement.set(node, virtualElement);\n return [virtualElement, false];\n }\n\n private getVirtualDOMElementForRealElementOrThrow(\n realElement: Element | Text,\n ): LiveVirtualDOMElement {\n const virtualElement = this.realElementToVirtualElement.get(realElement);\n if (!virtualElement) {\n throw new Error(`Virtual element not found for real element`);\n }\n return virtualElement;\n }\n\n private isIgnoredElement(node: Element | Text): boolean {\n if (this.ignoreTextNodes && node instanceof this.domRunner.getWindow().Text) {\n return true;\n } else if (node instanceof this.domRunner.getWindow().HTMLScriptElement) {\n return true;\n } else if (node instanceof this.domRunner.getWindow().Comment) {\n return true;\n }\n return false;\n }\n\n private isIgnoredAttribute(node: Element | Text, attributeName: string): boolean {\n return attributeName.startsWith(\"on\");\n }\n\n public dispatchRemoteEventFromConnectionId(\n connectionId: number,\n remoteEvent: ObservableDOMRemoteEvent,\n ): void {\n const domNode = this.nodeIdToNode.get(remoteEvent.nodeId);\n if (!domNode) {\n console.error(\"Unknown node ID in remote event: \" + remoteEvent.nodeId);\n return;\n }\n\n if (domNode instanceof this.domRunner.getWindow().Text) {\n console.warn(\"Cannot dispatch remote event to text node\");\n return;\n }\n\n this.domRunner.dispatchRemoteEventFromConnectionId(\n connectionId,\n domNode.realElement as Element,\n remoteEvent,\n );\n }\n\n public dispose() {\n clearInterval(this.documentTimeIntervalTimer);\n this.domRunner.dispose();\n }\n\n private getDocumentTime() {\n return this.domRunner.getDocumentTime();\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mml-io/observable-dom",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,18 +14,18 @@
14
14
  "type-check": "tsc --noEmit",
15
15
  "build": "tsx ./build.ts --build",
16
16
  "iterate": "tsx ./build.ts --watch",
17
- "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0",
18
- "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix",
17
+ "lint": "eslint \"./**/*.{js,jsx,ts,tsx}\" --max-warnings 0",
18
+ "lint-fix": "eslint \"./**/*.{js,jsx,ts,tsx}\" --fix",
19
19
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
20
20
  },
21
21
  "dependencies": {
22
- "@mml-io/observable-dom-common": "^0.18.0",
23
- "jsdom": "24.0.0",
22
+ "@mml-io/observable-dom-common": "^0.19.0",
23
+ "jsdom": "25.0.1",
24
24
  "node-fetch": "3.3.2"
25
25
  },
26
26
  "devDependencies": {
27
- "@types/jsdom": "^21.1.6",
27
+ "@types/jsdom": "^21.1.7",
28
28
  "@types/node-fetch": "2.6.11"
29
29
  },
30
- "gitHead": "b1a31e364d69287681b0afeecdca2b4bc576e3d3"
30
+ "gitHead": "edf5cd7afa62c6ad8b8bcaa70dda9ded4a51cc3b"
31
31
  }