@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.
Files changed (213) hide show
  1. package/CHANGELOG.md +333 -10
  2. package/README.md +100 -20
  3. package/bundle.js +5 -54
  4. package/package.json +7 -3
  5. package/src/ChangeTrailRefusedError.d.ts +27 -0
  6. package/src/ChangeTrailRefusedError.d.ts.map +1 -0
  7. package/src/ChangeTrailRefusedError.js +12 -0
  8. package/src/ChangeTrailRefusedError.js.map +7 -0
  9. package/src/EntityUuidInUseError.d.ts +19 -0
  10. package/src/EntityUuidInUseError.d.ts.map +1 -0
  11. package/src/EntityUuidInUseError.js +11 -0
  12. package/src/EntityUuidInUseError.js.map +7 -0
  13. package/src/WorkerTimeoutError.d.ts +25 -0
  14. package/src/WorkerTimeoutError.d.ts.map +1 -0
  15. package/src/WorkerTimeoutError.js +12 -0
  16. package/src/WorkerTimeoutError.js.map +7 -0
  17. package/src/bundle.d.ts +1 -1
  18. package/src/bundle.d.ts.map +1 -1
  19. package/src/bundle.js +1 -1
  20. package/src/bundle.js.map +2 -2
  21. package/src/constants.d.ts +9 -2
  22. package/src/constants.d.ts.map +1 -1
  23. package/src/constants.js +1 -1
  24. package/src/constants.js.map +2 -2
  25. package/src/create-worker.bundle.d.ts +1 -1
  26. package/src/create-worker.bundle.d.ts.map +1 -1
  27. package/src/create-worker.bundle.js.map +1 -1
  28. package/src/create-worker.d.ts +1 -1
  29. package/src/create-worker.d.ts.map +1 -1
  30. package/src/create-worker.js.map +1 -1
  31. package/src/elements/ShaeElement.d.ts +70 -2
  32. package/src/elements/ShaeElement.d.ts.map +1 -1
  33. package/src/elements/ShaeElement.js +129 -25
  34. package/src/elements/ShaeElement.js.map +3 -3
  35. package/src/elements/ShaeEntElement.d.ts +43 -5
  36. package/src/elements/ShaeEntElement.d.ts.map +1 -1
  37. package/src/elements/ShaeEntElement.js +399 -170
  38. package/src/elements/ShaeEntElement.js.map +2 -2
  39. package/src/elements/ShaeLifecycleElement.d.ts +71 -0
  40. package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
  41. package/src/elements/ShaeLifecycleElement.js +83 -0
  42. package/src/elements/ShaeLifecycleElement.js.map +7 -0
  43. package/src/elements/ShaePropElement.d.ts +57 -7
  44. package/src/elements/ShaePropElement.d.ts.map +1 -1
  45. package/src/elements/ShaePropElement.js +241 -220
  46. package/src/elements/ShaePropElement.js.map +2 -2
  47. package/src/elements/ShaeWorkerElement.d.ts +49 -5
  48. package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
  49. package/src/elements/ShaeWorkerElement.js +230 -74
  50. package/src/elements/ShaeWorkerElement.js.map +2 -2
  51. package/src/elements/constants.d.ts +6 -0
  52. package/src/elements/constants.d.ts.map +1 -1
  53. package/src/elements/constants.js +12 -0
  54. package/src/elements/constants.js.map +2 -2
  55. package/src/elements/deferredTeardown.d.ts +24 -0
  56. package/src/elements/deferredTeardown.d.ts.map +1 -0
  57. package/src/elements/deferredTeardown.js +30 -0
  58. package/src/elements/deferredTeardown.js.map +7 -0
  59. package/src/elements/displayContentsRule.d.ts +25 -0
  60. package/src/elements/displayContentsRule.d.ts.map +1 -0
  61. package/src/elements/displayContentsRule.js +37 -0
  62. package/src/elements/displayContentsRule.js.map +7 -0
  63. package/src/elements/events.d.ts +10 -7
  64. package/src/elements/events.d.ts.map +1 -1
  65. package/src/elements/forwardCustomEvents.d.ts +19 -0
  66. package/src/elements/forwardCustomEvents.d.ts.map +1 -0
  67. package/src/elements/forwardCustomEvents.js +47 -0
  68. package/src/elements/forwardCustomEvents.js.map +7 -0
  69. package/src/elements/hostedSlots.d.ts +36 -0
  70. package/src/elements/hostedSlots.d.ts.map +1 -0
  71. package/src/elements/hostedSlots.js +118 -0
  72. package/src/elements/hostedSlots.js.map +7 -0
  73. package/src/elements/parentRemoval.d.ts +18 -0
  74. package/src/elements/parentRemoval.d.ts.map +1 -0
  75. package/src/elements/parentRemoval.js +60 -0
  76. package/src/elements/parentRemoval.js.map +7 -0
  77. package/src/elements/propValueConverters.d.ts +3 -0
  78. package/src/elements/propValueConverters.d.ts.map +1 -0
  79. package/src/elements/propValueConverters.js +54 -0
  80. package/src/elements/propValueConverters.js.map +7 -0
  81. package/src/elements/requestEntAncestor.d.ts +32 -0
  82. package/src/elements/requestEntAncestor.d.ts.map +1 -0
  83. package/src/elements/requestEntAncestor.js +16 -0
  84. package/src/elements/requestEntAncestor.js.map +7 -0
  85. package/src/elements.js.map +1 -1
  86. package/src/in-the-dark/Entity.d.ts +113 -3
  87. package/src/in-the-dark/Entity.d.ts.map +1 -1
  88. package/src/in-the-dark/Entity.js +292 -63
  89. package/src/in-the-dark/Entity.js.map +3 -3
  90. package/src/in-the-dark/Kernel.d.ts +81 -17
  91. package/src/in-the-dark/Kernel.d.ts.map +1 -1
  92. package/src/in-the-dark/Kernel.js +449 -392
  93. package/src/in-the-dark/Kernel.js.map +3 -3
  94. package/src/in-the-dark/Registry.d.ts +1 -1
  95. package/src/in-the-dark/Registry.d.ts.map +1 -1
  96. package/src/in-the-dark/Registry.js +99 -26
  97. package/src/in-the-dark/Registry.js.map +2 -2
  98. package/src/in-the-dark/ShadowObject.d.ts +1 -1
  99. package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
  100. package/src/in-the-dark/ShadowObject.js +3 -2
  101. package/src/in-the-dark/ShadowObject.js.map +2 -2
  102. package/src/in-the-dark/ShadowObjectCreationScope.d.ts +126 -0
  103. package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
  104. package/src/in-the-dark/ShadowObjectCreationScope.js +596 -0
  105. package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
  106. package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
  107. package/src/in-the-dark/SignalsPath.js +2 -2
  108. package/src/in-the-dark/SignalsPath.js.map +2 -2
  109. package/src/in-the-dark/events.js.map +1 -1
  110. package/src/in-the-dark/importModule.d.ts +7 -0
  111. package/src/in-the-dark/importModule.d.ts.map +1 -1
  112. package/src/in-the-dark/importModule.js +8 -5
  113. package/src/in-the-dark/importModule.js.map +2 -2
  114. package/src/index.d.ts +7 -1
  115. package/src/index.d.ts.map +1 -1
  116. package/src/index.js +5 -1
  117. package/src/index.js.map +2 -2
  118. package/src/shadow-objects.d.ts +2 -0
  119. package/src/shadow-objects.d.ts.map +1 -1
  120. package/src/shadow-objects.js +2 -0
  121. package/src/shadow-objects.js.map +2 -2
  122. package/src/shadow-objects.worker.js +0 -1
  123. package/src/shadow-objects.worker.js.map +2 -2
  124. package/src/shae-ent.js.map +1 -1
  125. package/src/shae-prop.js +2 -2
  126. package/src/shae-prop.js.map +2 -2
  127. package/src/shae-worker.js.map +1 -1
  128. package/src/types.d.ts +39 -8
  129. package/src/types.d.ts.map +1 -1
  130. package/src/utils/ConsoleLogger.d.ts +45 -10
  131. package/src/utils/ConsoleLogger.d.ts.map +1 -1
  132. package/src/utils/ConsoleLogger.js +54 -28
  133. package/src/utils/ConsoleLogger.js.map +2 -2
  134. package/src/utils/FrameLoop.d.ts +42 -3
  135. package/src/utils/FrameLoop.d.ts.map +1 -1
  136. package/src/utils/FrameLoop.js +71 -12
  137. package/src/utils/FrameLoop.js.map +2 -2
  138. package/src/utils/MicrotaskCollector.d.ts +45 -0
  139. package/src/utils/MicrotaskCollector.d.ts.map +1 -0
  140. package/src/utils/MicrotaskCollector.js +33 -0
  141. package/src/utils/MicrotaskCollector.js.map +7 -0
  142. package/src/utils/MicrotaskGate.d.ts +17 -0
  143. package/src/utils/MicrotaskGate.d.ts.map +1 -0
  144. package/src/utils/MicrotaskGate.js +20 -0
  145. package/src/utils/MicrotaskGate.js.map +7 -0
  146. package/src/utils/array-utils.js.map +1 -1
  147. package/src/utils/attr-utils.d.ts +6 -0
  148. package/src/utils/attr-utils.d.ts.map +1 -1
  149. package/src/utils/attr-utils.js +4 -2
  150. package/src/utils/attr-utils.js.map +2 -2
  151. package/src/utils/constants.js.map +1 -1
  152. package/src/utils/generateUUID.d.ts +12 -1
  153. package/src/utils/generateUUID.d.ts.map +1 -1
  154. package/src/utils/generateUUID.js +31 -266
  155. package/src/utils/generateUUID.js.map +2 -2
  156. package/src/utils/props-utils.d.ts +3 -2
  157. package/src/utils/props-utils.d.ts.map +1 -1
  158. package/src/utils/props-utils.js +13 -24
  159. package/src/utils/props-utils.js.map +2 -2
  160. package/src/utils/runGuarded.d.ts +27 -0
  161. package/src/utils/runGuarded.d.ts.map +1 -0
  162. package/src/utils/runGuarded.js +11 -0
  163. package/src/utils/runGuarded.js.map +7 -0
  164. package/src/utils/toMaybe.d.ts.map +1 -1
  165. package/src/utils/toMaybe.js.map +1 -1
  166. package/src/utils/toNamespace.d.ts.map +1 -1
  167. package/src/utils/toNamespace.js.map +1 -1
  168. package/src/utils/toUrlString.d.ts +12 -0
  169. package/src/utils/toUrlString.d.ts.map +1 -1
  170. package/src/utils/toUrlString.js.map +2 -2
  171. package/src/utils/waitForMessageOfType.d.ts +16 -1
  172. package/src/utils/waitForMessageOfType.d.ts.map +1 -1
  173. package/src/utils/waitForMessageOfType.js +28 -3
  174. package/src/utils/waitForMessageOfType.js.map +2 -2
  175. package/src/view/ComponentChanges.d.ts +91 -1
  176. package/src/view/ComponentChanges.d.ts.map +1 -1
  177. package/src/view/ComponentChanges.js +253 -69
  178. package/src/view/ComponentChanges.js.map +2 -2
  179. package/src/view/ComponentContext.d.ts +239 -7
  180. package/src/view/ComponentContext.d.ts.map +1 -1
  181. package/src/view/ComponentContext.js +648 -115
  182. package/src/view/ComponentContext.js.map +2 -2
  183. package/src/view/ComponentMemory.d.ts +3 -3
  184. package/src/view/ComponentMemory.d.ts.map +1 -1
  185. package/src/view/ComponentMemory.js +3 -1
  186. package/src/view/ComponentMemory.js.map +2 -2
  187. package/src/view/IShadowObjectEnvProxy.d.ts +33 -1
  188. package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
  189. package/src/view/LocalShadowObjectEnv.d.ts +2 -2
  190. package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
  191. package/src/view/LocalShadowObjectEnv.js +18 -11
  192. package/src/view/LocalShadowObjectEnv.js.map +2 -2
  193. package/src/view/RemoteWorkerEnv.d.ts +129 -3
  194. package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
  195. package/src/view/RemoteWorkerEnv.js +290 -60
  196. package/src/view/RemoteWorkerEnv.js.map +2 -2
  197. package/src/view/ShadowEnv.d.ts +73 -2
  198. package/src/view/ShadowEnv.d.ts.map +1 -1
  199. package/src/view/ShadowEnv.js +301 -64
  200. package/src/view/ShadowEnv.js.map +2 -2
  201. package/src/view/ViewComponent.d.ts +93 -8
  202. package/src/view/ViewComponent.d.ts.map +1 -1
  203. package/src/view/ViewComponent.js +148 -28
  204. package/src/view/ViewComponent.js.map +2 -2
  205. package/src/view/cloneChangeTrail.js.map +2 -2
  206. package/src/worker/MessageRouter.d.ts +14 -0
  207. package/src/worker/MessageRouter.d.ts.map +1 -1
  208. package/src/worker/MessageRouter.js +80 -18
  209. package/src/worker/MessageRouter.js.map +2 -2
  210. package/src/worker/WorkerRuntime.d.ts +22 -1
  211. package/src/worker/WorkerRuntime.d.ts.map +1 -1
  212. package/src/worker/WorkerRuntime.js +60 -8
  213. package/src/worker/WorkerRuntime.js.map +2 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/in-the-dark/Kernel.ts"],
