@mml-io/observable-dom 0.1.3 → 0.3.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.
@@ -0,0 +1,24 @@
1
+ import { RemoteEvent } from "@mml-io/observable-dom-common";
2
+ import { DOMWindow } from "jsdom";
3
+ import { DOMRunnerFactory, DOMRunnerMessage } from "./ObservableDOM";
4
+ export declare const JSDOMRunnerFactory: DOMRunnerFactory;
5
+ export declare class JSDOMRunner {
6
+ private monkeyPatchMutationRecordCallback;
7
+ domWindow: DOMWindow | null;
8
+ private jsdom;
9
+ private callback;
10
+ private mutationObserver;
11
+ private htmlPath;
12
+ private documentStartTime;
13
+ private isLoaded;
14
+ private logBuffer;
15
+ constructor(htmlPath: string, htmlContents: string, params: object, callback: (domRunnerMessage: DOMRunnerMessage) => void);
16
+ private flushLogBuffer;
17
+ private log;
18
+ getDocument(): Document;
19
+ getWindow(): any;
20
+ dispose(): void;
21
+ getDocumentTime(): number;
22
+ dispatchRemoteEventFromConnectionId(connectionId: number, domNode: Element, remoteEvent: RemoteEvent): void;
23
+ private createVirtualConsole;
24
+ }
@@ -0,0 +1,51 @@
1
+ import { LogMessage, ObservableDOMInterface, ObservableDOMMessage, ObservableDOMParameters, RemoteEvent, StaticVirtualDOMElement } from "@mml-io/observable-dom-common";
2
+ export type DOMRunnerMessage = {
3
+ loaded?: boolean;
4
+ mutationList?: Array<MutationRecord>;
5
+ logMessage?: LogMessage;
6
+ };
7
+ export type DOMRunnerInterface = {
8
+ getDocument(): Document;
9
+ getWindow(): Window & {
10
+ CustomEvent: typeof CustomEvent;
11
+ Text: typeof Text;
12
+ HTMLScriptElement: typeof HTMLScriptElement;
13
+ Comment: typeof Comment;
14
+ };
15
+ dispatchRemoteEventFromConnectionId(connectionId: number, realElement: Element, remoteEvent: RemoteEvent): void;
16
+ dispose(): void;
17
+ getDocumentTime(): number;
18
+ };
19
+ export type DOMRunnerFactory = (htmlPath: string, htmlContents: string, params: object, callback: (domRunnerMessage: DOMRunnerMessage) => void) => DOMRunnerInterface;
20
+ export type LiveVirtualDOMElement = Omit<StaticVirtualDOMElement, "childNodes"> & {
21
+ realElement: Element | Text;
22
+ childNodes: Array<LiveVirtualDOMElement>;
23
+ parent: LiveVirtualDOMElement | null;
24
+ };
25
+ export declare class ObservableDOM implements ObservableDOMInterface {
26
+ private nodeToNodeId;
27
+ private nodeIdToNode;
28
+ private realElementToVirtualElement;
29
+ private ignoreTextNodes;
30
+ private callback;
31
+ private nextNodeId;
32
+ private htmlPath;
33
+ private domRunner;
34
+ private documentTimeIntervalTimer;
35
+ constructor(observableDOMParameters: ObservableDOMParameters, callback: (message: ObservableDOMMessage, observableDOM: ObservableDOMInterface) => void, runnerFactory: DOMRunnerFactory);
36
+ addConnectedUserId(connectionId: number): void;
37
+ removeConnectedUserId(connectionId: number): void;
38
+ private processModificationList;
39
+ private addKnownNodesInMutation;
40
+ private removeKnownNodesInMutation;
41
+ private removeVirtualDOMElement;
42
+ private createVirtualDOMElementWithChildren;
43
+ private createVirtualDOMElement;
44
+ private getFirstNonIgnoredPreviousSibling;
45
+ private getVirtualDOMElementForRealElementOrThrow;
46
+ private isIgnoredElement;
47
+ private isIgnoredAttribute;
48
+ dispatchRemoteEventFromConnectionId(connectionId: number, remoteEvent: RemoteEvent): void;
49
+ dispose(): void;
50
+ private getDocumentTime;
51
+ }
package/build/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export * from "../src/index";
1
+ export * from "./ObservableDOM";
2
+ export * from "./JSDOMRunner";
package/build/index.js CHANGED
@@ -31,23 +31,23 @@ var src_exports = {};
31
31
  __export(src_exports, {
32
32
  JSDOMRunner: () => JSDOMRunner,
33
33
  JSDOMRunnerFactory: () => JSDOMRunnerFactory,
34
- ObservableDom: () => ObservableDom
34
+ ObservableDOM: () => ObservableDOM
35
35
  });
