@pascal-app/core 0.9.2 → 1.0.0-beta.1

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 (339) hide show
  1. package/README.md +17 -10
  2. package/dist/events/bus.d.ts +21 -2
  3. package/dist/events/bus.d.ts.map +1 -1
  4. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +17 -1
  5. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
  6. package/dist/hooks/spatial-grid/floor-placed-elevation.js +61 -8
  7. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +116 -66
  8. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  9. package/dist/hooks/spatial-grid/spatial-grid-manager.js +316 -441
  10. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +46 -1
  11. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  12. package/dist/hooks/spatial-grid/spatial-grid-sync.js +193 -12
  13. package/dist/hooks/spatial-grid/support-host-id.d.ts +3 -0
  14. package/dist/hooks/spatial-grid/support-host-id.d.ts.map +1 -0
  15. package/dist/hooks/spatial-grid/support-host-id.js +2 -0
  16. package/dist/hooks/spatial-grid/support-host-patch.d.ts +51 -0
  17. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -0
  18. package/dist/hooks/spatial-grid/support-host-patch.js +164 -0
  19. package/dist/index.d.ts +23 -11
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +22 -10
  22. package/dist/lib/measurement-geometry.d.ts +4 -0
  23. package/dist/lib/measurement-geometry.d.ts.map +1 -1
  24. package/dist/lib/measurement-geometry.js +27 -10
  25. package/dist/lib/slab-polygon.d.ts.map +1 -1
  26. package/dist/lib/slab-polygon.js +33 -1
  27. package/dist/lib/space-detection.d.ts +15 -4
  28. package/dist/lib/space-detection.d.ts.map +1 -1
  29. package/dist/lib/space-detection.js +174 -88
  30. package/dist/lib/terrain-brush.d.ts +163 -0
  31. package/dist/lib/terrain-brush.d.ts.map +1 -0
  32. package/dist/lib/terrain-brush.js +359 -0
  33. package/dist/lib/terrain-codec.d.ts +51 -0
  34. package/dist/lib/terrain-codec.d.ts.map +1 -0
  35. package/dist/lib/terrain-codec.js +167 -0
  36. package/dist/lib/terrain-field.d.ts +150 -0
  37. package/dist/lib/terrain-field.d.ts.map +1 -0
  38. package/dist/lib/terrain-field.js +248 -0
  39. package/dist/lib/terrain-raycast.d.ts +44 -0
  40. package/dist/lib/terrain-raycast.d.ts.map +1 -0
  41. package/dist/lib/terrain-raycast.js +188 -0
  42. package/dist/lib/terrain-source.d.ts +60 -0
  43. package/dist/lib/terrain-source.d.ts.map +1 -0
  44. package/dist/lib/terrain-source.js +90 -0
  45. package/dist/lib/terrain-support.d.ts +60 -0
  46. package/dist/lib/terrain-support.d.ts.map +1 -0
  47. package/dist/lib/terrain-support.js +150 -0
  48. package/dist/lib/zone-quantities.d.ts +1 -1
  49. package/dist/lib/zone-quantities.d.ts.map +1 -1
  50. package/dist/lib/zone-quantities.js +311 -66
  51. package/dist/material-library.d.ts +9 -1
  52. package/dist/material-library.d.ts.map +1 -1
  53. package/dist/material-library.js +56 -4
  54. package/dist/registry/handles.d.ts +16 -1
  55. package/dist/registry/handles.d.ts.map +1 -1
  56. package/dist/registry/index.d.ts +1 -1
  57. package/dist/registry/index.d.ts.map +1 -1
  58. package/dist/registry/subtree.d.ts.map +1 -1
  59. package/dist/registry/subtree.js +5 -2
  60. package/dist/registry/types.d.ts +64 -1
  61. package/dist/registry/types.d.ts.map +1 -1
  62. package/dist/schema/index.d.ts +6 -3
  63. package/dist/schema/index.d.ts.map +1 -1
  64. package/dist/schema/index.js +6 -3
  65. package/dist/schema/nodes/cabinet.d.ts +2 -0
  66. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  67. package/dist/schema/nodes/cabinet.js +4 -2
  68. package/dist/schema/nodes/ceiling.d.ts +1 -1
  69. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  70. package/dist/schema/nodes/ceiling.js +7 -1
  71. package/dist/schema/nodes/column.d.ts +1 -0
  72. package/dist/schema/nodes/column.d.ts.map +1 -1
  73. package/dist/schema/nodes/column.js +2 -0
  74. package/dist/schema/nodes/construction-dimension.d.ts +195 -0
  75. package/dist/schema/nodes/construction-dimension.d.ts.map +1 -0
  76. package/dist/schema/nodes/construction-dimension.js +151 -0
  77. package/dist/schema/nodes/door.d.ts +29 -0
  78. package/dist/schema/nodes/door.d.ts.map +1 -1
  79. package/dist/schema/nodes/door.js +20 -0
  80. package/dist/schema/nodes/duct-terminal.d.ts +1 -0
  81. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -1
  82. package/dist/schema/nodes/duct-terminal.js +2 -0
  83. package/dist/schema/nodes/fence.d.ts +2 -0
  84. package/dist/schema/nodes/fence.d.ts.map +1 -1
  85. package/dist/schema/nodes/fence.js +8 -0
  86. package/dist/schema/nodes/hvac-equipment.d.ts +1 -0
  87. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -1
  88. package/dist/schema/nodes/hvac-equipment.js +2 -0
  89. package/dist/schema/nodes/item.d.ts +1 -0
  90. package/dist/schema/nodes/item.d.ts.map +1 -1
  91. package/dist/schema/nodes/item.js +13 -0
  92. package/dist/schema/nodes/level.d.ts +2 -1
  93. package/dist/schema/nodes/level.d.ts.map +1 -1
  94. package/dist/schema/nodes/level.js +12 -33
  95. package/dist/schema/nodes/shelf.d.ts +1 -0
  96. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  97. package/dist/schema/nodes/shelf.js +2 -0
  98. package/dist/schema/nodes/site.d.ts +9 -0
  99. package/dist/schema/nodes/site.d.ts.map +1 -1
  100. package/dist/schema/nodes/site.js +8 -6
  101. package/dist/schema/nodes/slab.d.ts +5 -0
  102. package/dist/schema/nodes/slab.d.ts.map +1 -1
  103. package/dist/schema/nodes/slab.js +14 -2
  104. package/dist/schema/nodes/spawn.d.ts +1 -0
  105. package/dist/schema/nodes/spawn.d.ts.map +1 -1
  106. package/dist/schema/nodes/spawn.js +2 -0
  107. package/dist/schema/nodes/stair.d.ts +3 -1
  108. package/dist/schema/nodes/stair.d.ts.map +1 -1
  109. package/dist/schema/nodes/stair.js +8 -1
  110. package/dist/schema/nodes/structural-grid.d.ts +27 -0
  111. package/dist/schema/nodes/structural-grid.d.ts.map +1 -0
  112. package/dist/schema/nodes/structural-grid.js +17 -0
  113. package/dist/schema/nodes/wall.d.ts +5 -2
  114. package/dist/schema/nodes/wall.d.ts.map +1 -1
  115. package/dist/schema/nodes/wall.js +13 -4
  116. package/dist/schema/nodes/window.d.ts +29 -0
  117. package/dist/schema/nodes/window.d.ts.map +1 -1
  118. package/dist/schema/nodes/window.js +18 -0
  119. package/dist/schema/nodes/zone.d.ts +20 -0
  120. package/dist/schema/nodes/zone.d.ts.map +1 -1
  121. package/dist/schema/nodes/zone.js +15 -0
  122. package/dist/schema/terrain.d.ts +28 -0
  123. package/dist/schema/terrain.d.ts.map +1 -0
  124. package/dist/schema/terrain.js +30 -0
  125. package/dist/schema/types.d.ts +211 -3
  126. package/dist/schema/types.d.ts.map +1 -1
  127. package/dist/schema/types.js +4 -0
  128. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts +80 -0
  129. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -0
  130. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.js +89 -0
  131. package/dist/services/index.d.ts +2 -1
  132. package/dist/services/index.d.ts.map +1 -1
  133. package/dist/services/index.js +2 -1
  134. package/dist/services/level-height.d.ts +8 -9
  135. package/dist/services/level-height.d.ts.map +1 -1
  136. package/dist/services/level-height.js +48 -16
  137. package/dist/services/storey.d.ts +103 -0
  138. package/dist/services/storey.d.ts.map +1 -0
  139. package/dist/services/storey.js +296 -0
  140. package/dist/store/actions/node-actions.d.ts.map +1 -1
  141. package/dist/store/actions/node-actions.js +47 -3
  142. package/dist/store/history-control.d.ts +20 -0
  143. package/dist/store/history-control.d.ts.map +1 -1
  144. package/dist/store/history-control.js +110 -13
  145. package/dist/store/use-live-terrain.d.ts +65 -0
  146. package/dist/store/use-live-terrain.d.ts.map +1 -0
  147. package/dist/store/use-live-terrain.js +31 -0
  148. package/dist/store/use-live-transforms.d.ts +8 -0
  149. package/dist/store/use-live-transforms.d.ts.map +1 -1
  150. package/dist/store/use-scene.d.ts +31 -2
  151. package/dist/store/use-scene.d.ts.map +1 -1
  152. package/dist/store/use-scene.js +638 -8
  153. package/dist/systems/elevator/elevator-opening-system.d.ts +1 -0
  154. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
  155. package/dist/systems/elevator/elevator-opening-system.js +27 -21
  156. package/dist/systems/elevator/elevator-service.d.ts +0 -2
  157. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  158. package/dist/systems/elevator/elevator-service.js +2 -24
  159. package/dist/systems/slab/slab-placement.d.ts +11 -0
  160. package/dist/systems/slab/slab-placement.d.ts.map +1 -0
  161. package/dist/systems/slab/slab-placement.js +14 -0
  162. package/dist/systems/slab/slab-support.d.ts +137 -0
  163. package/dist/systems/slab/slab-support.d.ts.map +1 -0
  164. package/dist/systems/slab/slab-support.js +557 -0
  165. package/dist/systems/stair/stair-opening-preview.d.ts +1060 -935
  166. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  167. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  168. package/dist/systems/stair/stair-opening-sync.js +18 -15
  169. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  170. package/dist/systems/stair/stair-opening-system.js +32 -4
  171. package/dist/systems/stair/stair-rise.d.ts +22 -0
  172. package/dist/systems/stair/stair-rise.d.ts.map +1 -0
  173. package/dist/systems/stair/stair-rise.js +79 -0
  174. package/dist/systems/wall/wall-curve.d.ts +10 -0
  175. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  176. package/dist/systems/wall/wall-curve.js +1 -1
  177. package/dist/systems/wall/wall-mitering.js +6 -6
  178. package/dist/systems/wall/wall-top.d.ts +40 -0
  179. package/dist/systems/wall/wall-top.d.ts.map +1 -0
  180. package/dist/systems/wall/wall-top.js +46 -0
  181. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  182. package/dist/utils/clone-scene-graph.js +34 -3
  183. package/dist/utils/heal-scene-graph.d.ts +1 -1
  184. package/dist/utils/heal-scene-graph.d.ts.map +1 -1
  185. package/dist/utils/heal-scene-graph.js +25 -9
  186. package/dist/validation/validate-build-json.d.ts +2 -0
  187. package/dist/validation/validate-build-json.d.ts.map +1 -1
  188. package/dist/validation/validate-build-json.js +59 -3
  189. package/package.json +2 -2
  190. package/dist/hooks/scene-registry/scene-registry.test.d.ts +0 -2
  191. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +0 -1
  192. package/dist/hooks/scene-registry/scene-registry.test.js +0 -26
  193. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +0 -2
  194. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +0 -1
  195. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +0 -366
  196. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +0 -2
  197. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +0 -1
  198. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +0 -363
  199. package/dist/lib/measurement-geometry.test.d.ts +0 -2
  200. package/dist/lib/measurement-geometry.test.d.ts.map +0 -1
  201. package/dist/lib/measurement-geometry.test.js +0 -102
  202. package/dist/lib/slab-polygon.test.d.ts +0 -2
  203. package/dist/lib/slab-polygon.test.d.ts.map +0 -1
  204. package/dist/lib/slab-polygon.test.js +0 -635
  205. package/dist/lib/space-detection-pause.test.d.ts +0 -2
  206. package/dist/lib/space-detection-pause.test.d.ts.map +0 -1
  207. package/dist/lib/space-detection-pause.test.js +0 -42
  208. package/dist/lib/space-detection.test.d.ts +0 -2
  209. package/dist/lib/space-detection.test.d.ts.map +0 -1
  210. package/dist/lib/space-detection.test.js +0 -376
  211. package/dist/lib/zone-quantities.test.d.ts +0 -2
  212. package/dist/lib/zone-quantities.test.d.ts.map +0 -1
  213. package/dist/lib/zone-quantities.test.js +0 -82
  214. package/dist/registry/registry.test.d.ts +0 -2
  215. package/dist/registry/registry.test.d.ts.map +0 -1
  216. package/dist/registry/registry.test.js +0 -196
  217. package/dist/registry/relations-resolver.test.d.ts +0 -2
  218. package/dist/registry/relations-resolver.test.d.ts.map +0 -1
  219. package/dist/registry/relations-resolver.test.js +0 -183
  220. package/dist/registry/scene-api.test.d.ts +0 -2
  221. package/dist/registry/scene-api.test.d.ts.map +0 -1
  222. package/dist/registry/scene-api.test.js +0 -183
  223. package/dist/registry/subtree.test.d.ts +0 -2
  224. package/dist/registry/subtree.test.d.ts.map +0 -1
  225. package/dist/registry/subtree.test.js +0 -163
  226. package/dist/schema/asset-url.test.d.ts +0 -2
  227. package/dist/schema/asset-url.test.d.ts.map +0 -1
  228. package/dist/schema/asset-url.test.js +0 -134
  229. package/dist/schema/material.test.d.ts +0 -2
  230. package/dist/schema/material.test.d.ts.map +0 -1
  231. package/dist/schema/material.test.js +0 -43
  232. package/dist/schema/nodes/measurement.test.d.ts +0 -2
  233. package/dist/schema/nodes/measurement.test.d.ts.map +0 -1
  234. package/dist/schema/nodes/measurement.test.js +0 -139
  235. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +0 -2
  236. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +0 -1
  237. package/dist/schema/nodes/ridge-vent-defaults.test.js +0 -205
  238. package/dist/schema/nodes/roof-segment-shape.test.d.ts +0 -2
  239. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +0 -1
  240. package/dist/schema/nodes/roof-segment-shape.test.js +0 -175
  241. package/dist/schema/nodes/roof-segment-surface.test.d.ts +0 -2
  242. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +0 -1
  243. package/dist/schema/nodes/roof-segment-surface.test.js +0 -48
  244. package/dist/schema/nodes/roof-segment-trim.test.d.ts +0 -2
  245. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +0 -1
  246. package/dist/schema/nodes/roof-segment-trim.test.js +0 -107
  247. package/dist/schema/nodes/roof-segment-walls.test.d.ts +0 -2
  248. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +0 -1
  249. package/dist/schema/nodes/roof-segment-walls.test.js +0 -92
  250. package/dist/schema/nodes/wall.test.d.ts +0 -2
  251. package/dist/schema/nodes/wall.test.d.ts.map +0 -1
  252. package/dist/schema/nodes/wall.test.js +0 -208
  253. package/dist/services/alignment-anchors.test.d.ts +0 -2
  254. package/dist/services/alignment-anchors.test.d.ts.map +0 -1
  255. package/dist/services/alignment-anchors.test.js +0 -383
  256. package/dist/services/alignment.test.d.ts +0 -2
  257. package/dist/services/alignment.test.d.ts.map +0 -1
  258. package/dist/services/alignment.test.js +0 -92
  259. package/dist/services/drag-session.test.d.ts +0 -2
  260. package/dist/services/drag-session.test.d.ts.map +0 -1
  261. package/dist/services/drag-session.test.js +0 -219
  262. package/dist/services/hosting.test.d.ts +0 -2
  263. package/dist/services/hosting.test.d.ts.map +0 -1
  264. package/dist/services/hosting.test.js +0 -230
  265. package/dist/services/movement.test.d.ts +0 -2
  266. package/dist/services/movement.test.d.ts.map +0 -1
  267. package/dist/services/movement.test.js +0 -133
  268. package/dist/services/opening-guides.test.d.ts +0 -2
  269. package/dist/services/opening-guides.test.d.ts.map +0 -1
  270. package/dist/services/opening-guides.test.js +0 -208
  271. package/dist/services/port-connectivity.test.d.ts +0 -2
  272. package/dist/services/port-connectivity.test.d.ts.map +0 -1
  273. package/dist/services/port-connectivity.test.js +0 -297
  274. package/dist/services/riser-diagram.test.d.ts +0 -2
  275. package/dist/services/riser-diagram.test.d.ts.map +0 -1
  276. package/dist/services/riser-diagram.test.js +0 -66
  277. package/dist/services/single-undo-dance.test.d.ts +0 -2
  278. package/dist/services/single-undo-dance.test.d.ts.map +0 -1
  279. package/dist/services/single-undo-dance.test.js +0 -210
  280. package/dist/services/snap.test.d.ts +0 -2
  281. package/dist/services/snap.test.d.ts.map +0 -1
  282. package/dist/services/snap.test.js +0 -137
  283. package/dist/services/system-graph.test.d.ts +0 -2
  284. package/dist/services/system-graph.test.d.ts.map +0 -1
  285. package/dist/services/system-graph.test.js +0 -138
  286. package/dist/services/validate-dwv.test.d.ts +0 -2
  287. package/dist/services/validate-dwv.test.d.ts.map +0 -1
  288. package/dist/services/validate-dwv.test.js +0 -109
  289. package/dist/store/actions/node-mutation-sanitize.test.d.ts +0 -2
  290. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +0 -1
  291. package/dist/store/actions/node-mutation-sanitize.test.js +0 -147
  292. package/dist/store/actions/reparent.test.d.ts +0 -2
  293. package/dist/store/actions/reparent.test.d.ts.map +0 -1
  294. package/dist/store/actions/reparent.test.js +0 -212
  295. package/dist/store/actions/ridge-vent-update.test.d.ts +0 -2
  296. package/dist/store/actions/ridge-vent-update.test.d.ts.map +0 -1
  297. package/dist/store/actions/ridge-vent-update.test.js +0 -264
  298. package/dist/store/use-scene-dirty-tracking.test.d.ts +0 -2
  299. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +0 -1
  300. package/dist/store/use-scene-dirty-tracking.test.js +0 -68
  301. package/dist/store/use-scene-elevator-migration.test.d.ts +0 -2
  302. package/dist/store/use-scene-elevator-migration.test.d.ts.map +0 -1
  303. package/dist/store/use-scene-elevator-migration.test.js +0 -109
  304. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +0 -2
  305. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +0 -1
  306. package/dist/store/use-scene-measurement-roundtrip.test.js +0 -97
  307. package/dist/store/use-scene-plugins.test.d.ts +0 -2
  308. package/dist/store/use-scene-plugins.test.d.ts.map +0 -1
  309. package/dist/store/use-scene-plugins.test.js +0 -51
  310. package/dist/store/use-scene-wall-slot-migration.test.d.ts +0 -2
  311. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +0 -1
  312. package/dist/store/use-scene-wall-slot-migration.test.js +0 -210
  313. package/dist/store/use-scene-window-migration.test.d.ts +0 -2
  314. package/dist/store/use-scene-window-migration.test.d.ts.map +0 -1
  315. package/dist/store/use-scene-window-migration.test.js +0 -85
  316. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +0 -2
  317. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +0 -1
  318. package/dist/systems/elevator/elevator-opening-sync.test.js +0 -146
  319. package/dist/systems/elevator/elevator-runtime.test.d.ts +0 -2
  320. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +0 -1
  321. package/dist/systems/elevator/elevator-runtime.test.js +0 -64
  322. package/dist/systems/fence/fence-spline.test.d.ts +0 -2
  323. package/dist/systems/fence/fence-spline.test.d.ts.map +0 -1
  324. package/dist/systems/fence/fence-spline.test.js +0 -136
  325. package/dist/systems/stair/stair-opening-preview.test.d.ts +0 -2
  326. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +0 -1
  327. package/dist/systems/stair/stair-opening-preview.test.js +0 -80
  328. package/dist/systems/stair/stair-opening-sync.test.d.ts +0 -2
  329. package/dist/systems/stair/stair-opening-sync.test.d.ts.map +0 -1
  330. package/dist/systems/stair/stair-opening-sync.test.js +0 -485
  331. package/dist/systems/wall/wall-mitering.test.d.ts +0 -2
  332. package/dist/systems/wall/wall-mitering.test.d.ts.map +0 -1
  333. package/dist/systems/wall/wall-mitering.test.js +0 -63
  334. package/dist/utils/clone-scene-graph.test.d.ts +0 -2
  335. package/dist/utils/clone-scene-graph.test.d.ts.map +0 -1
  336. package/dist/utils/clone-scene-graph.test.js +0 -62
  337. package/dist/utils/heal-scene-graph.test.d.ts +0 -2
  338. package/dist/utils/heal-scene-graph.test.d.ts.map +0 -1
  339. package/dist/utils/heal-scene-graph.test.js +0 -88