4
- "sourcesContent": ["import {emit, eventize, off, on, once, Priority} from '@spearwolf/eventize';\nimport {\n batch,\n type CompareFunc,\n createEffect,\n createMemo,\n createSignal,\n destroySignal,\n isSignal,\n link,\n type Signal,\n type SignalReader,\n} from '@spearwolf/signalize';\nimport {ComponentChangeType, MessageToView} from '../constants.js';\nimport type {\n IComponentChangeType,\n IComponentEvent,\n Maybe,\n ProvideContextOptions,\n ShadowObjectConstructor,\n ShadowObjectType,\n SignalValueOptions,\n SyncEvent,\n} from '../types.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {toMaybe} from '../utils/toMaybe.js';\nimport {Entity} from './Entity.js';\nimport {type OnCreate, type OnDestroy, onCreate, onDestroy, onParentChanged, onViewEvent} from './events.js';\nimport {Registry} from './Registry.js';\nimport {SignalsPath} from './SignalsPath.js';\n\nexport interface MessageToViewEvent {\n uuid: string;\n type: string;\n data?: unknown;\n transferables?: Transferable[];\n traverseChildren?: boolean;\n}\n\ninterface EntityEntry {\n token: string;\n entity: Entity;\n usedConstructors: Map<ShadowObjectConstructor, Set<ShadowObjectType>>;\n}\n\ninterface EntityGraphNode {\n token: string;\n entity: Entity;\n props: Record<string, unknown>;\n children: EntityGraphNode[];\n}\n\nenum ShadowObjectAction {\n CreateAndDestroy = 0,\n JustCreate,\n DestroyOnly,\n}\n\nconst getDisplayName = (construct: ShadowObjectConstructor) => construct.displayName || construct.name;\n\nlet provideContextOptionsDeprecatedShown = false;\nlet provideGlobalContextOptionsDeprecatedShown = false;\nlet useContextOptionsDeprecatedShown = false;\nlet useParentContextOptionsDeprecatedShown = false;\nlet usePropertyOptionsDeprecatedShown = false;\n\n/**\n * The entity kernel manages the lifecycle of all entities and shadow-objects.\n *\n * An entity is created for each view-component. The entities act as containers for the shadow-objects.\n *\n * Which shadow-objects are created is determined by the token.\n */\nexport class Kernel {\n registry: Registry;\n\n readonly logger = new ConsoleLogger('Kernel');\n\n #entities: Map<string, EntityEntry> = new Map();\n #rootEntities: Set<string> = new Set();\n\n #allEntities?: Entity[];\n #allEntitiesReversed?: Entity[];\n #allEntitiesNeedUpdate = true;\n\n #rootContexts: Map<string | symbol, SignalsPath> = new Map();\n\n constructor(registry?: Registry) {\n eventize(this);\n this.registry = Registry.get(registry);\n }\n\n getEntity(uuid: string): Entity {\n const entity = this.#entities.get(uuid)?.entity;\n if (!entity) {\n throw new Error(`entity with uuid \"${uuid}\" not found!`);\n }\n return entity;\n }\n\n hasEntity(uuid: string): boolean {\n return this.#entities.has(uuid);\n }\n\n /**\n * @returns all entities in breadth-first order\n */\n traverseLevelOrderBFS(reverse = false): Entity[] {\n if (this.#allEntitiesNeedUpdate) {\n const lvl = new Map<number, Entity[]>();\n\n const traverse = (uuid: string, depth: number) => {\n const e = this.getEntity(uuid);\n\n if (lvl.has(depth)) {\n lvl.get(depth).push(e);\n } else {\n lvl.set(depth, [e]);\n }\n\n for (const child of e.children) {\n traverse(child.uuid, depth + 1);\n }\n };\n\n this.#rootEntities.forEach((uuid) => {\n traverse(uuid, 0);\n });\n\n this.#allEntities = Array.from(lvl.entries())\n .sort((a, b) => a[0] - b[0])\n .flatMap(([, entities]) => entities);\n\n this.#allEntitiesReversed = this.#allEntities.slice().reverse();\n this.#allEntitiesNeedUpdate = false;\n }\n\n return reverse ? this.#allEntitiesReversed : this.#allEntities;\n }\n\n getEntityGraph(): EntityGraphNode[] {\n return Array.from(this.#rootEntities).map((uuid) => this.getEntityGraphNode(uuid)!);\n }\n\n private getEntityGraphNode(uuid: string): EntityGraphNode | undefined {\n if (!this.#entities.has(uuid)) return undefined;\n\n const {token, entity} = this.#entities.get(uuid);\n return {\n token,\n entity,\n props: Object.fromEntries(entity.propEntries()),\n children: entity.children.map((child) => this.getEntityGraphNode(child.uuid)),\n };\n }\n\n upgradeEntities(): void {\n const entityConstructors = new Map<String, Set<ShadowObjectConstructor>>();\n\n for (const entity of this.traverseLevelOrderBFS(true)) {\n entityConstructors.set(entity.uuid, this.updateShadowObjects(entity.uuid, ShadowObjectAction.DestroyOnly));\n }\n\n for (const entity of this.traverseLevelOrderBFS(false)) {\n this.updateShadowObjects(entity.uuid, ShadowObjectAction.JustCreate, entityConstructors.get(entity.uuid));\n }\n\n entityConstructors.clear();\n }\n\n run(event: SyncEvent): void {\n if (this.logger.isDebug) {\n this.logger.debug('sync', event);\n }\n batch(() => {\n for (const entry of event.changeTrail) {\n this.parse(entry);\n }\n });\n }\n\n private parse(entry: IComponentChangeType): void {\n switch (entry.type) {\n case ComponentChangeType.CreateEntities:\n this.createEntity(\n entry.uuid,\n entry.token,\n entry.parentUuid,\n entry.order,\n entry.properties,\n entry.autoDestructionOnParentRemoval,\n );\n this.#allEntitiesNeedUpdate = true;\n break;\n\n case ComponentChangeType.DestroyEntities:\n this.destroyEntity(entry.uuid);\n this.#allEntitiesNeedUpdate = true;\n break;\n\n case ComponentChangeType.SetParent:\n this.setParent(entry.uuid, entry.parentUuid, entry.order);\n this.#allEntitiesNeedUpdate = true;\n break;\n\n case ComponentChangeType.UpdateOrder:\n this.updateOrder(entry.uuid, entry.order);\n this.#allEntitiesNeedUpdate = true;\n break;\n\n case ComponentChangeType.ChangeProperties:\n this.changeProperties(entry.uuid, entry.properties);\n break;\n\n case ComponentChangeType.ChangeToken:\n this.changeToken(entry.uuid, entry.token);\n break;\n\n case ComponentChangeType.SendEvents:\n this.dispatchEventsToEntity(entry.uuid, entry.events);\n break;\n }\n }\n\n createEntity(\n uuid: string,\n token: string,\n parentUuid?: string,\n order = 0,\n properties?: [string, unknown][],\n autoDestructionOnParentRemoval = false,\n ): void {\n const e = new Entity(this, uuid);\n\n e.order = order;\n\n const entry: EntityEntry = {token, entity: e, usedConstructors: new Map()};\n\n this.#entities.set(uuid, entry);\n\n if (parentUuid) {\n e.parentUuid = parentUuid;\n }\n\n e.autoDestructionOnParentRemoval = autoDestructionOnParentRemoval;\n\n if (!e.hasParent) {\n this.#rootEntities.add(uuid);\n }\n\n if (properties) {\n e.setProperties(properties);\n }\n\n this.createShadowObjects(uuid);\n }\n\n destroyEntity(uuid: string): void {\n if (!this.#entities.has(uuid)) return;\n\n const {entity, usedConstructors} = this.#entities.get(uuid);\n\n // Children with autoDestructionOnParentRemoval cascade; the rest are promoted\n // to root so they remain reachable instead of leaking inside the kernel.\n // Snapshot first because both branches mutate the children list.\n const childrenSnapshot = [...entity.children];\n for (const child of childrenSnapshot) {\n if (child.autoDestructionOnParentRemoval) {\n this.destroyEntity(child.uuid);\n } else {\n child.removeFromParent();\n this.#rootEntities.add(child.uuid);\n }\n }\n\n entity.removeFromParent();\n emit(entity, onDestroy, entity);\n\n usedConstructors.clear();\n\n this.#entities.delete(entity.uuid);\n this.#rootEntities.delete(entity.uuid);\n this.#allEntitiesNeedUpdate = true;\n }\n\n setParent(uuid: string, parentUuid?: string, order = 0): void {\n const e = this.getEntity(uuid);\n\n if (e.parentUuid === parentUuid && e.order === order) return;\n\n // Validate the new parent before detaching the current one, so a bad UUID\n // never leaves the entity orphaned (KERN-5).\n if (parentUuid && !this.#entities.has(parentUuid)) {\n throw new Error(`entity with uuid \"${parentUuid}\" not found!`);\n }\n\n e.removeFromParent();\n\n e.order = order;\n e.parentUuid = parentUuid;\n\n if (e.hasParent) {\n this.#rootEntities.delete(uuid);\n } else {\n this.#rootEntities.add(uuid);\n }\n\n e.reSubscribeToParentContexts();\n\n queueMicrotask(() => {\n if (this.logger.isDebug) {\n this.logger.debug('entity.onParentChanged', {uuid, parentUuid, order, entity: e});\n }\n emit(e, onParentChanged, e);\n });\n }\n\n updateOrder(uuid: string, order: number): void {\n this.getEntity(uuid).order = order;\n }\n\n dispatchEventsToEntity(uuid: string, events: IComponentEvent[]): void {\n this.getEntity(uuid)?.dispatchViewEvents(events);\n }\n\n changeProperties(uuid: string, properties: [string, unknown][]): void {\n this.getEntity(uuid).setProperties(properties);\n this.updateShadowObjects(uuid);\n }\n\n changeToken(uuid: string, token: string): void {\n if (!this.#entities.has(uuid)) return;\n\n const entry = this.#entities.get(uuid);\n\n if (entry.token === token) return;\n\n entry.token = token;\n\n this.updateShadowObjects(uuid);\n }\n\n dispatchMessageToView(message: MessageToViewEvent): void {\n queueMicrotask(() => {\n emit(this as Kernel, MessageToView, message);\n });\n }\n\n /**\n * Create or destroy the shadow-objects of an entity using the registered constructors.\n * After a token change or registry changes, an entity may be given different shadow-objects.\n */\n private updateShadowObjects(\n uuid: string,\n action = ShadowObjectAction.CreateAndDestroy,\n nextConstructors?: Set<ShadowObjectConstructor>,\n ): Set<ShadowObjectConstructor> {\n const entry = this.#entities.get(uuid);\n nextConstructors ??= new Set(this.registry.findConstructors(entry.token, entry.entity.truthyProps()));\n\n const shouldDestroy = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.DestroyOnly;\n const shouldCreate = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.JustCreate;\n\n // destroy all shadow-objects created by constructors no longer in the list\n //\n if (shouldDestroy) {\n for (const [construct, shadowObjects] of entry.usedConstructors) {\n if (!nextConstructors.has(construct)) {\n entry.usedConstructors.delete(construct);\n for (const obj of shadowObjects) {\n this.destroyShadowObject(obj, entry.entity);\n }\n }\n }\n }\n\n // shadow-objects for new constructors are now created using the updated constructor list\n //\n if (shouldCreate) {\n for (const construct of nextConstructors) {\n if (!entry.usedConstructors.has(construct)) {\n this.constructShadowObject(construct, entry);\n }\n }\n }\n\n return nextConstructors;\n }\n\n private constructShadowObject(construct: ShadowObjectConstructor, entry: EntityEntry): ShadowObjectType {\n const unsubscribePrimary = new Set<() => any>();\n const unsubscribeSecondary = new Set<() => any>();\n\n const contextReaders = new Map<string | symbol, SignalReader<any>>();\n const contextReaderCompares = new Map<string | symbol, CompareFunc<any> | undefined>();\n const contextParentReaders = new Map<string | symbol, SignalReader<any>>();\n const contextParentReaderCompares = new Map<string | symbol, CompareFunc<any> | undefined>();\n const contextProviders = new Map<string | symbol, Signal<any>>();\n const contextRootProviders = new Map<string | symbol, Signal<any>>();\n\n const propertyReaders = new Map<string, SignalReader<any>>();\n const propertyCompares = new Map<string, CompareFunc<any> | undefined>();\n\n const getUseProperty = <T = any>(\n name: string,\n options?: SignalValueOptions<T> | CompareFunc<T | undefined>,\n ): SignalReader<T> => {\n if (!usePropertyOptionsDeprecatedShown && options != null && typeof options === 'function') {\n console.warn(\n '[shadow-objects] Deprecation Warning: The \"isEqual\" option of \"useProperty()\" is now passed as {compare} argument. Please update your code accordingly.',\n );\n usePropertyOptionsDeprecatedShown = true;\n }\n\n const opts = typeof options === 'function' ? {compare: options} : options;\n\n let propReader = propertyReaders.get(name);\n\n if (propReader === undefined) {\n propReader = createSignal<any>(undefined, opts).get;\n propertyReaders.set(name, propReader);\n propertyCompares.set(name, opts?.compare);\n const con = link(entry.entity.getPropertyReader(name), propReader);\n unsubscribeSecondary.add(con.destroy.bind(con));\n } else if (opts?.compare != null && propertyCompares.get(name) !== opts.compare) {\n console.warn(\n `[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.`,\n );\n }\n\n return propReader;\n };\n\n const shadowObject = eventize(\n new construct({\n entity: entry.entity,\n\n provideContext<T = unknown>(\n name: string | symbol,\n sourceOrInitialValue?: T | SignalReader<T | undefined>,\n options?: ProvideContextOptions<T> | CompareFunc<T | undefined>,\n ) {\n if (!provideContextOptionsDeprecatedShown && options != null && typeof options === 'function') {\n console.warn(\n '[shadow-objects] Deprecation Warning: The \"isEqual\" option of \"provideContext()\" is now passed as {compare} argument. Please update your code accordingly.',\n );\n provideContextOptionsDeprecatedShown = true;\n }\n\n const opts = typeof options === 'function' ? {compare: options} : options;\n\n let ctxProvider = contextProviders.get(name);\n\n if (ctxProvider == null) {\n const isSig = isSignal(sourceOrInitialValue);\n const initialValue = isSig ? undefined : toMaybe(sourceOrInitialValue as T);\n\n ctxProvider = createSignal(initialValue, opts?.compare ? {compare: opts.compare} : undefined);\n\n if (isSig) {\n const ln = link(sourceOrInitialValue as SignalReader<T>, ctxProvider);\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n }\n\n const ln = link(ctxProvider, entry.entity.provideContext(name));\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n contextProviders.set(name, ctxProvider);\n }\n\n if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {\n unsubscribeSecondary.add(() => {\n ctxProvider.set(undefined);\n });\n }\n\n return ctxProvider;\n },\n\n provideGlobalContext<T = unknown>(\n name: string | symbol,\n sourceOrInitialValue?: T | SignalReader<T | undefined>,\n options?: ProvideContextOptions<T> | CompareFunc<T | undefined>,\n ) {\n if (!provideGlobalContextOptionsDeprecatedShown && options != null && typeof options === 'function') {\n console.warn(\n '[shadow-objects] Deprecation Warning: The \"isEqual\" option of \"provideGlobalContext()\" is now passed as {compare} argument. Please update your code accordingly.',\n );\n provideGlobalContextOptionsDeprecatedShown = true;\n }\n\n const opts = typeof options === 'function' ? {compare: options} : options;\n\n let ctxProvider = contextRootProviders.get(name);\n\n if (ctxProvider == null) {\n const isSig = isSignal(sourceOrInitialValue);\n const initialValue = isSig ? undefined : toMaybe(sourceOrInitialValue as T);\n\n ctxProvider = createSignal(initialValue, opts?.compare ? {compare: opts.compare} : undefined);\n\n if (isSig) {\n const ln = link(sourceOrInitialValue as SignalReader<T>, ctxProvider);\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n }\n\n const ln = link(ctxProvider, entry.entity.provideGlobalContext(name));\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n contextRootProviders.set(name, ctxProvider);\n }\n\n if (ctxProvider != null && (opts?.clearOnDestroy ?? true)) {\n unsubscribeSecondary.add(() => {\n ctxProvider.set(undefined);\n });\n }\n\n return ctxProvider;\n },\n\n useContext<T = unknown>(name: string | symbol, options?: SignalValueOptions<T> | CompareFunc<T | undefined>) {\n if (!useContextOptionsDeprecatedShown && options != null && typeof options === 'function') {\n console.warn(\n '[shadow-objects] Deprecation Warning: The \"isEqual\" option of \"useContext()\" is now passed as {compare} argument. Please update your code accordingly.',\n );\n useContextOptionsDeprecatedShown = true;\n }\n\n const opts = typeof options === 'function' ? {compare: options} : options;\n\n let ctxReader = contextReaders.get(name);\n\n if (ctxReader === undefined) {\n ctxReader = createSignal<any>(undefined, opts).get;\n contextReaders.set(name, ctxReader);\n contextReaderCompares.set(name, opts?.compare);\n const ln = link(entry.entity.useContext(name), ctxReader);\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n } else if (opts?.compare != null && contextReaderCompares.get(name) !== opts.compare) {\n console.warn(\n `[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.`,\n );\n }\n\n return ctxReader;\n },\n\n useParentContext<T = unknown>(name: string | symbol, options?: SignalValueOptions<T> | CompareFunc<T | undefined>) {\n if (!useParentContextOptionsDeprecatedShown && options != null && typeof options === 'function') {\n console.warn(\n '[shadow-objects] Deprecation Warning: The \"isEqual\" option of \"useParentContext()\" is now passed as {compare} argument. Please update your code accordingly.',\n );\n useParentContextOptionsDeprecatedShown = true;\n }\n\n const opts = typeof options === 'function' ? {compare: options} : options;\n\n let ctxReader = contextParentReaders.get(name);\n\n if (ctxReader === undefined) {\n ctxReader = createSignal<any>(undefined, opts).get;\n contextParentReaders.set(name, ctxReader);\n contextParentReaderCompares.set(name, opts?.compare);\n const ln = link(entry.entity.useParentContext(name), ctxReader);\n unsubscribeSecondary.add(ln.destroy.bind(ln));\n } else if (opts?.compare != null && contextParentReaderCompares.get(name) !== opts.compare) {\n console.warn(\n `[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.`,\n );\n }\n\n return ctxReader;\n },\n\n dispatchMessageToView(type: string, data?: unknown, transferables?: Transferable[], traverseChildren = false) {\n entry.entity.dispatchMessageToView(type, data, transferables, traverseChildren);\n },\n\n useProperty: getUseProperty,\n\n useProperties<T extends Record<string, unknown> = Record<string, unknown>>(\n props: {[K in keyof T]: string},\n ): {\n [K in keyof T]: SignalReader<Maybe<T[K]>>;\n } {\n const result = {} as {[K in keyof T]: SignalReader<Maybe<T[K]>>};\n for (const key in props) {\n if (Object.hasOwn(props, key)) {\n result[key] = getUseProperty(props[key]);\n }\n }\n return result;\n },\n\n createResource<T = unknown>(\n factory: () => T | undefined,\n cleanup?: (resource: NonNullable<T>) => unknown,\n ): Signal<Maybe<T>> {\n const resourceSignal = createSignal<Maybe<T>>();\n\n const effect = createEffect(() => {\n const resource = toMaybe(factory());\n resourceSignal.set(resource);\n\n if (resource !== undefined && cleanup) {\n return () => {\n cleanup(resource);\n resourceSignal.set(undefined);\n };\n }\n\n return () => {\n resourceSignal.set(undefined);\n };\n });\n\n unsubscribeSecondary.add(() => {\n effect.destroy();\n resourceSignal.set(undefined);\n destroySignal(resourceSignal);\n });\n\n return resourceSignal;\n },\n\n createEffect(...args: Parameters<typeof createEffect>): ReturnType<typeof createEffect> {\n const effect = createEffect(...args);\n unsubscribeSecondary.add(effect.destroy);\n return effect;\n },\n\n createSignal<T = unknown>(...args: Parameters<typeof createSignal<T>>): ReturnType<typeof createSignal<T>> {\n const sig = createSignal<T>(...args);\n unsubscribeSecondary.add(() => {\n destroySignal(sig);\n });\n return sig;\n },\n\n createMemo<T = unknown>(...args: Parameters<typeof createMemo<T>>): SignalReader<T> {\n const sig = createMemo<T>(...args);\n unsubscribeSecondary.add(() => {\n destroySignal(sig);\n });\n return sig;\n },\n\n on(...args: any[]): ReturnType<typeof on> {\n const [firstArg] = args;\n if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {\n // @ts-ignore\n const unsub = on(entry.entity, ...args);\n unsubscribeSecondary.add(unsub);\n return unsub;\n }\n // @ts-ignore\n const unsub = on(...args);\n unsubscribeSecondary.add(unsub);\n // return unsub;\n return Object.assign(() => {\n unsubscribeSecondary.delete(unsub);\n unsub();\n }, unsub);\n },\n\n once(...args: any[]): ReturnType<typeof once> {\n const [firstArg] = args;\n if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {\n // @ts-ignore\n const unsub = once(entry.entity, ...args);\n unsubscribeSecondary.add(unsub);\n return unsub;\n }\n // @ts-ignore\n const unsub = once(...args);\n unsubscribeSecondary.add(unsub);\n // return unsub;\n return Object.assign(() => {\n unsubscribeSecondary.delete(unsub);\n unsub();\n }, unsub);\n },\n\n emit(...args: any[]): void {\n const [firstArg] = args;\n if (typeof firstArg === 'string' || typeof firstArg === 'symbol' || Array.isArray(firstArg)) {\n // @ts-ignore\n emit(entry.entity, ...args);\n } else {\n // @ts-ignore\n emit(...args);\n }\n },\n\n onViewEvent(callback: (type: string, data: unknown) => any) {\n const unsub = on(entry.entity, onViewEvent, (type: string, data: unknown) => {\n callback(type, data);\n });\n unsubscribeSecondary.add(unsub);\n },\n\n onDestroy(callback: () => any) {\n unsubscribePrimary.add(callback);\n },\n }),\n );\n\n if (this.logger.isInfo) {\n this.logger.info('create shadow-object', getDisplayName(construct), {shadowObject, entity: entry.entity});\n }\n\n once(entry.entity, onDestroy, Priority.Low, () => {\n if (this.logger.isInfo) {\n this.logger.info('destroy shadow-object', getDisplayName(construct), {shadowObject, entity: entry.entity});\n }\n\n for (const callback of unsubscribePrimary) {\n callback();\n }\n\n for (const callback of unsubscribeSecondary) {\n callback();\n }\n\n for (const sig of contextReaders.values()) {\n destroySignal(sig);\n }\n\n for (const sig of contextParentReaders.values()) {\n destroySignal(sig);\n }\n\n for (const sig of propertyReaders.values()) {\n destroySignal(sig);\n }\n\n for (const sig of contextProviders.values()) {\n destroySignal(sig);\n }\n\n for (const sig of contextRootProviders.values()) {\n destroySignal(sig);\n }\n\n unsubscribePrimary.clear();\n unsubscribeSecondary.clear();\n contextReaders.clear();\n contextParentReaders.clear();\n propertyReaders.clear();\n contextProviders.clear();\n contextRootProviders.clear();\n\n const otherShadowObjects = entry.usedConstructors.get(construct);\n if (otherShadowObjects) {\n otherShadowObjects.delete(shadowObject);\n if (otherShadowObjects.size === 0) {\n entry.usedConstructors.delete(construct);\n }\n }\n });\n\n // We want to keep track which shadow-objects are created by which constructors.\n // This will all\n //\n if (entry.usedConstructors.has(construct)) {\n entry.usedConstructors.get(construct).add(shadowObject);\n } else {\n entry.usedConstructors.set(construct, new Set([shadowObject]));\n }\n\n this.attachShadowObject(shadowObject, entry.entity);\n\n return shadowObject;\n }\n\n private createShadowObjects(uuid: string): void {\n const entry = this.#entities.get(uuid);\n\n this.registry.findConstructors(entry.token, entry.entity.truthyProps())?.forEach((construct) => {\n this.constructShadowObject(construct, entry);\n });\n }\n\n findShadowObjects(uuid: string): ShadowObjectType[] {\n if (!this.#entities.has(uuid)) return [];\n\n const {usedConstructors} = this.#entities.get(uuid);\n\n return Array.from(new Set(Array.from(usedConstructors.values()).flatMap((objs) => Array.from(objs))));\n }\n\n private attachShadowObject(shadowObject: object, entity: Entity): void {\n // Like all other objects, the new shadow-object should be able to respond to the events that the entity receives.\n //\n on(entity, shadowObject);\n\n // Finally, the `shadowObject.onCreate(entity)` callback is called on the shadow-object.\n //\n if (typeof (shadowObject as any)[onCreate] === 'function') {\n (shadowObject as OnCreate)[onCreate](entity);\n }\n }\n\n private destroyShadowObject(shadowObject: object, entity: Entity): void {\n if (typeof (shadowObject as any)[onDestroy] === 'function') {\n (shadowObject as OnDestroy)[onDestroy](entity);\n }\n\n emit(shadowObject, onDestroy, entity);\n\n off(entity, shadowObject);\n }\n\n findOrCreateRootContext(name: string | symbol): SignalsPath {\n let ctx = this.#rootContexts.get(name);\n if (!ctx) {\n ctx = new SignalsPath();\n this.#rootContexts.set(name, ctx);\n }\n return ctx;\n }\n\n destroy(): void {\n for (const ctx of this.#rootContexts.values()) {\n ctx.dispose();\n }\n this.#rootContexts.clear();\n\n for (const entity of this.traverseLevelOrderBFS().reverse()) {\n this.destroyEntity(entity.uuid);\n }\n }\n}"],
5
- "mappings": "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",
6
- "names": ["ShadowObjectAction", "ln", "unsub"]
4
+ "sourcesContent": ["import {emitSafe, emitStrict, eventize, off, on} from '@spearwolf/eventize';\nimport {batch} from '@spearwolf/signalize';\nimport {ChangeTrailRefusedError} from '../ChangeTrailRefusedError.js';\nimport {ComponentChangeType, MessageToView} from '../constants.js';\nimport {EntityUuidInUseError} from '../EntityUuidInUseError.js';\nimport type {\n ComponentPropertiesType,\n IComponentChangeType,\n IComponentEvent,\n ShadowObjectConstructor,\n ShadowObjectType,\n SyncEvent,\n} from '../types.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {runGuarded} from '../utils/runGuarded.js';\nimport {Entity} from './Entity.js';\nimport {type OnCreate, type OnDestroy, onCreate, onDestroy, onParentChanged, onViewEvent} from './events.js';\nimport {Registry} from './Registry.js';\nimport {ShadowObjectCreationScope} from './ShadowObjectCreationScope.js';\nimport {SignalsPath} from './SignalsPath.js';\n\nexport interface MessageToViewEvent {\n uuid: string;\n type: string;\n data?: unknown;\n transferables?: Transferable[] | undefined;\n traverseChildren?: boolean | undefined;\n}\n\ninterface EntityEntry {\n token: string;\n entity: Entity;\n usedConstructors: Map<ShadowObjectConstructor, Set<ShadowObjectType>>;\n}\n\ninterface OmittedGraphChild {\n uuid: string;\n reason: 'already-in-graph' | 'not-in-kernel';\n}\n\ninterface EntityGraphNode {\n token: string;\n entity: Entity;\n props: Record<string, unknown>;\n children: EntityGraphNode[];\n omittedChildren?: OmittedGraphChild[];\n}\n\nenum ShadowObjectAction {\n CreateAndDestroy = 0,\n JustCreate,\n DestroyOnly,\n}\n\nconst getDisplayName = (construct: ShadowObjectConstructor) => construct.displayName || construct.name;\n\n// The four lifecycle hooks are symbols, and a string key of the same name is never picked up by\n// eventize or by the direct calls in `#attachShadowObject()` -- a shadow-object that writes one as\n// a plain method looks correct and never runs, with nothing to say so. This table is what\n// `#attachShadowObject()` walks to catch that case.\nconst LIFECYCLE_HOOKS: [string, symbol][] = [\n ['onCreate', onCreate],\n ['onDestroy', onDestroy],\n ['onParentChanged', onParentChanged],\n ['onViewEvent', onViewEvent],\n];\n\n/**\n * The entity kernel manages the lifecycle of all entities and shadow-objects.\n *\n * An entity is created for each view-component. The entities act as containers for the shadow-objects.\n *\n * Which shadow-objects are created is determined by the token.\n */\nexport class Kernel {\n registry: Registry;\n\n readonly #logger = new ConsoleLogger('Kernel');\n\n /** The logger this Kernel reports through. */\n get logger(): ConsoleLogger {\n return this.#logger;\n }\n\n #entities: Map<string, EntityEntry> = new Map();\n #rootEntities: Set<string> = new Set();\n\n #allEntities: Entity[] = [];\n #allEntitiesReversed: Entity[] = [];\n #allEntitiesNeedUpdate = true;\n\n #rootContexts: Map<string | symbol, SignalsPath> = new Map();\n\n /**\n * The creation scope of a shadow-object, keyed by the shadow-object itself.\n *\n * `#destroyShadowObject()` needs to reach the scope from the outside when a shadow-object leaves the\n * constructor set of an entity that stays alive. The scope removes its own entry when it tears down,\n * so nothing here outlives the shadow-object it belongs to.\n *\n * The key is the shadow-object instance, which assumes one instance per construction. A\n * constructor handing out the same instance twice \u2014 to a second entity, or to the same one\n * under another token \u2014 leaves only the later scope reachable from here; the earlier one\n * still tears down when its entity is destroyed.\n */\n readonly #shadowObjectScopes = new WeakMap<object, ShadowObjectCreationScope>();\n\n // The member names whose deprecation report this kernel has already made, one entry each. Handed\n // to every creation scope this kernel builds, which is what gives the report the lifetime of the\n // kernel rather than that of this module: an application running two shadow environments would\n // otherwise report the deprecated call form to whichever of them got there first and to no other.\n // One entry per name rather than a single flag, because a flag would swallow the reports of the\n // four members that come after the first. `destroy()` leaves the set alone -- a kernel that has\n // said it once has said it.\n readonly #shownDeprecations = new Set<string>();\n\n constructor(registry?: Registry) {\n eventize(this);\n this.registry = Registry.get(registry);\n }\n\n getEntity(uuid: string): Entity {\n return this.#requireEntry(uuid).entity;\n }\n\n /**\n * The entity behind a uuid, or `undefined` when the kernel does not hold one.\n *\n * The counterpart to `getEntity()`, which throws. Which of the two a caller wants follows from what an\n * absent entity means to it: a change that describes the entity tree -- a new parent, a new order, new\n * properties -- names an entity the view believes to be there, and a uuid the kernel does not know is a\n * disagreement the caller has to hear about. An event is the other case: it carries no structure, and the\n * entity it was meant for may have been torn down between the two sides.\n */\n findEntity(uuid: string): Entity | undefined {\n return this.#entities.get(uuid)?.entity;\n }\n\n /**\n * The entry for an entity that is expected to exist.\n *\n * The uuid is the caller's responsibility: `getEntity()` hands the throw on to its own\n * callers, and `#updateShadowObjects()` is reached only for an entity the caller has just\n * confirmed. Failing here names the uuid instead of failing later on an undefined field.\n */\n #requireEntry(uuid: string): EntityEntry {\n const entry = this.#entities.get(uuid);\n if (entry === undefined) {\n throw new Error(`entity with uuid \"${uuid}\" not found!`);\n }\n return entry;\n }\n\n hasEntity(uuid: string): boolean {\n return this.#entities.has(uuid);\n }\n\n /**\n * How many entities the kernel is holding, one count per store, read without waiting on a garbage\n * collector: a test can destroy a kernel and see that it let go of every one of them, rather than\n * inferring it from what a collector happened to do. The two traversal counts are the cached\n * breadth-first order and its reverse.\n *\n * @internal\n */\n get debugEntityCounts(): {entities: number; rootEntities: number; traversal: number; traversalReversed: number} {\n return {\n entities: this.#entities.size,\n rootEntities: this.#rootEntities.size,\n traversal: this.#allEntities.length,\n traversalReversed: this.#allEntitiesReversed.length,\n };\n }\n\n /**\n * @returns all entities in breadth-first order\n *\n * The list belongs to the caller: sorting or reversing it changes nothing about what the next call\n * hands out. The walk behind it visits every entity once, which also carries it over a children list\n * that points back at an ancestor -- `Entity.addChild()` writes such a list without touching the parent\n * link, so no check along the parent chain can cover it.\n *\n * A uuid the kernel no longer holds drops out, and what hangs below it with it -- `getEntityGraph()`\n * walks the same tree by the same rule.\n */\n traverseLevelOrderBFS(reverse = false): Entity[] {\n if (this.#allEntitiesNeedUpdate) {\n const lvl = new Map<number, Entity[]>();\n const visited = new Set<string>();\n\n const traverse = (uuid: string, depth: number) => {\n if (visited.has(uuid)) return;\n visited.add(uuid);\n\n // A uuid the kernel no longer holds drops out of the walk, the same way it drops out of\n // `getEntityGraph()`. A children list keeps naming an entity the kernel has let go whenever the\n // detachment that would have cut it does not happen: `addChild()` writes such a list without the\n // parent link `removeFromParent()` follows, and a detachment that throws inside `destroyEntity()`\n // is logged rather than handed on. `destroy()` and `upgradeEntities()` both walk from here, so a\n // lookup that threw would cost every entity behind that one name its own teardown.\n const e = this.findEntity(uuid);\n if (e === undefined) return;\n\n const entities = lvl.get(depth);\n if (entities) {\n entities.push(e);\n } else {\n lvl.set(depth, [e]);\n }\n\n for (const child of e.children) {\n traverse(child.uuid, depth + 1);\n }\n };\n\n this.#rootEntities.forEach((uuid) => {\n traverse(uuid, 0);\n });\n\n this.#allEntities = Array.from(lvl.entries())\n .sort((a, b) => a[0] - b[0])\n .flatMap(([, entities]) => entities);\n\n this.#allEntitiesReversed = this.#allEntities.slice().reverse();\n this.#allEntitiesNeedUpdate = false;\n }\n\n return reverse ? this.#allEntitiesReversed.slice() : this.#allEntities.slice();\n }\n\n /**\n * The entity tree as nested nodes, one node per entity. The visited set is what makes that count\n * hold: a children list that points back at an ancestor would otherwise be walked forever, and this\n * is the one traversal a caller reaches for while debugging a tree that is already broken. A child\n * the walk leaves out is named at its parent under `omittedChildren`, with the reason -- a uuid the\n * kernel does not hold, or one the walk has already placed elsewhere in the graph. A root the walk\n * has already reached through another root's children falls off the top level without a note; it\n * still stands in the graph, just at the other position.\n */\n getEntityGraph(): EntityGraphNode[] {\n const visited = new Set<string>();\n return Array.from(this.#rootEntities)\n .map((uuid) => this.#getEntityGraphNode(uuid, visited))\n .filter((node) => node !== undefined);\n }\n\n #getEntityGraphNode(uuid: string, visited: Set<string>, omitted?: OmittedGraphChild[]): EntityGraphNode | undefined {\n const entry = this.#entities.get(uuid);\n if (entry === undefined) {\n omitted?.push({uuid, reason: 'not-in-kernel'});\n return undefined;\n }\n\n // The kernel lookup goes first so that a uuid the kernel does not hold is named at every\n // parent that lists it, not just at the one the walk reaches first. `visited` is written\n // only for an entity that actually enters the graph.\n if (visited.has(uuid)) {\n omitted?.push({uuid, reason: 'already-in-graph'});\n return undefined;\n }\n visited.add(uuid);\n\n const {token, entity} = entry;\n\n const omittedChildren: OmittedGraphChild[] = [];\n const children = entity.children\n .map((child) => this.#getEntityGraphNode(child.uuid, visited, omittedChildren))\n .filter((node) => node !== undefined);\n\n return {\n token,\n entity,\n props: Object.fromEntries(entity.propEntries()),\n children,\n ...(omittedChildren.length > 0 ? {omittedChildren} : {}),\n };\n }\n\n upgradeEntities(): void {\n const entityConstructors = new Map<string, Set<ShadowObjectConstructor>>();\n\n // Both loops walk a snapshot of the entity tree, and a lifecycle callback is free to destroy\n // an entity while the upgrade is running. An entry from the snapshot can therefore be gone by\n // the time its turn comes: it needs no upgrade, and the entities behind it still do.\n for (const entity of this.traverseLevelOrderBFS(true)) {\n if (!this.hasEntity(entity.uuid)) continue;\n entityConstructors.set(entity.uuid, this.#updateShadowObjects(entity.uuid, ShadowObjectAction.DestroyOnly));\n }\n\n for (const entity of this.traverseLevelOrderBFS(false)) {\n if (!this.hasEntity(entity.uuid)) continue;\n this.#updateShadowObjects(entity.uuid, ShadowObjectAction.JustCreate, entityConstructors.get(entity.uuid));\n }\n\n entityConstructors.clear();\n }\n\n /**\n * Apply a change trail, entry by entry, and say how far it got if it cannot be applied in full.\n *\n * The loop ends at the entry that throws, so what the kernel holds afterwards is a prefix of the\n * trail; the {@link ChangeTrailRefusedError} names its length. The counter sits behind\n * `#parse` and therefore counts only entries that returned normally.\n *\n * An effect the batch defers belongs to no single entry: the batch releases it once the loop is\n * through, and a throw from there arrives with every entry already counted. `appliedCount` then\n * equals `entryCount` \u2014 everything was applied, something failed nevertheless, and both\n * statements are true at once.\n *\n * @throws {ChangeTrailRefusedError} if any entry, or any effect the batch deferred, threw\n */\n run(event: SyncEvent): void {\n this.logger.debug('sync', event);\n\n let appliedCount = 0;\n\n try {\n batch(() => {\n for (const entry of event.changeTrail) {\n this.#parse(entry);\n appliedCount++;\n }\n });\n } catch (error) {\n throw new ChangeTrailRefusedError(appliedCount, event.changeTrail.length, {cause: error});\n }\n }\n\n #parse(entry: IComponentChangeType): void {\n switch (entry.type) {\n case ComponentChangeType.CreateEntities:\n this.createEntity(\n entry.uuid,\n entry.token,\n entry.parentUuid,\n entry.order,\n entry.properties,\n entry.autoDestructionOnParentRemoval,\n );\n break;\n\n case ComponentChangeType.DestroyEntities:\n this.destroyEntity(entry.uuid);\n break;\n\n case ComponentChangeType.SetParent:\n this.setParent(entry.uuid, entry.parentUuid, entry.order);\n break;\n\n case ComponentChangeType.UpdateOrder:\n this.updateOrder(entry.uuid, entry.order);\n break;\n\n case ComponentChangeType.ChangeProperties:\n this.changeProperties(entry.uuid, entry.properties);\n break;\n\n case ComponentChangeType.ChangeToken:\n this.changeToken(entry.uuid, entry.token);\n break;\n\n case ComponentChangeType.SendEvents:\n this.dispatchEventsToEntity(entry.uuid, entry.events);\n break;\n }\n }\n\n createEntity(\n uuid: string,\n token: string,\n parentUuid?: string,\n order = 0,\n properties?: ComponentPropertiesType,\n autoDestructionOnParentRemoval = false,\n ): void {\n // A uuid names one entity at a time. Taking the entry over would leave the entity behind it\n // standing -- with its shadow objects, its signals and its contexts -- and out of reach of\n // every teardown the kernel has, because nothing holds that uuid any more. The uuid is free\n // again once `destroyEntity()` has been through.\n if (this.#entities.has(uuid)) {\n throw new EntityUuidInUseError(uuid);\n }\n\n const e = new Entity(this, uuid);\n\n e.order = order;\n\n const entry: EntityEntry = {token, entity: e, usedConstructors: new Map()};\n\n this.#entities.set(uuid, entry);\n\n // A new entity is a root until a parent takes it. No write on the entity itself can say so\n // while the kernel does not hold it yet, so the creation says it: from here on the entity is\n // in the traversal and in the root set, and the parent link below takes it out again.\n this.noteEntityTreeChange(uuid);\n\n // A shadow-object constructor may address the kernel with the uuid of the entity being created --\n // `createEntity(child, token, entity.uuid)` and `setParent(other, entity.uuid)` both look that uuid\n // up in `#entities` -- so the entry has to stand while the constructors run. Everything past it\n // therefore runs under the rollback: a creation that does not get through leaves no entity behind.\n try {\n if (parentUuid) {\n e.parentUuid = parentUuid;\n }\n\n e.autoDestructionOnParentRemoval = autoDestructionOnParentRemoval;\n\n if (properties) {\n e.setProperties(properties);\n }\n\n this.#createShadowObjects(entry);\n } catch (error) {\n this.#rollbackFailedCreation(uuid);\n throw error;\n }\n }\n\n /**\n * Takes back what a creation managed before it failed. The teardown is the regular one, so a\n * shadow-object that already stands hears its `onDestroy` and its creation scope ends the way\n * it would on any other destruction; the entry, the root registration and the link to the\n * parent go with it. `destroyEntity()` clears the bookkeeping of the entity whatever a callback\n * along the way does, so there is nothing left here to take back by hand; only a failure of the\n * teardown itself is reported, because the creation error is the one the caller is waiting for.\n *\n * The rollback reaches this one entity, not the kernel around it. What a constructor did to other\n * entities before it threw stands, and the teardown even adds to it, because `destroyEntity()` walks\n * the children list: an entity the constructor hung under this one survives as a root, and one it\n * moved under this one is taken off the parent it came from -- or destroyed outright, where it\n * carries `autoDestructionOnParentRemoval`. Both leave an entity in a state that is neither the one\n * before the call nor the one the constructor built. A rollback that covers those cases needs a\n * snapshot of the kernel, which this path does not take.\n */\n #rollbackFailedCreation(uuid: string): void {\n runGuarded(\n this.logger,\n () => this.destroyEntity(uuid),\n 'rollback of a failed entity creation could not destroy the entity:',\n uuid,\n );\n }\n\n destroyEntity(uuid: string): void {\n const entry = this.#entities.get(uuid);\n if (entry === undefined) return;\n\n const {entity, usedConstructors} = entry;\n\n try {\n // Children with autoDestructionOnParentRemoval cascade; the rest are promoted\n // to root so they remain reachable instead of leaking inside the kernel, which\n // `removeFromParent()` writes down on its own.\n // Snapshot first because both branches mutate the children list.\n const childrenSnapshot = [...entity.children];\n for (const child of childrenSnapshot) {\n // One guard per child, so that a cascade breaking off somewhere below still leaves the\n // siblings next to it with the treatment they were owed.\n runGuarded(\n this.logger,\n () => {\n if (child.autoDestructionOnParentRemoval) {\n this.destroyEntity(child.uuid);\n } else {\n child.removeFromParent();\n }\n },\n 'child of a destroyed entity could not be handed on:',\n child.uuid,\n );\n }\n\n runGuarded(this.logger, () => entity.removeFromParent(), 'entity could not be detached from its parent:', entity.uuid);\n\n // The list is read before the first notification goes out, because the bookkeeping behind it is\n // emptied while they run: every scope that tears down takes its shadow-object out of it.\n const shadowObjects = this.findShadowObjects(entity.uuid);\n\n for (const shadowObject of shadowObjects) {\n // One shadow-object at a time rather than through the entity-wide notification below, so that\n // a teardown that throws costs its own shadow-object and none of its siblings. The\n // subscription comes off first, because that notification would otherwise reach the same\n // shadow-object a second time -- it hangs on the entity as a listener object.\n //\n // This is the one point at which the two teardown paths differ, and it is worth knowing which\n // way round: a shadow-object that emits an event on the entity from inside its `[onDestroy]`\n // does not reach its own siblings here, because they are taken off one by one as their turn\n // comes. `#destroyShadowObject()` leaves the subscription in place until after the hook for\n // exactly the opposite reason -- there the entity lives on, so there is no second delivery to\n // avoid. An entity that is being destroyed is no address for an event either way.\n off(entity, shadowObject);\n this.#notifyShadowObjectDestroy(shadowObject, entity);\n }\n\n // What is left listening here are the creation scopes at `Priority.Low`: they tear down once\n // every shadow-object has been told. Below them the kernel has nothing of its own on this\n // notification, so a listener on `Priority.Min` is the last one the delivery reaches, and it\n // reads an entity that still holds its properties and its contexts.\n // `emitStrict()` rather than `emit()`: the notification reaches every listener whatever the one\n // before it did, and what they threw comes back here as one error or, from several of them, as an\n // `AggregateError` in dispatch order. The guard around it turns that into the report this teardown\n // owes -- with the uuid of the entity in it, which is why the guard stays rather than giving way to\n // `emitSafe()` and its bare `console.warn`.\n runGuarded(this.logger, () => emitStrict(entity, onDestroy, entity), 'entity onDestroy notification failed:', entity.uuid);\n\n // The creation scopes listen on that notification at `Priority.Low`, and the guarded dispatch above\n // is what gets them there. This loop is the backstop behind it, for the one way a delivery can still\n // fall short of its end: a listener that unsubscribes the ones behind it and returns perfectly\n // normally. The kernel tears down whatever is left and releases the entity behind it, each behind a\n // guard of its own. Both are written to happen once: a scope that has torn down is no longer in\n // `#shadowObjectScopes`, and the entity releases once, whoever calls it.\n for (const shadowObject of shadowObjects) {\n runGuarded(\n this.logger,\n () => this.#shadowObjectScopes.get(shadowObject)?.tearDown(),\n 'creation scope teardown of a destroyed entity failed:',\n entity.uuid,\n );\n }\n\n // `Entity[onDestroy]()` guards every one of its own steps and reports a failing one through\n // this same logger under its own label, so this catch is a backstop rather than the path a\n // failing release actually takes -- it stands for whatever reaches this call from outside that\n // guarantee.\n runGuarded(this.logger, () => entity[onDestroy](), 'entity release failed:', entity.uuid);\n } finally {\n // The kernel lets go of the entity whatever the notifications above did, so that a failing\n // teardown cannot leave an entity standing that nothing points at any more.\n usedConstructors.clear();\n\n this.#entities.delete(entity.uuid);\n this.#rootEntities.delete(entity.uuid);\n this.#allEntitiesNeedUpdate = true;\n }\n }\n\n /**\n * @param order the new order, or `undefined` to keep the current one. A set-parent change\n * only carries an order when it actually changed, so an absent order must not be read as\n * a reset to `0` \u2014 that would silently drop the order the view side still holds.\n */\n setParent(uuid: string, parentUuid?: string, order?: number): void {\n const e = this.getEntity(uuid);\n\n const nextOrder = order ?? e.order;\n\n if (e.parentUuid === parentUuid && e.order === nextOrder) return;\n\n // The new parent is resolved before the current one is detached: an unknown UUID throws, and\n // a throw after the detachment would leave the entity with no parent at all instead of the\n // one it came in with.\n if (parentUuid && !this.#entities.has(parentUuid)) {\n throw new Error(`entity with uuid \"${parentUuid}\" not found!`);\n }\n\n // Before the detachment as well, and for the same reason: a parent that would close the entity\n // tree into a ring is refused while the entity still hangs where it was.\n if (parentUuid) {\n e.assertAttachableTo(this.getEntity(parentUuid));\n }\n\n // The detachment is what places the entity anew, which is the point of a call that keeps the\n // parent and changes the order alone. It skips the rebinding of the contexts whenever a parent\n // follows right away -- that parent binds them, and the root value in between would be visible\n // to every `useParentContext()` reader on the entity.\n e.removeFromParent(parentUuid == null);\n\n e.order = nextOrder;\n e.parentUuid = parentUuid;\n\n // The root set and the traversal cache follow the three writes above: each of them reports to\n // `noteEntityTreeChange()` from inside the entity, on this route as on any other.\n\n this.logger.debug('entity.onParentChanged', {uuid, parentUuid, order: nextOrder, entity: e});\n\n // The notification is the last thing this method does, and it goes out while the caller is\n // still inside the call: the entity is fully placed by now, and an entity that is destroyed\n // later in the same task has heard about its last move before its listeners come off.\n //\n // What a handler reads inline differs by reader. `useParentContext()` is a direct link to the\n // parent's own context signal (`Entity.#subscribeToParent()`), rebound the moment\n // `e.parentUuid = parentUuid` runs above -- it already names the new parent here. That link\n // reads whatever the parent's own context signal currently holds, though, and that signal runs\n // through the same one-microtask collector named below: a parent whose own provided value was\n // set in the same task has not settled it there yet, and `useParentContext()` reads `undefined`\n // until it does. `useContext()` runs through `Entity`'s `deferContextValueUpdate()`, a\n // one-microtask batch collector of its own; it still names the value the entity is leaving here,\n // and a handler that needs the new one reads it through an effect instead.\n //\n // Inside a change trail this call runs inside the `batch()` of `Kernel.run()`: a signal write the\n // handler makes here settles its dependent effects only once that batch releases at the end of\n // the trail, where the same write outside a change trail settles them right away.\n //\n // The guard is the one `destroyEntity()` puts around its own entity-wide notification: a\n // handler that throws is reported and costs nothing else -- and so is an error a Kernel call\n // the handler makes throws back into it, such as `createEntity()` refusing a uuid already in\n // use. Without it either throw would leave through `setParent()` and turn one bad handler into\n // a refused change trail. And, for the same reason, one bad handler does not cost the handlers\n // behind it their notification either: the dispatch is `emitStrict()`, so every one of them\n // hears about the new parent and the guard reports what they threw.\n runGuarded(this.logger, () => emitStrict(e, onParentChanged, e), 'entity onParentChanged notification failed:', uuid);\n }\n\n updateOrder(uuid: string, order: number): void {\n this.getEntity(uuid).order = order;\n }\n\n /**\n * Records that an entity has changed its place in the entity tree: it took a parent, lost one,\n * or moved among its siblings. Two pieces of bookkeeping follow from that -- the cached\n * traversal is dropped, and an entity without a parent joins the set of root entities while one\n * with a parent leaves it.\n *\n * `Entity` reports here from every write that moves it, because those writes are reachable from\n * a shadow-object with no kernel call in between: `entity.parent`, `entity.parentUuid`,\n * `entity.order` and `entity.removeFromParent()`. The state is read off the entity rather than\n * taken as an argument, so a caller cannot describe a move the entity did not make.\n *\n * A uuid the kernel does not hold reaches the cache and stops there: an entity joins the root\n * set when the kernel takes it in and leaves it when the kernel lets go.\n *\n * That such a uuid passes in silence, where `setParent()` and `updateOrder()` throw at one, is the\n * difference between a request and a report. Those two are asked to move an entity and cannot do it\n * without one, so an unknown uuid is a disagreement the caller has to hear about. This is an entity\n * saying where it stands, and it says so while the kernel is still taking it in: `createEntity()`\n * writes the order on the entity before the entry is registered, so an entity created with an order\n * of its own reports once before the kernel holds it. A throw there would cost the creation its own\n * bookkeeping, and there is nothing to disagree about -- dropping the cache is right either way.\n */\n noteEntityTreeChange(uuid: string): void {\n this.#allEntitiesNeedUpdate = true;\n\n const entry = this.#entities.get(uuid);\n if (entry === undefined) return;\n\n if (entry.entity.hasParent) {\n this.#rootEntities.delete(uuid);\n } else {\n this.#rootEntities.add(uuid);\n }\n }\n\n dispatchEventsToEntity(uuid: string, events: IComponentEvent[]): void {\n this.findEntity(uuid)?.dispatchViewEvents(events);\n }\n\n changeProperties(uuid: string, properties: ComponentPropertiesType): void {\n this.getEntity(uuid).setProperties(properties);\n this.#updateShadowObjects(uuid);\n }\n\n changeToken(uuid: string, token: string): void {\n const entry = this.#entities.get(uuid);\n if (entry === undefined) return;\n\n if (entry.token === token) return;\n\n // The new token has to stand before the constructors run, because `#updateShadowObjects()` resolves\n // the constructor set out of `entry.token`. A change that does not get through hands the previous\n // token back and rebuilds what belongs to it, as far as the rebuild gets. Taking the change back\n // belongs to `#updateShadowObjects()` rather than here: it is one act with the rebuilding of the\n // shadow-objects, and the order within it matters -- the token first, then the objects.\n const previousToken = entry.token;\n entry.token = token;\n\n this.#updateShadowObjects(uuid, ShadowObjectAction.CreateAndDestroy, undefined, previousToken);\n }\n\n dispatchMessageToView(message: MessageToViewEvent): void {\n queueMicrotask(() => {\n // `emitSafe()` because of the microtask: a throw from here has no caller left to reach and\n // would surface as an unhandled error in the realm. Every listener is served and a failure\n // is reported through `console.warn` -- the kernel has nothing to add to it, and nothing to\n // do about it either.\n emitSafe(this as Kernel, MessageToView, message);\n });\n }\n\n /**\n * Create or destroy the shadow-objects of an entity using the registered constructors.\n * After a token change or registry changes, an entity may be given different shadow-objects.\n *\n * @param previousToken the token the entry carried before the caller wrote the new one, or\n * `undefined` where the caller left the token alone. A rebuild that does not get through puts it\n * back before it restores the shadow-objects, so an entity is never built against a token it does\n * not carry.\n */\n #updateShadowObjects(\n uuid: string,\n action = ShadowObjectAction.CreateAndDestroy,\n nextConstructors?: Set<ShadowObjectConstructor>,\n previousToken?: string,\n ): Set<ShadowObjectConstructor> {\n const entry = this.#requireEntry(uuid);\n nextConstructors ??= new Set(this.registry.findConstructors(entry.token, entry.entity.truthyProps()));\n\n const shouldDestroy = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.DestroyOnly;\n const shouldCreate = action === ShadowObjectAction.CreateAndDestroy || action === ShadowObjectAction.JustCreate;\n\n // What the rebuild has done so far, in the two directions it can go, so that a creation that\n // throws can be taken back to the state the call came in on.\n const removed: {construct: ShadowObjectConstructor; count: number}[] = [];\n const created: ShadowObjectType[] = [];\n\n // destroy all shadow-objects created by constructors no longer in the list\n //\n if (shouldDestroy) {\n for (const [construct, shadowObjects] of entry.usedConstructors) {\n if (!nextConstructors.has(construct)) {\n entry.usedConstructors.delete(construct);\n // The size is read before the teardown, which empties the set through `forgetShadowObject`.\n // A count rather than a flag because the bookkeeping holds a set per constructor: the\n // deduplicated list `Registry.findConstructors()` hands out makes it `1` today, and the\n // restoration reads what is written down instead of assuming that.\n removed.push({construct, count: shadowObjects.size});\n for (const obj of shadowObjects) {\n this.#destroyShadowObject(obj, entry.entity);\n }\n }\n }\n }\n\n // shadow-objects for new constructors are now created using the updated constructor list\n //\n if (shouldCreate) {\n for (const construct of nextConstructors) {\n if (!entry.usedConstructors.has(construct)) {\n try {\n created.push(this.#constructShadowObject(construct, entry));\n } catch (error) {\n this.#rollbackFailedShadowObjectUpdate(entry, created, removed, previousToken);\n throw error;\n }\n }\n }\n }\n\n return nextConstructors;\n }\n\n /**\n * Takes a rebuild of the shadow-objects of one entity back to where the call found it.\n *\n * The identity check comes first, because a constructor may destroy the entity it is coming to life\n * on. Where the kernel no longer holds this entry -- including where another entry stands under the\n * same uuid by now -- `destroyEntity()` has already notified every shadow-object of the entry and\n * cleared `usedConstructors`; both halves of the rollback would find nothing to work with.\n *\n * The token before the shadow-objects: what is rebuilt is built against the token the entity carries\n * afterwards.\n *\n * Backwards down, forwards up: the new shadow-objects leave before the previous ones come back, so\n * the two sets never stand on the entity at the same time.\n *\n * Every step behind a guard of its own and nothing re-thrown -- the caller is waiting for the error\n * of the construction, not for one from the way back.\n *\n * What the rollback does not reach is named rather than passed over. `changeProperties()` has written its\n * properties before it gets here, and they stay written -- a constructor restored below can therefore\n * stand on an entity whose properties no longer route to it, until the next re-resolution of the set\n * leaves it out and takes it down. And `upgradeEntities()` takes its shadow-objects down in one pass over\n * the entity tree and builds in the next, so a rollback in the second pass knows nothing of what the first\n * one took -- at this entity as much as at any other; the entity keeps the token it came in with, an\n * upgrade having written none, and is left with whatever the first pass spared. Both would need a snapshot\n * of the kernel, which this path does not take.\n */\n #rollbackFailedShadowObjectUpdate(\n entry: EntityEntry,\n created: ShadowObjectType[],\n removed: {construct: ShadowObjectConstructor; count: number}[],\n previousToken?: string,\n ): void {\n if (this.#entities.get(entry.entity.uuid) !== entry) return;\n\n if (previousToken !== undefined) {\n entry.token = previousToken;\n }\n\n for (let i = created.length - 1; i >= 0; i--) {\n runGuarded(\n this.logger,\n () => this.#destroyShadowObject(created[i]!, entry.entity),\n 'rollback of a failed shadow-object update could not remove a new shadow-object:',\n entry.entity.uuid,\n );\n }\n\n for (const {construct, count} of removed) {\n for (let i = 0; i < count; i++) {\n runGuarded(\n this.logger,\n () => this.#constructShadowObject(construct, entry),\n 'rollback of a failed shadow-object update could not restore a shadow-object:',\n getDisplayName(construct),\n entry.entity.uuid,\n );\n }\n }\n }\n\n #constructShadowObject(construct: ShadowObjectConstructor, entry: EntityEntry): ShadowObjectType {\n const scope = new ShadowObjectCreationScope(entry.entity, this.logger, getDisplayName(construct), this.#shownDeprecations);\n\n let shadowObject: ShadowObjectType;\n\n try {\n shadowObject = eventize(new construct(scope.createAPI()));\n } catch (error) {\n // Until `bindTo()` below has run, nothing else can reach this scope: it is in neither\n // `#shadowObjectScopes` nor the destroy subscription of the entity. A constructor that does\n // not return therefore ends its own scope here, or nobody does. The scope is all there is to\n // take back at this point, because no shadow-object came out of the call.\n scope.tearDown();\n throw error;\n }\n\n this.#shadowObjectScopes.set(shadowObject, scope);\n\n scope.bindTo(\n shadowObject,\n () => {\n this.#shadowObjectScopes.delete(shadowObject);\n },\n () => {\n const otherShadowObjects = entry.usedConstructors.get(construct);\n if (otherShadowObjects) {\n otherShadowObjects.delete(shadowObject);\n if (otherShadowObjects.size === 0) {\n entry.usedConstructors.delete(construct);\n }\n }\n },\n );\n\n // `entry.usedConstructors` tracks, per constructor, the set of shadow-objects it created.\n // `#updateShadowObjects()` reads this bookkeeping to tell which shadow-objects belong to a\n // constructor that has left the entity's current constructor set, so it knows which ones to\n // tear down. An entry disappears from the set above when the tear-down of its shadow-object\n // runs, so this bookkeeping never outlives what it describes.\n const createdBy = entry.usedConstructors.get(construct);\n if (createdBy) {\n createdBy.add(shadowObject);\n } else {\n entry.usedConstructors.set(construct, new Set([shadowObject]));\n }\n\n try {\n this.#attachShadowObject(shadowObject, entry.entity);\n } catch (error) {\n // Attaching is the last step of a creation, and a shadow-object whose `[onCreate]` does not get\n // through is none: it goes the way one takes that leaves the constructor set of its entity, so it\n // hears its `[onDestroy]` hook and its `onDestroy` callbacks, gives up its creation scope and\n // comes off the entity before the error travels on. A second guard rather than one around both\n // steps, because there is more to take back here: the shadow-object stands in\n // `#shadowObjectScopes`, in `entry.usedConstructors` and, since `#attachShadowObject()` set its\n // `on(entity, shadowObject)`, as a listener of the entity -- and `#destroyShadowObject()` is the\n // only exit that clears all three.\n this.#destroyShadowObject(shadowObject, entry.entity);\n throw error;\n }\n\n return shadowObject;\n }\n\n #createShadowObjects(entry: EntityEntry): void {\n this.registry.findConstructors(entry.token, entry.entity.truthyProps())?.forEach((construct) => {\n this.#constructShadowObject(construct, entry);\n });\n }\n\n findShadowObjects(uuid: string): ShadowObjectType[] {\n const entry = this.#entities.get(uuid);\n if (entry === undefined) return [];\n\n const {usedConstructors} = entry;\n\n return Array.from(new Set(Array.from(usedConstructors.values()).flatMap((objs) => Array.from(objs))));\n }\n\n #attachShadowObject(shadowObject: object, entity: Entity): void {\n // A plain method under one of the four hook names, without the matching symbol, is the\n // silent-failure case `LIFECYCLE_HOOKS` exists for: report it through the logger before the\n // shadow-object goes live, on the same `warn`-vs-`error` reasoning as the refusal notice at\n // `ShaeWorkerElement.ts` -- `logger.error` always prints, where `logger.warn` is gated behind\n // `isWarn` and stays off outside `localhost`, which would make this check as silent as the\n // bug it looks for.\n for (const [name, symbol] of LIFECYCLE_HOOKS) {\n if (typeof (shadowObject as any)[name] === 'function' && typeof (shadowObject as any)[symbol] !== 'function') {\n const displayName = this.#shadowObjectScopes.get(shadowObject)?.displayName;\n this.logger.error(\n `the \"${name}\" lifecycle hook is a plain method and is never called; use the [${name}] symbol from \"@spearwolf/shadow-objects/shadow-objects.js\":`,\n displayName,\n );\n }\n }\n\n // Like all other objects, the new shadow-object should be able to respond to the events that the entity receives.\n //\n on(entity, shadowObject);\n\n // Finally, the `shadowObject.onCreate(entity)` callback is called on the shadow-object.\n //\n if (typeof (shadowObject as any)[onCreate] === 'function') {\n (shadowObject as OnCreate)[onCreate](entity);\n }\n }\n\n /**\n * Tells one shadow-object that it is about to end, in both halves the notification has: the\n * class-side `[onDestroy]` hook and the event other objects can listen for.\n *\n * Each half stands behind a guard of its own rather than a shared one, because neither is allowed to\n * cost the other: a hook that throws still lets the event go out, and a listener that throws leaves\n * the hook it came after untouched. Within the event half the same rule holds one level down, through\n * `emitStrict()`: a listener that throws costs no other listener its turn. Nothing is re-thrown -- the\n * shadow-objects of one entity reach their end in one sweep, and a failure at one of them may not take\n * the sweep with it. Reports are\n * keyed by the name the scope carries rather than the one the instance would give -- see\n * `ShadowObjectCreationScope.displayName` for where the two part ways.\n */\n #notifyShadowObjectDestroy(shadowObject: object, entity: Entity): void {\n const displayName = this.#shadowObjectScopes.get(shadowObject)?.displayName;\n\n if (typeof (shadowObject as any)[onDestroy] === 'function') {\n runGuarded(\n this.logger,\n () => (shadowObject as OnDestroy)[onDestroy](entity),\n 'shadow-object onDestroy hook failed:',\n displayName,\n );\n }\n\n // A listener a Shadow Object put directly on this one's own `onDestroy` notification -- through\n // `on(otherShadowObject, onDestroy, \u2026)` -- runs here.\n runGuarded(\n this.logger,\n () => emitStrict(shadowObject, onDestroy, entity),\n 'shadow-object onDestroy notification failed:',\n displayName,\n );\n }\n\n #destroyShadowObject(shadowObject: object, entity: Entity): void {\n this.#notifyShadowObjectDestroy(shadowObject, entity);\n\n // The teardown runs after the destroy notifications, so a shadow-object that reacts to its own\n // end still sees the signals, contexts and subscriptions the creation API gave it.\n this.#shadowObjectScopes.get(shadowObject)?.tearDown();\n\n // Last of all, because the entity lives on and only this one object is leaving: nothing else is\n // being delivered to the entity in the meantime, so the subscription can stand until the object\n // has said everything it had to say -- an event its `[onDestroy]` emits on the entity still comes\n // back to it. `destroyEntity()` cannot afford that; the reason is named there.\n off(entity, shadowObject);\n }\n\n findOrCreateRootContext(name: string | symbol): SignalsPath {\n let ctx = this.#rootContexts.get(name);\n if (!ctx) {\n ctx = new SignalsPath();\n this.#rootContexts.set(name, ctx);\n }\n return ctx;\n }\n\n destroy(): void {\n // Leaves first, and to the end. `destroyEntity()` keeps a failing callback to itself, so the guard\n // here covers what is left: whatever else fails at one entity, the ones behind it in the sweep still\n // reach their own teardown. The reversed order is already cached, so the walk does not turn its own\n // result around.\n for (const entity of this.traverseLevelOrderBFS(true)) {\n runGuarded(\n this.logger,\n () => this.destroyEntity(entity.uuid),\n 'entity teardown during kernel destroy failed:',\n entity.uuid,\n );\n }\n\n // Whatever a failing callback left half torn down, the kernel holds none of it afterwards.\n this.#entities.clear();\n this.#rootEntities.clear();\n\n // The flag on its own would only mark the cached order stale -- the two arrays behind it would go\n // on holding every entity of this kernel until some later walk overwrote them, and a caller that\n // keeps the kernel past its teardown never makes that walk happen.\n this.#allEntities.length = 0;\n this.#allEntitiesReversed.length = 0;\n this.#allEntitiesNeedUpdate = true;\n\n // After the entities, not before: a shadow-object callback that reads a global context during its\n // teardown reaches the path the kernel held, not a fresh empty one.\n for (const ctx of this.#rootContexts.values()) {\n ctx.dispose();\n }\n this.#rootContexts.clear();\n\n // One microtask later, not on this line: `dispatchMessageToView()` hands every message to a\n // microtask, and the teardown above queues its own -- what a shadow-object sends towards the\n // view from its `onDestroy`, which the creation API is open for. The queue is served in the\n // order it was filled, so those messages run ahead of this and reach their listeners, and\n // everything dispatched after them reaches nobody. What the kernel then holds is no\n // subscription that could keep it, or a listener, alive.\n queueMicrotask(() => {\n off(this);\n });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ShadowObjectAction"]
7
7
  }
