@spearwolf/shadow-objects 0.32.0 → 0.34.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 +333 -10
- package/README.md +100 -20
- package/bundle.js +5 -54
- package/package.json +7 -3
- package/src/ChangeTrailRefusedError.d.ts +27 -0
- package/src/ChangeTrailRefusedError.d.ts.map +1 -0
- package/src/ChangeTrailRefusedError.js +12 -0
- package/src/ChangeTrailRefusedError.js.map +7 -0
- package/src/EntityUuidInUseError.d.ts +19 -0
- package/src/EntityUuidInUseError.d.ts.map +1 -0
- package/src/EntityUuidInUseError.js +11 -0
- package/src/EntityUuidInUseError.js.map +7 -0
- package/src/WorkerTimeoutError.d.ts +25 -0
- package/src/WorkerTimeoutError.d.ts.map +1 -0
- package/src/WorkerTimeoutError.js +12 -0
- package/src/WorkerTimeoutError.js.map +7 -0
- package/src/bundle.d.ts +1 -1
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +1 -1
- package/src/bundle.js.map +2 -2
- package/src/constants.d.ts +9 -2
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +1 -1
- package/src/constants.js.map +2 -2
- package/src/create-worker.bundle.d.ts +1 -1
- package/src/create-worker.bundle.d.ts.map +1 -1
- package/src/create-worker.bundle.js.map +1 -1
- package/src/create-worker.d.ts +1 -1
- package/src/create-worker.d.ts.map +1 -1
- package/src/create-worker.js.map +1 -1
- package/src/elements/ShaeElement.d.ts +70 -2
- package/src/elements/ShaeElement.d.ts.map +1 -1
- package/src/elements/ShaeElement.js +129 -25
- package/src/elements/ShaeElement.js.map +3 -3
- package/src/elements/ShaeEntElement.d.ts +43 -5
- package/src/elements/ShaeEntElement.d.ts.map +1 -1
- package/src/elements/ShaeEntElement.js +399 -170
- package/src/elements/ShaeEntElement.js.map +2 -2
- package/src/elements/ShaeLifecycleElement.d.ts +71 -0
- package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
- package/src/elements/ShaeLifecycleElement.js +83 -0
- package/src/elements/ShaeLifecycleElement.js.map +7 -0
- package/src/elements/ShaePropElement.d.ts +57 -7
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +241 -220
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts +49 -5
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +230 -74
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/elements/constants.d.ts +6 -0
- package/src/elements/constants.d.ts.map +1 -1
- package/src/elements/constants.js +12 -0
- package/src/elements/constants.js.map +2 -2
- package/src/elements/deferredTeardown.d.ts +24 -0
- package/src/elements/deferredTeardown.d.ts.map +1 -0
- package/src/elements/deferredTeardown.js +30 -0
- package/src/elements/deferredTeardown.js.map +7 -0
- package/src/elements/displayContentsRule.d.ts +25 -0
- package/src/elements/displayContentsRule.d.ts.map +1 -0
- package/src/elements/displayContentsRule.js +37 -0
- package/src/elements/displayContentsRule.js.map +7 -0
- package/src/elements/events.d.ts +10 -7
- package/src/elements/events.d.ts.map +1 -1
- package/src/elements/forwardCustomEvents.d.ts +19 -0
- package/src/elements/forwardCustomEvents.d.ts.map +1 -0
- package/src/elements/forwardCustomEvents.js +47 -0
- package/src/elements/forwardCustomEvents.js.map +7 -0
- package/src/elements/hostedSlots.d.ts +36 -0
- package/src/elements/hostedSlots.d.ts.map +1 -0
- package/src/elements/hostedSlots.js +118 -0
- package/src/elements/hostedSlots.js.map +7 -0
- package/src/elements/parentRemoval.d.ts +18 -0
- package/src/elements/parentRemoval.d.ts.map +1 -0
- package/src/elements/parentRemoval.js +60 -0
- package/src/elements/parentRemoval.js.map +7 -0
- package/src/elements/propValueConverters.d.ts +3 -0
- package/src/elements/propValueConverters.d.ts.map +1 -0
- package/src/elements/propValueConverters.js +54 -0
- package/src/elements/propValueConverters.js.map +7 -0
- package/src/elements/requestEntAncestor.d.ts +32 -0
- package/src/elements/requestEntAncestor.d.ts.map +1 -0
- package/src/elements/requestEntAncestor.js +16 -0
- package/src/elements/requestEntAncestor.js.map +7 -0
- package/src/elements.js.map +1 -1
- package/src/in-the-dark/Entity.d.ts +113 -3
- package/src/in-the-dark/Entity.d.ts.map +1 -1
- package/src/in-the-dark/Entity.js +292 -63
- package/src/in-the-dark/Entity.js.map +3 -3
- package/src/in-the-dark/Kernel.d.ts +81 -17
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +449 -392
- package/src/in-the-dark/Kernel.js.map +3 -3
- package/src/in-the-dark/Registry.d.ts +1 -1
- package/src/in-the-dark/Registry.d.ts.map +1 -1
- package/src/in-the-dark/Registry.js +99 -26
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObject.d.ts +1 -1
- package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObject.js +3 -2
- package/src/in-the-dark/ShadowObject.js.map +2 -2
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts +126 -0
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js +596 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
- package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
- package/src/in-the-dark/SignalsPath.js +2 -2
- package/src/in-the-dark/SignalsPath.js.map +2 -2
- package/src/in-the-dark/events.js.map +1 -1
- package/src/in-the-dark/importModule.d.ts +7 -0
- package/src/in-the-dark/importModule.d.ts.map +1 -1
- package/src/in-the-dark/importModule.js +8 -5
- package/src/in-the-dark/importModule.js.map +2 -2
- package/src/index.d.ts +7 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +5 -1
- package/src/index.js.map +2 -2
- package/src/shadow-objects.d.ts +2 -0
- package/src/shadow-objects.d.ts.map +1 -1
- package/src/shadow-objects.js +2 -0
- package/src/shadow-objects.js.map +2 -2
- package/src/shadow-objects.worker.js +0 -1
- package/src/shadow-objects.worker.js.map +2 -2
- package/src/shae-ent.js.map +1 -1
- package/src/shae-prop.js +2 -2
- package/src/shae-prop.js.map +2 -2
- package/src/shae-worker.js.map +1 -1
- package/src/types.d.ts +39 -8
- package/src/types.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.d.ts +45 -10
- package/src/utils/ConsoleLogger.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.js +54 -28
- package/src/utils/ConsoleLogger.js.map +2 -2
- package/src/utils/FrameLoop.d.ts +42 -3
- package/src/utils/FrameLoop.d.ts.map +1 -1
- package/src/utils/FrameLoop.js +71 -12
- package/src/utils/FrameLoop.js.map +2 -2
- package/src/utils/MicrotaskCollector.d.ts +45 -0
- package/src/utils/MicrotaskCollector.d.ts.map +1 -0
- package/src/utils/MicrotaskCollector.js +33 -0
- package/src/utils/MicrotaskCollector.js.map +7 -0
- package/src/utils/MicrotaskGate.d.ts +17 -0
- package/src/utils/MicrotaskGate.d.ts.map +1 -0
- package/src/utils/MicrotaskGate.js +20 -0
- package/src/utils/MicrotaskGate.js.map +7 -0
- package/src/utils/array-utils.js.map +1 -1
- package/src/utils/attr-utils.d.ts +6 -0
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +4 -2
- package/src/utils/attr-utils.js.map +2 -2
- package/src/utils/constants.js.map +1 -1
- package/src/utils/generateUUID.d.ts +12 -1
- package/src/utils/generateUUID.d.ts.map +1 -1
- package/src/utils/generateUUID.js +31 -266
- package/src/utils/generateUUID.js.map +2 -2
- package/src/utils/props-utils.d.ts +3 -2
- package/src/utils/props-utils.d.ts.map +1 -1
- package/src/utils/props-utils.js +13 -24
- package/src/utils/props-utils.js.map +2 -2
- package/src/utils/runGuarded.d.ts +27 -0
- package/src/utils/runGuarded.d.ts.map +1 -0
- package/src/utils/runGuarded.js +11 -0
- package/src/utils/runGuarded.js.map +7 -0
- package/src/utils/toMaybe.d.ts.map +1 -1
- package/src/utils/toMaybe.js.map +1 -1
- package/src/utils/toNamespace.d.ts.map +1 -1
- package/src/utils/toNamespace.js.map +1 -1
- package/src/utils/toUrlString.d.ts +12 -0
- package/src/utils/toUrlString.d.ts.map +1 -1
- package/src/utils/toUrlString.js.map +2 -2
- package/src/utils/waitForMessageOfType.d.ts +16 -1
- package/src/utils/waitForMessageOfType.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.js +28 -3
- package/src/utils/waitForMessageOfType.js.map +2 -2
- package/src/view/ComponentChanges.d.ts +91 -1
- package/src/view/ComponentChanges.d.ts.map +1 -1
- package/src/view/ComponentChanges.js +253 -69
- package/src/view/ComponentChanges.js.map +2 -2
- package/src/view/ComponentContext.d.ts +239 -7
- package/src/view/ComponentContext.d.ts.map +1 -1
- package/src/view/ComponentContext.js +648 -115
- package/src/view/ComponentContext.js.map +2 -2
- package/src/view/ComponentMemory.d.ts +3 -3
- package/src/view/ComponentMemory.d.ts.map +1 -1
- package/src/view/ComponentMemory.js +3 -1
- package/src/view/ComponentMemory.js.map +2 -2
- package/src/view/IShadowObjectEnvProxy.d.ts +33 -1
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +2 -2
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +18 -11
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +129 -3
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +290 -60
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +73 -2
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +301 -64
- package/src/view/ShadowEnv.js.map +2 -2
- package/src/view/ViewComponent.d.ts +93 -8
- package/src/view/ViewComponent.d.ts.map +1 -1
- package/src/view/ViewComponent.js +148 -28
- package/src/view/ViewComponent.js.map +2 -2
- package/src/view/cloneChangeTrail.js.map +2 -2
- package/src/worker/MessageRouter.d.ts +14 -0
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +80 -18
- package/src/worker/MessageRouter.js.map +2 -2
- package/src/worker/WorkerRuntime.d.ts +22 -1
- package/src/worker/WorkerRuntime.d.ts.map +1 -1
- package/src/worker/WorkerRuntime.js +60 -8
- package/src/worker/WorkerRuntime.js.map +2 -2
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { ChangeTrailPhase, ComponentChangeType, VoidToken } from "../constants.js";
|
|
2
2
|
import { appendToEnd, removeFrom } from "../utils/array-utils.js";
|
|
3
3
|
const ROOT = "#root";
|
|
4
|
+
const PropertyWithoutValue = /* @__PURE__ */ Symbol("shadow-objects/property-without-value");
|
|
4
5
|
class ComponentChanges {
|
|
5
6
|
#uuid;
|
|
6
7
|
get uuid() {
|
|
7
8
|
return this.#uuid;
|
|
8
9
|
}
|
|
9
|
-
#serial = 0;
|
|
10
10
|
constructor(uuid) {
|
|
11
11
|
this.#uuid = uuid;
|
|
12
12
|
}
|
|
13
13
|
#isNew = true;
|
|
14
14
|
#createCount = 0;
|
|
15
15
|
#destroyCount = 0;
|
|
16
|
+
/**
|
|
17
|
+
* Whether this component owes the next change trail anything: a creation, a destruction, or a
|
|
18
|
+
* pending value in one of the four written ↔ pending pairs.
|
|
19
|
+
*/
|
|
16
20
|
hasChanges() {
|
|
17
|
-
return this.#
|
|
21
|
+
return this.#isNew && this.isCreated || this.isDestroyed || this.#nextToken !== void 0 && this.#nextToken !== this.#token || this.#hasPendingParent() || this.#nextOrder !== void 0 && this.#nextOrder !== this.#order || this.#propsChangeOrder.length > 0 || this.#events.length > 0;
|
|
18
22
|
}
|
|
19
23
|
get isNew() {
|
|
20
24
|
return this.#isNew;
|
|
@@ -33,7 +37,6 @@ class ComponentChanges {
|
|
|
33
37
|
#nextParentUuid;
|
|
34
38
|
#nextOrder;
|
|
35
39
|
create(token = VoidToken, parentUuid, order = 0, autoDestructionOnParentRemoval = false) {
|
|
36
|
-
this.#serial++;
|
|
37
40
|
this.#createCount++;
|
|
38
41
|
this.#nextToken = token;
|
|
39
42
|
this.#nextParentUuid = parentUuid ?? ROOT;
|
|
@@ -42,77 +45,161 @@ class ComponentChanges {
|
|
|
42
45
|
}
|
|
43
46
|
destroy() {
|
|
44
47
|
this.#destroyCount++;
|
|
45
|
-
this.#serial++;
|
|
46
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether the pending parent asks for something the confirmed one is not already. A pending
|
|
51
|
+
* value that has come back to the confirmed parent is a change that cancelled itself out.
|
|
52
|
+
*/
|
|
53
|
+
#hasPendingParent() {
|
|
54
|
+
if (this.#nextParentUuid === void 0) return false;
|
|
55
|
+
return (this.#nextParentUuid === ROOT ? void 0 : this.#nextParentUuid) !== this.#parentUuid;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Drop every pending value without writing any of them forward.
|
|
59
|
+
*
|
|
60
|
+
* This is the way out for a component whose bookkeeping is about to be replaced wholesale —
|
|
61
|
+
* `ComponentContext.reCreateChanges` does exactly that. A trail that has gone out is
|
|
62
|
+
* settled with {@link ComponentChanges.commitChange} instead.
|
|
63
|
+
*/
|
|
47
64
|
clear() {
|
|
48
|
-
this.#serial = 0;
|
|
49
|
-
this.#isNew = false;
|
|
50
65
|
this.#nextToken = void 0;
|
|
51
66
|
this.#nextParentUuid = void 0;
|
|
52
67
|
this.#nextOrder = void 0;
|
|
53
68
|
this.#nextProperties.clear();
|
|
54
69
|
this.#propsChangeOrder.length = 0;
|
|
70
|
+
this.#travellingProperties = void 0;
|
|
55
71
|
this.#events.length = 0;
|
|
56
72
|
this.#transferables.clear();
|
|
57
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* The three scalar pairs below all answer the same question the same way: is anything owed once
|
|
76
|
+
* the entry that is on its way out has landed?
|
|
77
|
+
*
|
|
78
|
+
* The written half alone cannot answer it. It is the last *confirmed* value and stays behind
|
|
79
|
+
* until the entry is committed, so a value the caller sets back to it while the entry travels
|
|
80
|
+
* would look like "nothing to do" — and the entry would then be the last word, leaving the
|
|
81
|
+
* Shadow Environment holding a value the view has already moved on from. So the pending half is
|
|
82
|
+
* only released where there is nothing in flight to contradict it; where there is, the new value
|
|
83
|
+
* takes the pending slot and the emitting side decides, against the written half it settles on.
|
|
84
|
+
*/
|
|
58
85
|
changeToken(token) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.#nextToken = token;
|
|
63
|
-
this.#serial++;
|
|
64
|
-
}
|
|
86
|
+
token ??= VoidToken;
|
|
87
|
+
if (token === this.#token && this.#nextToken === void 0 && !this.#isNew) return;
|
|
88
|
+
this.#nextToken = token;
|
|
65
89
|
}
|
|
66
90
|
setParent(parentUuid) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.#nextParentUuid = parentUuid ?? ROOT;
|
|
71
|
-
this.#serial++;
|
|
72
|
-
}
|
|
91
|
+
const nextParentUuid = parentUuid ?? ROOT;
|
|
92
|
+
if (nextParentUuid === (this.#parentUuid ?? ROOT) && this.#nextParentUuid === void 0) return;
|
|
93
|
+
this.#nextParentUuid = nextParentUuid;
|
|
73
94
|
}
|
|
74
95
|
changeOrder(order) {
|
|
75
|
-
if (order === this.#order)
|
|
76
|
-
|
|
77
|
-
} else {
|
|
78
|
-
this.#nextOrder = order;
|
|
79
|
-
this.#serial++;
|
|
80
|
-
}
|
|
96
|
+
if (order === this.#order && this.#nextOrder === void 0) return;
|
|
97
|
+
this.#nextOrder = order;
|
|
81
98
|
}
|
|
82
99
|
#properties = /* @__PURE__ */ new Map();
|
|
83
100
|
#nextProperties = /* @__PURE__ */ new Map();
|
|
101
|
+
/**
|
|
102
|
+
* The keys with a queued change, in the order their changes happened — the order an entry
|
|
103
|
+
* carries them in, and the reason this is a list and not a set.
|
|
104
|
+
*
|
|
105
|
+
* A set beside it would answer membership in one step, and per call it does win from about eight
|
|
106
|
+
* keys on: 8.0 ns for the set against 10.7 ns for the list at eight keys, 10.4 ns against 43.9 ns
|
|
107
|
+
* at 64. The distance is what decides against it. At the upper stop this repository can produce —
|
|
108
|
+
* 64 keys, every one of them changed in every frame at 60 fps, so 3840 calls per second — that is
|
|
109
|
+
* 0.13 ms saved per second of animation. And membership is the smaller half: `removeFrom()` and
|
|
110
|
+
* `appendToEnd()` are an `indexOf` plus a `splice`, and the splice stays linear no matter what
|
|
111
|
+
* answers the membership. Numbers measured 2026-08-31 on node v25.9.0.
|
|
112
|
+
*/
|
|
84
113
|
#propsChangeOrder = [];
|
|
85
|
-
|
|
114
|
+
/**
|
|
115
|
+
* The keys an entry on its way out carries, until that entry is settled. For those keys the
|
|
116
|
+
* written half is behind, and {@link ComponentChanges.changeProperty} must not cancel against it.
|
|
117
|
+
*/
|
|
118
|
+
#travellingProperties;
|
|
119
|
+
/**
|
|
120
|
+
* @returns `true` if the value differs from the last value this component asked for
|
|
121
|
+
*/
|
|
86
122
|
changeProperty(key, value, isEqual) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
123
|
+
const equals = (a, b) => (
|
|
124
|
+
// a registered rule compares values, and the marker is not one -- handed to it, a rule
|
|
125
|
+
// would be asked about a property it never saw, and one that reaches into its arguments
|
|
126
|
+
// throws on a symbol. Where either side is the marker the only question left is whether
|
|
127
|
+
// it is still the same third form, and identity answers that.
|
|
128
|
+
a === PropertyWithoutValue || b === PropertyWithoutValue ? a === b : isEqual == null ? a === b : isEqual(a, b)
|
|
129
|
+
);
|
|
130
|
+
const isQueued = this.#propsChangeOrder.includes(key);
|
|
131
|
+
const isTravelling = this.#travellingProperties?.has(key) ?? false;
|
|
132
|
+
let prevValue;
|
|
133
|
+
if (isQueued) {
|
|
134
|
+
prevValue = this.#nextProperties.get(key);
|
|
135
|
+
} else if (isTravelling) {
|
|
136
|
+
prevValue = this.#travellingProperties.get(key);
|
|
93
137
|
} else {
|
|
138
|
+
prevValue = this.#properties.get(key);
|
|
139
|
+
}
|
|
140
|
+
const valueChanged = !equals(value, prevValue);
|
|
141
|
+
const nothingToSend = !isTravelling && (isQueued ? equals(value, this.#properties.get(key)) : !valueChanged);
|
|
142
|
+
if (nothingToSend) {
|
|
94
143
|
this.#nextProperties.delete(key);
|
|
95
144
|
removeFrom(this.#propsChangeOrder, key);
|
|
145
|
+
} else {
|
|
146
|
+
this.#nextProperties.set(key, value);
|
|
147
|
+
appendToEnd(this.#propsChangeOrder, key);
|
|
96
148
|
}
|
|
149
|
+
return valueChanged;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Mark `key` as set without giving it a value: the next trail carries an entry that names
|
|
153
|
+
* only the key. A later {@link ComponentChanges.changeProperty} replaces it with a value,
|
|
154
|
+
* and {@link ComponentChanges.removeProperty} takes it away like any other property.
|
|
155
|
+
*
|
|
156
|
+
* @returns `true` if this differs from the last value this component asked for
|
|
157
|
+
*/
|
|
158
|
+
setPropertyWithoutValue(key) {
|
|
159
|
+
return this.changeProperty(key, PropertyWithoutValue);
|
|
97
160
|
}
|
|
98
161
|
removeProperty(key) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
162
|
+
const isQueued = this.#propsChangeOrder.includes(key);
|
|
163
|
+
this.#nextProperties.delete(key);
|
|
164
|
+
if (!this.#properties.has(key) && !this.#travellingProperties?.has(key)) {
|
|
165
|
+
removeFrom(this.#propsChangeOrder, key);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!isQueued) {
|
|
106
169
|
appendToEnd(this.#propsChangeOrder, key);
|
|
107
|
-
this.#serial++;
|
|
108
170
|
}
|
|
109
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* The properties this component holds at this moment: the ones a change trail has already
|
|
174
|
+
* carried, overlaid with everything that has accrued since.
|
|
175
|
+
*
|
|
176
|
+
* The overlay is what makes the result the current state instead of the state of the last
|
|
177
|
+
* trail — `#properties` is only written forward while a trail is being built
|
|
178
|
+
* ({@link ComponentChanges.makeCreateEntityChange},
|
|
179
|
+
* {@link ComponentChanges.makeChangePropertyChange}). A key whose accrued value is `undefined`
|
|
180
|
+
* and a key queued for change without an accrued value are both removals, and neither appears
|
|
181
|
+
* in the result. A key that is set without a value stands in the result with
|
|
182
|
+
* {@link PropertyWithoutValue}.
|
|
183
|
+
*/
|
|
184
|
+
getProperties() {
|
|
185
|
+
const properties = new Map(this.#properties);
|
|
186
|
+
for (const key of this.#propsChangeOrder) {
|
|
187
|
+
const value = this.#nextProperties.get(key);
|
|
188
|
+
if (value === void 0) {
|
|
189
|
+
properties.delete(key);
|
|
190
|
+
} else {
|
|
191
|
+
properties.set(key, value);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return properties;
|
|
195
|
+
}
|
|
110
196
|
#events = [];
|
|
111
197
|
#transferables = /* @__PURE__ */ new Set();
|
|
112
198
|
createEvent(type, data, transferables) {
|
|
113
199
|
this.#events.push({ type, data });
|
|
114
|
-
|
|
115
|
-
|
|
200
|
+
for (const transferable of transferables ?? []) {
|
|
201
|
+
this.#transferables.add(transferable);
|
|
202
|
+
}
|
|
116
203
|
}
|
|
117
204
|
transferEventsTo(changes) {
|
|
118
205
|
if (this.#events.length > 0) {
|
|
@@ -132,7 +219,7 @@ class ComponentChanges {
|
|
|
132
219
|
if (isNew) {
|
|
133
220
|
trail.push(this.makeCreateEntityChange());
|
|
134
221
|
} else if (!isDestroyed) {
|
|
135
|
-
if (this.#
|
|
222
|
+
if (this.#hasPendingParent()) {
|
|
136
223
|
trail.push(this.makeSetParentChange());
|
|
137
224
|
} else if (this.#nextOrder !== void 0 && this.#nextOrder !== this.#order) {
|
|
138
225
|
trail.push(this.makeUpdateOrderChange());
|
|
@@ -169,25 +256,31 @@ class ComponentChanges {
|
|
|
169
256
|
return event;
|
|
170
257
|
}
|
|
171
258
|
makeCreateEntityChange() {
|
|
259
|
+
const token = this.#nextToken ?? this.#token;
|
|
172
260
|
const entry = {
|
|
173
261
|
type: ComponentChangeType.CreateEntities,
|
|
174
262
|
uuid: this.#uuid,
|
|
175
|
-
token
|
|
263
|
+
token
|
|
176
264
|
};
|
|
177
|
-
this.#
|
|
178
|
-
|
|
179
|
-
const nextParentUuid = this.#nextParentUuid === ROOT ? void 0 : this.#nextParentUuid;
|
|
180
|
-
this.#parentUuid = nextParentUuid;
|
|
181
|
-
if (nextParentUuid !== void 0) {
|
|
182
|
-
entry.parentUuid = nextParentUuid;
|
|
183
|
-
}
|
|
265
|
+
if (this.#nextParentUuid !== void 0 && this.#nextParentUuid !== ROOT) {
|
|
266
|
+
entry.parentUuid = this.#nextParentUuid;
|
|
184
267
|
}
|
|
185
268
|
if (this.#nextProperties.size > 0) {
|
|
186
|
-
|
|
187
|
-
|
|
269
|
+
const properties = [];
|
|
270
|
+
for (const [key, value] of this.#nextProperties) {
|
|
271
|
+
if (value === PropertyWithoutValue) {
|
|
272
|
+
properties.push([key]);
|
|
273
|
+
} else if (value !== void 0) {
|
|
274
|
+
properties.push([key, value]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
this.#noteTravellingProperties(properties);
|
|
278
|
+
if (properties.length > 0) {
|
|
279
|
+
entry.properties = properties;
|
|
280
|
+
}
|
|
188
281
|
}
|
|
189
282
|
if (this.#nextOrder !== void 0 && this.#nextOrder !== this.#order) {
|
|
190
|
-
entry.order = this.#
|
|
283
|
+
entry.order = this.#nextOrder;
|
|
191
284
|
}
|
|
192
285
|
if (this.#autoDestructionOnParentRemoval) {
|
|
193
286
|
entry.autoDestructionOnParentRemoval = true;
|
|
@@ -201,52 +294,143 @@ class ComponentChanges {
|
|
|
201
294
|
};
|
|
202
295
|
}
|
|
203
296
|
makeSetParentChange() {
|
|
204
|
-
this.#parentUuid = this.#nextParentUuid === ROOT ? void 0 : this.#nextParentUuid;
|
|
205
297
|
const entry = {
|
|
206
298
|
type: ComponentChangeType.SetParent,
|
|
207
299
|
uuid: this.#uuid,
|
|
208
|
-
parentUuid: this.#
|
|
300
|
+
parentUuid: this.#nextParentUuid === ROOT ? void 0 : this.#nextParentUuid
|
|
209
301
|
};
|
|
210
302
|
if (this.#nextOrder !== void 0 && this.#nextOrder !== this.#order) {
|
|
211
|
-
entry.order = this.#
|
|
303
|
+
entry.order = this.#nextOrder;
|
|
212
304
|
}
|
|
213
305
|
return entry;
|
|
214
306
|
}
|
|
215
307
|
makeUpdateOrderChange() {
|
|
216
|
-
this.#order = this.#nextOrder ?? 0;
|
|
217
308
|
return {
|
|
218
309
|
type: ComponentChangeType.UpdateOrder,
|
|
219
310
|
uuid: this.#uuid,
|
|
220
|
-
order: this.#
|
|
311
|
+
order: this.#nextOrder ?? 0
|
|
221
312
|
};
|
|
222
313
|
}
|
|
223
314
|
makeChangeToken() {
|
|
224
|
-
this.#token = this.#nextToken ?? VoidToken;
|
|
225
315
|
return {
|
|
226
316
|
type: ComponentChangeType.ChangeToken,
|
|
227
317
|
uuid: this.#uuid,
|
|
228
|
-
token: this.#
|
|
318
|
+
token: this.#nextToken ?? VoidToken
|
|
229
319
|
};
|
|
230
320
|
}
|
|
231
321
|
makeChangePropertyChange() {
|
|
232
322
|
const properties = this.#propsChangeOrder.map((key) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this.#properties.set(key, nextValue);
|
|
236
|
-
return [key, nextValue];
|
|
237
|
-
} else {
|
|
238
|
-
this.#properties.delete(key);
|
|
239
|
-
return [key, void 0];
|
|
240
|
-
}
|
|
323
|
+
const value = this.#nextProperties.get(key);
|
|
324
|
+
return value === PropertyWithoutValue ? [key] : [key, value];
|
|
241
325
|
});
|
|
326
|
+
this.#noteTravellingProperties(properties);
|
|
242
327
|
return {
|
|
243
328
|
type: ComponentChangeType.ChangeProperties,
|
|
244
329
|
uuid: this.#uuid,
|
|
245
330
|
properties
|
|
246
331
|
};
|
|
247
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Records the keys of an entry that is going out, so a later change knows the written half
|
|
335
|
+
* is behind.
|
|
336
|
+
*/
|
|
337
|
+
#noteTravellingProperties(properties) {
|
|
338
|
+
this.#travellingProperties = new Map(
|
|
339
|
+
properties.map((entry) => [entry[0], entry.length === 1 ? PropertyWithoutValue : entry[1]])
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Fold one trail entry into the written half of this component's bookkeeping: the values the
|
|
344
|
+
* entry carries become the values the next diff is taken against, and the pending half that
|
|
345
|
+
* produced them is released. Called once per entry the Shadow Environment has applied.
|
|
346
|
+
*
|
|
347
|
+
* A pending value is released only while it is still the value the entry carried. Between the
|
|
348
|
+
* build of a trail and its confirmation lies a round trip, and whatever changed in that window
|
|
349
|
+
* is owed to the Shadow Environment — releasing it here would leave the two sides holding
|
|
350
|
+
* different values with nothing left to correct them.
|
|
351
|
+
*/
|
|
352
|
+
commitChange(entry) {
|
|
353
|
+
switch (entry.type) {
|
|
354
|
+
case ComponentChangeType.CreateEntities:
|
|
355
|
+
this.#commitToken(entry.token);
|
|
356
|
+
this.#commitParentUuid(entry.parentUuid);
|
|
357
|
+
this.#commitOrder(entry.order ?? this.#order);
|
|
358
|
+
this.#commitProperties(entry.properties);
|
|
359
|
+
for (const key of this.#propsChangeOrder.slice(0)) {
|
|
360
|
+
if (this.#nextProperties.get(key) === void 0 && !this.#properties.has(key)) {
|
|
361
|
+
this.#nextProperties.delete(key);
|
|
362
|
+
removeFrom(this.#propsChangeOrder, key);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
this.#travellingProperties = void 0;
|
|
366
|
+
this.#isNew = false;
|
|
367
|
+
break;
|
|
368
|
+
case ComponentChangeType.SetParent:
|
|
369
|
+
this.#commitParentUuid(entry.parentUuid);
|
|
370
|
+
this.#commitOrder(entry.order ?? this.#order);
|
|
371
|
+
break;
|
|
372
|
+
case ComponentChangeType.UpdateOrder:
|
|
373
|
+
this.#commitOrder(entry.order);
|
|
374
|
+
break;
|
|
375
|
+
case ComponentChangeType.ChangeToken:
|
|
376
|
+
this.#commitToken(entry.token);
|
|
377
|
+
break;
|
|
378
|
+
case ComponentChangeType.ChangeProperties:
|
|
379
|
+
this.#commitProperties(entry.properties);
|
|
380
|
+
this.#travellingProperties = void 0;
|
|
381
|
+
break;
|
|
382
|
+
case ComponentChangeType.SendEvents:
|
|
383
|
+
this.#events.splice(0, entry.events.length);
|
|
384
|
+
for (const transferable of entry.transferables ?? []) {
|
|
385
|
+
this.#transferables.delete(transferable);
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
case ComponentChangeType.DestroyEntities:
|
|
389
|
+
this.#token = VoidToken;
|
|
390
|
+
this.#parentUuid = void 0;
|
|
391
|
+
this.#order = 0;
|
|
392
|
+
this.#properties.clear();
|
|
393
|
+
this.#travellingProperties = void 0;
|
|
394
|
+
this.#isNew = true;
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
#commitToken(token) {
|
|
399
|
+
this.#token = token;
|
|
400
|
+
if (this.#nextToken === token) {
|
|
401
|
+
this.#nextToken = void 0;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
#commitParentUuid(parentUuid) {
|
|
405
|
+
this.#parentUuid = parentUuid;
|
|
406
|
+
if ((this.#nextParentUuid === ROOT ? void 0 : this.#nextParentUuid) === parentUuid) {
|
|
407
|
+
this.#nextParentUuid = void 0;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
#commitOrder(order) {
|
|
411
|
+
this.#order = order;
|
|
412
|
+
if (this.#nextOrder === order) {
|
|
413
|
+
this.#nextOrder = void 0;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
#commitProperties(properties) {
|
|
417
|
+
for (const entry of properties ?? []) {
|
|
418
|
+
const key = entry[0];
|
|
419
|
+
const value = entry.length === 1 ? PropertyWithoutValue : entry[1];
|
|
420
|
+
if (value === void 0) {
|
|
421
|
+
this.#properties.delete(key);
|
|
422
|
+
} else {
|
|
423
|
+
this.#properties.set(key, value);
|
|
424
|
+
}
|
|
425
|
+
if (this.#nextProperties.get(key) === value) {
|
|
426
|
+
this.#nextProperties.delete(key);
|
|
427
|
+
removeFrom(this.#propsChangeOrder, key);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
248
431
|
}
|
|
249
432
|
export {
|
|
250
|
-
ComponentChanges
|
|
433
|
+
ComponentChanges,
|
|
434
|
+
PropertyWithoutValue
|
|
251
435
|
};
|
|
252
436
|
//# sourceMappingURL=ComponentChanges.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/view/ComponentChanges.ts"],
|
|
4
|
-
"sourcesContent": ["import {ChangeTrailPhase, ComponentChangeType, VoidToken} from '../constants.js';\nimport type {\n IChangeToken,\n IComponentChangeType,\n IComponentEvent,\n ICreateEntitiesChange,\n IDestroyEntitiesChange,\n IPropertiesChange,\n ISendEvents,\n ISetParentChange,\n IUpdateOrderChange,\n} from '../types.js';\nimport {appendToEnd, removeFrom} from '../utils/array-utils.js';\n\nconst ROOT = '#root';\n\nexport class ComponentChanges {\n readonly #uuid: string;\n\n get uuid(): string {\n return this.#uuid;\n }\n\n #serial = 0;\n\n constructor(uuid: string) {\n this.#uuid = uuid;\n }\n\n #isNew = true;\n #createCount = 0;\n #destroyCount = 0;\n\n hasChanges(): boolean {\n return this.#serial > 0;\n }\n\n get isNew(): boolean {\n return this.#isNew;\n }\n\n get isCreated(): boolean {\n return this.#createCount > 0 && this.#createCount > this.#destroyCount;\n }\n\n get isDestroyed(): boolean {\n return this.#destroyCount > 0 && this.#destroyCount >= this.#createCount;\n }\n\n #token: string = VoidToken;\n #parentUuid?: string;\n #order: number = 0;\n #autoDestructionOnParentRemoval = false;\n\n #nextToken?: string;\n #nextParentUuid?: string;\n #nextOrder?: number;\n\n create(token: string = VoidToken, parentUuid?: string, order: number = 0, autoDestructionOnParentRemoval = false) {\n this.#serial++;\n this.#createCount++;\n\n this.#nextToken = token;\n this.#nextParentUuid = parentUuid ?? ROOT;\n this.#nextOrder = !order ? undefined : order;\n this.#autoDestructionOnParentRemoval = autoDestructionOnParentRemoval;\n }\n\n destroy() {\n this.#destroyCount++;\n this.#serial++;\n }\n\n clear() {\n this.#serial = 0;\n\n this.#isNew = false;\n\n this.#nextToken = undefined;\n this.#nextParentUuid = undefined;\n this.#nextOrder = undefined;\n\n this.#nextProperties.clear();\n this.#propsChangeOrder.length = 0;\n\n this.#events.length = 0;\n this.#transferables.clear();\n }\n\n changeToken(token: string | undefined) {\n if (token === this.#token) {\n this.#nextToken = undefined;\n } else {\n this.#nextToken = token;\n this.#serial++;\n }\n }\n\n setParent(parentUuid?: string) {\n if (parentUuid === this.#parentUuid) {\n this.#nextParentUuid = undefined;\n } else {\n this.#nextParentUuid = parentUuid ?? ROOT;\n this.#serial++;\n }\n }\n\n changeOrder(order: number) {\n if (order === this.#order) {\n this.#nextOrder = undefined;\n } else {\n this.#nextOrder = order;\n this.#serial++;\n }\n }\n\n #properties: Map<string, unknown> = new Map();\n #nextProperties: Map<string, unknown> = new Map();\n #propsChangeOrder: string[] = []; // we use an Array here and not a Set, because we want to keep the change order\n\n changeProperty<T = unknown>(key: string, value: T, isEqual?: (a: T, b: T) => boolean) {\n const prevValue = this.#properties.get(key) as T;\n const valueChanged = (isEqual == null && value !== prevValue) || (isEqual != null && !isEqual(value, prevValue));\n\n if (valueChanged) {\n this.#nextProperties.set(key, value);\n appendToEnd(this.#propsChangeOrder, key);\n this.#serial++;\n } else {\n this.#nextProperties.delete(key);\n removeFrom(this.#propsChangeOrder, key);\n }\n }\n\n removeProperty(key: string) {\n const propExists = this.#properties.has(key);\n if (this.#nextProperties.has(key)) {\n this.#nextProperties.delete(key);\n if (!propExists) {\n removeFrom(this.#propsChangeOrder, key);\n }\n } else if (propExists) {\n appendToEnd(this.#propsChangeOrder, key);\n this.#serial++;\n }\n }\n\n #events: IComponentEvent[] = [];\n #transferables = new Set<Transferable>();\n\n createEvent(type: string, data: unknown, transferables?: Transferable[]) {\n this.#events.push({type, data});\n transferables?.forEach((transferable) => this.#transferables.add(transferable));\n this.#serial++;\n }\n\n transferEventsTo(changes: ComponentChanges) {\n if (this.#events.length > 0) {\n changes.#events.push(...this.#events);\n this.#events.length = 0;\n }\n if (this.#transferables.size > 0) {\n changes.#transferables = new Set([...changes.#transferables, ...this.#transferables]);\n this.#transferables.clear();\n }\n }\n\n buildChangeTrail(trail: IComponentChangeType[], trailPhase: ChangeTrailPhase) {\n const {isNew, isCreated, isDestroyed} = this;\n\n if (isNew && isDestroyed) return;\n\n switch (trailPhase) {\n case ChangeTrailPhase.StructuralChanges:\n if (isNew) {\n trail.push(this.makeCreateEntityChange());\n } else if (!isDestroyed) {\n if (this.#nextParentUuid !== undefined && !(this.#nextParentUuid === ROOT && this.#parentUuid === undefined)) {\n trail.push(this.makeSetParentChange());\n } else if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n trail.push(this.makeUpdateOrderChange());\n }\n if (this.#nextToken !== undefined && this.#nextToken !== this.#token) {\n trail.push(this.makeChangeToken());\n }\n }\n break;\n\n case ChangeTrailPhase.ContentUpdates:\n if (!isNew && isCreated && this.#propsChangeOrder.length > 0) {\n trail.push(this.makeChangePropertyChange());\n }\n if (this.#events.length > 0) {\n trail.push(this.makeEvents());\n }\n break;\n\n case ChangeTrailPhase.Removal:\n if (isDestroyed) {\n trail.push(this.makeDestroyEntityChange());\n }\n break;\n }\n }\n\n makeEvents(): ISendEvents {\n const event: ISendEvents = {\n type: ComponentChangeType.SendEvents,\n uuid: this.#uuid,\n events: this.#events.slice(0),\n };\n if (this.#transferables.size > 0) {\n event.transferables = Array.from(this.#transferables);\n }\n return event;\n }\n\n makeCreateEntityChange(): ICreateEntitiesChange {\n const entry: ICreateEntitiesChange = {\n type: ComponentChangeType.CreateEntities,\n uuid: this.#uuid,\n token: this.#nextToken,\n };\n\n this.#token = this.#nextToken;\n\n if (this.#nextParentUuid !== undefined) {\n const nextParentUuid = this.#nextParentUuid === ROOT ? undefined : this.#nextParentUuid;\n this.#parentUuid = nextParentUuid;\n if (nextParentUuid !== undefined) {\n entry.parentUuid = nextParentUuid;\n }\n }\n\n if (this.#nextProperties.size > 0) {\n entry.properties = Array.from(this.#nextProperties.entries()).filter(([, value]) => value !== undefined);\n entry.properties.forEach(([key, value]) => this.#properties.set(key, value));\n }\n\n if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n entry.order = this.#order = this.#nextOrder;\n }\n\n if (this.#autoDestructionOnParentRemoval) {\n entry.autoDestructionOnParentRemoval = true;\n }\n\n return entry;\n }\n\n makeDestroyEntityChange(): IDestroyEntitiesChange {\n return {\n type: ComponentChangeType.DestroyEntities,\n uuid: this.#uuid,\n };\n }\n\n makeSetParentChange(): ISetParentChange {\n this.#parentUuid = this.#nextParentUuid === ROOT ? undefined : this.#nextParentUuid;\n\n const entry: ISetParentChange = {\n type: ComponentChangeType.SetParent,\n uuid: this.#uuid,\n parentUuid: this.#parentUuid,\n };\n\n if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n entry.order = this.#order = this.#nextOrder;\n }\n\n return entry;\n }\n\n makeUpdateOrderChange(): IUpdateOrderChange {\n this.#order = this.#nextOrder ?? 0;\n\n return {\n type: ComponentChangeType.UpdateOrder,\n uuid: this.#uuid,\n order: this.#order,\n };\n }\n\n makeChangeToken(): IChangeToken {\n this.#token = this.#nextToken ?? VoidToken;\n\n return {\n type: ComponentChangeType.ChangeToken,\n uuid: this.#uuid,\n token: this.#token,\n };\n }\n\n makeChangePropertyChange(): IPropertiesChange {\n const properties = this.#propsChangeOrder.map((key) => {\n if (this.#nextProperties.has(key)) {\n // set prop\n const nextValue = this.#nextProperties.get(key);\n this.#properties.set(key, nextValue);\n return [key, nextValue] as [string, unknown];\n } else {\n // remove prop\n this.#properties.delete(key);\n return [key, undefined] as [string, unknown];\n }\n });\n\n return {\n type: ComponentChangeType.ChangeProperties,\n uuid: this.#uuid,\n properties,\n };\n }\n}"],
|
|
5
|
-
"mappings": "AAAA,SAAQ,kBAAkB,qBAAqB,iBAAgB;
|
|
4
|
+
"sourcesContent": ["import {ChangeTrailPhase, ComponentChangeType, VoidToken} from '../constants.js';\nimport type {\n ComponentPropertiesType,\n IChangeToken,\n IComponentChangeType,\n IComponentEvent,\n ICreateEntitiesChange,\n IDestroyEntitiesChange,\n IPropertiesChange,\n ISendEvents,\n ISetParentChange,\n IUpdateOrderChange,\n} from '../types.js';\nimport {appendToEnd, removeFrom} from '../utils/array-utils.js';\n\nconst ROOT = '#root';\n\n/**\n * The value a property carries in this bookkeeping when it is set without one \u2014 the third form\n * of {@link ComponentPropertiesType}, which travels as a one-element `[key]`. `undefined`\n * cannot say it: that is what a removal reads as, and the two have to stay apart all the way\n * to the entry.\n *\n * It never leaves the View Layer. A change trail runs through `structuredClone()` on its way\n * to a worker, and a symbol on that wire is a `DataCloneError` \u2014 so every method that builds\n * an entry turns it back into the one-element form, and the one reader outside this class,\n * `ComponentContext.transferPropertiesTo()`, tests for it before it hands a value on.\n */\nexport const PropertyWithoutValue = Symbol('shadow-objects/property-without-value');\n\n/**\n * Tracks one component's outstanding changes between two change trails as four written \u2194\n * pending pairs: `#token`/`#nextToken`, `#parentUuid`/`#nextParentUuid`, `#order`/`#nextOrder`\n * and `#properties`/`#nextProperties`. The `make*` methods read the pending half and leave it\n * where it is: a trail entry is a request, and until the Shadow Environment has applied it the\n * change is still owed. {@link ComponentChanges.commitChange} is what moves the line \u2014 it folds\n * one applied entry into the written half and releases exactly the pending values that entry\n * carried, so a value that changed again while the entry was on its way goes out with the next\n * trail instead of being lost.\n *\n * Whether anything is outstanding follows from those pairs rather than from a counter, which is\n * what lets a partly applied trail leave the rest of the component untouched.\n *\n * The create/destroy counts behind {@link ComponentChanges.isCreated} and {@link\n * ComponentChanges.isDestroyed} belong to the uuid, not to a `ViewComponent` instance. They\n * carry the rule `ComponentContext.addComponent` keeps: a uuid names one component of a\n * `ComponentContext` at a time, so a later component takes this bookkeeping over only once\n * its predecessor has counted its own `destroy()`. A count pair that outlives its component\n * therefore describes an entity, and the successor on that uuid continues the same entity\n * rather than starting a second.\n */\nexport class ComponentChanges {\n readonly #uuid: string;\n\n get uuid(): string {\n return this.#uuid;\n }\n\n constructor(uuid: string) {\n this.#uuid = uuid;\n }\n\n #isNew = true;\n #createCount = 0;\n #destroyCount = 0;\n\n /**\n * Whether this component owes the next change trail anything: a creation, a destruction, or a\n * pending value in one of the four written \u2194 pending pairs.\n */\n hasChanges(): boolean {\n return (\n (this.#isNew && this.isCreated) ||\n this.isDestroyed ||\n (this.#nextToken !== undefined && this.#nextToken !== this.#token) ||\n this.#hasPendingParent() ||\n (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) ||\n this.#propsChangeOrder.length > 0 ||\n this.#events.length > 0\n );\n }\n\n get isNew(): boolean {\n return this.#isNew;\n }\n\n get isCreated(): boolean {\n return this.#createCount > 0 && this.#createCount > this.#destroyCount;\n }\n\n get isDestroyed(): boolean {\n return this.#destroyCount > 0 && this.#destroyCount >= this.#createCount;\n }\n\n #token: string = VoidToken;\n #parentUuid?: string | undefined;\n #order: number = 0;\n #autoDestructionOnParentRemoval = false;\n\n #nextToken?: string | undefined;\n #nextParentUuid?: string | undefined;\n #nextOrder?: number | undefined;\n\n create(token: string = VoidToken, parentUuid?: string, order: number = 0, autoDestructionOnParentRemoval = false) {\n this.#createCount++;\n\n this.#nextToken = token;\n this.#nextParentUuid = parentUuid ?? ROOT;\n this.#nextOrder = !order ? undefined : order;\n this.#autoDestructionOnParentRemoval = autoDestructionOnParentRemoval;\n }\n\n destroy() {\n this.#destroyCount++;\n }\n\n /**\n * Whether the pending parent asks for something the confirmed one is not already. A pending\n * value that has come back to the confirmed parent is a change that cancelled itself out.\n */\n #hasPendingParent(): boolean {\n if (this.#nextParentUuid === undefined) return false;\n return (this.#nextParentUuid === ROOT ? undefined : this.#nextParentUuid) !== this.#parentUuid;\n }\n\n /**\n * Drop every pending value without writing any of them forward.\n *\n * This is the way out for a component whose bookkeeping is about to be replaced wholesale \u2014\n * `ComponentContext.reCreateChanges` does exactly that. A trail that has gone out is\n * settled with {@link ComponentChanges.commitChange} instead.\n */\n clear() {\n this.#nextToken = undefined;\n this.#nextParentUuid = undefined;\n this.#nextOrder = undefined;\n\n this.#nextProperties.clear();\n this.#propsChangeOrder.length = 0;\n this.#travellingProperties = undefined;\n\n this.#events.length = 0;\n this.#transferables.clear();\n }\n\n /**\n * The three scalar pairs below all answer the same question the same way: is anything owed once\n * the entry that is on its way out has landed?\n *\n * The written half alone cannot answer it. It is the last *confirmed* value and stays behind\n * until the entry is committed, so a value the caller sets back to it while the entry travels\n * would look like \"nothing to do\" \u2014 and the entry would then be the last word, leaving the\n * Shadow Environment holding a value the view has already moved on from. So the pending half is\n * only released where there is nothing in flight to contradict it; where there is, the new value\n * takes the pending slot and the emitting side decides, against the written half it settles on.\n */\n changeToken(token: string | undefined) {\n // an absent token means the void token everywhere else, so normalize here too;\n // otherwise `undefined` would mark the component dirty without ever emitting a change\n token ??= VoidToken;\n\n // nothing pending and the confirmed token is the wanted one: nothing to queue. A component\n // that has not been flushed yet is the exception \u2014 it still owes the trail its create-token,\n // and dropping it here would emit a CreateEntities change without any token at all.\n if (token === this.#token && this.#nextToken === undefined && !this.#isNew) return;\n\n this.#nextToken = token;\n }\n\n setParent(parentUuid?: string) {\n const nextParentUuid = parentUuid ?? ROOT;\n\n if (nextParentUuid === (this.#parentUuid ?? ROOT) && this.#nextParentUuid === undefined) return;\n\n this.#nextParentUuid = nextParentUuid;\n }\n\n changeOrder(order: number) {\n if (order === this.#order && this.#nextOrder === undefined) return;\n\n this.#nextOrder = order;\n }\n\n #properties: Map<string, unknown> = new Map();\n #nextProperties: Map<string, unknown> = new Map();\n /**\n * The keys with a queued change, in the order their changes happened \u2014 the order an entry\n * carries them in, and the reason this is a list and not a set.\n *\n * A set beside it would answer membership in one step, and per call it does win from about eight\n * keys on: 8.0 ns for the set against 10.7 ns for the list at eight keys, 10.4 ns against 43.9 ns\n * at 64. The distance is what decides against it. At the upper stop this repository can produce \u2014\n * 64 keys, every one of them changed in every frame at 60 fps, so 3840 calls per second \u2014 that is\n * 0.13 ms saved per second of animation. And membership is the smaller half: `removeFrom()` and\n * `appendToEnd()` are an `indexOf` plus a `splice`, and the splice stays linear no matter what\n * answers the membership. Numbers measured 2026-08-31 on node v25.9.0.\n */\n #propsChangeOrder: string[] = [];\n\n /**\n * The keys an entry on its way out carries, until that entry is settled. For those keys the\n * written half is behind, and {@link ComponentChanges.changeProperty} must not cancel against it.\n */\n #travellingProperties?: Map<string, unknown> | undefined;\n\n /**\n * @returns `true` if the value differs from the last value this component asked for\n */\n changeProperty<T = unknown>(key: string, value: T, isEqual?: (a: T, b: T) => boolean): boolean {\n const equals = (a: T, b: T) =>\n // a registered rule compares values, and the marker is not one -- handed to it, a rule\n // would be asked about a property it never saw, and one that reaches into its arguments\n // throws on a symbol. Where either side is the marker the only question left is whether\n // it is still the same third form, and identity answers that.\n (a as unknown) === PropertyWithoutValue || (b as unknown) === PropertyWithoutValue\n ? (a as unknown) === (b as unknown)\n : isEqual == null\n ? a === b\n : isEqual(a, b);\n\n const isQueued = this.#propsChangeOrder.includes(key);\n const isTravelling = this.#travellingProperties?.has(key) ?? false;\n\n // the value this component last said the property should have: the pending half where\n // something is queued, else what an entry on its way out carries, else the confirmed value.\n // A key that is none of the three reads as `undefined`, and a registered rule decides that\n // comparison too -- a rule that calls the value equal to `undefined` says there is nothing\n // to send.\n let prevValue: T;\n if (isQueued) {\n prevValue = this.#nextProperties.get(key) as T;\n } else if (isTravelling) {\n prevValue = this.#travellingProperties!.get(key) as T;\n } else {\n prevValue = this.#properties.get(key) as T;\n }\n\n const valueChanged = !equals(value, prevValue);\n\n // The pending half is released only where the confirmed value is the wanted one and no entry\n // carrying another one is on its way out -- such an entry would otherwise be the last word.\n // The travelling test comes first because it decides the branch on its own, and a comparison\n // rule can be expensive on a path that runs once per frame. Where nothing is queued the\n // comparison above was already the one against the confirmed value, so it is reused.\n const nothingToSend = !isTravelling && (isQueued ? equals(value, this.#properties.get(key) as T) : !valueChanged);\n\n if (nothingToSend) {\n this.#nextProperties.delete(key);\n removeFrom(this.#propsChangeOrder, key);\n } else {\n this.#nextProperties.set(key, value);\n appendToEnd(this.#propsChangeOrder, key);\n }\n\n return valueChanged;\n }\n\n /**\n * Mark `key` as set without giving it a value: the next trail carries an entry that names\n * only the key. A later {@link ComponentChanges.changeProperty} replaces it with a value,\n * and {@link ComponentChanges.removeProperty} takes it away like any other property.\n *\n * @returns `true` if this differs from the last value this component asked for\n */\n setPropertyWithoutValue(key: string): boolean {\n return this.changeProperty(key, PropertyWithoutValue as unknown);\n }\n\n removeProperty(key: string) {\n const isQueued = this.#propsChangeOrder.includes(key);\n\n this.#nextProperties.delete(key);\n\n if (!this.#properties.has(key) && !this.#travellingProperties?.has(key)) {\n // nothing confirmed and nothing travelling: there is nothing to remove\n removeFrom(this.#propsChangeOrder, key);\n return;\n }\n\n // a key that was already queued keeps the place it took: the entry carries the changes in\n // the order they happened, and a removal is not a second change to the same key\n if (!isQueued) {\n appendToEnd(this.#propsChangeOrder, key);\n }\n }\n\n /**\n * The properties this component holds at this moment: the ones a change trail has already\n * carried, overlaid with everything that has accrued since.\n *\n * The overlay is what makes the result the current state instead of the state of the last\n * trail \u2014 `#properties` is only written forward while a trail is being built\n * ({@link ComponentChanges.makeCreateEntityChange},\n * {@link ComponentChanges.makeChangePropertyChange}). A key whose accrued value is `undefined`\n * and a key queued for change without an accrued value are both removals, and neither appears\n * in the result. A key that is set without a value stands in the result with\n * {@link PropertyWithoutValue}.\n */\n getProperties(): Map<string, unknown> {\n const properties = new Map(this.#properties);\n\n for (const key of this.#propsChangeOrder) {\n const value = this.#nextProperties.get(key);\n if (value === undefined) {\n properties.delete(key);\n } else {\n properties.set(key, value);\n }\n }\n\n return properties;\n }\n\n #events: IComponentEvent[] = [];\n #transferables = new Set<Transferable>();\n\n createEvent(type: string, data: unknown, transferables?: Transferable[]) {\n this.#events.push({type, data});\n for (const transferable of transferables ?? []) {\n this.#transferables.add(transferable);\n }\n }\n\n transferEventsTo(changes: ComponentChanges) {\n if (this.#events.length > 0) {\n changes.#events.push(...this.#events);\n this.#events.length = 0;\n }\n if (this.#transferables.size > 0) {\n changes.#transferables = new Set([...changes.#transferables, ...this.#transferables]);\n this.#transferables.clear();\n }\n }\n\n buildChangeTrail(trail: IComponentChangeType[], trailPhase: ChangeTrailPhase) {\n const {isNew, isCreated, isDestroyed} = this;\n\n if (isNew && isDestroyed) return;\n\n switch (trailPhase) {\n case ChangeTrailPhase.StructuralChanges:\n if (isNew) {\n trail.push(this.makeCreateEntityChange());\n } else if (!isDestroyed) {\n if (this.#hasPendingParent()) {\n trail.push(this.makeSetParentChange());\n } else if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n trail.push(this.makeUpdateOrderChange());\n }\n if (this.#nextToken !== undefined && this.#nextToken !== this.#token) {\n trail.push(this.makeChangeToken());\n }\n }\n break;\n\n case ChangeTrailPhase.ContentUpdates:\n if (!isNew && isCreated && this.#propsChangeOrder.length > 0) {\n trail.push(this.makeChangePropertyChange());\n }\n if (this.#events.length > 0) {\n trail.push(this.makeEvents());\n }\n break;\n\n case ChangeTrailPhase.Removal:\n if (isDestroyed) {\n trail.push(this.makeDestroyEntityChange());\n }\n break;\n }\n }\n\n makeEvents(): ISendEvents {\n const event: ISendEvents = {\n type: ComponentChangeType.SendEvents,\n uuid: this.#uuid,\n events: this.#events.slice(0),\n };\n if (this.#transferables.size > 0) {\n event.transferables = Array.from(this.#transferables);\n }\n return event;\n }\n\n makeCreateEntityChange(): ICreateEntitiesChange {\n // never emit a create without a token: the kernel would register an entity that no\n // shadow object can ever be looked up for\n const token = this.#nextToken ?? this.#token;\n\n const entry: ICreateEntitiesChange = {\n type: ComponentChangeType.CreateEntities,\n uuid: this.#uuid,\n token,\n };\n\n if (this.#nextParentUuid !== undefined && this.#nextParentUuid !== ROOT) {\n entry.parentUuid = this.#nextParentUuid;\n }\n\n if (this.#nextProperties.size > 0) {\n // a create carries only the keys that have a value or are set without one; where nothing\n // is left, the field stays off the entry \u2014 an absent `properties` and an empty one say\n // the same thing, and the shorter one is what travels. The note is taken either way: it\n // records what this entry carries, and an entry with no property is travelling with none\n const properties: ComponentPropertiesType = [];\n for (const [key, value] of this.#nextProperties) {\n if (value === PropertyWithoutValue) {\n properties.push([key]);\n } else if (value !== undefined) {\n properties.push([key, value]);\n }\n }\n this.#noteTravellingProperties(properties);\n if (properties.length > 0) {\n entry.properties = properties;\n }\n }\n\n if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n entry.order = this.#nextOrder;\n }\n\n if (this.#autoDestructionOnParentRemoval) {\n entry.autoDestructionOnParentRemoval = true;\n }\n\n return entry;\n }\n\n makeDestroyEntityChange(): IDestroyEntitiesChange {\n return {\n type: ComponentChangeType.DestroyEntities,\n uuid: this.#uuid,\n };\n }\n\n makeSetParentChange(): ISetParentChange {\n const entry: ISetParentChange = {\n type: ComponentChangeType.SetParent,\n uuid: this.#uuid,\n parentUuid: this.#nextParentUuid === ROOT ? undefined : this.#nextParentUuid,\n };\n\n if (this.#nextOrder !== undefined && this.#nextOrder !== this.#order) {\n entry.order = this.#nextOrder;\n }\n\n return entry;\n }\n\n makeUpdateOrderChange(): IUpdateOrderChange {\n return {\n type: ComponentChangeType.UpdateOrder,\n uuid: this.#uuid,\n order: this.#nextOrder ?? 0,\n };\n }\n\n makeChangeToken(): IChangeToken {\n return {\n type: ComponentChangeType.ChangeToken,\n uuid: this.#uuid,\n token: this.#nextToken ?? VoidToken,\n };\n }\n\n makeChangePropertyChange(): IPropertiesChange {\n // a key without a pending value is a removal, and so is a pending value of `undefined` --\n // `get()` answers the same for both, which is what the receiving side reads them as. A key\n // set without a value is the third form and travels as the bare key\n const properties: ComponentPropertiesType = this.#propsChangeOrder.map((key) => {\n const value = this.#nextProperties.get(key);\n return value === PropertyWithoutValue ? [key] : [key, value];\n });\n\n this.#noteTravellingProperties(properties);\n\n return {\n type: ComponentChangeType.ChangeProperties,\n uuid: this.#uuid,\n properties,\n };\n }\n\n /**\n * Records the keys of an entry that is going out, so a later change knows the written half\n * is behind.\n */\n #noteTravellingProperties(properties: ComponentPropertiesType): void {\n // the arity carries the meaning on the wire, the marker carries it in here\n this.#travellingProperties = new Map(\n properties.map((entry) => [entry[0], entry.length === 1 ? PropertyWithoutValue : entry[1]]),\n );\n }\n\n /**\n * Fold one trail entry into the written half of this component's bookkeeping: the values the\n * entry carries become the values the next diff is taken against, and the pending half that\n * produced them is released. Called once per entry the Shadow Environment has applied.\n *\n * A pending value is released only while it is still the value the entry carried. Between the\n * build of a trail and its confirmation lies a round trip, and whatever changed in that window\n * is owed to the Shadow Environment \u2014 releasing it here would leave the two sides holding\n * different values with nothing left to correct them.\n */\n commitChange(entry: IComponentChangeType): void {\n switch (entry.type) {\n case ComponentChangeType.CreateEntities:\n this.#commitToken(entry.token);\n this.#commitParentUuid(entry.parentUuid);\n this.#commitOrder(entry.order ?? this.#order);\n this.#commitProperties(entry.properties);\n // a create carries only the properties that have a value; a pending removal of a key the\n // entity was never given has nothing left to ask for and is released along with it\n for (const key of this.#propsChangeOrder.slice(0)) {\n if (this.#nextProperties.get(key) === undefined && !this.#properties.has(key)) {\n this.#nextProperties.delete(key);\n removeFrom(this.#propsChangeOrder, key);\n }\n }\n this.#travellingProperties = undefined;\n this.#isNew = false;\n break;\n\n case ComponentChangeType.SetParent:\n this.#commitParentUuid(entry.parentUuid);\n this.#commitOrder(entry.order ?? this.#order);\n break;\n\n case ComponentChangeType.UpdateOrder:\n this.#commitOrder(entry.order);\n break;\n\n case ComponentChangeType.ChangeToken:\n this.#commitToken(entry.token);\n break;\n\n case ComponentChangeType.ChangeProperties:\n this.#commitProperties(entry.properties);\n this.#travellingProperties = undefined;\n break;\n\n case ComponentChangeType.SendEvents:\n // the entry carries a snapshot taken while the trail was built; anything that arrived\n // behind it is still waiting to go out\n this.#events.splice(0, entry.events.length);\n for (const transferable of entry.transferables ?? []) {\n this.#transferables.delete(transferable);\n }\n break;\n\n case ComponentChangeType.DestroyEntities:\n // The entity behind this uuid is gone. Usually the component entry goes with it, but a\n // uuid its holder has left is free again, and a component that took it over in the\n // meantime keeps the entry alive. The written half describes an entity that no longer\n // exists, so it is reset to what a component nobody knows yet looks like -- otherwise the\n // successor would diff against it and ask for a change to something that is not there.\n this.#token = VoidToken;\n this.#parentUuid = undefined;\n this.#order = 0;\n this.#properties.clear();\n this.#travellingProperties = undefined;\n this.#isNew = true;\n break;\n }\n }\n\n #commitToken(token: string): void {\n this.#token = token;\n if (this.#nextToken === token) {\n this.#nextToken = undefined;\n }\n }\n\n #commitParentUuid(parentUuid: string | undefined): void {\n this.#parentUuid = parentUuid;\n if ((this.#nextParentUuid === ROOT ? undefined : this.#nextParentUuid) === parentUuid) {\n this.#nextParentUuid = undefined;\n }\n }\n\n #commitOrder(order: number): void {\n this.#order = order;\n if (this.#nextOrder === order) {\n this.#nextOrder = undefined;\n }\n }\n\n #commitProperties(properties: ComponentPropertiesType | undefined): void {\n for (const entry of properties ?? []) {\n const key = entry[0];\n // an entry that names only the key is the third form and not a removal: the written\n // half has to hold it, or the next diff reads the key as one that was never set\n const value = entry.length === 1 ? PropertyWithoutValue : entry[1];\n\n if (value === undefined) {\n this.#properties.delete(key);\n } else {\n this.#properties.set(key, value);\n }\n\n if (this.#nextProperties.get(key) === value) {\n this.#nextProperties.delete(key);\n removeFrom(this.#propsChangeOrder, key);\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|