@spearwolf/shadow-objects 0.30.1 → 0.31.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +34 -10
  3. package/bundle.js +13 -13
  4. package/package.json +3 -3
  5. package/src/bundle.js +4 -4
  6. package/src/bundle.js.map +7 -1
  7. package/src/constants.js +53 -40
  8. package/src/constants.js.map +7 -1
  9. package/src/create-worker.bundle.js +6 -8
  10. package/src/create-worker.bundle.js.map +7 -1
  11. package/src/create-worker.js +5 -2
  12. package/src/create-worker.js.map +7 -1
  13. package/src/elements/ShaeElement.js +57 -54
  14. package/src/elements/ShaeElement.js.map +7 -1
  15. package/src/elements/ShaeEntElement.d.ts.map +1 -1
  16. package/src/elements/ShaeEntElement.js +320 -341
  17. package/src/elements/ShaeEntElement.js.map +7 -1
  18. package/src/elements/ShaePropElement.js +312 -320
  19. package/src/elements/ShaePropElement.js.map +7 -1
  20. package/src/elements/ShaeWorkerElement.js +234 -229
  21. package/src/elements/ShaeWorkerElement.js.map +7 -1
  22. package/src/elements/constants.js +37 -22
  23. package/src/elements/constants.js.map +7 -1
  24. package/src/elements/events.d.ts +1 -1
  25. package/src/elements/events.d.ts.map +1 -1
  26. package/src/elements/events.js +1 -2
  27. package/src/elements/events.js.map +7 -1
  28. package/src/elements.js +4 -4
  29. package/src/elements.js.map +7 -1
  30. package/src/in-the-dark/Entity.d.ts +3 -1
  31. package/src/in-the-dark/Entity.d.ts.map +1 -1
  32. package/src/in-the-dark/Entity.js +299 -275
  33. package/src/in-the-dark/Entity.js.map +7 -1
  34. package/src/in-the-dark/Kernel.d.ts +1 -1
  35. package/src/in-the-dark/Kernel.d.ts.map +1 -1
  36. package/src/in-the-dark/Kernel.js +556 -532
  37. package/src/in-the-dark/Kernel.js.map +7 -1
  38. package/src/in-the-dark/Registry.d.ts.map +1 -1
  39. package/src/in-the-dark/Registry.js +101 -104
  40. package/src/in-the-dark/Registry.js.map +7 -1
  41. package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
  42. package/src/in-the-dark/ShadowObject.js +21 -23
  43. package/src/in-the-dark/ShadowObject.js.map +7 -1
  44. package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
  45. package/src/in-the-dark/SignalsPath.js +139 -123
  46. package/src/in-the-dark/SignalsPath.js.map +7 -1
  47. package/src/in-the-dark/events.js +11 -9
  48. package/src/in-the-dark/events.js.map +7 -1
  49. package/src/in-the-dark/importModule.js +31 -29
  50. package/src/in-the-dark/importModule.js.map +7 -1
  51. package/src/index.d.ts +2 -2
  52. package/src/index.d.ts.map +1 -1
  53. package/src/index.js +14 -14
  54. package/src/index.js.map +7 -1
  55. package/src/shadow-objects.js +6 -6
  56. package/src/shadow-objects.js.map +7 -1
  57. package/src/shadow-objects.worker.js +3 -3
  58. package/src/shadow-objects.worker.js.map +7 -1
  59. package/src/shae-ent.js +3 -3
  60. package/src/shae-ent.js.map +7 -1
  61. package/src/shae-prop.js +3 -3
  62. package/src/shae-prop.js.map +7 -1
  63. package/src/shae-worker.js +3 -3
  64. package/src/shae-worker.js.map +7 -1
  65. package/src/types.d.ts +5 -4
  66. package/src/types.d.ts.map +1 -1
  67. package/src/types.js +1 -2
  68. package/src/types.js.map +7 -1
  69. package/src/utils/ConsoleLogger.js +179 -185
  70. package/src/utils/ConsoleLogger.js.map +7 -1
  71. package/src/utils/FrameLoop.js +41 -40
  72. package/src/utils/FrameLoop.js.map +7 -1
  73. package/src/utils/array-utils.js +22 -24
  74. package/src/utils/array-utils.js.map +7 -1
  75. package/src/utils/attr-utils.js +15 -11
  76. package/src/utils/attr-utils.js.map +7 -1
  77. package/src/utils/constants.js +5 -2
  78. package/src/utils/constants.js.map +7 -1
  79. package/src/utils/generateUUID.d.ts.map +1 -1
  80. package/src/utils/generateUUID.js +269 -32
  81. package/src/utils/generateUUID.js.map +7 -1
  82. package/src/utils/props-utils.js +34 -43
  83. package/src/utils/props-utils.js.map +7 -1
  84. package/src/utils/toMaybe.js +5 -2
  85. package/src/utils/toMaybe.js.map +7 -1
  86. package/src/utils/toNamespace.js +6 -3
  87. package/src/utils/toNamespace.js.map +7 -1
  88. package/src/utils/toUrlString.js +9 -6
  89. package/src/utils/toUrlString.js.map +7 -1
  90. package/src/utils/waitForMessageOfType.js +30 -32
  91. package/src/utils/waitForMessageOfType.js.map +7 -1
  92. package/src/view/ComponentChanges.d.ts +1 -1
  93. package/src/view/ComponentChanges.d.ts.map +1 -1
  94. package/src/view/ComponentChanges.js +249 -251
  95. package/src/view/ComponentChanges.js.map +7 -1
  96. package/src/view/ComponentContext.d.ts.map +1 -1
  97. package/src/view/ComponentContext.js +303 -331
  98. package/src/view/ComponentContext.js.map +7 -1
  99. package/src/view/ComponentMemory.d.ts +1 -0
  100. package/src/view/ComponentMemory.d.ts.map +1 -1
  101. package/src/view/ComponentMemory.js +73 -76
  102. package/src/view/ComponentMemory.js.map +7 -1
  103. package/src/view/IShadowObjectEnvProxy.js +1 -2
  104. package/src/view/IShadowObjectEnvProxy.js.map +7 -1
  105. package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
  106. package/src/view/LocalShadowObjectEnv.js +57 -52
  107. package/src/view/LocalShadowObjectEnv.js.map +7 -1
  108. package/src/view/RemoteWorkerEnv.js +134 -123
  109. package/src/view/RemoteWorkerEnv.js.map +7 -1
  110. package/src/view/ShadowEnv.d.ts.map +1 -1
  111. package/src/view/ShadowEnv.js +232 -228
  112. package/src/view/ShadowEnv.js.map +7 -1
  113. package/src/view/ViewComponent.d.ts +9 -0
  114. package/src/view/ViewComponent.d.ts.map +1 -1
  115. package/src/view/ViewComponent.js +142 -130
  116. package/src/view/ViewComponent.js.map +7 -1
  117. package/src/view/cloneChangeTrail.js +13 -11
  118. package/src/view/cloneChangeTrail.js.map +7 -1
  119. package/src/worker/MessageRouter.d.ts.map +1 -1
  120. package/src/worker/MessageRouter.js +78 -67
  121. package/src/worker/MessageRouter.js.map +7 -1
  122. package/src/worker/WorkerRuntime.js +22 -21
  123. package/src/worker/WorkerRuntime.js.map +7 -1
  124. package/tsconfig.lib.tsbuildinfo +0 -1