@@ -4,7 +4,7 @@ export declare class Registry {
4
4
  #private;
5
5
  /** return the specified registry or, if not defined, the default registry */
6
6
  static get(registry?: Registry): Registry;
7
- define(token: string, constructor: ShadowObjectConstructor): void;
7
+ define(token: string, constructa: ShadowObjectConstructor): void;
8
8
  appendRoute(token: string, routes: string[]): void;
9
9
  clearRoute(route: string): void;
10
10
  findTokensByRoute(route: string, truthyProps?: Set<string>): Set<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"Registry.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,aAAa,CAAC;AA+BzD,uCAAuC;AACvC,qBAAa,QAAQ;;IACnB,6EAA6E;IAC7E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAQ9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,uBAAuB;IAQ1D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAiB3C,UAAU,CAAC,KAAK,EAAE,MAAM;IASxB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;IA2CxE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,uBAAuB,EAAE,GAAG,SAAS;IAWjG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,KAAK;CAKN"}
1
+ {"version":3,"file":"Registry.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,aAAa,CAAC;AA0BzD,uCAAuC;AACvC,qBAAa,QAAQ;;IACnB,6EAA6E;IAC7E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,QAAQ,YAE7B;IA2BD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,uBAAuB,QAQxD;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAoB1C;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,QAQvB;IA6FD,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAEvE;IAED,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,uBAAuB,EAAE,GAAG,SAAS,CAWhG;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/B;IAED,KAAK,SAMJ;CACF"}
@@ -2,7 +2,7 @@ import { appendTo } from "../utils/array-utils.js";
2
2
  const toPropRoute = (route) => {
3
3
  const parts = route.split("@").map((part) => part.trim());
4
4
  if (parts.length === 2 && parts[1]) {
5
- return parts[0] ? { key: `${parts[0]}@${parts[1]}`, prop: parts[1], token: parts[0] } : { key: parts[1], prop: parts[1] };
5
+ return parts[0] ? { key: `${parts[0]}@${parts[1]}`, prop: parts[1] } : { key: parts[1], prop: parts[1] };
6
6
  } else {
7
7
  return void 0;
8
8
  }
@@ -12,10 +12,10 @@ const addRoutes = (set, routes) => {
12
12
  set.add(route);
13
13
  }
14
14
  };
