@pascal-app/core 0.8.0 → 0.9.2

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 (471) hide show
  1. package/dist/events/bus.d.ts +67 -13
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
  4. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
  5. package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
  6. package/dist/hooks/scene-registry/scene-registry.d.ts +14 -23
  7. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  8. package/dist/hooks/scene-registry/scene-registry.js +59 -26
  9. package/dist/hooks/scene-registry/scene-registry.test.d.ts +2 -0
  10. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +1 -0
  11. package/dist/hooks/scene-registry/scene-registry.test.js +26 -0
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
  13. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
  14. package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
  15. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
  16. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
  17. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +366 -0
  18. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +79 -11
  19. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  20. package/dist/hooks/spatial-grid/spatial-grid-manager.js +508 -141
  21. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
  22. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  23. package/dist/hooks/spatial-grid/spatial-grid-sync.js +109 -18
  24. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +2 -0
  25. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +1 -0
  26. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +363 -0
  27. package/dist/index.d.ts +36 -8
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +33 -6
  30. package/dist/lib/level-name.d.ts +4 -0
  31. package/dist/lib/level-name.d.ts.map +1 -0
  32. package/dist/lib/level-name.js +10 -0
  33. package/dist/lib/measurement-geometry.d.ts +19 -0
  34. package/dist/lib/measurement-geometry.d.ts.map +1 -0
  35. package/dist/lib/measurement-geometry.js +232 -0
  36. package/dist/lib/measurement-geometry.test.d.ts +2 -0
  37. package/dist/lib/measurement-geometry.test.d.ts.map +1 -0
  38. package/dist/lib/measurement-geometry.test.js +102 -0
  39. package/dist/lib/polygon-geometry.d.ts +0 -1
  40. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  41. package/dist/lib/polygon-geometry.js +0 -18
  42. package/dist/lib/polygon-relations.d.ts +10 -0
  43. package/dist/lib/polygon-relations.d.ts.map +1 -0
  44. package/dist/lib/polygon-relations.js +73 -0
  45. package/dist/lib/selection-proxy.d.ts +4 -0
  46. package/dist/lib/selection-proxy.d.ts.map +1 -0
  47. package/dist/lib/selection-proxy.js +12 -0
  48. package/dist/lib/slab-polygon.d.ts +31 -2
  49. package/dist/lib/slab-polygon.d.ts.map +1 -1
  50. package/dist/lib/slab-polygon.js +525 -31
  51. package/dist/lib/slab-polygon.test.d.ts +2 -0
  52. package/dist/lib/slab-polygon.test.d.ts.map +1 -0
  53. package/dist/lib/slab-polygon.test.js +635 -0
  54. package/dist/lib/slots.d.ts +14 -0
  55. package/dist/lib/slots.d.ts.map +1 -0
  56. package/dist/lib/slots.js +26 -0
  57. package/dist/lib/space-detection-pause.test.d.ts +2 -0
  58. package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
  59. package/dist/lib/space-detection-pause.test.js +42 -0
  60. package/dist/lib/space-detection.d.ts +54 -2
  61. package/dist/lib/space-detection.d.ts.map +1 -1
  62. package/dist/lib/space-detection.js +599 -124
  63. package/dist/lib/space-detection.test.d.ts +2 -0
  64. package/dist/lib/space-detection.test.d.ts.map +1 -0
  65. package/dist/lib/space-detection.test.js +376 -0
  66. package/dist/lib/wall-distance.d.ts +60 -0
  67. package/dist/lib/wall-distance.d.ts.map +1 -0
  68. package/dist/lib/wall-distance.js +85 -0
  69. package/dist/lib/zone-quantities.d.ts +21 -0
  70. package/dist/lib/zone-quantities.d.ts.map +1 -0
  71. package/dist/lib/zone-quantities.js +183 -0
  72. package/dist/lib/zone-quantities.test.d.ts +2 -0
  73. package/dist/lib/zone-quantities.test.d.ts.map +1 -0
  74. package/dist/lib/zone-quantities.test.js +82 -0
  75. package/dist/material-library.d.ts +20 -1
  76. package/dist/material-library.d.ts.map +1 -1
  77. package/dist/material-library.js +3737 -200
  78. package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
  79. package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
  80. package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
  81. package/dist/registry/handles.d.ts +394 -0
  82. package/dist/registry/handles.d.ts.map +1 -0
  83. package/dist/registry/handles.js +24 -0
  84. package/dist/registry/index.d.ts +7 -0
  85. package/dist/registry/index.d.ts.map +1 -0
  86. package/dist/registry/index.js +4 -0
  87. package/dist/registry/registry.d.ts +136 -0
  88. package/dist/registry/registry.d.ts.map +1 -0
  89. package/dist/registry/registry.js +282 -0
  90. package/dist/registry/registry.test.d.ts +2 -0
  91. package/dist/registry/registry.test.d.ts.map +1 -0
  92. package/dist/registry/registry.test.js +196 -0
  93. package/dist/registry/relations-resolver.d.ts +42 -0
  94. package/dist/registry/relations-resolver.d.ts.map +1 -0
  95. package/dist/registry/relations-resolver.js +77 -0
  96. package/dist/registry/relations-resolver.test.d.ts +2 -0
  97. package/dist/registry/relations-resolver.test.d.ts.map +1 -0
  98. package/dist/registry/relations-resolver.test.js +183 -0
  99. package/dist/registry/scene-api.d.ts +44 -0
  100. package/dist/registry/scene-api.d.ts.map +1 -0
  101. package/dist/registry/scene-api.js +111 -0
  102. package/dist/registry/scene-api.test.d.ts +2 -0
  103. package/dist/registry/scene-api.test.d.ts.map +1 -0
  104. package/dist/registry/scene-api.test.js +183 -0
  105. package/dist/registry/subtree.d.ts +67 -0
  106. package/dist/registry/subtree.d.ts.map +1 -0
  107. package/dist/registry/subtree.js +123 -0
  108. package/dist/registry/subtree.test.d.ts +2 -0
  109. package/dist/registry/subtree.test.d.ts.map +1 -0
  110. package/dist/registry/subtree.test.js +163 -0
  111. package/dist/registry/types.d.ts +2099 -0
  112. package/dist/registry/types.d.ts.map +1 -0
  113. package/dist/registry/types.js +1 -0
  114. package/dist/schema/index.d.ts +35 -4
  115. package/dist/schema/index.d.ts.map +1 -1
  116. package/dist/schema/index.js +32 -4
  117. package/dist/schema/material.d.ts +13 -2
  118. package/dist/schema/material.d.ts.map +1 -1
  119. package/dist/schema/material.js +17 -5
  120. package/dist/schema/material.test.d.ts +2 -0
  121. package/dist/schema/material.test.d.ts.map +1 -0
  122. package/dist/schema/material.test.js +43 -0
  123. package/dist/schema/nodes/box-vent.d.ts +74 -0
  124. package/dist/schema/nodes/box-vent.d.ts.map +1 -0
  125. package/dist/schema/nodes/box-vent.js +63 -0
  126. package/dist/schema/nodes/building.d.ts +1 -1
  127. package/dist/schema/nodes/building.d.ts.map +1 -1
  128. package/dist/schema/nodes/building.js +3 -2
  129. package/dist/schema/nodes/cabinet.d.ts +534 -0
  130. package/dist/schema/nodes/cabinet.d.ts.map +1 -0
  131. package/dist/schema/nodes/cabinet.js +137 -0
  132. package/dist/schema/nodes/ceiling.d.ts +5 -2
  133. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  134. package/dist/schema/nodes/ceiling.js +5 -1
  135. package/dist/schema/nodes/chimney.d.ts +158 -0
  136. package/dist/schema/nodes/chimney.d.ts.map +1 -0
  137. package/dist/schema/nodes/chimney.js +67 -0
  138. package/dist/schema/nodes/column.d.ts +600 -7
  139. package/dist/schema/nodes/column.d.ts.map +1 -1
  140. package/dist/schema/nodes/column.js +589 -6
  141. package/dist/schema/nodes/cupola.d.ts +66 -0
  142. package/dist/schema/nodes/cupola.d.ts.map +1 -0
  143. package/dist/schema/nodes/cupola.js +28 -0
  144. package/dist/schema/nodes/door.d.ts +13 -5
  145. package/dist/schema/nodes/door.d.ts.map +1 -1
  146. package/dist/schema/nodes/door.js +12 -0
  147. package/dist/schema/nodes/dormer.d.ts +228 -0
  148. package/dist/schema/nodes/dormer.d.ts.map +1 -0
  149. package/dist/schema/nodes/dormer.js +119 -0
  150. package/dist/schema/nodes/downspout.d.ts +75 -0
  151. package/dist/schema/nodes/downspout.d.ts.map +1 -0
  152. package/dist/schema/nodes/downspout.js +63 -0
  153. package/dist/schema/nodes/duct-fitting.d.ts +91 -0
  154. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
  155. package/dist/schema/nodes/duct-fitting.js +92 -0
  156. package/dist/schema/nodes/duct-segment.d.ts +61 -0
  157. package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
  158. package/dist/schema/nodes/duct-segment.js +73 -0
  159. package/dist/schema/nodes/duct-terminal.d.ts +57 -0
  160. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
  161. package/dist/schema/nodes/duct-terminal.js +51 -0
  162. package/dist/schema/nodes/elevator.d.ts +106 -0
  163. package/dist/schema/nodes/elevator.d.ts.map +1 -0
  164. package/dist/schema/nodes/elevator.js +57 -0
  165. package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
  166. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
  167. package/dist/schema/nodes/eyebrow-vent.js +40 -0
  168. package/dist/schema/nodes/fence.d.ts +19 -2
  169. package/dist/schema/nodes/fence.d.ts.map +1 -1
  170. package/dist/schema/nodes/fence.js +27 -2
  171. package/dist/schema/nodes/gutter.d.ts +84 -0
  172. package/dist/schema/nodes/gutter.d.ts.map +1 -0
  173. package/dist/schema/nodes/gutter.js +76 -0
  174. package/dist/schema/nodes/hvac-equipment.d.ts +63 -0
  175. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
  176. package/dist/schema/nodes/hvac-equipment.js +55 -0
  177. package/dist/schema/nodes/item.d.ts +12 -0
  178. package/dist/schema/nodes/item.d.ts.map +1 -1
  179. package/dist/schema/nodes/item.js +20 -0
  180. package/dist/schema/nodes/level.d.ts +1 -1
  181. package/dist/schema/nodes/level.d.ts.map +1 -1
  182. package/dist/schema/nodes/level.js +4 -0
  183. package/dist/schema/nodes/lineset.d.ts +42 -0
  184. package/dist/schema/nodes/lineset.d.ts.map +1 -0
  185. package/dist/schema/nodes/lineset.js +38 -0
  186. package/dist/schema/nodes/liquid-line.d.ts +34 -0
  187. package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
  188. package/dist/schema/nodes/liquid-line.js +24 -0
  189. package/dist/schema/nodes/measurement.d.ts +306 -0
  190. package/dist/schema/nodes/measurement.d.ts.map +1 -0
  191. package/dist/schema/nodes/measurement.js +87 -0
  192. package/dist/schema/nodes/measurement.test.d.ts +2 -0
  193. package/dist/schema/nodes/measurement.test.d.ts.map +1 -0
  194. package/dist/schema/nodes/measurement.test.js +139 -0
  195. package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
  196. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
  197. package/dist/schema/nodes/pipe-fitting.js +45 -0
  198. package/dist/schema/nodes/pipe-segment.d.ts +48 -0
  199. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
  200. package/dist/schema/nodes/pipe-segment.js +36 -0
  201. package/dist/schema/nodes/pipe-trap.d.ts +43 -0
  202. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
  203. package/dist/schema/nodes/pipe-trap.js +36 -0
  204. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +2 -0
  205. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +1 -0
  206. package/dist/schema/nodes/ridge-vent-defaults.test.js +205 -0
  207. package/dist/schema/nodes/ridge-vent.d.ts +82 -0
  208. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
  209. package/dist/schema/nodes/ridge-vent.js +248 -0
  210. package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
  211. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
  212. package/dist/schema/nodes/roof-segment-shape.js +318 -0
  213. package/dist/schema/nodes/roof-segment-shape.test.d.ts +2 -0
  214. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +1 -0
  215. package/dist/schema/nodes/roof-segment-shape.test.js +175 -0
  216. package/dist/schema/nodes/roof-segment-surface.test.d.ts +2 -0
  217. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +1 -0
  218. package/dist/schema/nodes/roof-segment-surface.test.js +48 -0
  219. package/dist/schema/nodes/roof-segment-trim.test.d.ts +2 -0
  220. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +1 -0
  221. package/dist/schema/nodes/roof-segment-trim.test.js +107 -0
  222. package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
  223. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
  224. package/dist/schema/nodes/roof-segment-walls.js +330 -0
  225. package/dist/schema/nodes/roof-segment-walls.test.d.ts +2 -0
  226. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +1 -0
  227. package/dist/schema/nodes/roof-segment-walls.test.js +92 -0
  228. package/dist/schema/nodes/roof-segment.d.ts +273 -3
  229. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  230. package/dist/schema/nodes/roof-segment.js +539 -3
  231. package/dist/schema/nodes/roof.d.ts +8 -8
  232. package/dist/schema/nodes/roof.d.ts.map +1 -1
  233. package/dist/schema/nodes/roof.js +4 -16
  234. package/dist/schema/nodes/shelf.d.ts +106 -0
  235. package/dist/schema/nodes/shelf.d.ts.map +1 -0
  236. package/dist/schema/nodes/shelf.js +90 -0
  237. package/dist/schema/nodes/site.d.ts +1 -122
  238. package/dist/schema/nodes/site.d.ts.map +1 -1
  239. package/dist/schema/nodes/site.js +2 -6
  240. package/dist/schema/nodes/skylight.d.ts +279 -0
  241. package/dist/schema/nodes/skylight.d.ts.map +1 -0
  242. package/dist/schema/nodes/skylight.js +152 -0
  243. package/dist/schema/nodes/slab.d.ts +5 -2
  244. package/dist/schema/nodes/slab.d.ts.map +1 -1
  245. package/dist/schema/nodes/slab.js +5 -1
  246. package/dist/schema/nodes/solar-panel.d.ts +117 -0
  247. package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
  248. package/dist/schema/nodes/solar-panel.js +47 -0
  249. package/dist/schema/nodes/stair-segment.d.ts +4 -4
  250. package/dist/schema/nodes/stair.d.ts +13 -12
  251. package/dist/schema/nodes/stair.d.ts.map +1 -1
  252. package/dist/schema/nodes/stair.js +3 -0
  253. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
  254. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  255. package/dist/schema/nodes/surface-hole-metadata.js +3 -1
  256. package/dist/schema/nodes/turbine-vent.d.ts +68 -0
  257. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
  258. package/dist/schema/nodes/turbine-vent.js +41 -0
  259. package/dist/schema/nodes/wall.d.ts +245 -6
  260. package/dist/schema/nodes/wall.d.ts.map +1 -1
  261. package/dist/schema/nodes/wall.js +257 -0
  262. package/dist/schema/nodes/wall.test.d.ts +2 -0
  263. package/dist/schema/nodes/wall.test.d.ts.map +1 -0
  264. package/dist/schema/nodes/wall.test.js +208 -0
  265. package/dist/schema/nodes/window.d.ts +11 -3
  266. package/dist/schema/nodes/window.d.ts.map +1 -1
  267. package/dist/schema/nodes/window.js +12 -0
  268. package/dist/schema/nodes/zone.d.ts +2 -0
  269. package/dist/schema/nodes/zone.d.ts.map +1 -1
  270. package/dist/schema/nodes/zone.js +6 -0
  271. package/dist/schema/scene-material.d.ts +41 -0
  272. package/dist/schema/scene-material.d.ts.map +1 -0
  273. package/dist/schema/scene-material.js +9 -0
  274. package/dist/schema/types.d.ts +2850 -655
  275. package/dist/schema/types.d.ts.map +1 -1
  276. package/dist/schema/types.js +49 -0
  277. package/dist/services/alignment-anchors.d.ts +100 -0
  278. package/dist/services/alignment-anchors.d.ts.map +1 -0
  279. package/dist/services/alignment-anchors.js +312 -0
  280. package/dist/services/alignment-anchors.test.d.ts +2 -0
  281. package/dist/services/alignment-anchors.test.d.ts.map +1 -0
  282. package/dist/services/alignment-anchors.test.js +383 -0
  283. package/dist/services/alignment.d.ts +131 -0
  284. package/dist/services/alignment.d.ts.map +1 -0
  285. package/dist/services/alignment.js +171 -0
  286. package/dist/services/alignment.test.d.ts +2 -0
  287. package/dist/services/alignment.test.d.ts.map +1 -0
  288. package/dist/services/alignment.test.js +92 -0
  289. package/dist/services/drag-session.d.ts +47 -0
  290. package/dist/services/drag-session.d.ts.map +1 -0
  291. package/dist/services/drag-session.js +100 -0
  292. package/dist/services/drag-session.test.d.ts +2 -0
  293. package/dist/services/drag-session.test.d.ts.map +1 -0
  294. package/dist/services/drag-session.test.js +219 -0
  295. package/dist/services/hosting.d.ts +88 -0
  296. package/dist/services/hosting.d.ts.map +1 -0
  297. package/dist/services/hosting.js +131 -0
  298. package/dist/services/hosting.test.d.ts +2 -0
  299. package/dist/services/hosting.test.d.ts.map +1 -0
  300. package/dist/services/hosting.test.js +230 -0
  301. package/dist/services/index.d.ts +13 -0
  302. package/dist/services/index.d.ts.map +1 -0
  303. package/dist/services/index.js +12 -0
  304. package/dist/services/level-height.d.ts +28 -0
  305. package/dist/services/level-height.d.ts.map +1 -0
  306. package/dist/services/level-height.js +62 -0
  307. package/dist/services/movement.d.ts +48 -0
  308. package/dist/services/movement.d.ts.map +1 -0
  309. package/dist/services/movement.js +65 -0
  310. package/dist/services/movement.test.d.ts +2 -0
  311. package/dist/services/movement.test.d.ts.map +1 -0
  312. package/dist/services/movement.test.js +133 -0
  313. package/dist/services/opening-guides.d.ts +141 -0
  314. package/dist/services/opening-guides.d.ts.map +1 -0
  315. package/dist/services/opening-guides.js +267 -0
  316. package/dist/services/opening-guides.test.d.ts +2 -0
  317. package/dist/services/opening-guides.test.d.ts.map +1 -0
  318. package/dist/services/opening-guides.test.js +208 -0
  319. package/dist/services/port-connectivity.d.ts +115 -0
  320. package/dist/services/port-connectivity.d.ts.map +1 -0
  321. package/dist/services/port-connectivity.js +300 -0
  322. package/dist/services/port-connectivity.test.d.ts +2 -0
  323. package/dist/services/port-connectivity.test.d.ts.map +1 -0
  324. package/dist/services/port-connectivity.test.js +297 -0
  325. package/dist/services/riser-diagram.d.ts +40 -0
  326. package/dist/services/riser-diagram.d.ts.map +1 -0
  327. package/dist/services/riser-diagram.js +110 -0
  328. package/dist/services/riser-diagram.test.d.ts +2 -0
  329. package/dist/services/riser-diagram.test.d.ts.map +1 -0
  330. package/dist/services/riser-diagram.test.js +66 -0
  331. package/dist/services/single-undo-dance.test.d.ts +2 -0
  332. package/dist/services/single-undo-dance.test.d.ts.map +1 -0
  333. package/dist/services/single-undo-dance.test.js +210 -0
  334. package/dist/services/snap.d.ts +80 -0
  335. package/dist/services/snap.d.ts.map +1 -0
  336. package/dist/services/snap.js +140 -0
  337. package/dist/services/snap.test.d.ts +2 -0
  338. package/dist/services/snap.test.d.ts.map +1 -0
  339. package/dist/services/snap.test.js +137 -0
  340. package/dist/services/system-graph.d.ts +30 -0
  341. package/dist/services/system-graph.d.ts.map +1 -0
  342. package/dist/services/system-graph.js +164 -0
  343. package/dist/services/system-graph.test.d.ts +2 -0
  344. package/dist/services/system-graph.test.d.ts.map +1 -0
  345. package/dist/services/system-graph.test.js +138 -0
  346. package/dist/services/validate-dwv.d.ts +32 -0
  347. package/dist/services/validate-dwv.d.ts.map +1 -0
  348. package/dist/services/validate-dwv.js +118 -0
  349. package/dist/services/validate-dwv.test.d.ts +2 -0
  350. package/dist/services/validate-dwv.test.d.ts.map +1 -0
  351. package/dist/services/validate-dwv.test.js +109 -0
  352. package/dist/solar-panel-presets.d.ts +17 -0
  353. package/dist/solar-panel-presets.d.ts.map +1 -0
  354. package/dist/solar-panel-presets.js +43 -0
  355. package/dist/store/actions/node-actions.d.ts +14 -2
  356. package/dist/store/actions/node-actions.d.ts.map +1 -1
  357. package/dist/store/actions/node-actions.js +585 -15
  358. package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
  359. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
  360. package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
  361. package/dist/store/actions/reparent.test.d.ts +2 -0
  362. package/dist/store/actions/reparent.test.d.ts.map +1 -0
  363. package/dist/store/actions/reparent.test.js +212 -0
  364. package/dist/store/actions/ridge-vent-update.test.d.ts +2 -0
  365. package/dist/store/actions/ridge-vent-update.test.d.ts.map +1 -0
  366. package/dist/store/actions/ridge-vent-update.test.js +264 -0
  367. package/dist/store/history-control.d.ts +11 -0
  368. package/dist/store/history-control.d.ts.map +1 -1
  369. package/dist/store/history-control.js +33 -0
  370. package/dist/store/use-interactive.d.ts +39 -0
  371. package/dist/store/use-interactive.d.ts.map +1 -1
  372. package/dist/store/use-interactive.js +75 -0
  373. package/dist/store/use-live-node-overrides.d.ts +22 -0
  374. package/dist/store/use-live-node-overrides.d.ts.map +1 -0
  375. package/dist/store/use-live-node-overrides.js +59 -0
  376. package/dist/store/use-scene-dirty-tracking.test.d.ts +2 -0
  377. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +1 -0
  378. package/dist/store/use-scene-dirty-tracking.test.js +68 -0
  379. package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
  380. package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
  381. package/dist/store/use-scene-elevator-migration.test.js +109 -0
  382. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +2 -0
  383. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +1 -0
  384. package/dist/store/use-scene-measurement-roundtrip.test.js +97 -0
  385. package/dist/store/use-scene-plugins.test.d.ts +2 -0
  386. package/dist/store/use-scene-plugins.test.d.ts.map +1 -0
  387. package/dist/store/use-scene-plugins.test.js +51 -0
  388. package/dist/store/use-scene-wall-slot-migration.test.d.ts +2 -0
  389. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +1 -0
  390. package/dist/store/use-scene-wall-slot-migration.test.js +210 -0
  391. package/dist/store/use-scene-window-migration.test.d.ts +2 -0
  392. package/dist/store/use-scene-window-migration.test.d.ts.map +1 -0
  393. package/dist/store/use-scene-window-migration.test.js +85 -0
  394. package/dist/store/use-scene.d.ts +28 -2
  395. package/dist/store/use-scene.d.ts.map +1 -1
  396. package/dist/store/use-scene.js +546 -49
  397. package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
  398. package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
  399. package/dist/systems/elevator/elevator-dispatch.js +57 -0
  400. package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
  401. package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
  402. package/dist/systems/elevator/elevator-geometry.js +50 -0
  403. package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
  404. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
  405. package/dist/systems/elevator/elevator-opening-sync.js +218 -0
  406. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
  407. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
  408. package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
  409. package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
  410. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
  411. package/dist/systems/elevator/elevator-opening-system.js +48 -0
  412. package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
  413. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
  414. package/dist/systems/elevator/elevator-runtime-system.js +8 -0
  415. package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
  416. package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
  417. package/dist/systems/elevator/elevator-runtime.js +225 -0
  418. package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
  419. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
  420. package/dist/systems/elevator/elevator-runtime.test.js +64 -0
  421. package/dist/systems/elevator/elevator-service.d.ts +19 -0
  422. package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
  423. package/dist/systems/elevator/elevator-service.js +111 -0
  424. package/dist/systems/fence/fence-centerline.d.ts +12 -0
  425. package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
  426. package/dist/systems/fence/fence-centerline.js +37 -0
  427. package/dist/systems/fence/fence-spline.d.ts +39 -0
  428. package/dist/systems/fence/fence-spline.d.ts.map +1 -0
  429. package/dist/systems/fence/fence-spline.js +196 -0
  430. package/dist/systems/fence/fence-spline.test.d.ts +2 -0
  431. package/dist/systems/fence/fence-spline.test.d.ts.map +1 -0
  432. package/dist/systems/fence/fence-spline.test.js +136 -0
  433. package/dist/systems/stair/stair-footprint.d.ts +44 -0
  434. package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
  435. package/dist/systems/stair/stair-footprint.js +178 -0
  436. package/dist/systems/stair/stair-opening-preview.d.ts +2447 -0
  437. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
  438. package/dist/systems/stair/stair-opening-preview.js +93 -0
  439. package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
  440. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
  441. package/dist/systems/stair/stair-opening-preview.test.js +80 -0
  442. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  443. package/dist/systems/stair/stair-opening-sync.js +155 -147
  444. package/dist/systems/stair/stair-opening-sync.test.js +424 -2
  445. package/dist/systems/stair/stair-opening-system.d.ts +2 -0
  446. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
  447. package/dist/systems/stair/stair-opening-system.js +104 -0
  448. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  449. package/dist/systems/wall/wall-mitering.js +38 -2
  450. package/dist/systems/wall/wall-mitering.test.d.ts +2 -0
  451. package/dist/systems/wall/wall-mitering.test.d.ts.map +1 -0
  452. package/dist/systems/wall/wall-mitering.test.js +63 -0
  453. package/dist/systems/wall/wall-move.d.ts +48 -0
  454. package/dist/systems/wall/wall-move.d.ts.map +1 -0
  455. package/dist/systems/wall/wall-move.js +193 -0
  456. package/dist/utils/clone-scene-graph.d.ts +7 -4
  457. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  458. package/dist/utils/clone-scene-graph.js +29 -7
  459. package/dist/utils/clone-scene-graph.test.d.ts +2 -0
  460. package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
  461. package/dist/utils/clone-scene-graph.test.js +62 -0
  462. package/dist/utils/heal-scene-graph.d.ts +18 -0
  463. package/dist/utils/heal-scene-graph.d.ts.map +1 -0
  464. package/dist/utils/heal-scene-graph.js +90 -0
  465. package/dist/utils/heal-scene-graph.test.d.ts +2 -0
  466. package/dist/utils/heal-scene-graph.test.d.ts.map +1 -0
  467. package/dist/utils/heal-scene-graph.test.js +88 -0
  468. package/dist/validation/validate-build-json.d.ts +44 -0
  469. package/dist/validation/validate-build-json.d.ts.map +1 -0
  470. package/dist/validation/validate-build-json.js +256 -0
  471. package/package.json +11 -4