@@ -1,568 +1,592 @@
1
- import { emit, eventize, off, on, once, Priority } from '@spearwolf/eventize';
2
- import { batch, createEffect, createMemo, createSignal, destroySignal, isSignal, link, } from '@spearwolf/signalize';
3
- import { ComponentChangeType, MessageToView } from '../constants.js';
4
- import { ConsoleLogger } from '../utils/ConsoleLogger.js';
5
- import { toMaybe } from '../utils/toMaybe.js';
6
- import { Entity } from './Entity.js';
7
- import { onCreate, onDestroy, onParentChanged, onViewEvent } from './events.js';
8
- import { Registry } from './Registry.js';
9
- import { SignalsPath } from './SignalsPath.js';
10
- var ShadowObjectAction;
11
- (function (ShadowObjectAction) {
12
- ShadowObjectAction[ShadowObjectAction["CreateAndDestroy"] = 0] = "CreateAndDestroy";
13
- ShadowObjectAction[ShadowObjectAction["JustCreate"] = 1] = "JustCreate";
14
- ShadowObjectAction[ShadowObjectAction["DestroyOnly"] = 2] = "DestroyOnly";
15
- })(ShadowObjectAction || (ShadowObjectAction = {}));
1
+ import { emit, eventize, off, on, once, Priority } from "@spearwolf/eventize";
2
+ import {
3
+ batch,
4
+ createEffect,
5
+ createMemo,
6
+ createSignal,
7
+ destroySignal,
8
+ isSignal,
9
+ link
10
+ } from "@spearwolf/signalize";
11
+ import { ComponentChangeType, MessageToView } from "../constants.js";
12
+ import { ConsoleLogger } from "../utils/ConsoleLogger.js";
13
+ import { toMaybe } from "../utils/toMaybe.js";
14
+ import { Entity } from "./Entity.js";
15
+ import { onCreate, onDestroy, onParentChanged, onViewEvent } from "./events.js";
16
+ import { Registry } from "./Registry.js";
17
+ import { SignalsPath } from "./SignalsPath.js";
18
+ var ShadowObjectAction = /* @__PURE__ */ ((ShadowObjectAction2) => {
19
+ ShadowObjectAction2[ShadowObjectAction2["CreateAndDestroy"] = 0] = "CreateAndDestroy";
20
+ ShadowObjectAction2[ShadowObjectAction2["JustCreate"] = 1] = "JustCreate";
21
+ ShadowObjectAction2[ShadowObjectAction2["DestroyOnly"] = 2] = "DestroyOnly";
22
+ return ShadowObjectAction2;
23
+ })(ShadowObjectAction || {});
16
24
  const getDisplayName = (construct) => construct.displayName || construct.name;
17
25
  let provideContextOptionsDeprecatedShown = false;
18
26
  let provideGlobalContextOptionsDeprecatedShown = false;
19
27
  let useContextOptionsDeprecatedShown = false;
20
28
  let useParentContextOptionsDeprecatedShown = false;
21
29
  let usePropertyOptionsDeprecatedShown = false;
