@mml-io/observable-dom 0.0.42
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/build/index.d.ts +1 -0
- package/build/index.js +601 -0
- package/build/index.js.map +7 -0
- package/package.json +23 -0
- package/src/JSDOMRunner.ts +299 -0
- package/src/ObservableDom.ts +447 -0
- package/src/index.ts +2 -0
- package/src/utils.ts +13 -0
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../src/index";
|
package/build/index.js
ADDED
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var src_exports = {};
|
|
31
|
+
__export(src_exports, {
|
|
32
|
+
JSDOMRunner: () => JSDOMRunner,
|
|
33
|
+
JSDOMRunnerFactory: () => JSDOMRunnerFactory,
|
|
34
|
+
ObservableDom: () => ObservableDom
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/utils.ts
|
|
39
|
+
function virtualDomElementToStatic(el) {
|
|
40
|
+
return {
|
|
41
|
+
nodeId: el.nodeId,
|
|
42
|
+
tag: el.tag,
|
|
43
|
+
attributes: el.attributes,
|
|
44
|
+
childNodes: el.childNodes.map((child) => virtualDomElementToStatic(child)),
|
|
45
|
+
textContent: el.textContent
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/ObservableDom.ts
|
|
50
|
+
var ObservableDom = class {
|
|
51
|
+
constructor(observableDOMParameters, callback, runnerFactory) {
|
|
52
|
+
this.nodeToNodeId = /* @__PURE__ */ new Map();
|
|
53
|
+
this.nodeIdToNode = /* @__PURE__ */ new Map();
|
|
54
|
+
this.realElementToVirtualElement = /* @__PURE__ */ new Map();
|
|
55
|
+
this.ignoreTextNodes = true;
|
|
56
|
+
this.nextNodeId = 1;
|
|
57
|
+
this.htmlPath = observableDOMParameters.htmlPath;
|
|
58
|
+
this.ignoreTextNodes = observableDOMParameters.ignoreTextNodes;
|
|
59
|
+
this.callback = callback;
|
|
60
|
+
this.documentTimeIntervalTimer = setInterval(() => {
|
|
61
|
+
this.callback({
|
|
62
|
+
documentTime: this.getDocumentTime()
|
|
63
|
+
});
|
|
64
|
+
}, observableDOMParameters.pingIntervalMilliseconds || 5e3);
|
|
65
|
+
this.domRunner = runnerFactory(
|
|
66
|
+
observableDOMParameters.htmlPath,
|
|
67
|
+
observableDOMParameters.htmlContents,
|
|
68
|
+
observableDOMParameters.params,
|
|
69
|
+
(domRunnerMessage) => {
|
|
70
|
+
if (domRunnerMessage.loaded) {
|
|
71
|
+
this.createVirtualDomElementWithChildren(
|
|
72
|
+
this.domRunner.getDocument(),
|
|
73
|
+
null
|
|
74
|
+
);
|
|
75
|
+
const snapshot = virtualDomElementToStatic(
|
|
76
|
+
this.getVirtualDomElementForRealElementOrThrow(
|
|
77
|
+
this.domRunner.getDocument()
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
this.callback({
|
|
81
|
+
snapshot,
|
|
82
|
+
documentTime: this.getDocumentTime()
|
|
83
|
+
});
|
|
84
|
+
} else if (domRunnerMessage.mutationList) {
|
|
85
|
+
this.processModificationList(domRunnerMessage.mutationList);
|
|
86
|
+
} else if (domRunnerMessage.logMessage) {
|
|
87
|
+
this.callback({
|
|
88
|
+
logMessage: domRunnerMessage.logMessage,
|
|
89
|
+
documentTime: this.getDocumentTime()
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
addIPCWebsocket(webSocket) {
|
|
96
|
+
return this.domRunner.addIPCWebsocket(webSocket);
|
|
97
|
+
}
|
|
98
|
+
addConnectedUserId(connectionId) {
|
|
99
|
+
this.domRunner.getWindow().dispatchEvent(
|
|
100
|
+
new (this.domRunner.getWindow()).CustomEvent("connected", {
|
|
101
|
+
detail: { connectionId }
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
removeConnectedUserId(connectionId) {
|
|
106
|
+
this.domRunner.getWindow().dispatchEvent(
|
|
107
|
+
new (this.domRunner.getWindow()).CustomEvent("disconnected", {
|
|
108
|
+
detail: { connectionId }
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
processModificationList(mutationList) {
|
|
113
|
+
const documentEl = this.domRunner.getDocument();
|
|
114
|
+
const documentVirtualDomElement = this.realElementToVirtualElement.get(documentEl);
|
|
115
|
+
if (!documentVirtualDomElement) {
|
|
116
|
+
throw new Error(`document not created in processModificationList`);
|
|
117
|
+
}
|
|
118
|
+
if (mutationList.length > 1) {
|
|
119
|
+
console.error(
|
|
120
|
+
"More than one mutation record received. It is possible that intermediate states are incorrect."
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
for (const mutation of mutationList) {
|
|
124
|
+
if (this.isIgnoredElement(mutation.target)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (mutation.type === "attributes" && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
128
|
+
this.isIgnoredAttribute(mutation.target, mutation.attributeName)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
this.addKnownNodesInMutation(mutation);
|
|
132
|
+
const firstNonIgnoredPreviousSibling = mutation.previousSibling ? this.getFirstNonIgnoredPreviousSibling(mutation.previousSibling) : null;
|
|
133
|
+
const targetElement = this.getVirtualDomElementForRealElementOrThrow(
|
|
134
|
+
mutation.target
|
|
135
|
+
);
|
|
136
|
+
const addedNodes = [];
|
|
137
|
+
for (const node of mutation.addedNodes) {
|
|
138
|
+
if (this.isIgnoredElement(node)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const virtualDomElement = this.getVirtualDomElementForRealElementOrThrow(
|
|
142
|
+
node
|
|
143
|
+
);
|
|
144
|
+
addedNodes.push(virtualDomElementToStatic(virtualDomElement));
|
|
145
|
+
}
|
|
146
|
+
const removedNodeIds = [];
|
|
147
|
+
for (const node of mutation.removedNodes) {
|
|
148
|
+
if (this.isIgnoredElement(node)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const virtualDomElement = this.getVirtualDomElementForRealElementOrThrow(
|
|
152
|
+
node
|
|
153
|
+
);
|
|
154
|
+
removedNodeIds.push(virtualDomElement.nodeId);
|
|
155
|
+
}
|
|
156
|
+
const mutationRecord = {
|
|
157
|
+
type: mutation.type,
|
|
158
|
+
targetId: targetElement.nodeId,
|
|
159
|
+
addedNodes,
|
|
160
|
+
removedNodeIds,
|
|
161
|
+
previousSiblingId: firstNonIgnoredPreviousSibling !== null ? this.getVirtualDomElementForRealElementOrThrow(firstNonIgnoredPreviousSibling).nodeId : null,
|
|
162
|
+
attribute: mutation.attributeName ? {
|
|
163
|
+
attributeName: mutation.attributeName,
|
|
164
|
+
value: mutation.target.getAttribute(mutation.attributeName)
|
|
165
|
+
} : null
|
|
166
|
+
};
|
|
167
|
+
this.callback({
|
|
168
|
+
mutation: mutationRecord,
|
|
169
|
+
documentTime: this.getDocumentTime()
|
|
170
|
+
});
|
|
171
|
+
this.removeKnownNodesInMutation(mutation);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
addKnownNodesInMutation(mutation) {
|
|
175
|
+
const targetNode = mutation.target;
|
|
176
|
+
const virtualDomElement = this.realElementToVirtualElement.get(targetNode);
|
|
177
|
+
if (!virtualDomElement) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"Unknown node in addKnownNodesInMutation:" + targetNode + "," + mutation.type
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (mutation.type === "childList") {
|
|
183
|
+
let previousSibling = mutation.previousSibling;
|
|
184
|
+
let index = 0;
|
|
185
|
+
while (previousSibling && this.isIgnoredElement(previousSibling)) {
|
|
186
|
+
previousSibling = previousSibling.previousSibling;
|
|
187
|
+
}
|
|
188
|
+
if (previousSibling) {
|
|
189
|
+
const previousSiblingElement = this.realElementToVirtualElement.get(
|
|
190
|
+
previousSibling
|
|
191
|
+
);
|
|
192
|
+
if (!previousSiblingElement) {
|
|
193
|
+
throw new Error("Unknown previous sibling");
|
|
194
|
+
}
|
|
195
|
+
index = virtualDomElement.childNodes.indexOf(previousSiblingElement);
|
|
196
|
+
if (index === -1) {
|
|
197
|
+
throw new Error("Previous sibling is not currently a child of the parent element");
|
|
198
|
+
}
|
|
199
|
+
index += 1;
|
|
200
|
+
}
|
|
201
|
+
mutation.addedNodes.forEach((node) => {
|
|
202
|
+
const asElementOrText = node;
|
|
203
|
+
const childVirtualDomElement = this.createVirtualDomElementWithChildren(
|
|
204
|
+
asElementOrText,
|
|
205
|
+
virtualDomElement
|
|
206
|
+
);
|
|
207
|
+
if (childVirtualDomElement) {
|
|
208
|
+
if (virtualDomElement.childNodes.indexOf(childVirtualDomElement) === -1) {
|
|
209
|
+
virtualDomElement.childNodes.splice(index, 0, childVirtualDomElement);
|
|
210
|
+
index++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
} else if (mutation.type === "attributes") {
|
|
215
|
+
const attributeName = mutation.attributeName;
|
|
216
|
+
if (this.isIgnoredAttribute(targetNode, attributeName)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const attributeValue = targetNode.getAttribute(attributeName);
|
|
220
|
+
if (attributeValue === null) {
|
|
221
|
+
delete virtualDomElement.attributes[attributeName];
|
|
222
|
+
} else {
|
|
223
|
+
virtualDomElement.attributes[attributeName] = attributeValue;
|
|
224
|
+
}
|
|
225
|
+
} else if (mutation.type === "characterData") {
|
|
226
|
+
virtualDomElement.textContent = targetNode.textContent ? targetNode.textContent : void 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
removeKnownNodesInMutation(mutation) {
|
|
230
|
+
const targetNode = mutation.target;
|
|
231
|
+
const virtualDomElement = this.realElementToVirtualElement.get(targetNode);
|
|
232
|
+
if (!virtualDomElement) {
|
|
233
|
+
throw new Error("Unknown node in mutation list:" + targetNode + ", " + mutation.type);
|
|
234
|
+
}
|
|
235
|
+
if (mutation.type === "childList") {
|
|
236
|
+
for (const node of mutation.removedNodes) {
|
|
237
|
+
const asElementOrText = node;
|
|
238
|
+
if (this.isIgnoredElement(asElementOrText)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const childDomElement = this.realElementToVirtualElement.get(asElementOrText);
|
|
242
|
+
if (!childDomElement) {
|
|
243
|
+
console.warn(this.htmlPath, "Unknown node in removeKnownNodesInMutation");
|
|
244
|
+
continue;
|
|
245
|
+
} else {
|
|
246
|
+
this.removeVirtualDomElement(childDomElement);
|
|
247
|
+
const index = virtualDomElement.childNodes.indexOf(childDomElement);
|
|
248
|
+
virtualDomElement.childNodes.splice(index, 1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
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);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
createVirtualDomElementWithChildren(node, parent) {
|
|
263
|
+
const virtualElement = this.createVirtualDomElement(node, parent);
|
|
264
|
+
if (!virtualElement) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
if (node.childNodes) {
|
|
268
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
269
|
+
const child = node.childNodes[i];
|
|
270
|
+
const childVirtualElement = this.createVirtualDomElementWithChildren(
|
|
271
|
+
child,
|
|
272
|
+
virtualElement
|
|
273
|
+
);
|
|
274
|
+
if (childVirtualElement) {
|
|
275
|
+
virtualElement.childNodes.push(childVirtualElement);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return virtualElement;
|
|
280
|
+
}
|
|
281
|
+
createVirtualDomElement(node, parent) {
|
|
282
|
+
if (this.isIgnoredElement(node)) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
const existingValue = this.realElementToVirtualElement.get(node);
|
|
286
|
+
if (existingValue !== void 0) {
|
|
287
|
+
throw new Error("Node already has a virtual element: " + node.nodeName);
|
|
288
|
+
}
|
|
289
|
+
if (!node) {
|
|
290
|
+
throw new Error("Cannot assign node id to null");
|
|
291
|
+
}
|
|
292
|
+
const attributes = {};
|
|
293
|
+
if (node.attributes) {
|
|
294
|
+
const asHTMLElement = node;
|
|
295
|
+
for (const key of asHTMLElement.getAttributeNames()) {
|
|
296
|
+
const value = asHTMLElement.getAttribute(key);
|
|
297
|
+
if (value === null) {
|
|
298
|
+
throw new Error("Null attribute value for key: " + key);
|
|
299
|
+
}
|
|
300
|
+
if (!this.isIgnoredAttribute(node, key)) {
|
|
301
|
+
attributes[key] = value;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const nodeId = this.nextNodeId++;
|
|
306
|
+
const virtualElement = {
|
|
307
|
+
nodeId,
|
|
308
|
+
tag: node.nodeName,
|
|
309
|
+
attributes,
|
|
310
|
+
childNodes: [],
|
|
311
|
+
realElement: node,
|
|
312
|
+
parent
|
|
313
|
+
};
|
|
314
|
+
if (node instanceof this.domRunner.getWindow().Text && node.textContent) {
|
|
315
|
+
virtualElement.textContent = node.textContent;
|
|
316
|
+
}
|
|
317
|
+
this.nodeToNodeId.set(virtualElement, nodeId);
|
|
318
|
+
this.nodeIdToNode.set(nodeId, virtualElement);
|
|
319
|
+
this.realElementToVirtualElement.set(node, virtualElement);
|
|
320
|
+
return virtualElement;
|
|
321
|
+
}
|
|
322
|
+
getFirstNonIgnoredPreviousSibling(node) {
|
|
323
|
+
let currentNode = node;
|
|
324
|
+
if (!this.isIgnoredElement(currentNode)) {
|
|
325
|
+
return currentNode;
|
|
326
|
+
}
|
|
327
|
+
while (currentNode && currentNode.previousSibling) {
|
|
328
|
+
currentNode = currentNode.previousSibling;
|
|
329
|
+
if (!this.isIgnoredElement(currentNode)) {
|
|
330
|
+
return currentNode;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
getVirtualDomElementForRealElementOrThrow(realElement) {
|
|
336
|
+
const virtualElement = this.realElementToVirtualElement.get(realElement);
|
|
337
|
+
if (!virtualElement) {
|
|
338
|
+
throw new Error(`Virtual element not found for real element`);
|
|
339
|
+
}
|
|
340
|
+
return virtualElement;
|
|
341
|
+
}
|
|
342
|
+
isIgnoredElement(node) {
|
|
343
|
+
if (this.ignoreTextNodes && node instanceof this.domRunner.getWindow().Text) {
|
|
344
|
+
return true;
|
|
345
|
+
} else if (node instanceof this.domRunner.getWindow().HTMLScriptElement) {
|
|
346
|
+
return true;
|
|
347
|
+
} else if (node instanceof this.domRunner.getWindow().Comment) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
isIgnoredAttribute(node, attributeName) {
|
|
353
|
+
return attributeName.startsWith("on");
|
|
354
|
+
}
|
|
355
|
+
dispatchRemoteEventFromConnectionId(connectionId, remoteEvent) {
|
|
356
|
+
const domNode = this.nodeIdToNode.get(remoteEvent.nodeId);
|
|
357
|
+
if (!domNode) {
|
|
358
|
+
console.error("Unknown node ID in remote event: " + remoteEvent.nodeId);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (domNode instanceof this.domRunner.getWindow().Text) {
|
|
362
|
+
console.warn("Cannot dispatch remote event to text node");
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this.domRunner.dispatchRemoteEventFromConnectionId(
|
|
366
|
+
connectionId,
|
|
367
|
+
domNode.realElement,
|
|
368
|
+
remoteEvent
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
dispose() {
|
|
372
|
+
clearInterval(this.documentTimeIntervalTimer);
|
|
373
|
+
this.domRunner.dispose();
|
|
374
|
+
}
|
|
375
|
+
getDocumentTime() {
|
|
376
|
+
return this.domRunner.getDocumentTime();
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// src/JSDOMRunner.ts
|
|
381
|
+
var import_vm = __toESM(require("vm"));
|
|
382
|
+
var import_jsdom = require("jsdom");
|
|
383
|
+
var monkeyPatchedMutationRecordCallbacks = /* @__PURE__ */ new Set();
|
|
384
|
+
function installMutationObserverMonkeyPatch() {
|
|
385
|
+
const MutationRecordExports = require("jsdom/lib/jsdom/living/generated/MutationRecord");
|
|
386
|
+
const originalCreateImpl = MutationRecordExports.createImpl;
|
|
387
|
+
MutationRecordExports.createImpl = (...args) => {
|
|
388
|
+
for (const callback of monkeyPatchedMutationRecordCallbacks) {
|
|
389
|
+
callback();
|
|
390
|
+
}
|
|
391
|
+
return originalCreateImpl.call(null, ...args);
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
var monkeyPatchInstalled = false;
|
|
395
|
+
var JSDOMRunnerFactory = (htmlPath, htmlContents, params, callback) => {
|
|
396
|
+
return new JSDOMRunner(htmlPath, htmlContents, params, callback);
|
|
397
|
+
};
|
|
398
|
+
var RejectionResourceLoader = class extends import_jsdom.ResourceLoader {
|
|
399
|
+
fetch(url) {
|
|
400
|
+
console.error("RejectionResourceLoader.fetch", url);
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var JSDOMRunner = class {
|
|
405
|
+
constructor(htmlPath, htmlContents, params, callback) {
|
|
406
|
+
this.ipcWebsockets = /* @__PURE__ */ new Set();
|
|
407
|
+
this.ipcListeners = /* @__PURE__ */ new Set();
|
|
408
|
+
this.documentStartTime = Date.now();
|
|
409
|
+
this.isLoaded = false;
|
|
410
|
+
this.logBuffer = [];
|
|
411
|
+
this.htmlPath = htmlPath;
|
|
412
|
+
this.callback = callback;
|
|
413
|
+
if (!monkeyPatchInstalled) {
|
|
414
|
+
installMutationObserverMonkeyPatch();
|
|
415
|
+
monkeyPatchInstalled = true;
|
|
416
|
+
}
|
|
417
|
+
this.monkeyPatchMutationRecordCallback = () => {
|
|
418
|
+
const records = this.mutationObserver.takeRecords();
|
|
419
|
+
if (records.length > 1) {
|
|
420
|
+
throw new Error(
|
|
421
|
+
"The monkey patching should have prevented more than one record being handled at a time"
|
|
422
|
+
);
|
|
423
|
+
} else if (records.length > 0) {
|
|
424
|
+
this.callback({
|
|
425
|
+
mutationList: records
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
monkeyPatchedMutationRecordCallbacks.add(this.monkeyPatchMutationRecordCallback);
|
|
430
|
+
this.jsDom = new import_jsdom.JSDOM(htmlContents, {
|
|
431
|
+
runScripts: "dangerously",
|
|
432
|
+
resources: new RejectionResourceLoader(),
|
|
433
|
+
url: this.htmlPath,
|
|
434
|
+
virtualConsole: this.createVirtualConsole(),
|
|
435
|
+
beforeParse: (window) => {
|
|
436
|
+
this.domWindow = window;
|
|
437
|
+
const timeline = {};
|
|
438
|
+
Object.defineProperty(timeline, "currentTime", {
|
|
439
|
+
get: () => {
|
|
440
|
+
return this.getDocumentTime();
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
window.document.timeline = timeline;
|
|
444
|
+
window.params = JSON.parse(JSON.stringify(params));
|
|
445
|
+
const oldDocumentAddEventListener = window.document.addEventListener;
|
|
446
|
+
window.document.addEventListener = (...args) => {
|
|
447
|
+
const [eventName, listener] = args;
|
|
448
|
+
if (eventName === "ipc") {
|
|
449
|
+
this.ipcListeners.add(listener);
|
|
450
|
+
}
|
|
451
|
+
return oldDocumentAddEventListener.call(window.document, ...args);
|
|
452
|
+
};
|
|
453
|
+
const oldDocumentRemoveEventListener = window.document.addEventListener;
|
|
454
|
+
window.document.removeEventListener = (...args) => {
|
|
455
|
+
const [eventName, listener] = args;
|
|
456
|
+
if (eventName === "ipc") {
|
|
457
|
+
this.ipcListeners.delete(listener);
|
|
458
|
+
}
|
|
459
|
+
return oldDocumentRemoveEventListener.call(window.document, ...args);
|
|
460
|
+
};
|
|
461
|
+
this.mutationObserver = new window.MutationObserver((mutationList) => {
|
|
462
|
+
this.callback({
|
|
463
|
+
mutationList
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
window.addEventListener("load", () => {
|
|
467
|
+
this.mutationObserver.observe(window.document, {
|
|
468
|
+
attributes: true,
|
|
469
|
+
childList: true,
|
|
470
|
+
subtree: true,
|
|
471
|
+
characterData: true
|
|
472
|
+
});
|
|
473
|
+
this.isLoaded = true;
|
|
474
|
+
this.callback({
|
|
475
|
+
loaded: true
|
|
476
|
+
});
|
|
477
|
+
this.flushLogBuffer();
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
flushLogBuffer() {
|
|
483
|
+
for (const logMessage of this.logBuffer) {
|
|
484
|
+
this.callback({
|
|
485
|
+
logMessage
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
this.logBuffer = [];
|
|
489
|
+
}
|
|
490
|
+
log(message) {
|
|
491
|
+
if (!this.isLoaded) {
|
|
492
|
+
this.logBuffer.push(message);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
this.callback({
|
|
496
|
+
logMessage: message
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
getDocument() {
|
|
500
|
+
return this.domWindow.document;
|
|
501
|
+
}
|
|
502
|
+
getWindow() {
|
|
503
|
+
return this.domWindow;
|
|
504
|
+
}
|
|
505
|
+
addIPCWebsocket(webSocket) {
|
|
506
|
+
if (this.ipcListeners.size === 0) {
|
|
507
|
+
console.error("ipc requested, but no ipc listeners registered on document:", this.htmlPath);
|
|
508
|
+
webSocket.close();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
this.ipcWebsockets.add(webSocket);
|
|
512
|
+
const event = new this.domWindow.CustomEvent("ipc", {
|
|
513
|
+
detail: {
|
|
514
|
+
webSocket
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
for (const ipcListener of this.ipcListeners) {
|
|
518
|
+
ipcListener(event);
|
|
519
|
+
}
|
|
520
|
+
webSocket.addEventListener("close", () => {
|
|
521
|
+
this.ipcWebsockets.delete(webSocket);
|
|
522
|
+
});
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
dispose() {
|
|
526
|
+
const records = this.mutationObserver.takeRecords();
|
|
527
|
+
this.callback({
|
|
528
|
+
mutationList: records
|
|
529
|
+
});
|
|
530
|
+
monkeyPatchedMutationRecordCallbacks.delete(this.monkeyPatchMutationRecordCallback);
|
|
531
|
+
this.mutationObserver.disconnect();
|
|
532
|
+
this.jsDom.window.close();
|
|
533
|
+
}
|
|
534
|
+
getDocumentTime() {
|
|
535
|
+
return Date.now() - this.documentStartTime;
|
|
536
|
+
}
|
|
537
|
+
dispatchRemoteEventFromConnectionId(connectionId, domNode, remoteEvent) {
|
|
538
|
+
const bubbles = remoteEvent.bubbles || false;
|
|
539
|
+
const remoteEventObject = new this.domWindow.CustomEvent(remoteEvent.name, {
|
|
540
|
+
bubbles,
|
|
541
|
+
detail: { ...remoteEvent.params, connectionId }
|
|
542
|
+
});
|
|
543
|
+
const eventTypeLowerCase = remoteEvent.name.toLowerCase();
|
|
544
|
+
if (eventTypeLowerCase !== "click") {
|
|
545
|
+
const handlerAttributeName = "on" + eventTypeLowerCase;
|
|
546
|
+
const handlerAttributeValue = domNode.getAttribute(handlerAttributeName);
|
|
547
|
+
if (handlerAttributeValue) {
|
|
548
|
+
const script = handlerAttributeValue;
|
|
549
|
+
const vmContext = this.jsDom.getInternalVMContext();
|
|
550
|
+
try {
|
|
551
|
+
const invoke = import_vm.default.runInContext(`(function(event){ ${script} })`, vmContext);
|
|
552
|
+
Reflect.apply(invoke, domNode, [remoteEventObject]);
|
|
553
|
+
} catch (e) {
|
|
554
|
+
console.error("Error running event handler:", e);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
domNode.dispatchEvent(remoteEventObject);
|
|
559
|
+
}
|
|
560
|
+
createVirtualConsole() {
|
|
561
|
+
const virtualConsole = new import_jsdom.VirtualConsole();
|
|
562
|
+
virtualConsole.on("jsdomError", (...args) => {
|
|
563
|
+
this.log({
|
|
564
|
+
level: "system",
|
|
565
|
+
content: args
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
virtualConsole.on("error", (...args) => {
|
|
569
|
+
this.log({
|
|
570
|
+
level: "error",
|
|
571
|
+
content: args
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
virtualConsole.on("warn", (...args) => {
|
|
575
|
+
this.log({
|
|
576
|
+
level: "warn",
|
|
577
|
+
content: args
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
virtualConsole.on("log", (...args) => {
|
|
581
|
+
this.log({
|
|
582
|
+
level: "log",
|
|
583
|
+
content: args
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
virtualConsole.on("info", (...args) => {
|
|
587
|
+
this.log({
|
|
588
|
+
level: "info",
|
|
589
|
+
content: args
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
return virtualConsole;
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
596
|
+
0 && (module.exports = {
|
|
597
|
+
JSDOMRunner,
|
|
598
|
+
JSDOMRunnerFactory,
|
|
599
|
+
ObservableDom
|
|
600
|
+
});
|
|
601
|
+
//# sourceMappingURL=index.js.map
|