36
36
  module.exports = __toCommonJS(src_exports);
37
37
 
38
38
  // src/utils.ts
39
- function virtualDomElementToStatic(el) {
39
+ function virtualDOMElementToStatic(el) {
40
40
  return {
41
41
  nodeId: el.nodeId,
42
42
  tag: el.tag,
43
43
  attributes: el.attributes,
44
- childNodes: el.childNodes.map((child) => virtualDomElementToStatic(child)),
44
+ childNodes: el.childNodes.map((child) => virtualDOMElementToStatic(child)),
45
45
  textContent: el.textContent
46
46
  };
47
47
  }
48
48
 
49
- // src/ObservableDom.ts
50
- var ObservableDom = class {
49
+ // src/ObservableDOM.ts
50
+ var ObservableDOM = class {
51
51
  constructor(observableDOMParameters, callback, runnerFactory) {
52
52
  this.nodeToNodeId = /* @__PURE__ */ new Map();
53
53
  this.nodeIdToNode = /* @__PURE__ */ new Map();
@@ -58,9 +58,12 @@ var ObservableDom = class {
58
58
  this.ignoreTextNodes = observableDOMParameters.ignoreTextNodes;
59
59
  this.callback = callback;
60
60
  this.documentTimeIntervalTimer = setInterval(() => {
61
- this.callback({
62
- documentTime: this.getDocumentTime()
63
- });
61
+ this.callback(
62
+ {
63
+ documentTime: this.getDocumentTime()
64
+ },
65
+ this
66
+ );
64
67
  }, observableDOMParameters.pingIntervalMilliseconds || 5e3);
65
68
  this.domRunner = runnerFactory(
66
69
  observableDOMParameters.htmlPath,
@@ -68,33 +71,36 @@ var ObservableDom = class {
68
71
  observableDOMParameters.params,
69
72
  (domRunnerMessage) => {
70
73
  if (domRunnerMessage.loaded) {
71
- this.createVirtualDomElementWithChildren(
74
+ this.createVirtualDOMElementWithChildren(
72
75
  this.domRunner.getDocument(),
73
76
  null
74
77
  );
75
- const snapshot = virtualDomElementToStatic(
76
- this.getVirtualDomElementForRealElementOrThrow(
78
+ const snapshot = virtualDOMElementToStatic(
79
+ this.getVirtualDOMElementForRealElementOrThrow(
77
80
  this.domRunner.getDocument()
78
81
  )
79
82
  );
80
- this.callback({
81
- snapshot,
82
- documentTime: this.getDocumentTime()
83
- });
83
+ this.callback(
84
+ {
85
+ snapshot,
86
+ documentTime: this.getDocumentTime()
87
+ },
88
+ this
89
+ );
84
90
  } else if (domRunnerMessage.mutationList) {
85
91
  this.processModificationList(domRunnerMessage.mutationList);
86
92
  } else if (domRunnerMessage.logMessage) {
87
- this.callback({
88
- logMessage: domRunnerMessage.logMessage,
89
- documentTime: this.getDocumentTime()
90
- });
93
+ this.callback(
94
+ {
95
+ logMessage: domRunnerMessage.logMessage,
96
+ documentTime: this.getDocumentTime()
97
+ },
98
+ this
99
+ );
91
100
  }
92
101
  }
93
102
  );
94
103
  }
95
- addIPCWebsocket(webSocket) {
96
- return this.domRunner.addIPCWebsocket(webSocket);
97
- }
98
104
  addConnectedUserId(connectionId) {
99
105
  this.domRunner.getWindow().dispatchEvent(
100
106
  new (this.domRunner.getWindow()).CustomEvent("connected", {
@@ -111,8 +117,8 @@ var ObservableDom = class {
111
117
  }
112
118
  processModificationList(mutationList) {
113
119
  const documentEl = this.domRunner.getDocument();
114
- const documentVirtualDomElement = this.realElementToVirtualElement.get(documentEl);
115
- if (!documentVirtualDomElement) {
120
+ const documentVirtualDOMElement = this.realElementToVirtualElement.get(documentEl);
121
+ if (!documentVirtualDOMElement) {
116
122
  throw new Error(`document not created in processModificationList`);
117
123
  }
118
124
  if (mutationList.length > 1) {
@@ -130,7 +136,7 @@ var ObservableDom = class {
130
136
  }
131
137
  this.addKnownNodesInMutation(mutation);
132
138
  const firstNonIgnoredPreviousSibling = mutation.previousSibling ? this.getFirstNonIgnoredPreviousSibling(mutation.previousSibling) : null;
133
- const targetElement = this.getVirtualDomElementForRealElementOrThrow(
139
+ const targetElement = this.getVirtualDOMElementForRealElementOrThrow(
134
140
  mutation.target
135
141
  );
136
142
  const addedNodes = [];
@@ -138,43 +144,46 @@ var ObservableDom = class {
138
144
  if (this.isIgnoredElement(node)) {
139
145
  continue;
140
146
  }
141
- const virtualDomElement = this.getVirtualDomElementForRealElementOrThrow(
147
+ const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(
142
148
  node
143
149
  );
144
- addedNodes.push(virtualDomElementToStatic(virtualDomElement));
150
+ addedNodes.push(virtualDOMElementToStatic(virtualDOMElement));
145
151
  }
146
152
  const removedNodeIds = [];
147
153
  for (const node of mutation.removedNodes) {
148
154
  if (this.isIgnoredElement(node)) {
149
155
  continue;
150
156
  }
151
- const virtualDomElement = this.getVirtualDomElementForRealElementOrThrow(
157
+ const virtualDOMElement = this.getVirtualDOMElementForRealElementOrThrow(
152
158
  node
153
159
  );
154
- removedNodeIds.push(virtualDomElement.nodeId);
160
+ removedNodeIds.push(virtualDOMElement.nodeId);
155
161
  }
156
162
  const mutationRecord = {
157
163
  type: mutation.type,
158
164
  targetId: targetElement.nodeId,
159
165
  addedNodes,
160
166
  removedNodeIds,
161
- previousSiblingId: firstNonIgnoredPreviousSibling !== null ? this.getVirtualDomElementForRealElementOrThrow(firstNonIgnoredPreviousSibling).nodeId : null,
167
+ previousSiblingId: firstNonIgnoredPreviousSibling !== null ? this.getVirtualDOMElementForRealElementOrThrow(firstNonIgnoredPreviousSibling).nodeId : null,
162
168
  attribute: mutation.attributeName ? {
163
169
  attributeName: mutation.attributeName,
164
170
  value: mutation.target.getAttribute(mutation.attributeName)
165
171
  } : null
166
172
  };
167
- this.callback({
168
- mutation: mutationRecord,
169
- documentTime: this.getDocumentTime()
170
- });
173
+ this.callback(
174
+ {
175
+ mutation: mutationRecord,
176
+ documentTime: this.getDocumentTime()
177
+ },
178
+ this
179
+ );
171
180
  this.removeKnownNodesInMutation(mutation);
172
181
  }
173
182
  }
174
183
  addKnownNodesInMutation(mutation) {
175
184
  const targetNode = mutation.target;
176
- const virtualDomElement = this.realElementToVirtualElement.get(targetNode);
177
- if (!virtualDomElement) {
185
+ const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);
186
+ if (!virtualDOMElement) {
178
187
  throw new Error(
179
188
  "Unknown node in addKnownNodesInMutation:" + targetNode + "," + mutation.type
180
189
  );
@@ -192,7 +201,7 @@ var ObservableDom = class {
192
201
  if (!previousSiblingElement) {
193
202
  throw new Error("Unknown previous sibling");
194
203
  }
195
- index = virtualDomElement.childNodes.indexOf(previousSiblingElement);
204
+ index = virtualDOMElement.childNodes.indexOf(previousSiblingElement);
196
205
  if (index === -1) {
197
206
  throw new Error("Previous sibling is not currently a child of the parent element");
198
207
  }
@@ -200,13 +209,13 @@ var ObservableDom = class {
200
209
  }
201
210
  mutation.addedNodes.forEach((node) => {
202
211
  const asElementOrText = node;
203
- const childVirtualDomElement = this.createVirtualDomElementWithChildren(
212
+ const childVirtualDOMElement = this.createVirtualDOMElementWithChildren(
204
213
  asElementOrText,
205
- virtualDomElement
214
+ virtualDOMElement
206
215
  );
207
- if (childVirtualDomElement) {
208
- if (virtualDomElement.childNodes.indexOf(childVirtualDomElement) === -1) {
209
- virtualDomElement.childNodes.splice(index, 0, childVirtualDomElement);
216
+ if (childVirtualDOMElement) {
217
+ if (virtualDOMElement.childNodes.indexOf(childVirtualDOMElement) === -1) {
218
+ virtualDOMElement.childNodes.splice(index, 0, childVirtualDOMElement);
210
219
  index++;
211
220
  }
212
221
  }
@@ -218,18 +227,18 @@ var ObservableDom = class {
218
227
  }
219
228
  const attributeValue = targetNode.getAttribute(attributeName);
220
229
  if (attributeValue === null) {
221
- delete virtualDomElement.attributes[attributeName];
230
+ delete virtualDOMElement.attributes[attributeName];
222
231
  } else {
223
- virtualDomElement.attributes[attributeName] = attributeValue;
232
+ virtualDOMElement.attributes[attributeName] = attributeValue;
224
233
  }
225
234
  } else if (mutation.type === "characterData") {
226
- virtualDomElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
235
+ virtualDOMElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
227
236
  }
228
237
  }
229
238
  removeKnownNodesInMutation(mutation) {
230
239
  const targetNode = mutation.target;
231
- const virtualDomElement = this.realElementToVirtualElement.get(targetNode);
232
- if (!virtualDomElement) {
240
+ const virtualDOMElement = this.realElementToVirtualElement.get(targetNode);
241
+ if (!virtualDOMElement) {
233
242
  throw new Error("Unknown node in mutation list:" + targetNode + ", " + mutation.type);
234
243
  }
235
244
  if (mutation.type === "childList") {
@@ -238,36 +247,36 @@ var ObservableDom = class {
238
247
  if (this.isIgnoredElement(asElementOrText)) {
239
248
  continue;
240
249
  }
241
- const childDomElement = this.realElementToVirtualElement.get(asElementOrText);
242
- if (!childDomElement) {
250
+ const childDOMElement = this.realElementToVirtualElement.get(asElementOrText);
251
+ if (!childDOMElement) {
243
252
  console.warn(this.htmlPath, "Unknown node in removeKnownNodesInMutation");
244
253
  continue;
245
254
  } else {
246
- this.removeVirtualDomElement(childDomElement);
247
- const index = virtualDomElement.childNodes.indexOf(childDomElement);
248
- virtualDomElement.childNodes.splice(index, 1);
255
+ this.removeVirtualDOMElement(childDOMElement);
256
+ const index = virtualDOMElement.childNodes.indexOf(childDOMElement);
257
+ virtualDOMElement.childNodes.splice(index, 1);
249
258
  }
250
259
  }
251
260
  return;
252
261
  }
253
262
  }
254
- removeVirtualDomElement(virtualDomElement) {
255
- this.nodeIdToNode.delete(virtualDomElement.nodeId);
256
- this.nodeToNodeId.delete(virtualDomElement);
257
- this.realElementToVirtualElement.delete(virtualDomElement.realElement);
258
- for (const child of virtualDomElement.childNodes) {
259
- this.removeVirtualDomElement(child);
263
+ removeVirtualDOMElement(virtualDOMElement) {
264
+ this.nodeIdToNode.delete(virtualDOMElement.nodeId);
265
+ this.nodeToNodeId.delete(virtualDOMElement);
266
+ this.realElementToVirtualElement.delete(virtualDOMElement.realElement);
267
+ for (const child of virtualDOMElement.childNodes) {
268
+ this.removeVirtualDOMElement(child);
260
269
  }
261
270
  }
262
- createVirtualDomElementWithChildren(node, parent) {
263
- const virtualElement = this.createVirtualDomElement(node, parent);
271
+ createVirtualDOMElementWithChildren(node, parent) {
272
+ const virtualElement = this.createVirtualDOMElement(node, parent);
264
273
  if (!virtualElement) {
265
274
  return null;
266
275
  }
267
276
  if (node.childNodes) {
268
277
  for (let i = 0; i < node.childNodes.length; i++) {
269
278
  const child = node.childNodes[i];
270
- const childVirtualElement = this.createVirtualDomElementWithChildren(
279
+ const childVirtualElement = this.createVirtualDOMElementWithChildren(
271
280
  child,
272
281
  virtualElement
273
282
  );
@@ -278,7 +287,7 @@ var ObservableDom = class {
278
287
  }
279
288
  return virtualElement;
280
289
  }
281
- createVirtualDomElement(node, parent) {
290
+ createVirtualDOMElement(node, parent) {
282
291
  if (this.isIgnoredElement(node)) {
283
292
  return null;
284
293
  }
@@ -332,7 +341,7 @@ var ObservableDom = class {
332
341
  }
333
342
  return null;
334
343
  }
335
- getVirtualDomElementForRealElementOrThrow(realElement) {
344
+ getVirtualDOMElementForRealElementOrThrow(realElement) {
336
345
  const virtualElement = this.realElementToVirtualElement.get(realElement);
337
346
  if (!virtualElement) {
338
347
  throw new Error(`Virtual element not found for real element`);
@@ -382,7 +391,7 @@ var import_vm = __toESM(require("vm"));
382
391
  var import_jsdom = require("jsdom");
383
392
  var nodeFetch = __toESM(require("node-fetch"));
384
393
  var import_node_fetch = __toESM(require("node-fetch"));
385
- var ErrDomWindowNotInitialized = "DOMWindow not initialized";
394
+ var ErrDOMWindowNotInitialized = "DOMWindow not initialized";
386
395
  var monkeyPatchedMutationRecordCallbacks = /* @__PURE__ */ new Set();
387
396
  function installMutationObserverMonkeyPatch() {
388
397
  const MutationRecordExports = require("jsdom/lib/jsdom/living/generated/MutationRecord");
@@ -406,10 +415,8 @@ var RejectionResourceLoader = class extends import_jsdom.ResourceLoader {
406
415
  };
407
416
  var JSDOMRunner = class {
408
417
  constructor(htmlPath, htmlContents, params, callback) {
409
- this.ipcWebsockets = /* @__PURE__ */ new Set();
410
418
  this.domWindow = null;
411
419
  this.mutationObserver = null;
412
- this.ipcListeners = /* @__PURE__ */ new Set();
413
420
  this.documentStartTime = Date.now();
414
421
  this.isLoaded = false;
415
422
  this.logBuffer = [];
@@ -433,7 +440,7 @@ var JSDOMRunner = class {
433
440
  }
434
441
  };
435
442
  monkeyPatchedMutationRecordCallbacks.add(this.monkeyPatchMutationRecordCallback);
436
- this.jsDom = new import_jsdom.JSDOM(htmlContents, {
443
+ this.jsdom = new import_jsdom.JSDOM(htmlContents, {
437
444
  runScripts: "dangerously",
438
445
  resources: new RejectionResourceLoader(),
439
446
  url: this.htmlPath,
@@ -452,22 +459,6 @@ var JSDOMRunner = class {
452
459
  });
453
460
  window.document.timeline = timeline;
454
461
  window.params = JSON.parse(JSON.stringify(params));
455
- const oldDocumentAddEventListener = window.document.addEventListener;
456
- window.document.addEventListener = (...args) => {
457
- const [eventName, listener] = args;
458
- if (eventName === "ipc") {
459
- this.ipcListeners.add(listener);
460
- }
461
- return oldDocumentAddEventListener.call(window.document, ...args);
462
- };
463
- const oldDocumentRemoveEventListener = window.document.addEventListener;
464
- window.document.removeEventListener = (...args) => {
465
- const [eventName, listener] = args;
466
- if (eventName === "ipc") {
467
- this.ipcListeners.delete(listener);
468
- }
469
- return oldDocumentRemoveEventListener.call(window.document, ...args);
470
- };
471
462
  this.mutationObserver = new window.MutationObserver((mutationList) => {
472
463
  this.callback({
473
464
  mutationList
@@ -509,36 +500,13 @@ var JSDOMRunner = class {
509
500
  }
510
501
  getDocument() {
511
502
  if (!this.domWindow) {
512
- throw new Error(ErrDomWindowNotInitialized);
503
+ throw new Error(ErrDOMWindowNotInitialized);
513
504
  }
514
505
  return this.domWindow.document;
515
506
  }
516
507
  getWindow() {
517
508
  return this.domWindow;
518
509
  }
519
- addIPCWebsocket(webSocket) {
520
- if (!this.domWindow) {
521
- throw new Error(ErrDomWindowNotInitialized);
522
- }
523
- if (this.ipcListeners.size === 0) {
524
- console.error("ipc requested, but no ipc listeners registered on document:", this.htmlPath);
525
- webSocket.close();
526
- return;
527
- }
528
- this.ipcWebsockets.add(webSocket);
529
- const event = new this.domWindow.CustomEvent("ipc", {
530
- detail: {
531
- webSocket
532
- }
533
- });
534
- for (const ipcListener of this.ipcListeners) {
535
- ipcListener(event);
536
- }
537
- webSocket.addEventListener("close", () => {
538
- this.ipcWebsockets.delete(webSocket);
539
- });
540
- return;
541
- }
542
510
  dispose() {
543
511
  var _a, _b;
544
512
  const records = (_a = this.mutationObserver) == null ? void 0 : _a.takeRecords();
@@ -547,14 +515,14 @@ var JSDOMRunner = class {
547
515
  });
548
516
  monkeyPatchedMutationRecordCallbacks.delete(this.monkeyPatchMutationRecordCallback);
549
517
  (_b = this.mutationObserver) == null ? void 0 : _b.disconnect();
550
- this.jsDom.window.close();
518
+ this.jsdom.window.close();
551
519
  }
552
520
  getDocumentTime() {
553
521
  return Date.now() - this.documentStartTime;
554
522
  }
555
523
  dispatchRemoteEventFromConnectionId(connectionId, domNode, remoteEvent) {
556
524
  if (!this.domWindow) {
557
- throw new Error(ErrDomWindowNotInitialized);
525
+ throw new Error(ErrDOMWindowNotInitialized);
558
526
  }
559
527
  const bubbles = remoteEvent.bubbles || false;
560
528
  const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {
@@ -567,7 +535,7 @@ var JSDOMRunner = class {
567
535
  const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);
568
536
  if (handlerAttributeValue) {
569
537
  const script = handlerAttributeValue;
570
- const vmContext = this.jsDom.getInternalVMContext();
538
+ const vmContext = this.jsdom.getInternalVMContext();
571
539
  try {
572
540
  const invoke = import_vm.default.runInContext(`(function(event){ ${script} })`, vmContext);
573
541
  Reflect.apply(invoke, domNode, [remoteEventObject]);
@@ -617,6 +585,6 @@ var JSDOMRunner = class {
617
585
  0 && (module.exports = {
618
586
  JSDOMRunner,
619
587
  JSDOMRunnerFactory,
620
- ObservableDom
588
+ ObservableDOM
621
589
  });
622
590
  //# sourceMappingURL=index.js.map