22
- /**
23
- * The entity kernel manages the lifecycle of all entities and shadow-objects.
24
- *
25
- * An entity is created for each view-component. The entities act as containers for the shadow-objects.
26
- *
27
- * Which shadow-objects are created is determined by the token.
28
- */
29
- export class Kernel {
30
- #entities;
31
- #rootEntities;
32
- #allEntities;
33
- #allEntitiesReversed;
34
- #allEntitiesNeedUpdate;
35
- #rootContexts;
36
- constructor(registry) {
37
- this.logger = new ConsoleLogger('Kernel');
38
- this.#entities = new Map();
39
- this.#rootEntities = new Set();
40
- this.#allEntitiesNeedUpdate = true;
41
- this.#rootContexts = new Map();
42
- eventize(this);
43
- this.registry = Registry.get(registry);
30
+ class Kernel {
31
+ constructor(registry) {
32
+ this.logger = new ConsoleLogger("Kernel");
33
+ this.#entities = /* @__PURE__ */ new Map();
34
+ this.#rootEntities = /* @__PURE__ */ new Set();
35
+ this.#allEntitiesNeedUpdate = true;
36
+ this.#rootContexts = /* @__PURE__ */ new Map();
37
+ eventize(this);
38
+ this.registry = Registry.get(registry);
39
+ }
40
+ #entities;
41
+ #rootEntities;
42
+ #allEntities;
43
+ #allEntitiesReversed;
44
+ #allEntitiesNeedUpdate;
45
+ #rootContexts;
46
+ getEntity(uuid) {
47
+ const entity = this.#entities.get(uuid)?.entity;
48
+ if (!entity) {
49
+ throw new Error(`entity with uuid "${uuid}" not found!`);
44
50
  }
45
- getEntity(uuid) {
46
- const entity = this.#entities.get(uuid)?.entity;
47
- if (!entity) {
48
- throw new Error(`entity with uuid "${uuid}" not found!`);
51
+ return entity;
52
+ }
53
+ hasEntity(uuid) {
54
+ return this.#entities.has(uuid);
55
+ }
56
+ /**
57
+ * @returns all entities in breadth-first order
58
+ */
59
+ traverseLevelOrderBFS(reverse = false) {
60
+ if (this.#allEntitiesNeedUpdate) {
61
+ const lvl = /* @__PURE__ */ new Map();
62
+ const traverse = (uuid, depth) => {
63
+ const e = this.getEntity(uuid);
64
+ if (lvl.has(depth)) {
65
+ lvl.get(depth).push(e);
66
+ } else {
67
+ lvl.set(depth, [e]);
49
68
  }
50
- return entity;
51
- }
52
- hasEntity(uuid) {
53
- return this.#entities.has(uuid);
54
- }
55
- /**
56
- * @returns all entities in breadth-first order
57
- */
58
- traverseLevelOrderBFS(reverse = false) {
59
- if (this.#allEntitiesNeedUpdate) {
60
- const lvl = new Map();
61
- const traverse = (uuid, depth) => {
62
- const e = this.getEntity(uuid);
63
- if (lvl.has(depth)) {
64
- lvl.get(depth).push(e);
65
- }
66
- else {
67
- lvl.set(depth, [e]);
68
- }
69
- for (const child of e.children) {
70
- traverse(child.uuid, depth + 1);
71
- }
72
- };
73
- this.#rootEntities.forEach((uuid) => {
74
- traverse(uuid, 0);
75
- });
76
- this.#allEntities = Array.from(lvl.entries())
77
- .sort((a, b) => a[0] - b[0])
78
- .flatMap(([, entities]) => entities);
79
- this.#allEntitiesReversed = this.#allEntities.slice().reverse();
80
- this.#allEntitiesNeedUpdate = false;
69
+ for (const child of e.children) {
70
+ traverse(child.uuid, depth + 1);
81
71
  }
82
- return reverse ? this.#allEntitiesReversed : this.#allEntities;
72
+ };
73
+ this.#rootEntities.forEach((uuid) => {
74
+ traverse(uuid, 0);
75
+ });
76
+ this.#allEntities = Array.from(lvl.entries()).sort((a, b) => a[0] - b[0]).flatMap(([, entities]) => entities);
77
+ this.#allEntitiesReversed = this.#allEntities.slice().reverse();
78
+ this.#allEntitiesNeedUpdate = false;
83
79
  }
84
- getEntityGraph() {
85
- return Array.from(this.#rootEntities).map((uuid) => this.getEntityGraphNode(uuid));
80
+ return reverse ? this.#allEntitiesReversed : this.#allEntities;
81
+ }
82
+ getEntityGraph() {
83
+ return Array.from(this.#rootEntities).map((uuid) => this.getEntityGraphNode(uuid));
84
+ }
85
+ getEntityGraphNode(uuid) {
86
+ if (!this.#entities.has(uuid)) return void 0;
87
+ const { token, entity } = this.#entities.get(uuid);
88
+ return {
89
+ token,
90
+ entity,
91
+ props: Object.fromEntries(entity.propEntries()),
92
+ children: entity.children.map((child) => this.getEntityGraphNode(child.uuid))
93
+ };
94
+ }
95
+ upgradeEntities() {
96
+ const entityConstructors = /* @__PURE__ */ new Map();
97
+ for (const entity of this.traverseLevelOrderBFS(true)) {
98
+ entityConstructors.set(entity.uuid, this.updateShadowObjects(entity.uuid, 2 /* DestroyOnly */));
86
99
  }
87
- getEntityGraphNode(uuid) {
88
- if (!this.#entities.has(uuid))
89
- return undefined;
90
- const { token, entity } = this.#entities.get(uuid);
91
- return {
92
- token,
93
- entity,
94
- props: Object.fromEntries(entity.propEntries()),
95
- children: entity.children.map((child) => this.getEntityGraphNode(child.uuid)),
96
- };
100
+ for (const entity of this.traverseLevelOrderBFS(false)) {
101
+ this.updateShadowObjects(entity.uuid, 1 /* JustCreate */, entityConstructors.get(entity.uuid));
97
102
  }
98
- upgradeEntities() {
99
- const entityConstructors = new Map();
100
- for (const entity of this.traverseLevelOrderBFS(true)) {
101
- entityConstructors.set(entity.uuid, this.updateShadowObjects(entity.uuid, ShadowObjectAction.DestroyOnly));
102
- }
103
- for (const entity of this.traverseLevelOrderBFS(false)) {
104
- this.updateShadowObjects(entity.uuid, ShadowObjectAction.JustCreate, entityConstructors.get(entity.uuid));
105
- }
106
- entityConstructors.clear();
107
- }
108
- run(event) {
109
- if (this.logger.isDebug) {
110
- this.logger.debug('sync', event);
111
- }
112
- batch(() => {
113
- for (const entry of event.changeTrail) {
114
- this.parse(entry);
115
- }
116
- });
103
+ entityConstructors.clear();
104
+ }
105
+ run(event) {
106
+ if (this.logger.isDebug) {
107
+ this.logger.debug("sync", event);
117
108
  }
118
- parse(entry) {
119
- switch (entry.type) {
120
- case ComponentChangeType.CreateEntities:
121
- this.createEntity(entry.uuid, entry.token, entry.parentUuid, entry.order, entry.properties);
122
- this.#allEntitiesNeedUpdate = true;
123
- break;
124
- case ComponentChangeType.DestroyEntities:
125
- this.destroyEntity(entry.uuid);
126
- this.#allEntitiesNeedUpdate = true;
127
- break;
128
- case ComponentChangeType.SetParent:
129
- this.setParent(entry.uuid, entry.parentUuid, entry.order);
130
- this.#allEntitiesNeedUpdate = true;
131
- break;
132
- case ComponentChangeType.UpdateOrder:
133
- this.updateOrder(entry.uuid, entry.order);
134
- this.#allEntitiesNeedUpdate = true;
135
- break;
136
- case ComponentChangeType.ChangeProperties:
137
- this.changeProperties(entry.uuid, entry.properties);
138
- break;
139
- case ComponentChangeType.ChangeToken:
140
- this.changeToken(entry.uuid, entry.token);
141
- break;
142
- case ComponentChangeType.SendEvents:
143
- this.dispatchEventsToEntity(entry.uuid, entry.events);
144
- break;
145
- }
146
- }
147
- createEntity(uuid, token, parentUuid, order = 0, properties) {
148
- const e = new Entity(this, uuid);
149
- e.order = order;
150
- const entry = { token, entity: e, usedConstructors: new Map() };
151
- this.#entities.set(uuid, entry);
152
- if (parentUuid) {
153
- e.parentUuid = parentUuid;
154
- }
155
- if (!e.hasParent) {
156
- this.#rootEntities.add(uuid);
157
- }
158
- if (properties) {
159
- e.setProperties(properties);
160
- }
161
- this.createShadowObjects(uuid);
162
- }
163
- destroyEntity(uuid) {
164
- if (!this.#entities.has(uuid))
165
- return;
166
- const { entity, usedConstructors } = this.#entities.get(uuid);
167
- entity.removeFromParent();
168
- emit(entity, onDestroy, entity);
169
- usedConstructors.clear();
170
- this.#entities.delete(entity.uuid);
171
- this.#rootEntities.delete(entity.uuid);
109
+ batch(() => {
110
+ for (const entry of event.changeTrail) {
111
+ this.parse(entry);
112
+ }
113
+ });
114
+ }
115
+ parse(entry) {
116
+ switch (entry.type) {
117
+ case ComponentChangeType.CreateEntities:
118
+ this.createEntity(
119
+ entry.uuid,
120
+ entry.token,
121
+ entry.parentUuid,
122
+ entry.order,
123
+ entry.properties,
124
+ entry.autoDestructionOnParentRemoval
125
+ );
126
+ this.#allEntitiesNeedUpdate = true;
127
+ break;
128
+ case ComponentChangeType.DestroyEntities:
129
+ this.destroyEntity(entry.uuid);
130
+ this.#allEntitiesNeedUpdate = true;
131
+ break;
132
+ case ComponentChangeType.SetParent:
133
+ this.setParent(entry.uuid, entry.parentUuid, entry.order);
134
+ this.#allEntitiesNeedUpdate = true;
135
+ break;
136
+ case ComponentChangeType.UpdateOrder:
137
+ this.updateOrder(entry.uuid, entry.order);
138
+ this.#allEntitiesNeedUpdate = true;
139
+ break;
140
+ case ComponentChangeType.ChangeProperties:
141
+ this.changeProperties(entry.uuid, entry.properties);
142
+ break;
143
+ case ComponentChangeType.ChangeToken:
144
+ this.changeToken(entry.uuid, entry.token);
145
+ break;
146
+ case ComponentChangeType.SendEvents:
147
+ this.dispatchEventsToEntity(entry.uuid, entry.events);
148
+ break;
172
149
  }
173
- setParent(uuid, parentUuid, order = 0) {
174
- const e = this.getEntity(uuid);
175
- if (e.parentUuid === parentUuid && e.order === order)
176
- return;
177
- e.removeFromParent();
178
- e.order = order;
179
- e.parentUuid = parentUuid;
180
- if (e.hasParent) {
181
- this.#rootEntities.delete(uuid);
182
- }
183
- else {
184
- this.#rootEntities.add(uuid);
185
- }
186
- e.reSubscribeToParentContexts();
187
- queueMicrotask(() => {
188
- if (this.logger.isDebug) {
189
- this.logger.debug('entity.onParentChanged', { uuid, parentUuid, order, entity: e });
190
- }
191
- emit(e, onParentChanged, e);
192
- });
150
+ }
151
+ createEntity(uuid, token, parentUuid, order = 0, properties, autoDestructionOnParentRemoval = false) {
152
+ const e = new Entity(this, uuid);
153
+ e.order = order;
154
+ const entry = { token, entity: e, usedConstructors: /* @__PURE__ */ new Map() };
155
+ this.#entities.set(uuid, entry);
156
+ if (parentUuid) {
157
+ e.parentUuid = parentUuid;
193
158
  }
194
- updateOrder(uuid, order) {
195
- this.getEntity(uuid).order = order;
159
+ e.autoDestructionOnParentRemoval = autoDestructionOnParentRemoval;
160
+ if (!e.hasParent) {
161
+ this.#rootEntities.add(uuid);
196
162
  }
197
- dispatchEventsToEntity(uuid, events) {
198
- this.getEntity(uuid)?.dispatchViewEvents(events);
163
+ if (properties) {
164
+ e.setProperties(properties);
199
165
  }
200
- changeProperties(uuid, properties) {
201
- this.getEntity(uuid).setProperties(properties);
202
- this.updateShadowObjects(uuid);
166
+ this.createShadowObjects(uuid);
167
+ }
168
+ destroyEntity(uuid) {
169
+ if (!this.#entities.has(uuid)) return;
170
+ const { entity, usedConstructors } = this.#entities.get(uuid);
171
+ const childrenSnapshot = [...entity.children];
172
+ for (const child of childrenSnapshot) {
173
+ if (child.autoDestructionOnParentRemoval) {
174
+ this.destroyEntity(child.uuid);
175
+ } else {
176
+ child.removeFromParent();
177
+ this.#rootEntities.add(child.uuid);
178
+ }
203
179
  }
204
- changeToken(uuid, token) {
205
- if (!this.#entities.has(uuid))
206
- return;
207
- const entry = this.#entities.get(uuid);
208
- if (entry.token === token)
209
- return;
210
- entry.token = token;
211
- this.updateShadowObjects(uuid);
180
+ entity.removeFromParent();
181
+ emit(entity, onDestroy, entity);
182
+ usedConstructors.clear();
183
+ this.#entities.delete(entity.uuid);
184
+ this.#rootEntities.delete(entity.uuid);
185
+ this.#allEntitiesNeedUpdate = true;
186
+ }
187
+ setParent(uuid, parentUuid, order = 0) {
188
+ const e = this.getEntity(uuid);
189
+ if (e.parentUuid === parentUuid && e.order === order) return;
190
+ if (parentUuid && !this.#entities.has(parentUuid)) {
191
+ throw new Error(`entity with uuid "${parentUuid}" not found!`);
212
192
  }
213
- dispatchMessageToView(message) {
214
- queueMicrotask(() => {
215
- emit(this, MessageToView, message);
216
- });
193
+ e.removeFromParent();
194
+ e.order = order;
195
+ e.parentUuid = parentUuid;
196
+ if (e.hasParent) {
197
+ this.#rootEntities.delete(uuid);
198
+ } else {
199
+ this.#rootEntities.add(uuid);
217
200
  }
218
- /**
219
- * Create or destroy the shadow-objects of an entity using the registered constructors.
220
- * After a token change or registry changes, an entity may be given different shadow-objects.
221
- */
222
- updateShadowObjects(uuid, action = ShadowObjectAction.CreateAndDestroy, nextConstructors) {
223
- const entry = this.#entities.get(uuid);
224
- nextConstructors ??= new Set(this.registry.findConstructors(entry.token, entry.entity.truthyProps()));
225
- const shouldDestroy = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.DestroyOnly;
226
- const shouldCreate = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.JustCreate;
227
- // destroy all shadow-objects created by constructors no longer in the list
228
- //
229
- if (shouldDestroy) {
230
- for (const [construct, shadowObjects] of entry.usedConstructors) {
231
- if (!nextConstructors.has(construct)) {
232
- entry.usedConstructors.delete(construct);
233
- for (const obj of shadowObjects) {
234
- this.destroyShadowObject(obj, entry.entity);
235
- }
236
- }
237
- }
201
+ e.reSubscribeToParentContexts();
202
+ queueMicrotask(() => {
203
+ if (this.logger.isDebug) {
204
+ this.logger.debug("entity.onParentChanged", { uuid, parentUuid, order, entity: e });
205
+ }
206
+ emit(e, onParentChanged, e);
207
+ });
208
+ }
209
+ updateOrder(uuid, order) {
210
+ this.getEntity(uuid).order = order;
211
+ }
212
+ dispatchEventsToEntity(uuid, events) {
213
+ this.getEntity(uuid)?.dispatchViewEvents(events);
214
+ }
215
+ changeProperties(uuid, properties) {
216
+ this.getEntity(uuid).setProperties(properties);
217
+ this.updateShadowObjects(uuid);
218
+ }
219
+ changeToken(uuid, token) {
220
+ if (!this.#entities.has(uuid)) return;
221
+ const entry = this.#entities.get(uuid);
222
+ if (entry.token === token) return;
223
+ entry.token = token;
224
+ this.updateShadowObjects(uuid);
225
+ }
226
+ dispatchMessageToView(message) {
227
+ queueMicrotask(() => {
228
+ emit(this, MessageToView, message);
229
+ });
230
+ }
231
+ /**
232
+ * Create or destroy the shadow-objects of an entity using the registered constructors.
233
+ * After a token change or registry changes, an entity may be given different shadow-objects.
234
+ */
235
+ updateShadowObjects(uuid, action = 0 /* CreateAndDestroy */, nextConstructors) {
236
+ const entry = this.#entities.get(uuid);
237
+ nextConstructors ??= new Set(this.registry.findConstructors(entry.token, entry.entity.truthyProps()));
238
+ const shouldDestroy = action === 0 /* CreateAndDestroy */ || action === 2 /* DestroyOnly */;
239
+ const shouldCreate = action === 0 /* CreateAndDestroy */ || action === 1 /* JustCreate */;
240
+ if (shouldDestroy) {
241
+ for (const [construct, shadowObjects] of entry.usedConstructors) {
242
+ if (!nextConstructors.has(construct)) {
243
+ entry.usedConstructors.delete(construct);
244
+ for (const obj of shadowObjects) {
245
+ this.destroyShadowObject(obj, entry.entity);
246
+ }
238
247
  }
239
- // shadow-objects for new constructors are now created using the updated constructor list
240
- //
241
- if (shouldCreate) {
242
- for (const construct of nextConstructors) {
243
- if (!entry.usedConstructors.has(construct)) {
244
- this.constructShadowObject(construct, entry);
245
- }
246
- }
247
- }
248
- return nextConstructors;
248
+ }
249
249
  }
250
- constructShadowObject(construct, entry) {
251
- const unsubscribePrimary = new Set();
252
- const unsubscribeSecondary = new Set();
253
- const contextReaders = new Map();
254
- const contextParentReaders = new Map();
255
- const contextProviders = new Map();
256
- const contextRootProviders = new Map();
257
- const propertyReaders = new Map();
258
- const getUseProperty = (name, options) => {
259
- if (!usePropertyOptionsDeprecatedShown && options != null && typeof options === 'function') {
260
- console.warn('[shadow-objects] Deprecation Warning: The "isEqual" option of "useProperty()" is now passed as {compare} argument. Please update your code accordingly.');
261
- usePropertyOptionsDeprecatedShown = true;
262
- }
263
- const opts = typeof options === 'function' ? { compare: options } : options;
264
- let propReader = propertyReaders.get(name);
265
- if (propReader === undefined) {
266
- propReader = createSignal(undefined, opts).get;
267
- propertyReaders.set(name, propReader);
268
- const con = link(entry.entity.getPropertyReader(name), propReader);
269
- unsubscribeSecondary.add(con.destroy.bind(con));
270
- }
271
- return propReader;
272
- };
273
- const shadowObject = eventize(new construct({
274
- entity: entry.entity,
275
- provideContext(name, sourceOrInitialValue, options) {
276
- if (!provideContextOptionsDeprecatedShown && options != null && typeof options === 'function') {
277
- console.warn('[shadow-objects] Deprecation Warning: The "isEqual" option of "provideContext()" is now passed as {compare} argument. Please update your code accordingly.');
278
- provideContextOptionsDeprecatedShown = true;
279
- }
280
- const opts = typeof options === 'function' ? { compare: options } : options;
281
- let ctxProvider = contextProviders.get(name);
282
- if (ctxProvider == null) {
283
- const isSig = isSignal(sourceOrInitialValue);
284
- const initialValue = isSig ? undefined : toMaybe(sourceOrInitialValue);
285
- ctxProvider = createSignal(initialValue, opts?.compare ? { compare: opts.compare } : undefined);
286
- if (isSig) {
287
- const ln = link(sourceOrInitialValue, ctxProvider);
288
- unsubscribeSecondary.add(ln.destroy.bind(ln));
289
- }
290
- const ln = link(ctxProvider, entry.entity.provideContext(name));
291
- unsubscribeSecondary.add(ln.destroy.bind(ln));
292
- contextProviders.set(name, ctxProvider);
293
- }
294
- if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {
295
- unsubscribeSecondary.add(() => {
296
- ctxProvider.set(undefined);
297
- });
298
- }
299
- return ctxProvider;
300
- },
301
- provideGlobalContext(name, sourceOrInitialValue, options) {
302
- if (!provideGlobalContextOptionsDeprecatedShown && options != null && typeof options === 'function') {
303
- console.warn('[shadow-objects] Deprecation Warning: The "isEqual" option of "provideGlobalContext()" is now passed as {compare} argument. Please update your code accordingly.');
304
- provideGlobalContextOptionsDeprecatedShown = true;
305
- }
306
- const opts = typeof options === 'function' ? { compare: options } : options;
307
- let ctxProvider = contextRootProviders.get(name);
308
- if (ctxProvider == null) {
309
- const isSig = isSignal(sourceOrInitialValue);
310
- const initialValue = isSig ? undefined : toMaybe(sourceOrInitialValue);
311
- ctxProvider = createSignal(initialValue, opts?.compare ? { compare: opts.compare } : undefined);
312
- if (isSig) {
313
- const ln = link(sourceOrInitialValue, ctxProvider);
314
- unsubscribeSecondary.add(ln.destroy.bind(ln));
315
- }
316
- const ln = link(ctxProvider, entry.entity.provideGlobalContext(name));
317
- unsubscribeSecondary.add(ln.destroy.bind(ln));
318
- contextRootProviders.set(name, ctxProvider);
319
- }
320
- if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {
321
- unsubscribeSecondary.add(() => {
322
- ctxProvider.set(undefined);
323
- });
324
- }
325
- return ctxProvider;
326
- },
327
- useContext(name, options) {
328
- if (!useContextOptionsDeprecatedShown && options != null && typeof options === 'function') {
329
- console.warn('[shadow-objects] Deprecation Warning: The "isEqual" option of "useContext()" is now passed as {compare} argument. Please update your code accordingly.');
330
- useContextOptionsDeprecatedShown = true;
331
- }
332
- const opts = typeof options === 'function' ? { compare: options } : options;
333
- let ctxReader = contextReaders.get(name);
334
- if (ctxReader === undefined) {
335
- ctxReader = createSignal(undefined, opts).get;
336
- contextReaders.set(name, ctxReader);
337
- const ln = link(entry.entity.useContext(name), ctxReader);
338
- unsubscribeSecondary.add(ln.destroy.bind(ln));
339
- }
340
- return ctxReader;
341
- },
342
- useParentContext(name, options) {
343
- if (!useParentContextOptionsDeprecatedShown && options != null && typeof options === 'function') {
344
- console.warn('[shadow-objects] Deprecation Warning: The "isEqual" option of "useParentContext()" is now passed as {compare} argument. Please update your code accordingly.');
345
- useParentContextOptionsDeprecatedShown = true;
346
- }
347
- const opts = typeof options === 'function' ? { compare: options } : options;
348
- let ctxReader = contextParentReaders.get(name);
349
- if (ctxReader === undefined) {
350
- ctxReader = createSignal(undefined, opts).get;
351
- contextParentReaders.set(name, ctxReader);
352
- const ln = link(entry.entity.useParentContext(name), ctxReader);
353
- unsubscribeSecondary.add(ln.destroy.bind(ln));
354
- }
355
- return ctxReader;
356
- },
357
- dispatchMessageToView(type, data, transferables, traverseChildren = false) {
358
- entry.entity.dispatchMessageToView(type, data, transferables, traverseChildren);
359
- },
360
- useProperty: getUseProperty,
361
- useProperties(props) {
362
- const result = {};
363
- for (const key in props) {
364
- if (Object.hasOwn(props, key)) {
365
- result[key] = getUseProperty(props[key]);
366
- }
367
- }
368
- return result;
369
- },
370
- createResource(factory, cleanup) {
371
- const resourceSignal = createSignal();
372
- const effect = createEffect(() => {
373
- const resource = toMaybe(factory());
374
- resourceSignal.set(resource);
375
- if (resource !== undefined && cleanup) {
376
- return () => {
377
- cleanup(resource);
378
- resourceSignal.set(undefined);
379
- };
380
- }
381
- return () => {
382
- resourceSignal.set(undefined);
383
- };
384
- });
385
- unsubscribeSecondary.add(() => {
386
- effect.destroy();
387
- resourceSignal.set(undefined);
388
- destroySignal(resourceSignal);
389
- });
390
- return resourceSignal;
391
- },
392
- createEffect(...args) {
393
- const effect = createEffect(...args);
394
- unsubscribeSecondary.add(effect.destroy);
395
- return effect;
396
- },
397
- createSignal(...args) {
398
- const sig = createSignal(...args);
399
- unsubscribeSecondary.add(() => {
400
- destroySignal(sig);
401
- });
402
- return sig;
403
- },
404
- createMemo(...args) {
405
- const sig = createMemo(...args);
406
- unsubscribeSecondary.add(() => {
407
- destroySignal(sig);
408
- });
409
- return sig;
410
- },
411
- on(...args) {
412
- const [firstArg] = args;
413
- if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {
414
- // @ts-ignore
415
- const unsub = on(entry.entity, ...args);
416
- unsubscribeSecondary.add(unsub);
417
- return unsub;
418
- }
419
- // @ts-ignore
420
- const unsub = on(...args);
421
- unsubscribeSecondary.add(unsub);
422
- // return unsub;
423
- return Object.assign(() => {
424
- unsubscribeSecondary.delete(unsub);
425
- unsub();
426
- }, unsub);
427
- },
428
- once(...args) {
429
- const [firstArg] = args;
430
- if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {
431
- // @ts-ignore
432
- const unsub = once(entry.entity, ...args);
433
- unsubscribeSecondary.add(unsub);
434
- return unsub;
435
- }
436
- // @ts-ignore
437
- const unsub = once(...args);
438
- unsubscribeSecondary.add(unsub);
439
- // return unsub;
440
- return Object.assign(() => {
441
- unsubscribeSecondary.delete(unsub);
442
- unsub();
443
- }, unsub);
444
- },
445
- emit(...args) {
446
- const [firstArg] = args;
447
- if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {
448
- // @ts-ignore
449
- emit(entry.entity, ...args);
450
- }
451
- else {
452
- // @ts-ignore
453
- emit(...args);
454
- }
455
- },
456
- onViewEvent(callback) {
457
- const unsub = on(entry.entity, onViewEvent, (type, data) => {
458
- callback(type, data);
459
- });
460
- unsubscribeSecondary.add(unsub);
461
- },
462
- onDestroy(callback) {
463
- unsubscribePrimary.add(callback);
464
- },
465
- }));
466
- if (this.logger.isInfo) {
467
- this.logger.info('create shadow-object', getDisplayName(construct), { shadowObject, entity: entry.entity });
250
+ if (shouldCreate) {
251
+ for (const construct of nextConstructors) {
252
+ if (!entry.usedConstructors.has(construct)) {
253
+ this.constructShadowObject(construct, entry);
468
254
  }
469
- once(entry.entity, onDestroy, Priority.Low, () => {
470
- if (this.logger.isInfo) {
471
- this.logger.info('destroy shadow-object', getDisplayName(construct), { shadowObject, entity: entry.entity });
472
- }
473
- for (const callback of unsubscribePrimary) {
474
- callback();
475
- }
476
- for (const callback of unsubscribeSecondary) {
477
- callback();
478
- }
479
- for (const sig of contextReaders.values()) {
480
- destroySignal(sig);
481
- }
482
- for (const sig of contextParentReaders.values()) {
483
- destroySignal(sig);
484
- }
485
- for (const sig of propertyReaders.values()) {
486
- destroySignal(sig);
255
+ }
256
+ }
257
+ return nextConstructors;
258
+ }
259
+ constructShadowObject(construct, entry) {
260
+ const unsubscribePrimary = /* @__PURE__ */ new Set();
261
+ const unsubscribeSecondary = /* @__PURE__ */ new Set();
262
+ const contextReaders = /* @__PURE__ */ new Map();
263
+ const contextReaderCompares = /* @__PURE__ */ new Map();
264
+ const contextParentReaders = /* @__PURE__ */ new Map();
265
+ const contextParentReaderCompares = /* @__PURE__ */ new Map();
266
+ const contextProviders = /* @__PURE__ */ new Map();
267
+ const contextRootProviders = /* @__PURE__ */ new Map();
268
+ const propertyReaders = /* @__PURE__ */ new Map();
269
+ const propertyCompares = /* @__PURE__ */ new Map();
270
+ const getUseProperty = (name, options) => {
271
+ if (!usePropertyOptionsDeprecatedShown && options != null && typeof options === "function") {
272
+ console.warn(
273
+ '[shadow-objects] Deprecation Warning: The "isEqual" option of "useProperty()" is now passed as {compare} argument. Please update your code accordingly.'
274
+ );
275
+ usePropertyOptionsDeprecatedShown = true;
276
+ }
277
+ const opts = typeof options === "function" ? { compare: options } : options;
278
+ let propReader = propertyReaders.get(name);
279
+ if (propReader === void 0) {
280
+ propReader = createSignal(void 0, opts).get;
281
+ propertyReaders.set(name, propReader);
282
+ propertyCompares.set(name, opts?.compare);
283
+ const con = link(entry.entity.getPropertyReader(name), propReader);
284
+ unsubscribeSecondary.add(con.destroy.bind(con));
285
+ } else if (opts?.compare != null && propertyCompares.get(name) !== opts.compare) {
286
+ console.warn(
287
+ `[shadow-objects] useProperty("${name}"): the cached signal already exists with a different (or no) {compare} function \u2014 the new options are ignored. Pass options only on the first call per property.`
288
+ );
289
+ }
290
+ return propReader;
291
+ };
292
+ const shadowObject = eventize(
293
+ new construct({
294
+ entity: entry.entity,
295
+ provideContext(name, sourceOrInitialValue, options) {
296
+ if (!provideContextOptionsDeprecatedShown && options != null && typeof options === "function") {
297
+ console.warn(
298
+ '[shadow-objects] Deprecation Warning: The "isEqual" option of "provideContext()" is now passed as {compare} argument. Please update your code accordingly.'
299
+ );
300
+ provideContextOptionsDeprecatedShown = true;
301
+ }
302
+ const opts = typeof options === "function" ? { compare: options } : options;
303
+ let ctxProvider = contextProviders.get(name);
304
+ if (ctxProvider == null) {
305
+ const isSig = isSignal(sourceOrInitialValue);
306
+ const initialValue = isSig ? void 0 : toMaybe(sourceOrInitialValue);
307
+ ctxProvider = createSignal(initialValue, opts?.compare ? { compare: opts.compare } : void 0);
308
+ if (isSig) {
309
+ const ln2 = link(sourceOrInitialValue, ctxProvider);
310
+ unsubscribeSecondary.add(ln2.destroy.bind(ln2));
487
311
  }
488
- for (const sig of contextProviders.values()) {
489
- destroySignal(sig);
312
+ const ln = link(ctxProvider, entry.entity.provideContext(name));
313
+ unsubscribeSecondary.add(ln.destroy.bind(ln));
314
+ contextProviders.set(name, ctxProvider);
315
+ }
316
+ if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {
317
+ unsubscribeSecondary.add(() => {
318
+ ctxProvider.set(void 0);
319
+ });
320
+ }
321
+ return ctxProvider;
322
+ },
323
+ provideGlobalContext(name, sourceOrInitialValue, options) {
324
+ if (!provideGlobalContextOptionsDeprecatedShown && options != null && typeof options === "function") {
325
+ console.warn(
326
+ '[shadow-objects] Deprecation Warning: The "isEqual" option of "provideGlobalContext()" is now passed as {compare} argument. Please update your code accordingly.'
327
+ );
328
+ provideGlobalContextOptionsDeprecatedShown = true;
329
+ }
330
+ const opts = typeof options === "function" ? { compare: options } : options;
331
+ let ctxProvider = contextRootProviders.get(name);
332
+ if (ctxProvider == null) {
333
+ const isSig = isSignal(sourceOrInitialValue);
334
+ const initialValue = isSig ? void 0 : toMaybe(sourceOrInitialValue);
335
+ ctxProvider = createSignal(initialValue, opts?.compare ? { compare: opts.compare } : void 0);
336
+ if (isSig) {
337
+ const ln2 = link(sourceOrInitialValue, ctxProvider);
338
+ unsubscribeSecondary.add(ln2.destroy.bind(ln2));
490
339
  }
491
- for (const sig of contextRootProviders.values()) {
492
- destroySignal(sig);
340
+ const ln = link(ctxProvider, entry.entity.provideGlobalContext(name));
341
+ unsubscribeSecondary.add(ln.destroy.bind(ln));
342
+ contextRootProviders.set(name, ctxProvider);
343
+ }
344
+ if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {
345
+ unsubscribeSecondary.add(() => {
346
+ ctxProvider.set(void 0);
347
+ });
348
+ }
349
+ return ctxProvider;
350
+ },
351
+ useContext(name, options) {
352
+ if (!useContextOptionsDeprecatedShown && options != null && typeof options === "function") {
353
+ console.warn(
354
+ '[shadow-objects] Deprecation Warning: The "isEqual" option of "useContext()" is now passed as {compare} argument. Please update your code accordingly.'
355
+ );
356
+ useContextOptionsDeprecatedShown = true;
357
+ }
358
+ const opts = typeof options === "function" ? { compare: options } : options;
359
+ let ctxReader = contextReaders.get(name);
360
+ if (ctxReader === void 0) {
361
+ ctxReader = createSignal(void 0, opts).get;
362
+ contextReaders.set(name, ctxReader);
363
+ contextReaderCompares.set(name, opts?.compare);
364
+ const ln = link(entry.entity.useContext(name), ctxReader);
365
+ unsubscribeSecondary.add(ln.destroy.bind(ln));
366
+ } else if (opts?.compare != null && contextReaderCompares.get(name) !== opts.compare) {
367
+ console.warn(
368
+ `[shadow-objects] useContext("${String(name)}"): the cached signal already exists with a different (or no) {compare} function \u2014 the new options are ignored. Pass options only on the first call per context.`
369
+ );
370
+ }
371
+ return ctxReader;
372
+ },
373
+ useParentContext(name, options) {
374
+ if (!useParentContextOptionsDeprecatedShown && options != null && typeof options === "function") {
375
+ console.warn(
376
+ '[shadow-objects] Deprecation Warning: The "isEqual" option of "useParentContext()" is now passed as {compare} argument. Please update your code accordingly.'
377
+ );
378
+ useParentContextOptionsDeprecatedShown = true;
379
+ }
380
+ const opts = typeof options === "function" ? { compare: options } : options;
381
+ let ctxReader = contextParentReaders.get(name);
382
+ if (ctxReader === void 0) {
383
+ ctxReader = createSignal(void 0, opts).get;
384
+ contextParentReaders.set(name, ctxReader);
385
+ contextParentReaderCompares.set(name, opts?.compare);
386
+ const ln = link(entry.entity.useParentContext(name), ctxReader);
387
+ unsubscribeSecondary.add(ln.destroy.bind(ln));
388
+ } else if (opts?.compare != null && contextParentReaderCompares.get(name) !== opts.compare) {
389
+ console.warn(
390
+ `[shadow-objects] useParentContext("${String(name)}"): the cached signal already exists with a different (or no) {compare} function \u2014 the new options are ignored. Pass options only on the first call per parent context.`
391
+ );
392
+ }
393
+ return ctxReader;
394
+ },
395
+ dispatchMessageToView(type, data, transferables, traverseChildren = false) {
396
+ entry.entity.dispatchMessageToView(type, data, transferables, traverseChildren);
397
+ },
398
+ useProperty: getUseProperty,
399
+ useProperties(props) {
400
+ const result = {};
401
+ for (const key in props) {
402
+ if (Object.hasOwn(props, key)) {
403
+ result[key] = getUseProperty(props[key]);
493
404
  }
494
- unsubscribePrimary.clear();
495
- unsubscribeSecondary.clear();
496
- contextReaders.clear();
497
- contextParentReaders.clear();
498
- propertyReaders.clear();
499
- contextProviders.clear();
500
- contextRootProviders.clear();
501
- const otherShadowObjects = entry.usedConstructors.get(construct);
502
- if (otherShadowObjects) {
503
- otherShadowObjects.delete(shadowObject);
504
- if (otherShadowObjects.size === 0) {
505
- entry.usedConstructors.delete(construct);
506
- }
405
+ }
406
+ return result;
407
+ },
408
+ createResource(factory, cleanup) {
409
+ const resourceSignal = createSignal();
410
+ const effect = createEffect(() => {
411
+ const resource = toMaybe(factory());
412
+ resourceSignal.set(resource);
413
+ if (resource !== void 0 && cleanup) {
414
+ return () => {
415
+ cleanup(resource);
416
+ resourceSignal.set(void 0);
417
+ };
507
418
  }
508
- });
509
- // We want to keep track which shadow-objects are created by which constructors.
510
- // This will all
511
- //
512
- if (entry.usedConstructors.has(construct)) {
513
- entry.usedConstructors.get(construct).add(shadowObject);
419
+ return () => {
420
+ resourceSignal.set(void 0);
421
+ };
422
+ });
423
+ unsubscribeSecondary.add(() => {
424
+ effect.destroy();
425
+ resourceSignal.set(void 0);
426
+ destroySignal(resourceSignal);
427
+ });
428
+ return resourceSignal;
429
+ },
430
+ createEffect(...args) {
431
+ const effect = createEffect(...args);
432
+ unsubscribeSecondary.add(effect.destroy);
433
+ return effect;
434
+ },
435
+ createSignal(...args) {
436
+ const sig = createSignal(...args);
437
+ unsubscribeSecondary.add(() => {
438
+ destroySignal(sig);
439
+ });
440
+ return sig;
441
+ },
442
+ createMemo(...args) {
443
+ const sig = createMemo(...args);
444
+ unsubscribeSecondary.add(() => {
445
+ destroySignal(sig);
446
+ });
447
+ return sig;
448
+ },
449
+ on(...args) {
450
+ const [firstArg] = args;
451
+ if (typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg)) {
452
+ const unsub2 = on(entry.entity, ...args);
453
+ unsubscribeSecondary.add(unsub2);
454
+ return unsub2;
455
+ }
456
+ const unsub = on(...args);
457
+ unsubscribeSecondary.add(unsub);
458
+ return Object.assign(() => {
459
+ unsubscribeSecondary.delete(unsub);
460
+ unsub();
461
+ }, unsub);
462
+ },
463
+ once(...args) {
464
+ const [firstArg] = args;
465
+ if (typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg)) {
466
+ const unsub2 = once(entry.entity, ...args);
467
+ unsubscribeSecondary.add(unsub2);
468
+ return unsub2;
469
+ }
470
+ const unsub = once(...args);
471
+ unsubscribeSecondary.add(unsub);
472
+ return Object.assign(() => {
473
+ unsubscribeSecondary.delete(unsub);
474
+ unsub();
475
+ }, unsub);
476
+ },
477
+ emit(...args) {
478
+ const [firstArg] = args;
479
+ if (typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg)) {
480
+ emit(entry.entity, ...args);
481
+ } else {
482
+ emit(...args);
483
+ }
484
+ },
485
+ onViewEvent(callback) {
486
+ const unsub = on(entry.entity, onViewEvent, (type, data) => {
487
+ callback(type, data);
488
+ });
489
+ unsubscribeSecondary.add(unsub);
490
+ },
491
+ onDestroy(callback) {
492
+ unsubscribePrimary.add(callback);
514
493
  }
515
- else {
516
- entry.usedConstructors.set(construct, new Set([shadowObject]));
494
+ })
495
+ );
496
+ if (this.logger.isInfo) {
497
+ this.logger.info("create shadow-object", getDisplayName(construct), { shadowObject, entity: entry.entity });
498
+ }
499
+ once(entry.entity, onDestroy, Priority.Low, () => {
500
+ if (this.logger.isInfo) {
501
+ this.logger.info("destroy shadow-object", getDisplayName(construct), { shadowObject, entity: entry.entity });
502
+ }
503
+ for (const callback of unsubscribePrimary) {
504
+ callback();
505
+ }
506
+ for (const callback of unsubscribeSecondary) {
507
+ callback();
508
+ }
509
+ for (const sig of contextReaders.values()) {
510
+ destroySignal(sig);
511
+ }
512
+ for (const sig of contextParentReaders.values()) {
513
+ destroySignal(sig);
514
+ }
515
+ for (const sig of propertyReaders.values()) {
516
+ destroySignal(sig);
517
+ }
518
+ for (const sig of contextProviders.values()) {
519
+ destroySignal(sig);
520
+ }
521
+ for (const sig of contextRootProviders.values()) {
522
+ destroySignal(sig);
523
+ }
524
+ unsubscribePrimary.clear();
525
+ unsubscribeSecondary.clear();
526
+ contextReaders.clear();
527
+ contextParentReaders.clear();
528
+ propertyReaders.clear();
529
+ contextProviders.clear();
530
+ contextRootProviders.clear();
531
+ const otherShadowObjects = entry.usedConstructors.get(construct);
532
+ if (otherShadowObjects) {
533
+ otherShadowObjects.delete(shadowObject);
534
+ if (otherShadowObjects.size === 0) {
535
+ entry.usedConstructors.delete(construct);
517
536
  }
518
- this.attachShadowObject(shadowObject, entry.entity);
519
- return shadowObject;
537
+ }
538
+ });
539
+ if (entry.usedConstructors.has(construct)) {
540
+ entry.usedConstructors.get(construct).add(shadowObject);
541
+ } else {
542
+ entry.usedConstructors.set(construct, /* @__PURE__ */ new Set([shadowObject]));
520
543
  }
521
- createShadowObjects(uuid) {
522
- const entry = this.#entities.get(uuid);
523
- this.registry.findConstructors(entry.token, entry.entity.truthyProps())?.forEach((construct) => {
524
- this.constructShadowObject(construct, entry);
525
- });
544
+ this.attachShadowObject(shadowObject, entry.entity);
545
+ return shadowObject;
546
+ }
547
+ createShadowObjects(uuid) {
548
+ const entry = this.#entities.get(uuid);
549
+ this.registry.findConstructors(entry.token, entry.entity.truthyProps())?.forEach((construct) => {
550
+ this.constructShadowObject(construct, entry);
551
+ });
552
+ }
553
+ findShadowObjects(uuid) {
554
+ if (!this.#entities.has(uuid)) return [];
555
+ const { usedConstructors } = this.#entities.get(uuid);
556
+ return Array.from(new Set(Array.from(usedConstructors.values()).flatMap((objs) => Array.from(objs))));
557
+ }
558
+ attachShadowObject(shadowObject, entity) {
559
+ on(entity, shadowObject);
560
+ if (typeof shadowObject[onCreate] === "function") {
561
+ shadowObject[onCreate](entity);
526
562
  }
527
- findShadowObjects(uuid) {
528
- if (!this.#entities.has(uuid))
529
- return [];
530
- const { usedConstructors } = this.#entities.get(uuid);
531
- return Array.from(new Set(Array.from(usedConstructors.values()).flatMap((objs) => Array.from(objs))));
563
+ }
564
+ destroyShadowObject(shadowObject, entity) {
565
+ if (typeof shadowObject[onDestroy] === "function") {
566
+ shadowObject[onDestroy](entity);
532
567
  }
533
- attachShadowObject(shadowObject, entity) {
534
- // Like all other objects, the new shadow-object should be able to respond to the events that the entity receives.
535
- //
536
- on(entity, shadowObject);
537
- // Finally, the `shadowObject.onCreate(entity)` callback is called on the shadow-object.
538
- //
539
- if (typeof shadowObject[onCreate] === 'function') {
540
- shadowObject[onCreate](entity);
541
- }
568
+ emit(shadowObject, onDestroy, entity);
569
+ off(entity, shadowObject);
570
+ }
571
+ findOrCreateRootContext(name) {
572
+ let ctx = this.#rootContexts.get(name);
573
+ if (!ctx) {
574
+ ctx = new SignalsPath();
575
+ this.#rootContexts.set(name, ctx);
542
576
  }
543
- destroyShadowObject(shadowObject, entity) {
544
- if (typeof shadowObject[onDestroy] === 'function') {
545
- shadowObject[onDestroy](entity);
546
- }
547
- emit(shadowObject, onDestroy, entity);
548
- off(entity, shadowObject);
549
- }
550
- findOrCreateRootContext(name) {
551
- let ctx = this.#rootContexts.get(name);
552
- if (!ctx) {
553
- ctx = new SignalsPath();
554
- this.#rootContexts.set(name, ctx);
555
- }
556
- return ctx;
577
+ return ctx;
578
+ }
579
+ destroy() {
580
+ for (const ctx of this.#rootContexts.values()) {
581
+ ctx.dispose();
557
582
  }
558
- destroy() {
559
- for (const ctx of this.#rootContexts.values()) {
560
- ctx.dispose();
561
- }
562
- this.#rootContexts.clear();
563
- for (const entity of this.traverseLevelOrderBFS().reverse()) {
564
- this.destroyEntity(entity.uuid);
565
- }
583
+ this.#rootContexts.clear();
584
+ for (const entity of this.traverseLevelOrderBFS().reverse()) {
585
+ this.destroyEntity(entity.uuid);
566
586
  }
587
+ }
567
588
  }
568
- //# sourceMappingURL=Kernel.js.map
589
+ export {
590
+ Kernel
591
+ };
592
+ //# sourceMappingURL=Kernel.js.map