@mml-io/observable-dom 0.14.0 → 0.16.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.
@@ -2,6 +2,10 @@ import { RemoteEvent } 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;
5
+ export type ResourceURL = string | RegExp;
6
+ export type JSDOMRunnerOptions = {
7
+ allowResourceLoading: boolean | ResourceURL[];
8
+ };
5
9
  /**
6
10
  * The JSDOMRunner class is used to run HTML Documents using JSDOM and emit DOMRunnerMessages for document events such
7
11
  * as mutations.
@@ -17,7 +21,7 @@ export declare class JSDOMRunner implements DOMRunnerInterface {
17
21
  private documentStartTime;
18
22
  private isLoaded;
19
23
  private logBuffer;
20
- constructor(htmlPath: string, htmlContents: string, params: object, callback: (domRunnerMessage: DOMRunnerMessage) => void);
24
+ constructor(htmlPath: string, htmlContents: string, params: object, callback: (domRunnerMessage: DOMRunnerMessage) => void, { allowResourceLoading }?: JSDOMRunnerOptions);
21
25
  private flushLogBuffer;
22
26
  private log;
23
27
  getDocument(): Document;
@@ -42,12 +42,9 @@ export declare class ObservableDOM implements ObservableDOMInterface {
42
42
  addConnectedUserId(connectionId: number): void;
43
43
  removeConnectedUserId(connectionId: number): void;
44
44
  private processModificationList;
45
- private addKnownNodesInMutation;
46
- private removeKnownNodesInMutation;
47
45
  private removeVirtualDOMElement;
48
46
  private createVirtualDOMElementWithChildren;
49
47
  private createVirtualDOMElement;
50
- private getFirstNonIgnoredPreviousSibling;
51
48
  private getVirtualDOMElementForRealElementOrThrow;
52
49
  private isIgnoredElement;
53
50
  private isIgnoredAttribute;
package/build/index.js CHANGED
@@ -111,37 +111,92 @@ var ObservableDOM = class {
111
111
  this.isIgnoredAttribute(mutation.target, mutation.attributeName)) {
112
112
  continue;
113
113
  }
114
- this.addKnownNodesInMutation(mutation);
115
- const firstNonIgnoredPreviousSibling = mutation.previousSibling ? this.getFirstNonIgnoredPreviousSibling(mutation.previousSibling) : null;
116
- const targetElement = this.getVirtualDOMElementForRealElementOrThrow(
117
- mutation.target
118
- );
119
- const addedNodes = [];
120
- for (const node of mutation.addedNodes) {
121
- if (this.isIgnoredElement(node)) {
122
- continue;
123
- }
124
- const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(
125
- node
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 firstNonIgnoredPreviousSibling = mutation.previousSibling;
120
+ let insertionIndex = 0;
121
+ while (firstNonIgnoredPreviousSibling && this.isIgnoredElement(firstNonIgnoredPreviousSibling)) {
122
+ firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling;
123
+ }
124
+ let previousSiblingElement = void 0;
125
+ if (firstNonIgnoredPreviousSibling) {
126
+ previousSiblingElement = this.realElementToVirtualElement.get(
127
+ firstNonIgnoredPreviousSibling
126
128
  );
127
- addedNodes.push(virtualDOMElementToStatic(virtualDOMElement));
129
+ if (!previousSiblingElement) {
130
+ throw new Error("Unknown previous sibling");
131
+ }
132
+ insertionIndex = targetElement.childNodes.indexOf(previousSiblingElement);
133
+ if (insertionIndex === -1) {
134
+ throw new Error("Previous sibling is not currently a child of the parent element");
135
+ }
136
+ insertionIndex += 1;
128
137
  }
138
+ const toAdd = [];
129
139
  const removedNodeIds = [];
130
- for (const node of mutation.removedNodes) {
131
- if (this.isIgnoredElement(node)) {
132
- continue;
140
+ if (mutation.type === "childList") {
141
+ mutation.removedNodes.forEach((node) => {
142
+ const asElementOrText = node;
143
+ if (this.isIgnoredElement(asElementOrText)) {
144
+ return;
145
+ }
146
+ const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);
147
+ if (!childDOMElement) {
148
+ return;
149
+ } else {
150
+ const index = targetElement.childNodes.indexOf(childDOMElement);
151
+ if (index === -1) {
152
+ } else {
153
+ this.removeVirtualDOMElement(childDOMElement);
154
+ removedNodeIds.push(childDOMElement.nodeId);
155
+ const removal = targetElement.childNodes.splice(index, 1);
156
+ if (removal.length !== 1) {
157
+ throw new Error("Removal length not 1");
158
+ } else {
159
+ if (removal[0].nodeId !== childDOMElement.nodeId) {
160
+ throw new Error("Removal node id mismatch");
161
+ }
162
+ }
163
+ }
164
+ }
165
+ });
166
+ mutation.addedNodes.forEach((node) => {
167
+ const asElementOrText = node;
168
+ if (asElementOrText.parentNode !== targetNode) {
169
+ } else {
170
+ const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(
171
+ asElementOrText,
172
+ targetElement
173
+ );
174
+ if (childVirtualDOMElement) {
175
+ toAdd.push(childVirtualDOMElement);
176
+ }
177
+ }
178
+ });
179
+ targetElement.childNodes.splice(insertionIndex, 0, ...toAdd);
180
+ } else if (mutation.type === "attributes") {
181
+ const attributeName = mutation.attributeName;
182
+ if (!this.isIgnoredAttribute(targetNode, attributeName)) {
183
+ const attributeValue = targetNode.getAttribute(attributeName);
184
+ if (attributeValue === null) {
185
+ delete targetElement.attributes[attributeName];
186
+ } else {
187
+ targetElement.attributes[attributeName] = attributeValue;
188
+ }
133
189
  }
134
- const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(
135
- node
136
- );
137
- removedNodeIds.push(virtualDOMElement.nodeId);
190
+ } else if (mutation.type === "characterData") {
191
+ targetElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
138
192
  }
193
+ const addedNodes = toAdd.map(virtualDOMElementToStatic);
139
194
  const mutationRecord = {
140
195
  type: mutation.type,
141
196
  targetId: targetElement.nodeId,
142
197
  addedNodes,
143
198
  removedNodeIds,
144
- previousSiblingId: firstNonIgnoredPreviousSibling !== null ? this.getVirtualDOMElementForRealElementOrThrow(firstNonIgnoredPreviousSibling).nodeId : null,
199
+ previousSiblingId: previousSiblingElement ? previousSiblingElement.nodeId : null,
145
200
  attribute: mutation.attributeName ? {
146
201
  attributeName: mutation.attributeName,
147
202
  value: mutation.target.getAttribute(mutation.attributeName)
@@ -154,87 +209,6 @@ var ObservableDOM = class {
154
209
  },
155
210
  this
156
211
  );
157
- this.removeKnownNodesInMutation(mutation);
158
- }
159
- }
160
- addKnownNodesInMutation(mutation) {
161
- const targetNode = mutation.target;
162
- const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);
163
- if (!virtualDOMElement) {
164
- throw new Error(
165
- "Unknown node in addKnownNodesInMutation:" + targetNode + "," + mutation.type
166
- );
167
- }
168
- if (mutation.type === "childList") {
169
- let previousSibling = mutation.previousSibling;
170
- let index = 0;
171
- while (previousSibling && this.isIgnoredElement(previousSibling)) {
172
- previousSibling = previousSibling.previousSibling;
173
- }
174
- if (previousSibling) {
175
- const previousSiblingElement = this.realElementToVirtualElement.get(
176
- previousSibling
177
- );
178
- if (!previousSiblingElement) {
179
- throw new Error("Unknown previous sibling");
180
- }
181
- index = virtualDOMElement.childNodes.indexOf(previousSiblingElement);
182
- if (index === -1) {
183
- throw new Error("Previous sibling is not currently a child of the parent element");
184
- }
185
- index += 1;
186
- }
187
- mutation.addedNodes.forEach((node) => {
188
- const asElementOrText = node;
189
- const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(
190
- asElementOrText,
191
- virtualDOMElement
192
- );
193
- if (childVirtualDOMElement) {
194
- if (virtualDOMElement.childNodes.indexOf(childVirtualDOMElement) === -1) {
195
- virtualDOMElement.childNodes.splice(index, 0, childVirtualDOMElement);
196
- index++;
197
- }
198
- }
199
- });
200
- } else if (mutation.type === "attributes") {
201
- const attributeName = mutation.attributeName;
202
- if (this.isIgnoredAttribute(targetNode, attributeName)) {
203
- return;
204
- }
205
- const attributeValue = targetNode.getAttribute(attributeName);
206
- if (attributeValue === null) {
207
- delete virtualDOMElement.attributes[attributeName];
208
- } else {
209
- virtualDOMElement.attributes[attributeName] = attributeValue;
210
- }
211
- } else if (mutation.type === "characterData") {
212
- virtualDOMElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
213
- }
214
- }
215
- removeKnownNodesInMutation(mutation) {
216
- const targetNode = mutation.target;
217
- const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);
218
- if (!virtualDOMElement) {
219
- throw new Error("Unknown node in mutation list:" + targetNode + ", " + mutation.type);
220
- }
221
- if (mutation.type === "childList") {
222
- for (const node of mutation.removedNodes) {
223
- const asElementOrText = node;
224
- if (this.isIgnoredElement(asElementOrText)) {
225
- continue;
226
- }
227
- const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);
228
- if (!childDOMElement) {
229
- console.warn(this.htmlPath, "Unknown node in removeKnownNodesInMutation");
230
- continue;
231
- } else {
232
- this.removeVirtualDOMElement(childDOMElement);
233
- const index = virtualDOMElement.childNodes.indexOf(childDOMElement);
234
- virtualDOMElement.childNodes.splice(index, 1);
235
- }
236
- }
237
- return;
238
212
  }
239
213
  }
240
214
  removeVirtualDOMElement(virtualDOMElement) {
@@ -246,10 +220,13 @@ var ObservableDOM = class {
246
220
  }
247
221
  }
248
222
  createVirtualDOMElementWithChildren(node, parent) {
249
- const virtualElement = this.createVirtualDOMElement(node, parent);
223
+ const [virtualElement, existing] = this.createVirtualDOMElement(node, parent);
250
224
  if (!virtualElement) {
251
225
  return null;
252
226
  }
227
+ if (existing) {
228
+ return null;
229
+ }
253
230
  if (node.childNodes) {
254
231
  for (let i = 0; i < node.childNodes.length; i++) {
255
232
  const child = node.childNodes[i];
@@ -266,15 +243,15 @@ var ObservableDOM = class {
266
243
  }
267
244
  createVirtualDOMElement(node, parent) {
268
245
  if (this.isIgnoredElement(node)) {
269
- return null;
270
- }
271
- const existingValue = this.realElementToVirtualElement.get(node);
272
- if (existingValue !== void 0) {
273
- throw new Error("Node already has a virtual element: " + node.nodeName);
246
+ return [null, false];
274
247
  }
275
248
  if (!node) {
276
249
  throw new Error("Cannot assign node id to null");
277
250
  }
251
+ const existingValue = this.realElementToVirtualElement.get(node);
252
+ if (existingValue !== void 0) {
253
+ return [existingValue, true];
254
+ }
278
255
  const attributes = {};
279
256
  if (node.attributes) {
280
257
  const asHTMLElement = node;
@@ -303,20 +280,7 @@ var ObservableDOM = class {
303
280
  this.nodeToNodeId.set(virtualElement, nodeId);
304
281
  this.nodeIdToNode.set(nodeId, virtualElement);
305
282
  this.realElementToVirtualElement.set(node, virtualElement);
306
- return virtualElement;
307
- }
308
- getFirstNonIgnoredPreviousSibling(node) {
309
- let currentNode = node;
310
- if (!this.isIgnoredElement(currentNode)) {
311
- return currentNode;
312
- }
313
- while (currentNode && currentNode.previousSibling) {
314
- currentNode = currentNode.previousSibling;
315
- if (!this.isIgnoredElement(currentNode)) {
316
- return currentNode;
317
- }
318
- }
319
- return null;
283
+ return [virtualElement, false];
320
284
  }
321
285
  getVirtualDOMElementForRealElementOrThrow(realElement) {
322
286
  const virtualElement = this.realElementToVirtualElement.get(realElement);
@@ -365,7 +329,11 @@ var ObservableDOM = class {
365
329
 
366
330
  // src/JSDOMRunner.ts
367
331
  import vm from "vm";
368
- import { JSDOM, ResourceLoader, VirtualConsole } from "jsdom";
332
+ import {
333
+ JSDOM,
334
+ ResourceLoader,
335
+ VirtualConsole
336
+ } from "jsdom";
369
337
  import * as nodeFetch from "node-fetch";
370
338
  import nodeFetchFn from "node-fetch";
371
339
  var ErrDOMWindowNotInitialized = "DOMWindow not initialized";
@@ -378,8 +346,24 @@ var RejectionResourceLoader = class extends ResourceLoader {
378
346
  return null;
379
347
  }
380
348
  };
349
+ var AllowListResourceLoader = class extends ResourceLoader {
350
+ constructor(urls, opts) {
351
+ super(opts);
352
+ this.urls = urls;
353
+ }
354
+ fetch(url, opts) {
355
+ const allow = this.urls.some((allowedURL) => {
356
+ return typeof allowedURL === "string" ? allowedURL === url : allowedURL.test(url);
357
+ });
358
+ if (allow) {
359
+ return super.fetch(url, opts ?? {});
360
+ }
361
+ console.error("AllowListResourceLoader.fetch: resource not allowed", url);
362
+ return null;
363
+ }
364
+ };
381
365
  var JSDOMRunner = class {
382
- constructor(htmlPath, htmlContents, params, callback) {
366
+ constructor(htmlPath, htmlContents, params, callback, { allowResourceLoading } = { allowResourceLoading: false }) {
383
367
  this.domWindow = null;
384
368
  this.mutationObserver = null;
385
369
  this.documentStartTime = Date.now();
@@ -387,9 +371,10 @@ var JSDOMRunner = class {
387
371
  this.logBuffer = [];
388
372
  this.htmlPath = htmlPath;
389
373
  this.callback = callback;
374
+ const resources = Array.isArray(allowResourceLoading) ? new AllowListResourceLoader(allowResourceLoading) : allowResourceLoading ? "usable" : new RejectionResourceLoader();
390
375
  this.jsdom = new JSDOM(htmlContents, {
391
376
  runScripts: "dangerously",
392
- resources: new RejectionResourceLoader(),
377
+ resources,
393
378
  url: this.htmlPath,
394
379
  virtualConsole: this.createVirtualConsole(),
395
380
  beforeParse: (window) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 this.addKnownNodesInMutation(mutation);\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 firstNonIgnoredPreviousSibling = mutation.previousSibling\n ? this.getFirstNonIgnoredPreviousSibling(mutation.previousSibling as Element | Text)\n : null;\n const targetElement = this.getVirtualDOMElementForRealElementOrThrow(\n mutation.target as Element | Text,\n );\n const addedNodes: Array<StaticVirtualDOMElement> = [];\n for (const node of mutation.addedNodes) {\n if (this.isIgnoredElement(node as Element | Text)) {\n continue;\n }\n const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(\n node as Element | Text,\n );\n addedNodes.push(virtualDOMElementToStatic(virtualDOMElement));\n }\n\n const removedNodeIds: Array<number> = [];\n for (const node of mutation.removedNodes) {\n if (this.isIgnoredElement(node as Element | Text)) {\n continue;\n }\n const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(\n node as Element | Text,\n );\n removedNodeIds.push(virtualDOMElement.nodeId);\n }\n\n const mutationRecord: StaticVirtualDOMMutationIdsRecord = {\n type: mutation.type,\n targetId: targetElement.nodeId,\n addedNodes,\n removedNodeIds,\n previousSiblingId:\n firstNonIgnoredPreviousSibling !== null\n ? this.getVirtualDOMElementForRealElementOrThrow(firstNonIgnoredPreviousSibling).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 this.removeKnownNodesInMutation(mutation);\n }\n }\n\n private addKnownNodesInMutation(mutation: MutationRecord): void {\n const targetNode = mutation.target as Element | Text;\n const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);\n if (!virtualDOMElement) {\n throw new Error(\n \"Unknown node in addKnownNodesInMutation:\" + targetNode + \",\" + mutation.type,\n );\n }\n if (mutation.type === \"childList\") {\n let previousSibling = mutation.previousSibling;\n let index = 0;\n while (previousSibling && this.isIgnoredElement(previousSibling as Element | Text)) {\n previousSibling = previousSibling.previousSibling;\n }\n if (previousSibling) {\n const previousSiblingElement = this.realElementToVirtualElement.get(\n previousSibling as Element | Text,\n );\n if (!previousSiblingElement) {\n throw new Error(\"Unknown previous sibling\");\n }\n index = virtualDOMElement.childNodes.indexOf(previousSiblingElement);\n if (index === -1) {\n throw new Error(\"Previous sibling is not currently a child of the parent element\");\n }\n index += 1;\n }\n mutation.addedNodes.forEach((node: Node) => {\n const asElementOrText = node as Element | Text;\n const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(\n asElementOrText,\n virtualDOMElement,\n );\n if (childVirtualDOMElement) {\n if (virtualDOMElement.childNodes.indexOf(childVirtualDOMElement) === -1) {\n virtualDOMElement.childNodes.splice(index, 0, childVirtualDOMElement);\n index++;\n }\n }\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 return;\n }\n const attributeValue = (targetNode as Element).getAttribute(attributeName);\n if (attributeValue === null) {\n delete virtualDOMElement.attributes[attributeName];\n } else {\n virtualDOMElement.attributes[attributeName] = attributeValue;\n }\n } else if (mutation.type === \"characterData\") {\n virtualDOMElement.textContent = targetNode.textContent ? targetNode.textContent : undefined;\n }\n }\n\n private removeKnownNodesInMutation(mutation: MutationRecord): void {\n const targetNode = mutation.target as Element | Text;\n const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);\n if (!virtualDOMElement) {\n throw new Error(\"Unknown node in mutation list:\" + targetNode + \", \" + mutation.type);\n }\n if (mutation.type === \"childList\") {\n for (const node of mutation.removedNodes) {\n const asElementOrText = node as Element | Text;\n if (this.isIgnoredElement(asElementOrText)) {\n continue;\n }\n const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);\n if (!childDOMElement) {\n console.warn(this.htmlPath, \"Unknown node in removeKnownNodesInMutation\");\n continue;\n } else {\n this.removeVirtualDOMElement(childDOMElement);\n const index = virtualDOMElement.childNodes.indexOf(childDOMElement);\n virtualDOMElement.childNodes.splice(index, 1);\n }\n }\n return;\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 = this.createVirtualDOMElement(node, parent);\n if (!virtualElement) {\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 {\n if (this.isIgnoredElement(node)) {\n return null;\n }\n const existingValue = this.realElementToVirtualElement.get(node);\n if (existingValue !== undefined) {\n throw new Error(\"Node already has a virtual element: \" + node.nodeName);\n }\n if (!node) {\n throw new Error(\"Cannot assign node id to null\");\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;\n }\n\n private getFirstNonIgnoredPreviousSibling(node: Element | Text): Element | Text | null {\n let currentNode = node;\n if (!this.isIgnoredElement(currentNode)) {\n return currentNode;\n }\n while (currentNode && currentNode.previousSibling) {\n currentNode = currentNode.previousSibling as Element | Text;\n if (!this.isIgnoredElement(currentNode)) {\n return currentNode;\n }\n }\n return null;\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 { AbortablePromise, DOMWindow, JSDOM, ResourceLoader, VirtualConsole } 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\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 ) {\n this.htmlPath = htmlPath;\n this.callback = callback;\n\n this.jsdom = new JSDOM(htmlContents, {\n runScripts: \"dangerously\",\n resources: new RejectionResourceLoader(),\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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",
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 firstNonIgnoredPreviousSibling: Element | Text | null = mutation.previousSibling as\n | Element\n | Text;\n let insertionIndex = 0;\n while (\n firstNonIgnoredPreviousSibling &&\n this.isIgnoredElement(firstNonIgnoredPreviousSibling as Element | Text)\n ) {\n firstNonIgnoredPreviousSibling = firstNonIgnoredPreviousSibling.previousSibling as\n | Element\n | Text\n | null;\n }\n let previousSiblingElement: LiveVirtualDOMElement | undefined = undefined;\n if (firstNonIgnoredPreviousSibling) {\n previousSiblingElement = this.realElementToVirtualElement.get(\n firstNonIgnoredPreviousSibling as Element | Text,\n );\n if (!previousSiblingElement) {\n throw new Error(\"Unknown previous sibling\");\n }\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 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 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 ? previousSiblingElement.nodeId : 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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",
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.14.0",
3
+ "version": "0.16.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,7 +19,7 @@
19
19
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
20
20
  },
21
21
  "dependencies": {
22
- "@mml-io/observable-dom-common": "^0.14.0",
22
+ "@mml-io/observable-dom-common": "^0.16.0",
23
23
  "jsdom": "24.0.0",
24
24
  "node-fetch": "3.3.2"
25
25
  },
@@ -27,5 +27,5 @@
27
27
  "@types/jsdom": "^21.1.6",
28
28
  "@types/node-fetch": "2.6.11"
29
29
  },
30
- "gitHead": "3377c31117c59d05f3867f889946a06603420410"
30
+ "gitHead": "b63e712f9e21e9f165ba3845e4c8b5f66af064b1"
31
31
  }