cyborg-hunter 0.7.4 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/CITATION.cff +2 -2
- package/README.md +21 -6
- package/dist/cyborg-hunter-replay.js +3 -3
- package/dist/cyborg-hunter.esm.js +3 -2
- package/dist/cyborg-hunter.min.js +3 -3
- package/dist/extension-cyborg-hunter.js +1 -1
- package/dist/extension-guard-friction.js +5 -5
- package/package.json +10 -2
- package/src/cli/ingest.js +311 -57
- package/src/cli/renderers/html-index-core.js +66 -12
- package/src/cli/renderers/html-index.js +7 -5
- package/src/cli/renderers/replay-assets.js +61 -7
- package/src/cli/renderers/replay-client-source.js +102 -0
- package/src/cli/renderers/replay-viewer.client.js +1750 -595
- package/src/cli/report.js +6 -0
- package/src/core/monitor.js +12 -13
- package/src/jspsych/extension-cyborg-hunter-replay.js +64 -3
- package/src/jspsych/extension-cyborg-hunter.js +1 -1
- package/src/jspsych/extension-guard-friction.js +59 -1
- package/src/replay/capture-dom.js +470 -458
- package/src/replay/capture-trace.js +688 -271
- package/src/replay/delivery.js +82 -0
- package/src/replay/dom-instantiate.js +779 -0
- package/src/replay/index.js +88 -5
- package/src/replay/initial-state.js +295 -0
- package/src/replay/mutations.js +668 -0
- package/src/replay/node-registry.js +116 -0
- package/src/replay/persistence.js +19 -6
- package/src/replay/recorder.js +342 -73
- package/src/replay/redaction.js +165 -0
- package/src/replay/serializer.js +148 -43
- package/src/replay/snapshot.js +409 -0
- package/src/replay/span.js +55 -0
- package/src/replay/viewer-model.js +293 -102
- package/src/shared/constants.js +1 -1
- package/src/shared/inline-safe.js +80 -0
- package/src/shared/schema-v2-validator.js +595 -0
- package/tools/convert/jspsych-v1-to-v2.mjs +432 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/replay/delivery.js
|
|
2
|
+
// What the FILE currently contains: which nodes a player reading this
|
|
3
|
+
// recording holds, and under which parent.
|
|
4
|
+
//
|
|
5
|
+
// Every mutation question that matters turns out to be this one question.
|
|
6
|
+
// Should a removal be emitted? Only if the player holds that node under that
|
|
7
|
+
// parent. May a `before` name this sibling? Only if the player holds it. Does
|
|
8
|
+
// an insertion need its old copy removed first? Only if the player holds it
|
|
9
|
+
// somewhere else. Two review rounds fixed those one at a time by reasoning
|
|
10
|
+
// about the live DOM — the batch's own composition, detached parents, purged
|
|
11
|
+
// ancestors — and a differential fuzz kept finding compositions the reasoning
|
|
12
|
+
// missed, because the live DOM is not the question. It is the DESTINATION.
|
|
13
|
+
//
|
|
14
|
+
// Lifetime is the keyframe span, the same as node ids — which is why the two
|
|
15
|
+
// are handed out together (span.js) rather than left to be reset in step by
|
|
16
|
+
// convention. Nothing here is shared or ambient: a serialization that is not
|
|
17
|
+
// going into the file gets its own span, so it cannot tell a live recording
|
|
18
|
+
// that the player already holds what it has never been sent.
|
|
19
|
+
//
|
|
20
|
+
// Identity-keyed WeakMaps: nothing here holds a node alive, and two recorders
|
|
21
|
+
// on one page never see each other's nodes.
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @returns {{deliver, purge, holds, parentOf, childrenOf, reset}}
|
|
25
|
+
*/
|
|
26
|
+
export function createDelivery() {
|
|
27
|
+
var parents = new WeakMap(); // node → the parent it sits under in the file
|
|
28
|
+
var children = new WeakMap(); // node → Set of its delivered children
|
|
29
|
+
|
|
30
|
+
function detach(node) {
|
|
31
|
+
var parent = parents.get(node);
|
|
32
|
+
if (parent) {
|
|
33
|
+
var siblings = children.get(parent);
|
|
34
|
+
if (siblings) siblings.delete(node);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function purgeNode(node) {
|
|
39
|
+
var kids = children.get(node);
|
|
40
|
+
if (kids) {
|
|
41
|
+
kids.forEach(function (child) { purgeNode(child); });
|
|
42
|
+
children.delete(node);
|
|
43
|
+
}
|
|
44
|
+
parents.delete(node);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
// The file now carries `node` under `parent` (null for a keyframe root).
|
|
49
|
+
// A node delivered somewhere else first leaves that place, which is what
|
|
50
|
+
// makes a move a single fact rather than two.
|
|
51
|
+
deliver: function (node, parent) {
|
|
52
|
+
if (parents.has(node)) detach(node);
|
|
53
|
+
parents.set(node, parent || null);
|
|
54
|
+
if (parent) {
|
|
55
|
+
var siblings = children.get(parent);
|
|
56
|
+
if (!siblings) { siblings = new Set(); children.set(parent, siblings); }
|
|
57
|
+
siblings.add(node);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// The file no longer carries `node`, and a player removing it takes the
|
|
62
|
+
// subtree with it — so its delivered descendants go too.
|
|
63
|
+
purge: function (node) {
|
|
64
|
+
detach(node);
|
|
65
|
+
purgeNode(node);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
holds: function (node) { return parents.has(node); },
|
|
69
|
+
parentOf: function (node) {
|
|
70
|
+
var parent = parents.get(node);
|
|
71
|
+
return parent === undefined ? null : parent;
|
|
72
|
+
},
|
|
73
|
+
// Delivery order, not document order: callers use this to take children
|
|
74
|
+
// away, where order does not matter.
|
|
75
|
+
childrenOf: function (node) {
|
|
76
|
+
var kids = children.get(node);
|
|
77
|
+
return kids ? Array.from(kids) : [];
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
reset: function () { parents = new WeakMap(); children = new WeakMap(); },
|
|
81
|
+
};
|
|
82
|
+
}
|