15
- const addConstructors = (entry, constructors) => {
16
- if (entry != null) {
17
- for (const constructor of entry.constructors) {
18
- constructors.add(constructor);
15
+ const addConstructors = (known, constructors) => {
16
+ if (known != null) {
17
+ for (const c of known) {
18
+ constructors.add(c);
19
19
  }
20
20
  }
21
21
  };
@@ -27,28 +27,53 @@ class Registry {
27
27
  #registry = /* @__PURE__ */ new Map();
28
28
  #routes = /* @__PURE__ */ new Map();
29
29
  #truthyPropRoutes = /* @__PURE__ */ new Map();
30
- define(token, constructor) {
31
- if (this.#registry.has(token)) {
32
- appendTo(this.#registry.get(token).constructors, constructor);
30
+ // The set of property names that any routing rule mentions. It only decides how finely the
31
+ // resolution key is cut, never what a resolution yields -- so it may be too large, but never too
32
+ // small. A key that is too fine splits entries that belong together; a key that is too coarse
33
+ // answers two different questions with one answer. clearRoute() therefore takes nothing back out:
34
+ // a name that stops routing costs at most an extra entry, while removing it could drop a name that
35
+ // another rule still routes on.
36
+ #routingProps = /* @__PURE__ */ new Set();
37
+ // The store of resolved tokens: outer key is the route, inner key is built from the properties.
38
+ // Two levels so that the route name works as a key unchanged and needs no escaping anywhere.
39
+ //
40
+ // It has no upper bound and evicts nothing, and it lives exactly as long as the registry that owns
41
+ // it -- for the default registry, that is the lifetime of the process. What holds it small is its
42
+ // key space: the routes times the ordered subsets of the routing property names, because the key
43
+ // names only the properties some rule routes on, and names them in the caller's order. For n such
44
+ // names that is the sum over k of C(n, k) * k! keys per route -- 2 for one name, 5 for two, 16 for
45
+ // three, 65 for four -- and #routingProps, which supplies n, never gives a name back. Both counts
46
+ // are fixed by the module manifests a registry is built from, and a manifest declares a handful of
47
+ // routes and one or two routing properties, so n stays small where the growth in it is steep.
48
+ #resolvedTokens = /* @__PURE__ */ new Map();
49
+ define(token, constructa) {
50
+ const constructors = this.#registry.get(token);
51
+ if (constructors) {
52
+ appendTo(constructors, constructa);
33
53
  } else {
34
- this.#registry.set(token, { token, constructors: [constructor] });
54
+ this.#registry.set(token, [constructa]);
35
55
  }
56
+ this.#dropResolvedTokens();
36
57
  }
37
58
  appendRoute(token, routes) {
38
59
  const propRoute = toPropRoute(token);
39
60
  if (propRoute) {
40
- if (this.#truthyPropRoutes.has(propRoute.key)) {
41
- addRoutes(this.#truthyPropRoutes.get(propRoute.key).routes, routes);
61
+ this.#routingProps.add(propRoute.prop);
62
+ const knownPropRoutes = this.#truthyPropRoutes.get(propRoute.key);
63
+ if (knownPropRoutes) {
64
+ addRoutes(knownPropRoutes, routes);
42
65
  } else {
43
- this.#truthyPropRoutes.set(propRoute.key, { routes: new Set(routes), token: propRoute.token });
66
+ this.#truthyPropRoutes.set(propRoute.key, new Set(routes));
44
67
  }
45
68
  } else {
46
- if (this.#routes.has(token)) {
47
- addRoutes(this.#routes.get(token), routes);
69
+ const knownRoutes = this.#routes.get(token);
70
+ if (knownRoutes) {
71
+ addRoutes(knownRoutes, routes);
48
72
  } else {
49
73
  this.#routes.set(token, new Set(routes));
50
74
  }
51
75
  }
76
+ this.#dropResolvedTokens();
52
77
  }
53
78
  clearRoute(route) {
54
79
  const propRoute = toPropRoute(route);
@@ -57,24 +82,60 @@ class Registry {
57
82
  } else {
58
83
  this.#routes.delete(route);
59
84
  }
85
+ this.#dropResolvedTokens();
60
86
  }
61
- findTokensByRoute(route, truthyProps) {
87
+ // Every write drops the store, define() included, even though define() does not move the token
88
+ // resolution itself. No write path then has to know which half of a resolution it touches, and a
89
+ // registry is written while a module is imported, where rebuilding costs nothing.
90
+ //
91
+ // Dropping is re-entrancy safe: Map.clear() lets go of the sets, it does not empty them. A set that
92
+ // a resolution has already handed out therefore stays valid and complete, no matter how long its
93
+ // caller keeps walking it and no matter what is written to the registry meanwhile.
94
+ #dropResolvedTokens() {
95
+ this.#resolvedTokens.clear();
96
+ }
97
+ // The key is built in the caller's property order, not sorted. The order of the properties decides
98
+ // the order of the tokens in the result, and that in turn the order in which the kernel builds the
99
+ // shadow objects. A sorted key would map two differently ordered questions onto one answer and so
100
+ // change the build order for one of them. Caller order keeps the behaviour character for character
101
+ // and pays in entries: a question over k routing properties can arrive in k! orders and fills one
102
+ // entry per order, where a sorted key would fill one for all of them. What that comes to over the
103
+ // whole store is at #resolvedTokens.
104
+ //
105
+ // Each name follows its own length, which makes the key unambiguous: no property name can imitate
106
+ // the boundary between two others. A separator could, as soon as a name contains it.
107
+ #resolutionKey(truthyProps) {
108
+ if (truthyProps === void 0 || this.#routingProps.size === 0) return "";
109
+ let key = "";
110
+ for (const prop of truthyProps) {
111
+ if (this.#routingProps.has(prop)) {
112
+ key += `${prop.length}:${prop}`;
113
+ }
114
+ }
115
+ return key;
116
+ }
117
+ #resolveTokens(route, truthyProps) {
118
+ const key = this.#resolutionKey(truthyProps);
119
+ let byProps = this.#resolvedTokens.get(route);
120
+ const known = byProps?.get(key);
121
+ if (known !== void 0) return known;
62
122
  const tokens = /* @__PURE__ */ new Set([route]);
63
- const next = this.#routes.has(route) ? [...this.#routes.get(route)] : [];
64
- while (next.length) {
65
- const cur = next.shift();
123
+ const next = Array.from(this.#routes.get(route) ?? []);
124
+ for (let cur = next.shift(); cur !== void 0; cur = next.shift()) {
66
125
  if (tokens.has(cur)) {
67
126
  continue;
68
127
  }
69
128
  tokens.add(cur);
70
- if (this.#routes.has(cur)) {
71
- next.push(...Array.from(this.#routes.get(cur)).filter((route2) => !tokens.has(route2)));
129
+ const nextRoutes = this.#routes.get(cur);
130
+ if (nextRoutes) {
131
+ next.push(...Array.from(nextRoutes).filter((route2) => !tokens.has(route2)));
72
132
  }
73
133
  }
74
134
  if (truthyProps) {
75
135
  for (const prop of truthyProps) {
76
- if (this.#truthyPropRoutes.has(prop)) {
77
- addRoutes(tokens, this.#truthyPropRoutes.get(prop).routes);
136
+ const propRoutes = this.#truthyPropRoutes.get(prop);
137
+ if (propRoutes) {
138
+ addRoutes(tokens, propRoutes);
78
139
  }
79
140
  }
80
141
  let tokenCountBefore;
@@ -82,18 +143,28 @@ class Registry {
82
143
  tokenCountBefore = tokens.size;
83
144
  for (const token of new Set(tokens)) {
84
145
  for (const prop of truthyProps) {
85
- const key = `${token}@${prop}`;
86
- if (this.#truthyPropRoutes.has(key)) {
87
- addRoutes(tokens, this.#truthyPropRoutes.get(key).routes);
146
+ const keyedRoutes = this.#truthyPropRoutes.get(`${token}@${prop}`);
147
+ if (keyedRoutes) {
148
+ addRoutes(tokens, keyedRoutes);
88
149
  }
89
150
  }
90
151
  }
91
152
  } while (tokenCountBefore !== tokens.size);
92
153
  }
154
+ if (byProps === void 0) {
155
+ byProps = /* @__PURE__ */ new Map();
156
+ this.#resolvedTokens.set(route, byProps);
157
+ }
158
+ byProps.set(key, tokens);
93
159
  return tokens;
94
160
  }
161
+ // The store holds exactly one set per question, and what a caller does with what it got stays its
162
+ // own business -- so a copy goes out.
163
+ findTokensByRoute(route, truthyProps) {
164
+ return new Set(this.#resolveTokens(route, truthyProps));
165
+ }
95
166
  findConstructors(route, truthyProps) {
96
- const tokens = this.findTokensByRoute(route, truthyProps);
167
+ const tokens = this.#resolveTokens(route, truthyProps);
97
168
  const constructors = /* @__PURE__ */ new Set();
98
169
  for (const token of tokens) {
99
170
  addConstructors(this.#registry.get(token), constructors);
@@ -110,6 +181,8 @@ class Registry {
110
181
  this.#registry.clear();
111
182
  this.#routes.clear();
112
183
  this.#truthyPropRoutes.clear();
184
+ this.#routingProps.clear();
185
+ this.#dropResolvedTokens();
113
186
  }
114
187
  }
115
188
  const defaultRegistry = new Registry();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/in-the-dark/Registry.ts"],
4
- "sourcesContent": ["import type {ShadowObjectConstructor} from '../types.js';\nimport {appendTo} from '../utils/array-utils.js';\n\ninterface RegistryEntry {\n token: string;\n constructors: ShadowObjectConstructor[];\n}\n\nconst toPropRoute = (route: string): undefined | {key: string; prop: string; token?: string} => {\n const parts = route.split('@').map((part) => part.trim());\n if (parts.length === 2 && parts[1]) {\n return parts[0] ? {key: `${parts[0]}@${parts[1]}`, prop: parts[1], token: parts[0]} : {key: parts[1], prop: parts[1]};\n } else {\n return undefined;\n }\n};\n\nconst addRoutes = (set: Set<string>, routes: string[] | Set<string>) => {\n for (const route of routes) {\n set.add(route);\n }\n};\n\nconst addConstructors = (entry: RegistryEntry | null | undefined, constructors: Set<ShadowObjectConstructor>) => {\n if (entry != null) {\n for (const constructor of entry.constructors) {\n constructors.add(constructor);\n }\n }\n};\n\n/** The shadow-object class registry */\nexport class Registry {\n /** return the specified registry or, if not defined, the default registry */\n static get(registry?: Registry) {\n return registry ?? defaultRegistry;\n }\n\n readonly #registry = new Map<string, RegistryEntry>();\n readonly #routes = new Map<string, Set<string>>();\n readonly #truthyPropRoutes = new Map<string, {routes: Set<string>; token?: string}>();\n\n define(token: string, constructor: ShadowObjectConstructor) {\n if (this.#registry.has(token)) {\n appendTo(this.#registry.get(token)!.constructors, constructor);\n } else {\n this.#registry.set(token, {token, constructors: [constructor]});\n }\n }\n\n appendRoute(token: string, routes: string[]) {\n const propRoute = toPropRoute(token);\n if (propRoute) {\n if (this.#truthyPropRoutes.has(propRoute.key)) {\n addRoutes(this.#truthyPropRoutes.get(propRoute.key)!.routes, routes);\n } else {\n this.#truthyPropRoutes.set(propRoute.key, {routes: new Set(routes), token: propRoute.token});\n }\n } else {\n if (this.#routes.has(token)) {\n addRoutes(this.#routes.get(token), routes);\n } else {\n this.#routes.set(token, new Set(routes));\n }\n }\n }\n\n clearRoute(route: string) {\n const propRoute = toPropRoute(route);\n if (propRoute) {\n this.#truthyPropRoutes.delete(propRoute.key);\n } else {\n this.#routes.delete(route);\n }\n }\n\n findTokensByRoute(route: string, truthyProps?: Set<string>): Set<string> {\n const tokens = new Set<string>([route]);\n\n const next = this.#routes.has(route) ? [...this.#routes.get(route)] : [];\n\n while (next.length) {\n const cur = next.shift();\n\n if (tokens.has(cur)) {\n continue;\n }\n\n tokens.add(cur);\n\n if (this.#routes.has(cur)) {\n next.push(...Array.from(this.#routes.get(cur)).filter((route) => !tokens.has(route)));\n }\n }\n\n if (truthyProps) {\n for (const prop of truthyProps) {\n if (this.#truthyPropRoutes.has(prop)) {\n addRoutes(tokens, this.#truthyPropRoutes.get(prop)!.routes);\n }\n }\n\n let tokenCountBefore: number;\n do {\n tokenCountBefore = tokens.size;\n for (const token of new Set(tokens)) {\n for (const prop of truthyProps) {\n const key = `${token}@${prop}`;\n if (this.#truthyPropRoutes.has(key)) {\n addRoutes(tokens, this.#truthyPropRoutes.get(key)!.routes);\n }\n }\n }\n } while (tokenCountBefore !== tokens.size);\n }\n\n return tokens;\n }\n\n findConstructors(route: string, truthyProps?: Set<string>): ShadowObjectConstructor[] | undefined {\n const tokens = this.findTokensByRoute(route, truthyProps);\n const constructors = new Set<ShadowObjectConstructor>();\n\n for (const token of tokens) {\n addConstructors(this.#registry.get(token), constructors);\n }\n\n return constructors.size > 0 ? Array.from(constructors) : undefined;\n }\n\n hasToken(token: string): boolean {\n return this.#registry.has(token);\n }\n\n hasRoute(route: string): boolean {\n return this.#routes.has(route);\n }\n\n clear() {\n this.#registry.clear();\n this.#routes.clear();\n this.#truthyPropRoutes.clear();\n }\n}\n\nconst defaultRegistry = new Registry();"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {ShadowObjectConstructor} from '../types.js';\nimport {appendTo} from '../utils/array-utils.js';\n\nconst toPropRoute = (route: string): undefined | {key: string; prop: string} => {\n const parts = route.split('@').map((part) => part.trim());\n if (parts.length === 2 && parts[1]) {\n return parts[0] ? {key: `${parts[0]}@${parts[1]}`, prop: parts[1]} : {key: parts[1], prop: parts[1]};\n } else {\n return undefined;\n }\n};\n\nconst addRoutes = (set: Set<string>, routes: string[] | Set<string>) => {\n for (const route of routes) {\n set.add(route);\n }\n};\n\nconst addConstructors = (known: ShadowObjectConstructor[] | null | undefined, constructors: Set<ShadowObjectConstructor>) => {\n if (known != null) {\n for (const c of known) {\n constructors.add(c);\n }\n }\n};\n\n/** The shadow-object class registry */\nexport class Registry {\n /** return the specified registry or, if not defined, the default registry */\n static get(registry?: Registry) {\n return registry ?? defaultRegistry;\n }\n\n readonly #registry = new Map<string, ShadowObjectConstructor[]>();\n readonly #routes = new Map<string, Set<string>>();\n readonly #truthyPropRoutes = new Map<string, Set<string>>();\n\n // The set of property names that any routing rule mentions. It only decides how finely the\n // resolution key is cut, never what a resolution yields -- so it may be too large, but never too\n // small. A key that is too fine splits entries that belong together; a key that is too coarse\n // answers two different questions with one answer. clearRoute() therefore takes nothing back out:\n // a name that stops routing costs at most an extra entry, while removing it could drop a name that\n // another rule still routes on.\n readonly #routingProps = new Set<string>();\n\n // The store of resolved tokens: outer key is the route, inner key is built from the properties.\n // Two levels so that the route name works as a key unchanged and needs no escaping anywhere.\n //\n // It has no upper bound and evicts nothing, and it lives exactly as long as the registry that owns\n // it -- for the default registry, that is the lifetime of the process. What holds it small is its\n // key space: the routes times the ordered subsets of the routing property names, because the key\n // names only the properties some rule routes on, and names them in the caller's order. For n such\n // names that is the sum over k of C(n, k) * k! keys per route -- 2 for one name, 5 for two, 16 for\n // three, 65 for four -- and #routingProps, which supplies n, never gives a name back. Both counts\n // are fixed by the module manifests a registry is built from, and a manifest declares a handful of\n // routes and one or two routing properties, so n stays small where the growth in it is steep.\n readonly #resolvedTokens = new Map<string, Map<string, Set<string>>>();\n\n define(token: string, constructa: ShadowObjectConstructor) {\n const constructors = this.#registry.get(token);\n if (constructors) {\n appendTo(constructors, constructa);\n } else {\n this.#registry.set(token, [constructa]);\n }\n this.#dropResolvedTokens();\n }\n\n appendRoute(token: string, routes: string[]) {\n const propRoute = toPropRoute(token);\n if (propRoute) {\n this.#routingProps.add(propRoute.prop);\n const knownPropRoutes = this.#truthyPropRoutes.get(propRoute.key);\n if (knownPropRoutes) {\n addRoutes(knownPropRoutes, routes);\n } else {\n this.#truthyPropRoutes.set(propRoute.key, new Set(routes));\n }\n } else {\n const knownRoutes = this.#routes.get(token);\n if (knownRoutes) {\n addRoutes(knownRoutes, routes);\n } else {\n this.#routes.set(token, new Set(routes));\n }\n }\n // Behind both branches: a prop route and a plain route both change what a resolution finds.\n this.#dropResolvedTokens();\n }\n\n clearRoute(route: string) {\n const propRoute = toPropRoute(route);\n if (propRoute) {\n this.#truthyPropRoutes.delete(propRoute.key);\n } else {\n this.#routes.delete(route);\n }\n this.#dropResolvedTokens();\n }\n\n // Every write drops the store, define() included, even though define() does not move the token\n // resolution itself. No write path then has to know which half of a resolution it touches, and a\n // registry is written while a module is imported, where rebuilding costs nothing.\n //\n // Dropping is re-entrancy safe: Map.clear() lets go of the sets, it does not empty them. A set that\n // a resolution has already handed out therefore stays valid and complete, no matter how long its\n // caller keeps walking it and no matter what is written to the registry meanwhile.\n #dropResolvedTokens() {\n this.#resolvedTokens.clear();\n }\n\n // The key is built in the caller's property order, not sorted. The order of the properties decides\n // the order of the tokens in the result, and that in turn the order in which the kernel builds the\n // shadow objects. A sorted key would map two differently ordered questions onto one answer and so\n // change the build order for one of them. Caller order keeps the behaviour character for character\n // and pays in entries: a question over k routing properties can arrive in k! orders and fills one\n // entry per order, where a sorted key would fill one for all of them. What that comes to over the\n // whole store is at #resolvedTokens.\n //\n // Each name follows its own length, which makes the key unambiguous: no property name can imitate\n // the boundary between two others. A separator could, as soon as a name contains it.\n #resolutionKey(truthyProps: Set<string> | undefined): string {\n // The empty key covers both cases in which no property has a say -- no truthyProps, and no prop\n // route in the registry at all. The second is the common case and so costs no pass over the\n // properties.\n if (truthyProps === undefined || this.#routingProps.size === 0) return '';\n let key = '';\n for (const prop of truthyProps) {\n if (this.#routingProps.has(prop)) {\n key += `${prop.length}:${prop}`;\n }\n }\n return key;\n }\n\n #resolveTokens(route: string, truthyProps?: Set<string>): Set<string> {\n const key = this.#resolutionKey(truthyProps);\n let byProps = this.#resolvedTokens.get(route);\n const known = byProps?.get(key);\n if (known !== undefined) return known;\n\n const tokens = new Set<string>([route]);\n\n const next = Array.from(this.#routes.get(route) ?? []);\n\n for (let cur = next.shift(); cur !== undefined; cur = next.shift()) {\n if (tokens.has(cur)) {\n continue;\n }\n\n tokens.add(cur);\n\n const nextRoutes = this.#routes.get(cur);\n if (nextRoutes) {\n next.push(...Array.from(nextRoutes).filter((route) => !tokens.has(route)));\n }\n }\n\n if (truthyProps) {\n for (const prop of truthyProps) {\n const propRoutes = this.#truthyPropRoutes.get(prop);\n if (propRoutes) {\n addRoutes(tokens, propRoutes);\n }\n }\n\n let tokenCountBefore: number;\n do {\n tokenCountBefore = tokens.size;\n for (const token of new Set(tokens)) {\n for (const prop of truthyProps) {\n const keyedRoutes = this.#truthyPropRoutes.get(`${token}@${prop}`);\n if (keyedRoutes) {\n addRoutes(tokens, keyedRoutes);\n }\n }\n }\n } while (tokenCountBefore !== tokens.size);\n }\n\n if (byProps === undefined) {\n byProps = new Map();\n this.#resolvedTokens.set(route, byProps);\n }\n byProps.set(key, tokens);\n\n return tokens;\n }\n\n // The store holds exactly one set per question, and what a caller does with what it got stays its\n // own business -- so a copy goes out.\n findTokensByRoute(route: string, truthyProps?: Set<string>): Set<string> {\n return new Set(this.#resolveTokens(route, truthyProps));\n }\n\n findConstructors(route: string, truthyProps?: Set<string>): ShadowObjectConstructor[] | undefined {\n // Reads the stored set without a copy: this only iterates over it, and it belongs to the same\n // class. The constructor list itself is assembled per call and belongs to the caller.\n const tokens = this.#resolveTokens(route, truthyProps);\n const constructors = new Set<ShadowObjectConstructor>();\n\n for (const token of tokens) {\n addConstructors(this.#registry.get(token), constructors);\n }\n\n return constructors.size > 0 ? Array.from(constructors) : undefined;\n }\n\n hasToken(token: string): boolean {\n return this.#registry.has(token);\n }\n\n hasRoute(route: string): boolean {\n return this.#routes.has(route);\n }\n\n clear() {\n this.#registry.clear();\n this.#routes.clear();\n this.#truthyPropRoutes.clear();\n this.#routingProps.clear();\n this.#dropResolvedTokens();\n }\n}\n\nconst defaultRegistry = new Registry();\n"],
5
+ "mappings": "AACA,SAAQ,gBAAe;AAEvB,MAAM,cAAc,CAAC,UAA2D;AAC9E,QAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AACxD,MAAI,MAAM,WAAW,KAAK,MAAM,CAAC,GAAG;AAClC,WAAO,MAAM,CAAC,IAAI,EAAC,KAAK,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC,EAAC,IAAI,EAAC,KAAK,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,EAAC;AAAA,EACrG,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,MAAM,YAAY,CAAC,KAAkB,WAAmC;AACtE,aAAW,SAAS,QAAQ;AAC1B,QAAI,IAAI,KAAK;AAAA,EACf;AACF;AAEA,MAAM,kBAAkB,CAAC,OAAqD,iBAA+C;AAC3H,MAAI,SAAS,MAAM;AACjB,eAAW,KAAK,OAAO;AACrB,mBAAa,IAAI,CAAC;AAAA,IACpB;AAAA,EACF;AACF;AAGO,MAAM,SAAS;AAAA;AAAA,EAEpB,OAAO,IAAI,UAAqB;AAC9B,WAAO,YAAY;AAAA,EACrB;AAAA,EAES,YAAY,oBAAI,IAAuC;AAAA,EACvD,UAAU,oBAAI,IAAyB;AAAA,EACvC,oBAAoB,oBAAI,IAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjD,gBAAgB,oBAAI,IAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAahC,kBAAkB,oBAAI,IAAsC;AAAA,EAErE,OAAO,OAAe,YAAqC;AACzD,UAAM,eAAe,KAAK,UAAU,IAAI,KAAK;AAC7C,QAAI,cAAc;AAChB,eAAS,cAAc,UAAU;AAAA,IACnC,OAAO;AACL,WAAK,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;AAAA,IACxC;AACA,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,YAAY,OAAe,QAAkB;AAC3C,UAAM,YAAY,YAAY,KAAK;AACnC,QAAI,WAAW;AACb,WAAK,cAAc,IAAI,UAAU,IAAI;AACrC,YAAM,kBAAkB,KAAK,kBAAkB,IAAI,UAAU,GAAG;AAChE,UAAI,iBAAiB;AACnB,kBAAU,iBAAiB,MAAM;AAAA,MACnC,OAAO;AACL,aAAK,kBAAkB,IAAI,UAAU,KAAK,IAAI,IAAI,MAAM,CAAC;AAAA,MAC3D;AAAA,IACF,OAAO;AACL,YAAM,cAAc,KAAK,QAAQ,IAAI,KAAK;AAC1C,UAAI,aAAa;AACf,kBAAU,aAAa,MAAM;AAAA,MAC/B,OAAO;AACL,aAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,MAAM,CAAC;AAAA,MACzC;AAAA,IACF;AAEA,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,WAAW,OAAe;AACxB,UAAM,YAAY,YAAY,KAAK;AACnC,QAAI,WAAW;AACb,WAAK,kBAAkB,OAAO,UAAU,GAAG;AAAA,IAC7C,OAAO;AACL,WAAK,QAAQ,OAAO,KAAK;AAAA,IAC3B;AACA,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,sBAAsB;AACpB,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAAe,aAA8C;AAI3D,QAAI,gBAAgB,UAAa,KAAK,cAAc,SAAS,EAAG,QAAO;AACvE,QAAI,MAAM;AACV,eAAW,QAAQ,aAAa;AAC9B,UAAI,KAAK,cAAc,IAAI,IAAI,GAAG;AAChC,eAAO,GAAG,KAAK,MAAM,IAAI,IAAI;AAAA,MAC/B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,OAAe,aAAwC;AACpE,UAAM,MAAM,KAAK,eAAe,WAAW;AAC3C,QAAI,UAAU,KAAK,gBAAgB,IAAI,KAAK;AAC5C,UAAM,QAAQ,SAAS,IAAI,GAAG;AAC9B,QAAI,UAAU,OAAW,QAAO;AAEhC,UAAM,SAAS,oBAAI,IAAY,CAAC,KAAK,CAAC;AAEtC,UAAM,OAAO,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,CAAC,CAAC;AAErD,aAAS,MAAM,KAAK,MAAM,GAAG,QAAQ,QAAW,MAAM,KAAK,MAAM,GAAG;AAClE,UAAI,OAAO,IAAI,GAAG,GAAG;AACnB;AAAA,MACF;AAEA,aAAO,IAAI,GAAG;AAEd,YAAM,aAAa,KAAK,QAAQ,IAAI,GAAG;AACvC,UAAI,YAAY;AACd,aAAK,KAAK,GAAG,MAAM,KAAK,UAAU,EAAE,OAAO,CAACA,WAAU,CAAC,OAAO,IAAIA,MAAK,CAAC,CAAC;AAAA,MAC3E;AAAA,IACF;AAEA,QAAI,aAAa;AACf,iBAAW,QAAQ,aAAa;AAC9B,cAAM,aAAa,KAAK,kBAAkB,IAAI,IAAI;AAClD,YAAI,YAAY;AACd,oBAAU,QAAQ,UAAU;AAAA,QAC9B;AAAA,MACF;AAEA,UAAI;AACJ,SAAG;AACD,2BAAmB,OAAO;AAC1B,mBAAW,SAAS,IAAI,IAAI,MAAM,GAAG;AACnC,qBAAW,QAAQ,aAAa;AAC9B,kBAAM,cAAc,KAAK,kBAAkB,IAAI,GAAG,KAAK,IAAI,IAAI,EAAE;AACjE,gBAAI,aAAa;AACf,wBAAU,QAAQ,WAAW;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,qBAAqB,OAAO;AAAA,IACvC;AAEA,QAAI,YAAY,QAAW;AACzB,gBAAU,oBAAI,IAAI;AAClB,WAAK,gBAAgB,IAAI,OAAO,OAAO;AAAA,IACzC;AACA,YAAQ,IAAI,KAAK,MAAM;AAEvB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAIA,kBAAkB,OAAe,aAAwC;AACvE,WAAO,IAAI,IAAI,KAAK,eAAe,OAAO,WAAW,CAAC;AAAA,EACxD;AAAA,EAEA,iBAAiB,OAAe,aAAkE;AAGhG,UAAM,SAAS,KAAK,eAAe,OAAO,WAAW;AACrD,UAAM,eAAe,oBAAI,IAA6B;AAEtD,eAAW,SAAS,QAAQ;AAC1B,sBAAgB,KAAK,UAAU,IAAI,KAAK,GAAG,YAAY;AAAA,IACzD;AAEA,WAAO,aAAa,OAAO,IAAI,MAAM,KAAK,YAAY,IAAI;AAAA,EAC5D;AAAA,EAEA,SAAS,OAAwB;AAC/B,WAAO,KAAK,UAAU,IAAI,KAAK;AAAA,EACjC;AAAA,EAEA,SAAS,OAAwB;AAC/B,WAAO,KAAK,QAAQ,IAAI,KAAK;AAAA,EAC/B;AAAA,EAEA,QAAQ;AACN,SAAK,UAAU,MAAM;AACrB,SAAK,QAAQ,MAAM;AACnB,SAAK,kBAAkB,MAAM;AAC7B,SAAK,cAAc,MAAM;AACzB,SAAK,oBAAoB;AAAA,EAC3B;AACF;AAEA,MAAM,kBAAkB,IAAI,SAAS;",
6
6
  "names": ["route"]
7
7
  }
@@ -13,6 +13,6 @@ export declare function ShadowObject(options: ShadowObjectDecoratorOptions): <C
13
13
  * If you don't want to use the decorator, you can simply call this method instead.
14
14
  */
15
15
  export declare const shadowObjects: {
16
- define(token: string, constructor: ShadowObjectConstructor, registry?: Registry): void;
16
+ define(token: string, constructa: ShadowObjectConstructor, registry?: Registry): void;
17
17
  };
18
18
  //# sourceMappingURL=ShadowObject.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ShadowObject.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/ShadowObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAEvC,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,4BAA4B,IACxD,CAAC,SAAS,uBAAuB,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG;kBAG3C,GAAG,EAAE;;MAW/B;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;kBACV,MAAM,eAAe,uBAAuB,aAAa,QAAQ;CAGhF,CAAC"}
1
+ {"version":3,"file":"ShadowObject.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/ShadowObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAEvC,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,OAAO,EAAE,4BAA4B,IACxD,CAAC,SAAS,uBAAuB,UAAU,CAAC,aAAa,GAAG;kBAG3C,GAAG,EAAE;;MAgB/B;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB,MAAM,QAAQ,MAAM,cAAc,uBAAuB,aAAa,QAAQ;CAG/E,CAAC"}
@@ -8,13 +8,14 @@ function ShadowObject(options) {
8
8
  eventize(this);
9
9
  }
10
10
  };
11
+ Object.defineProperty(__ShadowObject, "name", { value: target.name, configurable: true });
11
12
  Registry.get(options.registry).define(options.token, __ShadowObject);
12
13
  return __ShadowObject;
13
14
  };
14
15
  }
15
16
  const shadowObjects = {
16
- define(token, constructor, registry) {
17
- Registry.get(registry).define(token, constructor);
17
+ define(token, constructa, registry) {
18
+ Registry.get(registry).define(token, constructa);
18
19
  }
19
20
  };
20
21
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/in-the-dark/ShadowObject.ts"],
4
- "sourcesContent": ["import {eventize} from '@spearwolf/eventize';\nimport type {ShadowObjectConstructor} from '../types.js';\nimport {Registry} from './Registry.js';\n\nexport interface ShadowObjectDecoratorOptions {\n token: string;\n registry?: Registry;\n}\n\n/** The `@ShadowObject` decorator */\nexport function ShadowObject(options: ShadowObjectDecoratorOptions) {\n return <C extends ShadowObjectConstructor>(target: C, _context?: any) => {\n // @ts-ignore\n const __ShadowObject = class extends target {\n constructor(...args: any[]) {\n // @ts-ignore\n super(...args);\n eventize(this);\n }\n };\n\n Registry.get(options.registry).define(options.token, __ShadowObject);\n\n return __ShadowObject;\n };\n}\n\n/**\n * If you don't want to use the decorator, you can simply call this method instead.\n */\nexport const shadowObjects = {\n define(token: string, constructor: ShadowObjectConstructor, registry?: Registry) {\n Registry.get(registry).define(token, constructor);\n },\n};"],
5
- "mappings": "AAAA,SAAQ,gBAAe;AAEvB,SAAQ,gBAAe;AAQhB,SAAS,aAAa,SAAuC;AAClE,SAAO,CAAoC,QAAW,aAAmB;AAEvE,UAAM,iBAAiB,cAAc,OAAO;AAAA,MAC1C,eAAe,MAAa;AAE1B,cAAM,GAAG,IAAI;AACb,iBAAS,IAAI;AAAA,MACf;AAAA,IACF;AAEA,aAAS,IAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,cAAc;AAEnE,WAAO;AAAA,EACT;AACF;AAKO,MAAM,gBAAgB;AAAA,EAC3B,OAAO,OAAe,aAAsC,UAAqB;AAC/E,aAAS,IAAI,QAAQ,EAAE,OAAO,OAAO,WAAW;AAAA,EAClD;AACF;",
4
+ "sourcesContent": ["import {eventize} from '@spearwolf/eventize';\nimport type {ShadowObjectConstructor} from '../types.js';\nimport {Registry} from './Registry.js';\n\nexport interface ShadowObjectDecoratorOptions {\n token: string;\n registry?: Registry;\n}\n\n/** The `@ShadowObject` decorator */\nexport function ShadowObject(options: ShadowObjectDecoratorOptions) {\n return <C extends ShadowObjectConstructor>(target: C, _context?: any) => {\n // @ts-ignore\n const __ShadowObject = class extends target {\n constructor(...args: any[]) {\n // @ts-ignore\n super(...args);\n eventize(this);\n }\n };\n\n // The wrapper is a class expression, so it owns a `name` that shadows the inherited one.\n // `getDisplayName()` in the Kernel reads that name for every diagnostic about this\n // shadow-object, so the wrapper carries the name of the class it wraps.\n Object.defineProperty(__ShadowObject, 'name', {value: target.name, configurable: true});\n\n Registry.get(options.registry).define(options.token, __ShadowObject);\n\n return __ShadowObject;\n };\n}\n\n/**\n * If you don't want to use the decorator, you can simply call this method instead.\n */\nexport const shadowObjects = {\n define(token: string, constructa: ShadowObjectConstructor, registry?: Registry) {\n Registry.get(registry).define(token, constructa);\n },\n};\n"],
5
+ "mappings": "AAAA,SAAQ,gBAAe;AAEvB,SAAQ,gBAAe;AAQhB,SAAS,aAAa,SAAuC;AAClE,SAAO,CAAoC,QAAW,aAAmB;AAEvE,UAAM,iBAAiB,cAAc,OAAO;AAAA,MAC1C,eAAe,MAAa;AAE1B,cAAM,GAAG,IAAI;AACb,iBAAS,IAAI;AAAA,MACf;AAAA,IACF;AAKA,WAAO,eAAe,gBAAgB,QAAQ,EAAC,OAAO,OAAO,MAAM,cAAc,KAAI,CAAC;AAEtF,aAAS,IAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,cAAc;AAEnE,WAAO;AAAA,EACT;AACF;AAKO,MAAM,gBAAgB;AAAA,EAC3B,OAAO,OAAe,YAAqC,UAAqB;AAC9E,aAAS,IAAI,QAAQ,EAAE,OAAO,OAAO,UAAU;AAAA,EACjD;AACF;",
6
6
  "names": []
7
7
  }