@@ -0,0 +1,67 @@
1
+ import type { AnyNode, AnyNodeId } from '../schema/types';
2
+ /** A flat live-scene subtree rooted at `root`. */
3
+ export type Subtree = {
4
+ /** The root node, exactly as stored in `useScene.nodes[rootId]`. */
5
+ root: AnyNode;
6
+ /** Every descendant reachable from `root` via the data-model `children` array, in BFS order. */
7
+ descendants: AnyNode[];
8
+ };
9
+ /**
10
+ * Collect the subtree of nodes rooted at `rootId` from the live scene.
11
+ *
12
+ * - BFS walk via `node.children` arrays — order is stable and matches
13
+ * declaration order on container kinds.
14
+ * - Returns the live node references (not clones). Cheap; the caller
15
+ * chooses whether to deep-clone for persistence.
16
+ * - Returns `null` if `rootId` is missing.
17
+ */
18
+ export declare function collectSubtree(nodes: Readonly<Record<AnyNodeId, AnyNode>>, rootId: AnyNodeId): Subtree | null;
19
+ export type CloneNodesIntoOptions = {
20
+ /**
21
+ * The id of the root node within `nodes` (i.e. the node whose
22
+ * `parentId` becomes `parentId` in the destination instead of being
23
+ * remapped to a sibling's fresh id). Required because `nodes` is a
24
+ * flat array — there's no other way to mark which one is the root.
25
+ */
26
+ rootId: AnyNodeId;
27
+ /**
28
+ * Parent for the cloned root in the destination scene. When omitted,
29
+ * the root is inserted as a scene root (its `parentId` becomes the
30
+ * preserved value, often `null`).
31
+ */
32
+ parentId?: AnyNodeId;
33
+ /**
34
+ * Optional override for the cloned root's `position` (most placement
35
+ * flows stamp the cursor / target point here). When omitted, the
36
+ * root's own `position` field is preserved verbatim. Descendants
37
+ * always keep their original positions — those are local to the root.
38
+ */
39
+ position?: readonly [number, number, number];
40
+ };
41
+ export type CloneNodesIntoResult = {
42
+ /** Fresh id assigned to the root in the destination scene. */
43
+ rootId: AnyNodeId;
44
+ /** Every cloned node, root first, ready to feed into `createNodes`. */
45
+ nodes: AnyNode[];
46
+ /** Original id → fresh id map, mostly useful for tests and host-side bookkeeping. */
47
+ idMap: Map<AnyNodeId, AnyNodeId>;
48
+ };
49
+ /**
50
+ * Clone a flat array of nodes with fresh IDs and rewired references,
51
+ * ready to insert via `useScene.createNodes`.
52
+ *
53
+ * Transformations applied:
54
+ * 1. Deep-clone each node via JSON round-trip (strips three.js refs,
55
+ * functions, circular links — same trick `cloneLevelSubtree` uses).
56
+ * 2. Mint a fresh id for every node, preserving the prefix
57
+ * (`wall_…`, `door_…`, etc.) so logs and lookups stay readable.
58
+ * 3. Rewrite `parentId`, `children[]` to use the fresh ids.
59
+ * 4. Stamp `position` onto the root if provided.
60
+ * 5. Set the root's `parentId` to `opts.parentId` when supplied.
61
+ *
62
+ * Intentionally generic — no awareness of host refs (`wallId`/`wallT`
63
+ * etc.). The caller is responsible for stripping or re-deriving those
64
+ * before / after calling this function. See `getHostRefFields(def)`.
65
+ */
66
+ export declare function cloneNodesInto(nodes: ReadonlyArray<AnyNode>, opts: CloneNodesIntoOptions): CloneNodesIntoResult;
67
+ //# sourceMappingURL=subtree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subtree.d.ts","sourceRoot":"","sources":["../../src/registry/subtree.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAmBzD,kDAAkD;AAClD,MAAM,MAAM,OAAO,GAAG;IACpB,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;IACb,gGAAgG;IAChG,WAAW,EAAE,OAAO,EAAE,CAAA;CACvB,CAAA;AAcD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAC3C,MAAM,EAAE,SAAS,GAChB,OAAO,GAAG,IAAI,CAmBhB;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;OAKG;IACH,MAAM,EAAE,SAAS,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,8DAA8D;IAC9D,MAAM,EAAE,SAAS,CAAA;IACjB,uEAAuE;IACvE,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,qFAAqF;IACrF,KAAK,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CACjC,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,IAAI,EAAE,qBAAqB,GAC1B,oBAAoB,CAiEtB"}
@@ -0,0 +1,123 @@
1
+ import { remapMeasurementReferences } from '../lib/measurement-geometry';
2
+ import { generateId } from '../schema/base';
3
+ function extractIdPrefix(id) {
4
+ const i = id.indexOf('_');
5
+ return i === -1 ? 'node' : id.slice(0, i);
6
+ }
7
+ function getChildIds(node) {
8
+ if ('children' in node && Array.isArray(node.children)) {
9
+ return node.children;
10
+ }
11
+ return [];
12
+ }
13
+ /**
14
+ * Collect the subtree of nodes rooted at `rootId` from the live scene.
15
+ *
16
+ * - BFS walk via `node.children` arrays — order is stable and matches
17
+ * declaration order on container kinds.
18
+ * - Returns the live node references (not clones). Cheap; the caller
19
+ * chooses whether to deep-clone for persistence.
20
+ * - Returns `null` if `rootId` is missing.
21
+ */
22
+ export function collectSubtree(nodes, rootId) {
23
+ const root = nodes[rootId];
24
+ if (!root)
25
+ return null;
26
+ const descendants = [];
27
+ const seen = new Set([rootId]);
28
+ const queue = [...getChildIds(root)];
29
+ let head = 0;
30
+ while (head < queue.length) {
31
+ const id = queue[head++];
32
+ if (seen.has(id))
33
+ continue;
34
+ const node = nodes[id];
35
+ if (!node)
36
+ continue;
37
+ seen.add(id);
38
+ descendants.push(node);
39
+ for (const childId of getChildIds(node))
40
+ queue.push(childId);
41
+ }
42
+ return { root, descendants };
43
+ }
44
+ /**
45
+ * Clone a flat array of nodes with fresh IDs and rewired references,
46
+ * ready to insert via `useScene.createNodes`.
47
+ *
48
+ * Transformations applied:
49
+ * 1. Deep-clone each node via JSON round-trip (strips three.js refs,
50
+ * functions, circular links — same trick `cloneLevelSubtree` uses).
51
+ * 2. Mint a fresh id for every node, preserving the prefix
52
+ * (`wall_…`, `door_…`, etc.) so logs and lookups stay readable.
53
+ * 3. Rewrite `parentId`, `children[]` to use the fresh ids.
54
+ * 4. Stamp `position` onto the root if provided.
55
+ * 5. Set the root's `parentId` to `opts.parentId` when supplied.
56
+ *
57
+ * Intentionally generic — no awareness of host refs (`wallId`/`wallT`
58
+ * etc.). The caller is responsible for stripping or re-deriving those
59
+ * before / after calling this function. See `getHostRefFields(def)`.
60
+ */
61
+ export function cloneNodesInto(nodes, opts) {
62
+ // Phase 1 — mint fresh ids for every node, preserving the prefix.
63
+ const idMap = new Map();
64
+ for (const node of nodes) {
65
+ const prefix = extractIdPrefix(node.id);
66
+ idMap.set(node.id, generateId(prefix));
67
+ }
68
+ const rootFreshId = idMap.get(opts.rootId);
69
+ if (!rootFreshId) {
70
+ throw new Error(`cloneNodesInto: rootId "${opts.rootId}" not found in supplied nodes array`);
71
+ }
72
+ // Phase 2 — clone each node + rewire references.
73
+ const out = [];
74
+ let root = null;
75
+ for (const original of nodes) {
76
+ const cloned = JSON.parse(JSON.stringify(original));
77
+ const freshId = idMap.get(original.id);
78
+ cloned.id = freshId;
79
+ // parentId: root's parentId becomes opts.parentId (or preserved
80
+ // value if not supplied). Descendants point at the remapped parent.
81
+ if (original.id === opts.rootId) {
82
+ ;
83
+ cloned.parentId =
84
+ opts.parentId !== undefined
85
+ ? opts.parentId
86
+ : (cloned.parentId ?? null);
87
+ }
88
+ else if (cloned.parentId) {
89
+ const parentFresh = idMap.get(cloned.parentId);
90
+ cloned.parentId = parentFresh ?? null;
91
+ }
92
+ // children[]: remap any internal references, drop external ones
93
+ // (a descendant pointing at a sibling that didn't make it into
94
+ // `nodes` would dangle — `filter` drops those gracefully).
95
+ if ('children' in cloned && Array.isArray(cloned.children)) {
96
+ ;
97
+ cloned.children = cloned.children
98
+ .map((cid) => idMap.get(cid))
99
+ .filter((cid) => cid !== undefined);
100
+ }
101
+ if (cloned.type === 'measurement') {
102
+ cloned.measurement = remapMeasurementReferences(cloned.measurement, idMap);
103
+ }
104
+ if (original.id === opts.rootId) {
105
+ if (opts.position) {
106
+ ;
107
+ cloned.position = [
108
+ opts.position[0],
109
+ opts.position[1],
110
+ opts.position[2],
111
+ ];
112
+ }
113
+ root = cloned;
114
+ }
115
+ else {
116
+ out.push(cloned);
117
+ }
118
+ }
119
+ if (!root) {
120
+ throw new Error('cloneNodesInto: root node missing after clone');
121
+ }
122
+ return { rootId: rootFreshId, nodes: [root, ...out], idMap };
123
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subtree.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subtree.test.d.ts","sourceRoot":"","sources":["../../src/registry/subtree.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,163 @@
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
+ });