@@ -1,183 +0,0 @@
1
- import { beforeEach, describe, expect, test } from 'bun:test';
2
- import { z } from 'zod';
3
- import { nodeRegistry, registerNode } from './registry';
4
- import { cascadeDirty, collectDescendants } from './relations-resolver';
5
- const id = (s) => s;
6
- function makeDef(kind, relations, overrides = {}) {
7
- return {
8
- kind,
9
- schemaVersion: 1,
10
- schema: z.object({ type: z.literal(kind) }),
11
- category: 'utility',
12
- defaults: () => ({}),
13
- capabilities: {},
14
- relations,
15
- renderer: { kind: 'parametric', module: async () => ({ default: () => null }) },
16
- ...overrides,
17
- };
18
- }
19
- function makeNode(kind, idStr, extra = {}) {
20
- return {
21
- id: id(idStr),
22
- type: kind,
23
- parentId: null,
24
- visible: true,
25
- ...extra,
26
- };
27
- }
28
- function makeFakeScene(nodes) {
29
- return {
30
- get: ((nid) => nodes[nid]),
31
- nodes: () => nodes,
32
- update: () => { },
33
- upsert: () => id(''),
34
- delete: () => { },
35
- restore: () => { },
36
- restoreAll: () => { },
37
- markDirty: () => { },
38
- pauseHistory: () => { },
39
- resumeHistory: () => { },
40
- getSubtree: () => null,
41
- cloneNodesInto: () => null,
42
- };
43
- }
44
- describe('cascadeDirty', () => {
45
- beforeEach(() => {
46
- nodeRegistry._reset();
47
- });
48
- test('starting node alone when registry is empty', () => {
49
- const scene = makeFakeScene({ a: makeNode('unknown', 'a') });
50
- const dirty = cascadeDirty(id('a'), { scene });
51
- expect(Array.from(dirty)).toEqual([id('a')]);
52
- });
53
- test('starting node alone when no relations declared', () => {
54
- registerNode(makeDef('thing'));
55
- const scene = makeFakeScene({ a: makeNode('thing', 'a') });
56
- const dirty = cascadeDirty(id('a'), { scene });
57
- expect(Array.from(dirty)).toEqual([id('a')]);
58
- });
59
- test('hosts cascade marks matching children dirty', () => {
60
- registerNode(makeDef('wall', { hosts: ['door', 'window'] }));
61
- registerNode(makeDef('door'));
62
- registerNode(makeDef('window'));
63
- registerNode(makeDef('lamp'));
64
- const wall = makeNode('wall', 'w1', {
65
- children: [id('d1'), id('w2'), id('l1')],
66
- });
67
- const scene = makeFakeScene({
68
- w1: wall,
69
- d1: makeNode('door', 'd1', { parentId: id('w1') }),
70
- w2: makeNode('window', 'w2', { parentId: id('w1') }),
71
- l1: makeNode('lamp', 'l1', { parentId: id('w1') }), // not in hosts list
72
- });
73
- const dirty = cascadeDirty(id('w1'), { scene });
74
- const ids = Array.from(dirty).sort();
75
- expect(ids).toEqual([id('d1'), id('w1'), id('w2')]); // l1 excluded
76
- });
77
- test('hosts cascade is recursive but bounded by maxDepth', () => {
78
- registerNode(makeDef('a', { hosts: ['a'] })); // a hosts more a
79
- const nodes = {};
80
- for (let i = 0; i < 25; i++) {
81
- const childId = i < 24 ? id(`a${i + 1}`) : undefined;
82
- nodes[`a${i}`] = makeNode('a', `a${i}`, {
83
- children: childId ? [childId] : [],
84
- });
85
- }
86
- const scene = makeFakeScene(nodes);
87
- const dirty = cascadeDirty(id('a0'), { scene, maxDepth: 5 });
88
- expect(dirty.size).toBe(6); // a0 + 5 descendants
89
- });
90
- test('affectsSpatial cascade uses spatialQuery to find neighbors', () => {
91
- registerNode(makeDef('wall', { affectsSpatial: ['slab', 'zone'] }));
92
- registerNode(makeDef('slab'));
93
- registerNode(makeDef('zone'));
94
- const scene = makeFakeScene({
95
- w1: makeNode('wall', 'w1'),
96
- s1: makeNode('slab', 's1'),
97
- z1: makeNode('zone', 'z1'),
98
- unrelated: makeNode('door', 'unrelated'),
99
- });
100
- const spatialQuery = (node, kinds) => {
101
- if (node.id !== id('w1'))
102
- return [];
103
- const matches = [];
104
- if (kinds.includes('slab'))
105
- matches.push(id('s1'));
106
- if (kinds.includes('zone'))
107
- matches.push(id('z1'));
108
- return matches;
109
- };
110
- const dirty = cascadeDirty(id('w1'), { scene, spatialQuery });
111
- expect(Array.from(dirty).sort()).toEqual([id('s1'), id('w1'), id('z1')]);
112
- });
113
- test('affectsSpatial is a no-op when no spatialQuery is provided', () => {
114
- registerNode(makeDef('wall', { affectsSpatial: ['slab'] }));
115
- const scene = makeFakeScene({ w1: makeNode('wall', 'w1') });
116
- const dirty = cascadeDirty(id('w1'), { scene });
117
- expect(Array.from(dirty)).toEqual([id('w1')]); // spatial branch silently skipped
118
- });
119
- test('cycle in hosts cascade does not loop forever', () => {
120
- registerNode(makeDef('a', { hosts: ['a'] }));
121
- const nodes = {
122
- a1: makeNode('a', 'a1', { children: [id('a2')] }),
123
- a2: makeNode('a', 'a2', { children: [id('a1')] }), // cycle
124
- };
125
- const scene = makeFakeScene(nodes);
126
- const dirty = cascadeDirty(id('a1'), { scene });
127
- expect(dirty.size).toBe(2);
128
- expect(dirty.has(id('a1'))).toBe(true);
129
- expect(dirty.has(id('a2'))).toBe(true);
130
- });
131
- test('custom childQuery overrides the default node.children lookup', () => {
132
- registerNode(makeDef('wall', { hosts: ['door'] }));
133
- registerNode(makeDef('door'));
134
- const scene = makeFakeScene({
135
- w1: makeNode('wall', 'w1'), // no children field
136
- d1: makeNode('door', 'd1', { parentId: id('w1') }),
137
- });
138
- // childQuery iterates the scene to find parentId matches — what you would
139
- // do for kinds that don't carry an explicit children array.
140
- const childQuery = (node) => {
141
- const result = [];
142
- for (const candidate of [id('d1')]) {
143
- const c = scene.get(candidate);
144
- if (c && c.parentId === node.id)
145
- result.push(c.id);
146
- }
147
- return result;
148
- };
149
- const dirty = cascadeDirty(id('w1'), { scene, childQuery });
150
- expect(Array.from(dirty).sort()).toEqual([id('d1'), id('w1')]);
151
- });
152
- });
153
- describe('collectDescendants', () => {
154
- beforeEach(() => {
155
- nodeRegistry._reset();
156
- });
157
- test('returns just the start when no children', () => {
158
- const scene = makeFakeScene({ a: makeNode('thing', 'a') });
159
- const result = collectDescendants(id('a'), { scene });
160
- expect(Array.from(result)).toEqual([id('a')]);
161
- });
162
- test('returns full subtree regardless of relations declarations', () => {
163
- // No def registered — descendants still found via the children array.
164
- const scene = makeFakeScene({
165
- root: makeNode('thing', 'root', { children: [id('c1'), id('c2')] }),
166
- c1: makeNode('thing', 'c1', { children: [id('g1')] }),
167
- c2: makeNode('thing', 'c2'),
168
- g1: makeNode('thing', 'g1'),
169
- });
170
- const result = collectDescendants(id('root'), { scene });
171
- expect(Array.from(result).sort()).toEqual([id('c1'), id('c2'), id('g1'), id('root')]);
172
- });
173
- test('respects maxDepth', () => {
174
- const scene = makeFakeScene({
175
- a: makeNode('thing', 'a', { children: [id('b')] }),
176
- b: makeNode('thing', 'b', { children: [id('c')] }),
177
- c: makeNode('thing', 'c', { children: [id('d')] }),
178
- d: makeNode('thing', 'd'),
179
- });
180
- const result = collectDescendants(id('a'), { scene, maxDepth: 2 });
181
- expect(Array.from(result).sort()).toEqual([id('a'), id('b'), id('c')]); // d truncated
182
- });
183
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=scene-api.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scene-api.test.d.ts","sourceRoot":"","sources":["../../src/registry/scene-api.test.ts"],"names":[],"mappings":""}
@@ -1,183 +0,0 @@
1
- import { beforeEach, describe, expect, test } from 'bun:test';
2
- import { resetSceneHistoryPauseDepth } from '../store/history-control';
3
- import { createSceneApi } from './scene-api';
4
- function makeFakeStore(initial = {}) {
5
- const state = {
6
- nodes: { ...initial },
7
- rootNodeIds: [],
8
- dirtyNodes: new Set(),
9
- createNode(node) {
10
- state.nodes[node.id] = node;
11
- },
12
- updateNode(id, data) {
13
- const existing = state.nodes[id];
14
- if (existing)
15
- state.nodes[id] = { ...existing, ...data };
16
- },
17
- deleteNode(id) {
18
- delete state.nodes[id];
19
- },
20
- markDirty(id) {
21
- state.dirtyNodes.add(id);
22
- },
23
- };
24
- let paused = 0;
25
- const temporal = {
26
- getState: () => ({
27
- pause: () => {
28
- paused += 1;
29
- },
30
- resume: () => {
31
- paused -= 1;
32
- },
33
- }),
34
- };
35
- const store = {
36
- getState: () => state,
37
- temporal,
38
- _state: state,
39
- _pausedCount: () => paused,
40
- };
41
- return store;
42
- }
43
- function makeNode(id, extra = {}) {
44
- return { id, type: 'site', parentId: null, visible: true, ...extra };
45
- }
46
- // Tests use short string IDs ("a", "b") for readability. The store's
47
- // AnyNodeId is a branded template-literal type — cast at the boundary.
48
- const id = (s) => s;
49
- const nodes = (store) => store._state.nodes;
50
- describe('SceneApi', () => {
51
- beforeEach(() => {
52
- resetSceneHistoryPauseDepth();
53
- });
54
- test('get reads node from store', () => {
55
- const store = makeFakeStore({ a: makeNode('a') });
56
- const api = createSceneApi(store);
57
- expect(api.get(id('a'))).toEqual(makeNode('a'));
58
- expect(api.get(id('missing'))).toBeUndefined();
59
- });
60
- test('update applies patch via store.updateNode', () => {
61
- const store = makeFakeStore({ a: makeNode('a', { visible: true }) });
62
- const api = createSceneApi(store);
63
- api.update(id('a'), { visible: false });
64
- expect(nodes(store)['a']).toMatchObject({ visible: false });
65
- });
66
- test('upsert calls createNode and returns the id', () => {
67
- const store = makeFakeStore();
68
- const api = createSceneApi(store);
69
- const returnedId = api.upsert(makeNode('a'));
70
- expect(returnedId).toBe(id('a'));
71
- expect(nodes(store)['a']).toBeDefined();
72
- });
73
- test('delete removes node from store', () => {
74
- const store = makeFakeStore({ a: makeNode('a') });
75
- const api = createSceneApi(store);
76
- api.delete(id('a'));
77
- expect(nodes(store)['a']).toBeUndefined();
78
- });
79
- test('markDirty forwards to store', () => {
80
- const store = makeFakeStore({ a: makeNode('a') });
81
- const api = createSceneApi(store);
82
- api.markDirty(id('a'));
83
- expect(store._state.dirtyNodes.has(id('a'))).toBe(true);
84
- });
85
- test('pauseHistory and resumeHistory bracket store.temporal pause/resume', () => {
86
- const store = makeFakeStore();
87
- const api = createSceneApi(store);
88
- expect(store._pausedCount()).toBe(0);
89
- api.pauseHistory();
90
- expect(store._pausedCount()).toBe(1);
91
- api.resumeHistory();
92
- expect(store._pausedCount()).toBe(0);
93
- });
94
- test('nested pause/resume use a depth counter (single pause call to temporal)', () => {
95
- const store = makeFakeStore();
96
- const api = createSceneApi(store);
97
- api.pauseHistory();
98
- api.pauseHistory();
99
- expect(store._pausedCount()).toBe(1); // only one actual pause
100
- api.resumeHistory();
101
- expect(store._pausedCount()).toBe(1); // still paused — inner resume
102
- api.resumeHistory();
103
- expect(store._pausedCount()).toBe(0);
104
- });
105
- });
106
- describe('SceneApi snapshot / restore', () => {
107
- beforeEach(() => {
108
- resetSceneHistoryPauseDepth();
109
- });
110
- test('restore returns a touched node to its pre-pause state', () => {
111
- const store = makeFakeStore({ a: makeNode('a', { visible: true }) });
112
- const api = createSceneApi(store);
113
- api.pauseHistory();
114
- api.update(id('a'), { visible: false });
115
- expect(nodes(store)['a']).toMatchObject({ visible: false });
116
- api.restore(id('a'));
117
- expect(nodes(store)['a']).toMatchObject({ visible: true });
118
- api.resumeHistory();
119
- });
120
- test('restore on a node never touched is a no-op', () => {
121
- const store = makeFakeStore({ a: makeNode('a', { visible: true }) });
122
- const api = createSceneApi(store);
123
- api.pauseHistory();
124
- api.restore(id('a'));
125
- expect(nodes(store)['a']).toMatchObject({ visible: true });
126
- api.resumeHistory();
127
- });
128
- test('restoreAll reverts every touched node', () => {
129
- const store = makeFakeStore({
130
- a: makeNode('a', { visible: true }),
131
- b: makeNode('b', { visible: true }),
132
- });
133
- const api = createSceneApi(store);
134
- api.pauseHistory();
135
- api.update(id('a'), { visible: false });
136
- api.update(id('b'), { visible: false });
137
- api.restoreAll();
138
- expect(nodes(store)['a']).toMatchObject({ visible: true });
139
- expect(nodes(store)['b']).toMatchObject({ visible: true });
140
- api.resumeHistory();
141
- });
142
- test('restore re-creates a node that was deleted mid-pause', () => {
143
- const original = makeNode('a', { visible: true });
144
- const store = makeFakeStore({ a: original });
145
- const api = createSceneApi(store);
146
- api.pauseHistory();
147
- api.delete(id('a'));
148
- expect(nodes(store)['a']).toBeUndefined();
149
- api.restore(id('a'));
150
- expect(nodes(store)['a']).toEqual(original);
151
- api.resumeHistory();
152
- });
153
- test('restore deletes a node that was upserted mid-pause', () => {
154
- const store = makeFakeStore();
155
- const api = createSceneApi(store);
156
- api.pauseHistory();
157
- api.upsert(makeNode('a'));
158
- expect(nodes(store)['a']).toBeDefined();
159
- api.restore(id('a'));
160
- expect(nodes(store)['a']).toBeUndefined();
161
- api.resumeHistory();
162
- });
163
- test('snapshot is dropped on resumeHistory; restore after resume is a no-op', () => {
164
- const store = makeFakeStore({ a: makeNode('a', { visible: true }) });
165
- const api = createSceneApi(store);
166
- api.pauseHistory();
167
- api.update(id('a'), { visible: false });
168
- api.resumeHistory();
169
- api.restore(id('a')); // snapshot gone — no effect
170
- expect(nodes(store)['a']).toMatchObject({ visible: false });
171
- });
172
- test('only the first mutation in a pause window captures the original', () => {
173
- const store = makeFakeStore({ a: makeNode('a', { visible: true }) });
174
- const api = createSceneApi(store);
175
- api.pauseHistory();
176
- api.update(id('a'), { visible: false });
177
- api.update(id('a'), { visible: true }); // second update — must not overwrite snapshot
178
- api.update(id('a'), { visible: false });
179
- api.restore(id('a'));
180
- expect(nodes(store)['a']).toMatchObject({ visible: true }); // the *first* pre-pause value
181
- api.resumeHistory();
182
- });
183
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=subtree.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subtree.test.d.ts","sourceRoot":"","sources":["../../src/registry/subtree.test.ts"],"names":[],"mappings":""}
@@ -1,163 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { cloneNodesInto, collectSubtree } from './subtree';
3
- function makeNode(id, type, extra = {}) {
4
- return {
5
- object: 'node',
6
- id,
7
- type,
8
- parentId: null,
9
- visible: true,
10
- metadata: {},
11
- ...extra,
12
- };
13
- }
14
- describe('collectSubtree', () => {
15
- test('returns null for missing root', () => {
16
- expect(collectSubtree({}, 'missing')).toBeNull();
17
- });
18
- test('returns just the root for a leaf node', () => {
19
- const root = makeNode('shelf_1', 'shelf', { width: 1 });
20
- const sub = collectSubtree({ ['shelf_1']: root }, 'shelf_1');
21
- expect(sub?.root).toBe(root);
22
- expect(sub?.descendants).toEqual([]);
23
- });
24
- test('walks descendants in BFS / declaration order', () => {
25
- const nodes = {
26
- ['shelf_1']: makeNode('shelf_1', 'shelf', {
27
- position: [0, 0, 0],
28
- children: ['item_a', 'item_b'],
29
- width: 1,
30
- }),
31
- ['item_a']: makeNode('item_a', 'item', {
32
- parentId: 'shelf_1',
33
- position: [0, 0, 0],
34
- }),
35
- ['item_b']: makeNode('item_b', 'item', {
36
- parentId: 'shelf_1',
37
- position: [0.3, 0, 0],
38
- }),
39
- };
40
- const sub = collectSubtree(nodes, 'shelf_1');
41
- expect(sub?.descendants.map((n) => n.id)).toEqual(['item_a', 'item_b']);
42
- });
43
- test('returned nodes are live references — no cloning', () => {
44
- const item = makeNode('item_a', 'item', { parentId: 'shelf_1', position: [0, 0, 0] });
45
- const nodes = {
46
- ['shelf_1']: makeNode('shelf_1', 'shelf', { children: ['item_a'] }),
47
- ['item_a']: item,
48
- };
49
- const sub = collectSubtree(nodes, 'shelf_1');
50
- expect(sub?.descendants[0]).toBe(item);
51
- });
52
- });
53
- describe('cloneNodesInto', () => {
54
- test('clones a single root with fresh id and supplied position', () => {
55
- const original = makeNode('door_orig', 'door', {
56
- position: [1, 2, 3],
57
- wallId: 'wall_x',
58
- width: 0.9,
59
- });
60
- const { rootId, nodes } = cloneNodesInto([original], {
61
- rootId: 'door_orig',
62
- position: [10, 0, -4],
63
- });
64
- expect(nodes).toHaveLength(1);
65
- const cloned = nodes[0];
66
- expect(cloned.id).toBe(rootId);
67
- expect(cloned.id).not.toBe('door_orig');
68
- expect(cloned.id.startsWith('door_')).toBe(true);
69
- expect(cloned.position).toEqual([10, 0, -4]);
70
- expect(cloned.width).toBe(0.9);
71
- // cloneNodesInto is host-ref-agnostic — wallId is preserved
72
- // verbatim. Stripping is the caller's job (see getHostRefFields).
73
- expect(cloned.wallId).toBe('wall_x');
74
- });
75
- test('preserves root position when none is supplied', () => {
76
- const original = makeNode('shelf_orig', 'shelf', { position: [5, 0, 5] });
77
- const { nodes } = cloneNodesInto([original], { rootId: 'shelf_orig' });
78
- expect(nodes[0].position).toEqual([5, 0, 5]);
79
- });
80
- test('preserves parent/child subtree with remapped ids and relative positions', () => {
81
- const shelf = makeNode('shelf_1', 'shelf', {
82
- position: [5, 0, 5],
83
- children: ['item_a', 'item_b'],
84
- });
85
- const itemA = makeNode('item_a', 'item', { parentId: 'shelf_1', position: [0, 0, 0] });
86
- const itemB = makeNode('item_b', 'item', { parentId: 'shelf_1', position: [0.3, 0, 0] });
87
- const { rootId, nodes: out } = cloneNodesInto([shelf, itemA, itemB], {
88
- rootId: 'shelf_1',
89
- position: [99, 0, -99],
90
- });
91
- expect(out).toHaveLength(3);
92
- const root = out[0];
93
- expect(root.id).toBe(rootId);
94
- expect(root.id).not.toBe('shelf_1');
95
- expect(root.position).toEqual([99, 0, -99]);
96
- // Root's children rewritten to fresh ids; descendants' parentIds
97
- // point at the new root id.
98
- const ids = new Set(out.map((n) => n.id));
99
- expect(root.children).toHaveLength(2);
100
- for (const cid of root.children)
101
- expect(ids.has(cid)).toBe(true);
102
- for (let i = 1; i < out.length; i += 1) {
103
- const desc = out[i];
104
- expect(desc.parentId).toBe(rootId);
105
- expect(Array.isArray(desc.position)).toBe(true);
106
- }
107
- });
108
- test('remaps associative measurement references inside the cloned subtree', () => {
109
- const wall = makeNode('wall_1', 'wall', { parentId: 'level_1' });
110
- const measurement = makeNode('measurement_1', 'measurement', {
111
- parentId: 'level_1',
112
- measurement: {
113
- kind: 'distance',
114
- points: [
115
- {
116
- kind: 'feature',
117
- reference: { nodeId: 'wall_1', featureId: 'wall:start' },
118
- fallback: [0, 0, 0],
119
- },
120
- [1, 0, 0],
121
- ],
122
- },
123
- });
124
- const result = cloneNodesInto([wall, measurement], {
125
- rootId: 'wall_1',
126
- });
127
- const clonedMeasurement = result.nodes.find((node) => node.type === 'measurement');
128
- expect(clonedMeasurement?.type).toBe('measurement');
129
- if (clonedMeasurement?.type === 'measurement' &&
130
- clonedMeasurement.measurement.kind === 'distance') {
131
- const anchor = clonedMeasurement.measurement.points[0];
132
- expect(Array.isArray(anchor)).toBe(false);
133
- if (!Array.isArray(anchor)) {
134
- expect(anchor.reference.nodeId).toBe(result.idMap.get('wall_1'));
135
- }
136
- }
137
- });
138
- test('parents the cloned root under opts.parentId when supplied', () => {
139
- const orig = makeNode('shelf_1', 'shelf', { parentId: 'level_old' });
140
- const { nodes } = cloneNodesInto([orig], {
141
- rootId: 'shelf_1',
142
- parentId: 'level_new',
143
- });
144
- expect(nodes[0].parentId).toBe('level_new');
145
- });
146
- test('two clones produce disjoint id sets', () => {
147
- const orig = makeNode('shelf_1', 'shelf', {
148
- position: [0, 0, 0],
149
- children: ['item_a'],
150
- });
151
- const child = makeNode('item_a', 'item', { parentId: 'shelf_1', position: [0, 0, 0] });
152
- const first = cloneNodesInto([orig, child], { rootId: 'shelf_1' });
153
- const second = cloneNodesInto([orig, child], { rootId: 'shelf_1' });
154
- const idsA = new Set(first.nodes.map((n) => n.id));
155
- const idsB = new Set(second.nodes.map((n) => n.id));
156
- for (const id of idsA)
157
- expect(idsB.has(id)).toBe(false);
158
- });
159
- test('throws if rootId is missing from the input array', () => {
160
- const orig = makeNode('shelf_1', 'shelf', {});
161
- expect(() => cloneNodesInto([orig], { rootId: 'shelf_other' })).toThrow(/rootId/);
162
- });
163
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=asset-url.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asset-url.test.d.ts","sourceRoot":"","sources":["../../src/schema/asset-url.test.ts"],"names":[],"mappings":""}