@faicad/faijs 0.22.2 → 0.29.3

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 (448) hide show
  1. package/LICENSE +202 -28
  2. package/dist/api/api-namespace.d.ts +5 -5
  3. package/dist/api/api-namespace.d.ts.map +1 -1
  4. package/dist/api/api-namespace.js +4 -4
  5. package/dist/api/api-namespace.js.map +1 -1
  6. package/dist/api/assert.d.ts +2 -2
  7. package/dist/api/assert.js +8 -8
  8. package/dist/api/assert.js.map +1 -1
  9. package/dist/api/asset.d.ts +1 -1
  10. package/dist/api/asset.js +2 -2
  11. package/dist/api/asset.js.map +1 -1
  12. package/dist/api/boolean.d.ts +1 -1
  13. package/dist/api/boolean.d.ts.map +1 -1
  14. package/dist/api/boolean.js +128 -16
  15. package/dist/api/boolean.js.map +1 -1
  16. package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
  17. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
  18. package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
  19. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
  20. package/dist/api/cadquery-selectors/edge.d.ts +40 -0
  21. package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
  22. package/dist/api/cadquery-selectors/edge.js +70 -0
  23. package/dist/api/cadquery-selectors/edge.js.map +1 -0
  24. package/dist/api/cadquery-selectors/entity.d.ts +121 -0
  25. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
  26. package/dist/api/cadquery-selectors/entity.js +167 -0
  27. package/dist/api/cadquery-selectors/entity.js.map +1 -0
  28. package/dist/api/cadquery-selectors/face.d.ts +33 -0
  29. package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
  30. package/dist/api/cadquery-selectors/face.js +353 -0
  31. package/dist/api/cadquery-selectors/face.js.map +1 -0
  32. package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
  33. package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
  34. package/dist/api/cadquery-selectors/grammar.js +345 -0
  35. package/dist/api/cadquery-selectors/grammar.js.map +1 -0
  36. package/dist/api/cadquery-selectors/index.d.ts +18 -0
  37. package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
  38. package/dist/api/cadquery-selectors/index.js +17 -0
  39. package/dist/api/cadquery-selectors/index.js.map +1 -0
  40. package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
  41. package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
  42. package/dist/api/cadquery-selectors/predicates.js +85 -0
  43. package/dist/api/cadquery-selectors/predicates.js.map +1 -0
  44. package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
  45. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
  46. package/dist/api/cadquery-selectors/resolve.js +243 -0
  47. package/dist/api/cadquery-selectors/resolve.js.map +1 -0
  48. package/dist/api/cadquery-selectors/types.d.ts +96 -0
  49. package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
  50. package/dist/api/cadquery-selectors/types.js +11 -0
  51. package/dist/api/cadquery-selectors/types.js.map +1 -0
  52. package/dist/api/chamfer.d.ts +13 -5
  53. package/dist/api/chamfer.d.ts.map +1 -1
  54. package/dist/api/chamfer.js +63 -7
  55. package/dist/api/chamfer.js.map +1 -1
  56. package/dist/api/compound-geom.d.ts +1 -1
  57. package/dist/api/compound-geom.js +1 -1
  58. package/dist/api/compound-geom.js.map +1 -1
  59. package/dist/api/draft.d.ts +1 -1
  60. package/dist/api/draft.js +1 -1
  61. package/dist/api/draft.js.map +1 -1
  62. package/dist/api/edge-ref.d.ts +1 -1
  63. package/dist/api/edge-ref.d.ts.map +1 -1
  64. package/dist/api/edge-ref.js +11 -3
  65. package/dist/api/edge-ref.js.map +1 -1
  66. package/dist/api/engrave.d.ts +1 -1
  67. package/dist/api/engrave.js +7 -7
  68. package/dist/api/engrave.js.map +1 -1
  69. package/dist/api/extrude.d.ts +6 -1
  70. package/dist/api/extrude.d.ts.map +1 -1
  71. package/dist/api/extrude.js +59 -5
  72. package/dist/api/extrude.js.map +1 -1
  73. package/dist/api/face-ref.d.ts +1 -1
  74. package/dist/api/face-ref.js +1 -1
  75. package/dist/api/face-ref.js.map +1 -1
  76. package/dist/api/feature-repair.d.ts +1 -1
  77. package/dist/api/feature-repair.js +1 -1
  78. package/dist/api/feature-repair.js.map +1 -1
  79. package/dist/api/fillet-variable.d.ts +1 -1
  80. package/dist/api/fillet-variable.js +1 -1
  81. package/dist/api/fillet-variable.js.map +1 -1
  82. package/dist/api/fillet.d.ts +28 -8
  83. package/dist/api/fillet.d.ts.map +1 -1
  84. package/dist/api/fillet.js +64 -9
  85. package/dist/api/fillet.js.map +1 -1
  86. package/dist/api/geom.d.ts +1 -1
  87. package/dist/api/geom.js +1 -1
  88. package/dist/api/geom.js.map +1 -1
  89. package/dist/api/helix.d.ts +1 -1
  90. package/dist/api/helix.js +1 -1
  91. package/dist/api/helix.js.map +1 -1
  92. package/dist/api/import-brep.d.ts +20 -2
  93. package/dist/api/import-brep.d.ts.map +1 -1
  94. package/dist/api/import-brep.js +28 -3
  95. package/dist/api/import-brep.js.map +1 -1
  96. package/dist/api/import-step.d.ts +17 -2
  97. package/dist/api/import-step.d.ts.map +1 -1
  98. package/dist/api/import-step.js +23 -3
  99. package/dist/api/import-step.js.map +1 -1
  100. package/dist/api/index.d.ts +2 -1
  101. package/dist/api/index.d.ts.map +1 -1
  102. package/dist/api/index.js +5 -2
  103. package/dist/api/index.js.map +1 -1
  104. package/dist/api/internal/compat-op.js +1 -1
  105. package/dist/api/internal/compat-op.js.map +1 -1
  106. package/dist/api/internal/mesh-solid-op.d.ts +236 -0
  107. package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
  108. package/dist/api/internal/mesh-solid-op.js +352 -0
  109. package/dist/api/internal/mesh-solid-op.js.map +1 -0
  110. package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
  111. package/dist/api/internal/svg-asset-resolver.js +1 -1
  112. package/dist/api/internal/svg-asset-resolver.js.map +1 -1
  113. package/dist/api/knurl.d.ts +1 -1
  114. package/dist/api/knurl.js +2 -2
  115. package/dist/api/knurl.js.map +1 -1
  116. package/dist/api/loft.d.ts +1 -1
  117. package/dist/api/loft.js +1 -1
  118. package/dist/api/loft.js.map +1 -1
  119. package/dist/api/measurement/index.d.ts +9 -5
  120. package/dist/api/measurement/index.d.ts.map +1 -1
  121. package/dist/api/measurement/index.js +47 -20
  122. package/dist/api/measurement/index.js.map +1 -1
  123. package/dist/api/pattern.d.ts +5 -3
  124. package/dist/api/pattern.d.ts.map +1 -1
  125. package/dist/api/pattern.js +32 -4
  126. package/dist/api/pattern.js.map +1 -1
  127. package/dist/api/place.d.ts +1 -1
  128. package/dist/api/place.js +1 -1
  129. package/dist/api/place.js.map +1 -1
  130. package/dist/api/primitives.d.ts +1 -1
  131. package/dist/api/primitives.js +2 -2
  132. package/dist/api/primitives.js.map +1 -1
  133. package/dist/api/profile.d.ts +39 -12
  134. package/dist/api/profile.d.ts.map +1 -1
  135. package/dist/api/profile.js +4 -4
  136. package/dist/api/profile.js.map +1 -1
  137. package/dist/api/reconcile.d.ts +1 -1
  138. package/dist/api/reconcile.js +1 -1
  139. package/dist/api/reconcile.js.map +1 -1
  140. package/dist/api/replicate.d.ts.map +1 -1
  141. package/dist/api/replicate.js +122 -1
  142. package/dist/api/replicate.js.map +1 -1
  143. package/dist/api/screw.d.ts +1 -1
  144. package/dist/api/screw.js +3 -3
  145. package/dist/api/screw.js.map +1 -1
  146. package/dist/api/sdf.d.ts +1 -1
  147. package/dist/api/sdf.js +2 -2
  148. package/dist/api/sdf.js.map +1 -1
  149. package/dist/api/section-by-plane.d.ts +1 -1
  150. package/dist/api/section-by-plane.d.ts.map +1 -1
  151. package/dist/api/section-by-plane.js +2 -1
  152. package/dist/api/section-by-plane.js.map +1 -1
  153. package/dist/api/shell.d.ts +11 -4
  154. package/dist/api/shell.d.ts.map +1 -1
  155. package/dist/api/shell.js +53 -7
  156. package/dist/api/shell.js.map +1 -1
  157. package/dist/api/sketch-on-face.d.ts +41 -0
  158. package/dist/api/sketch-on-face.d.ts.map +1 -1
  159. package/dist/api/sketch-on-face.js +100 -1
  160. package/dist/api/sketch-on-face.js.map +1 -1
  161. package/dist/api/sketch-on-plane.d.ts +7 -5
  162. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  163. package/dist/api/sketch-on-plane.js +6 -7
  164. package/dist/api/sketch-on-plane.js.map +1 -1
  165. package/dist/api/split-by-plane.d.ts +1 -1
  166. package/dist/api/split-by-plane.d.ts.map +1 -1
  167. package/dist/api/split-by-plane.js +2 -1
  168. package/dist/api/split-by-plane.js.map +1 -1
  169. package/dist/api/split.d.ts +1 -1
  170. package/dist/api/split.js +2 -2
  171. package/dist/api/split.js.map +1 -1
  172. package/dist/api/sweep.d.ts +1 -1
  173. package/dist/api/sweep.js +1 -1
  174. package/dist/api/sweep.js.map +1 -1
  175. package/dist/api/thicken.d.ts +1 -1
  176. package/dist/api/thicken.js +1 -1
  177. package/dist/api/thicken.js.map +1 -1
  178. package/dist/api/topo-resolve.d.ts +74 -1
  179. package/dist/api/topo-resolve.d.ts.map +1 -1
  180. package/dist/api/topo-resolve.js +180 -2
  181. package/dist/api/topo-resolve.js.map +1 -1
  182. package/dist/api/transform.d.ts +5 -1
  183. package/dist/api/transform.d.ts.map +1 -1
  184. package/dist/api/transform.js +62 -11
  185. package/dist/api/transform.js.map +1 -1
  186. package/dist/api/wire.d.ts +1 -1
  187. package/dist/api/wire.js +1 -1
  188. package/dist/api/wire.js.map +1 -1
  189. package/dist/brep/brep-ops.d.ts +9 -7
  190. package/dist/brep/brep-ops.d.ts.map +1 -1
  191. package/dist/brep/brep-ops.js +23 -24
  192. package/dist/brep/brep-ops.js.map +1 -1
  193. package/dist/brep/brep-topology.d.ts +5 -4
  194. package/dist/brep/brep-topology.d.ts.map +1 -1
  195. package/dist/brep/brep-topology.js +6 -5
  196. package/dist/brep/brep-topology.js.map +1 -1
  197. package/dist/brep/effective-deflection.d.ts +35 -0
  198. package/dist/brep/effective-deflection.d.ts.map +1 -0
  199. package/dist/brep/effective-deflection.js +49 -0
  200. package/dist/brep/effective-deflection.js.map +1 -0
  201. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  202. package/dist/brep/engine/adapters/brep-mock.js +27 -0
  203. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  204. package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
  205. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  206. package/dist/brep/engine/adapters/brepkit.js +46 -1
  207. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  208. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  209. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  210. package/dist/brep/engine/adapters/occt.js +3 -1
  211. package/dist/brep/engine/adapters/occt.js.map +1 -1
  212. package/dist/brep/engine/primitives.d.ts +29 -7
  213. package/dist/brep/engine/primitives.d.ts.map +1 -1
  214. package/dist/brep/engine/primitives.js.map +1 -1
  215. package/dist/brep/engine/registry.d.ts +24 -1
  216. package/dist/brep/engine/registry.d.ts.map +1 -1
  217. package/dist/brep/engine/registry.js +24 -0
  218. package/dist/brep/engine/registry.js.map +1 -1
  219. package/dist/brep/engine/types.d.ts +54 -3
  220. package/dist/brep/engine/types.d.ts.map +1 -1
  221. package/dist/brep/engine/types.js +10 -0
  222. package/dist/brep/engine/types.js.map +1 -1
  223. package/dist/brep/export/export-model.d.ts.map +1 -1
  224. package/dist/brep/export/export-model.js +6 -5
  225. package/dist/brep/export/export-model.js.map +1 -1
  226. package/dist/brep/face-evolution.d.ts +1 -1
  227. package/dist/brep/face-evolution.d.ts.map +1 -1
  228. package/dist/brep/face-evolution.js +20 -1
  229. package/dist/brep/face-evolution.js.map +1 -1
  230. package/dist/brep/handle-bridge.d.ts +1 -1
  231. package/dist/brep/handle-bridge.js +1 -1
  232. package/dist/brep/handle-bridge.js.map +1 -1
  233. package/dist/brep/mesh-solid.d.ts +218 -0
  234. package/dist/brep/mesh-solid.d.ts.map +1 -0
  235. package/dist/brep/mesh-solid.js +229 -0
  236. package/dist/brep/mesh-solid.js.map +1 -0
  237. package/dist/brep/text/fontRegistry.d.ts +32 -1
  238. package/dist/brep/text/fontRegistry.d.ts.map +1 -1
  239. package/dist/brep/text/fontRegistry.js +51 -1
  240. package/dist/brep/text/fontRegistry.js.map +1 -1
  241. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  242. package/dist/brep/text/text-to-solid.js +8 -3
  243. package/dist/brep/text/text-to-solid.js.map +1 -1
  244. package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
  245. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  246. package/dist/brepkit-kernel/brepkitKernel.js +449 -123
  247. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  248. package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
  249. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  250. package/dist/brepkit-kernel/brepkitWasm.js +10 -0
  251. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  252. package/dist/browser-host/browser-font-provider.d.ts +12 -0
  253. package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
  254. package/dist/browser-host/browser-font-provider.js +25 -0
  255. package/dist/browser-host/browser-font-provider.js.map +1 -1
  256. package/dist/browser.d.ts +6 -3
  257. package/dist/browser.d.ts.map +1 -1
  258. package/dist/browser.js +10 -3
  259. package/dist/browser.js.map +1 -1
  260. package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
  261. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  262. package/dist/cad-runtime/backend-dispatch.js +119 -4
  263. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  264. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  265. package/dist/cad-runtime/direct-executor.d.ts +15 -3
  266. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  267. package/dist/cad-runtime/direct-executor.js +33 -1
  268. package/dist/cad-runtime/direct-executor.js.map +1 -1
  269. package/dist/cad-runtime/ports.d.ts +3 -3
  270. package/dist/cad-runtime/ports.d.ts.map +1 -1
  271. package/dist/cad-runtime/ports.js.map +1 -1
  272. package/dist/cad-runtime/preview-exec.d.ts +4 -4
  273. package/dist/cad-runtime/preview-exec.js +2 -2
  274. package/dist/cad-runtime/preview-exec.js.map +1 -1
  275. package/dist/cad-runtime/runtime.d.ts +42 -7
  276. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  277. package/dist/cad-runtime/runtime.js +68 -5
  278. package/dist/cad-runtime/runtime.js.map +1 -1
  279. package/dist/define-op.d.ts +15 -1
  280. package/dist/define-op.d.ts.map +1 -1
  281. package/dist/define-op.js +10 -1
  282. package/dist/define-op.js.map +1 -1
  283. package/dist/env-agnostic.d.ts +2 -2
  284. package/dist/env-agnostic.d.ts.map +1 -1
  285. package/dist/env-agnostic.js +1 -1
  286. package/dist/env-agnostic.js.map +1 -1
  287. package/dist/geometry2d/adapt.d.ts +39 -4
  288. package/dist/geometry2d/adapt.d.ts.map +1 -1
  289. package/dist/geometry2d/adapt.js +14 -3
  290. package/dist/geometry2d/adapt.js.map +1 -1
  291. package/dist/geometry2d/blueprint.d.ts +2 -2
  292. package/dist/geometry2d/blueprint.js +2 -2
  293. package/dist/geometry2d/blueprint.js.map +1 -1
  294. package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
  295. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  296. package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
  297. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  298. package/dist/geometry2d/bridge/plane.d.ts +17 -0
  299. package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
  300. package/dist/geometry2d/bridge/plane.js +22 -0
  301. package/dist/geometry2d/bridge/plane.js.map +1 -1
  302. package/dist/geometry2d/curve2d.d.ts +25 -0
  303. package/dist/geometry2d/curve2d.d.ts.map +1 -1
  304. package/dist/geometry2d/curve2d.js +41 -5
  305. package/dist/geometry2d/curve2d.js.map +1 -1
  306. package/dist/index.d.ts +6 -2
  307. package/dist/index.d.ts.map +1 -1
  308. package/dist/index.js +10 -3
  309. package/dist/index.js.map +1 -1
  310. package/dist/io/bytes-node.d.ts +11 -0
  311. package/dist/io/bytes-node.d.ts.map +1 -0
  312. package/dist/io/bytes-node.js +28 -0
  313. package/dist/io/bytes-node.js.map +1 -0
  314. package/dist/io/bytes.d.ts +33 -0
  315. package/dist/io/bytes.d.ts.map +1 -0
  316. package/dist/io/bytes.js +41 -0
  317. package/dist/io/bytes.js.map +1 -0
  318. package/dist/io/fai-zip/container-read.d.ts +102 -0
  319. package/dist/io/fai-zip/container-read.d.ts.map +1 -0
  320. package/dist/io/fai-zip/container-read.js +305 -0
  321. package/dist/io/fai-zip/container-read.js.map +1 -0
  322. package/dist/io/fai-zip/container-write.d.ts +70 -0
  323. package/dist/io/fai-zip/container-write.d.ts.map +1 -0
  324. package/dist/io/fai-zip/container-write.js +186 -0
  325. package/dist/io/fai-zip/container-write.js.map +1 -0
  326. package/dist/io/fai-zip/container.d.ts +107 -0
  327. package/dist/io/fai-zip/container.d.ts.map +1 -0
  328. package/dist/io/fai-zip/container.js +89 -0
  329. package/dist/io/fai-zip/container.js.map +1 -0
  330. package/dist/io/fai-zip/index.d.ts +18 -0
  331. package/dist/io/fai-zip/index.d.ts.map +1 -0
  332. package/dist/io/fai-zip/index.js +4 -0
  333. package/dist/io/fai-zip/index.js.map +1 -0
  334. package/dist/io/index.d.ts +10 -0
  335. package/dist/io/index.d.ts.map +1 -0
  336. package/dist/io/index.js +13 -0
  337. package/dist/io/index.js.map +1 -0
  338. package/dist/io/zip.d.ts +68 -0
  339. package/dist/io/zip.d.ts.map +1 -0
  340. package/dist/io/zip.js +147 -0
  341. package/dist/io/zip.js.map +1 -0
  342. package/dist/lang/code-to-args.d.ts +1 -1
  343. package/dist/lang/code-to-args.js +1 -1
  344. package/dist/lang/code-to-args.js.map +1 -1
  345. package/dist/lang/statement-summary.d.ts +1 -1
  346. package/dist/lang/statement-summary.js +1 -1
  347. package/dist/lang/statement-summary.js.map +1 -1
  348. package/dist/lang/types.d.ts +1 -1
  349. package/dist/lang/types.js +1 -1
  350. package/dist/lang/types.js.map +1 -1
  351. package/dist/mesh/index.d.ts +2 -1
  352. package/dist/mesh/index.d.ts.map +1 -1
  353. package/dist/mesh/index.js +2 -1
  354. package/dist/mesh/index.js.map +1 -1
  355. package/dist/mesh/io.d.ts +7 -0
  356. package/dist/mesh/io.d.ts.map +1 -1
  357. package/dist/mesh/io.js +14 -17
  358. package/dist/mesh/io.js.map +1 -1
  359. package/dist/mesh/reconcile.d.ts +1 -1
  360. package/dist/mesh/reconcile.js +1 -1
  361. package/dist/mesh/reconcile.js.map +1 -1
  362. package/dist/mesh/rigid-transform.d.ts +3 -3
  363. package/dist/mesh/rigid-transform.js +3 -3
  364. package/dist/mesh/rigid-transform.js.map +1 -1
  365. package/dist/mesh/stl-unit.d.ts +24 -0
  366. package/dist/mesh/stl-unit.d.ts.map +1 -0
  367. package/dist/mesh/stl-unit.js +17 -0
  368. package/dist/mesh/stl-unit.js.map +1 -0
  369. package/dist/mesh/threemf-bambu.d.ts +142 -0
  370. package/dist/mesh/threemf-bambu.d.ts.map +1 -0
  371. package/dist/mesh/threemf-bambu.js +334 -0
  372. package/dist/mesh/threemf-bambu.js.map +1 -0
  373. package/dist/mesh/threemf-loader.d.ts +42 -7
  374. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  375. package/dist/mesh/threemf-loader.js +565 -100
  376. package/dist/mesh/threemf-loader.js.map +1 -1
  377. package/dist/mesh/threemf-view.d.ts +71 -0
  378. package/dist/mesh/threemf-view.d.ts.map +1 -0
  379. package/dist/mesh/threemf-view.js +100 -0
  380. package/dist/mesh/threemf-view.js.map +1 -0
  381. package/dist/node-host/cli.d.ts +44 -6
  382. package/dist/node-host/cli.d.ts.map +1 -1
  383. package/dist/node-host/cli.js +76 -26
  384. package/dist/node-host/cli.js.map +1 -1
  385. package/dist/node-host/font-family-index.d.ts +93 -0
  386. package/dist/node-host/font-family-index.d.ts.map +1 -0
  387. package/dist/node-host/font-family-index.js +273 -0
  388. package/dist/node-host/font-family-index.js.map +1 -0
  389. package/dist/node-host/fs-asset-resolver.d.ts +8 -3
  390. package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
  391. package/dist/node-host/fs-asset-resolver.js +13 -5
  392. package/dist/node-host/fs-asset-resolver.js.map +1 -1
  393. package/dist/node-host/index.d.ts +8 -0
  394. package/dist/node-host/index.d.ts.map +1 -1
  395. package/dist/node-host/index.js +1 -0
  396. package/dist/node-host/index.js.map +1 -1
  397. package/dist/node-host/node-font-provider.d.ts +28 -0
  398. package/dist/node-host/node-font-provider.d.ts.map +1 -1
  399. package/dist/node-host/node-font-provider.js +49 -0
  400. package/dist/node-host/node-font-provider.js.map +1 -1
  401. package/dist/node.d.ts +1 -0
  402. package/dist/node.d.ts.map +1 -1
  403. package/dist/node.js +1 -0
  404. package/dist/node.js.map +1 -1
  405. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  406. package/dist/occt-kernel/occt-primitives.js +35 -2
  407. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  408. package/dist/occt-kernel/occtKernel.d.ts +18 -13
  409. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  410. package/dist/occt-kernel/occtKernel.js +18 -31
  411. package/dist/occt-kernel/occtKernel.js.map +1 -1
  412. package/dist/occt-kernel/stepColorParser.d.ts +18 -0
  413. package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
  414. package/dist/occt-kernel/stepColorParser.js +38 -0
  415. package/dist/occt-kernel/stepColorParser.js.map +1 -1
  416. package/dist/occt-kernel/topologyExt.d.ts +1 -1
  417. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  418. package/dist/occt-kernel/topologyExt.js +4 -5
  419. package/dist/occt-kernel/topologyExt.js.map +1 -1
  420. package/dist/primitives/text/cjk-font.d.ts +2 -15
  421. package/dist/primitives/text/cjk-font.d.ts.map +1 -1
  422. package/dist/primitives/text/cjk-font.js +13 -1
  423. package/dist/primitives/text/cjk-font.js.map +1 -1
  424. package/dist/runtime-state.d.ts +85 -9
  425. package/dist/runtime-state.d.ts.map +1 -1
  426. package/dist/runtime-state.js +72 -2
  427. package/dist/runtime-state.js.map +1 -1
  428. package/dist/sdk.d.ts +3 -3
  429. package/dist/sdk.d.ts.map +1 -1
  430. package/dist/sdk.js +5 -5
  431. package/dist/sdk.js.map +1 -1
  432. package/dist/shape.d.ts +97 -2
  433. package/dist/shape.d.ts.map +1 -1
  434. package/dist/shape.js +126 -1
  435. package/dist/shape.js.map +1 -1
  436. package/dist/topology/naming/lineage.d.ts +6 -0
  437. package/dist/topology/naming/lineage.d.ts.map +1 -1
  438. package/dist/topology/naming/lineage.js +8 -0
  439. package/dist/topology/naming/lineage.js.map +1 -1
  440. package/dist/topology/naming/resolve-edge.d.ts +20 -1
  441. package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
  442. package/dist/topology/naming/resolve-edge.js +54 -20
  443. package/dist/topology/naming/resolve-edge.js.map +1 -1
  444. package/dist/weapp.d.ts +6 -2
  445. package/dist/weapp.d.ts.map +1 -1
  446. package/dist/weapp.js +7 -1
  447. package/dist/weapp.js.map +1 -1
  448. package/package.json +18 -2
@@ -0,0 +1,13 @@
1
+ /**
2
+ * io — unified ZIP container IO for faijs (and the host).
3
+ *
4
+ * Single read/write entry for ZIP bytes; every downstream consumer (3MF loader,
5
+ * export-model writer, fcstd, demo) should use these rather than fflate
6
+ * directly. See `io/zip.ts` for the behaviour contract.
7
+ */
8
+ export { readZipEntries, readZipEntriesAsync, writeZipEntries, writeZipEntriesAsync, DEFAULT_MAX_ENTRIES, DEFAULT_MAX_TOTAL_BYTES, } from './zip.js';
9
+ // toArrayBuffer is browser-safe; readFileArrayBuffer is Node-only and lives in
10
+ // bytes-node.ts — exporting it here would pull node:fs into browser bundles
11
+ // (seen as a hard rollup error in the 3d_editor web build).
12
+ export { toArrayBuffer } from './bytes.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,GAExB,MAAM,OAAO,CAAA;AACd,+EAA+E;AAC/E,4EAA4E;AAC5E,4DAA4D;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA","sourcesContent":["/**\n * io — unified ZIP container IO for faijs (and the host).\n *\n * Single read/write entry for ZIP bytes; every downstream consumer (3MF loader,\n * export-model writer, fcstd, demo) should use these rather than fflate\n * directly. See `io/zip.ts` for the behaviour contract.\n */\nexport {\n readZipEntries,\n readZipEntriesAsync,\n writeZipEntries,\n writeZipEntriesAsync,\n DEFAULT_MAX_ENTRIES,\n DEFAULT_MAX_TOTAL_BYTES,\n type ZipReadOptions,\n} from './zip'\n// toArrayBuffer is browser-safe; readFileArrayBuffer is Node-only and lives in\n// bytes-node.ts — exporting it here would pull node:fs into browser bundles\n// (seen as a hard rollup error in the 3d_editor web build).\nexport { toArrayBuffer } from './bytes'\n"]}
@@ -0,0 +1,68 @@
1
+ /** fflate's valid compression levels. */
2
+ export type ZipLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
3
+ /** Default compression level used by the sync/async writers. */
4
+ export declare const DEFAULT_ZIP_LEVEL: ZipLevel;
5
+ /** Read-side caps bounding what a single read materialises. */
6
+ export interface ZipReadOptions {
7
+ /** Max entry count; default `DEFAULT_MAX_ENTRIES` (9999). */
8
+ maxEntries?: number;
9
+ /** Max total uncompressed bytes; default `DEFAULT_MAX_TOTAL_BYTES` (512 MiB). */
10
+ maxTotalBytes?: number;
11
+ }
12
+ /**
13
+ * Default cap on the number of entries a single read materialises. Deliberately
14
+ * generous: loading a project container is not the same magnitude as a user
15
+ * picking an arbitrary file, and container members (byte-exact source shadows,
16
+ * baked `.brp` payloads) scale with the source document.
17
+ *
18
+ * NOTE these caps are *post-decompression* checks — `unzipSync` has already
19
+ * materialised the archive when they run, so they bound what a caller keeps
20
+ * and walks, not peak allocation. They are a resource budget, NOT a
21
+ * zip-bomb defence. Pre-decompression rejection would need fflate's
22
+ * `filter` (per-entry `originalSize` accounting) and is tracked separately.
23
+ */
24
+ export declare const DEFAULT_MAX_ENTRIES = 9999;
25
+ /** Default cap on total uncompressed bytes; same post-decompression caveat as {@link DEFAULT_MAX_ENTRIES}. */
26
+ export declare const DEFAULT_MAX_TOTAL_BYTES: number;
27
+ /**
28
+ * Unzip bytes to an entry table (directory entries filtered).
29
+ *
30
+ * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).
31
+ * @param opts - optional read caps (maxEntries / maxTotalBytes).
32
+ * @returns a map of archive path -> decompressed bytes.
33
+ * @throws on non-ZIP bytes or when caps are exceeded.
34
+ */
35
+ export declare function readZipEntries(data: Uint8Array | ArrayBuffer, opts?: ZipReadOptions): Map<string, Uint8Array>;
36
+ type EntryTable = Record<string, Uint8Array>;
37
+ /** Write-side options (compression level + advisory ZIP comment). */
38
+ export interface ZipWriteOptions {
39
+ /** Compression level; default `DEFAULT_ZIP_LEVEL` (6). */
40
+ level?: ZipLevel;
41
+ /** Optional ZIP comment (advisory — consumers read it via the EOCD record). */
42
+ comment?: string;
43
+ }
44
+ /**
45
+ * Zip an entry table into bytes.
46
+ *
47
+ * @param entries - archive path -> bytes to store.
48
+ * @param opts - optional compression level / ZIP comment.
49
+ * @returns the ZIP bytes.
50
+ * @throws on an empty entry table.
51
+ */
52
+ export declare function writeZipEntries(entries: EntryTable, opts?: ZipWriteOptions): Uint8Array;
53
+ /** Async read: yields to the event loop between chunks (see plan §D8).
54
+ *
55
+ * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).
56
+ * @param opts - optional read caps (maxEntries / maxTotalBytes).
57
+ * @returns a promise of the entry map.
58
+ */
59
+ export declare function readZipEntriesAsync(data: Uint8Array | ArrayBuffer, opts?: ZipReadOptions): Promise<Map<string, Uint8Array>>;
60
+ /** Zip an entry table into bytes, yielding between chunks.
61
+ *
62
+ * @param entries - archive path -> entry to store.
63
+ * @param opts - optional compression level / ZIP comment.
64
+ * @returns a promise of the ZIP bytes.
65
+ */
66
+ export declare function writeZipEntriesAsync(entries: EntryTable, opts?: ZipWriteOptions): Promise<Uint8Array>;
67
+ export {};
68
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/io/zip.ts"],"names":[],"mappings":"AAsBA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAE5D,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,EAAE,QAAY,CAAA;AAE5C,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAID;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAEvC,8GAA8G;AAC9G,eAAO,MAAM,uBAAuB,QAAoB,CAAA;AA4CxD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,GAAG,WAAW,EAC9B,IAAI,GAAE,cAAmB,GACxB,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAQzB;AAED,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAE5C,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,UAAU,CAKvF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,GAAG,WAAW,EAC9B,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAclC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,UAAU,CAAC,CAarB"}
package/dist/io/zip.js ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * io/zip — the single ZIP read/write entry for every faijs consumer.
3
+ *
4
+ * This is the one place faijs (and the host) reads and writes ZIP bytes. The
5
+ * plan unifies two previously-divergent behaviours: reading uses fflate's
6
+ * `unzipSync`, writing uses `zipSync`. Both surface as a plain entry map so
7
+ * no caller ever touches fflate's `Unzlib` / `Zip` objects directly.
8
+ *
9
+ * Contract:
10
+ * - Entries are keyed by the archive path (fflate normalises to forward
11
+ * slashes). Directory entries (keys ending in `/`) are filtered out — they
12
+ * are produced by fflate and are not data.
13
+ * - Every function throws on failure; there is no degraded return value.
14
+ * - A non-zip buffer throws `new Error('zip read failed: <msg>')`.
15
+ * - `writeZipEntries` rejects an empty entry table (never produces an empty zip).
16
+ *
17
+ * Environment: plain pure functions usable in node, browser, worker and the
18
+ * weapp worker — fflate's sync + async (callback) forms cover all of them
19
+ * (see plan D8: the async forms let the event loop yield between chunks).
20
+ */
21
+ import { zip, zipSync, unzip, unzipSync } from 'fflate';
22
+ /** Default compression level used by the sync/async writers. */
23
+ export const DEFAULT_ZIP_LEVEL = 6;
24
+ /**
25
+ * Default cap on the number of entries a single read materialises. Deliberately
26
+ * generous: loading a project container is not the same magnitude as a user
27
+ * picking an arbitrary file, and container members (byte-exact source shadows,
28
+ * baked `.brp` payloads) scale with the source document.
29
+ *
30
+ * NOTE these caps are *post-decompression* checks — `unzipSync` has already
31
+ * materialised the archive when they run, so they bound what a caller keeps
32
+ * and walks, not peak allocation. They are a resource budget, NOT a
33
+ * zip-bomb defence. Pre-decompression rejection would need fflate's
34
+ * `filter` (per-entry `originalSize` accounting) and is tracked separately.
35
+ */
36
+ export const DEFAULT_MAX_ENTRIES = 9999;
37
+ /** Default cap on total uncompressed bytes; same post-decompression caveat as {@link DEFAULT_MAX_ENTRIES}. */
38
+ export const DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;
39
+ function toBytes(data) {
40
+ return data instanceof Uint8Array ? data : new Uint8Array(data);
41
+ }
42
+ function resolveReadOptions(opts) {
43
+ return {
44
+ maxEntries: opts.maxEntries ?? DEFAULT_MAX_ENTRIES,
45
+ maxTotalBytes: opts.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES,
46
+ };
47
+ }
48
+ /** Strip directory entries (keys ending in `/`) and enforce size/entry caps. */
49
+ function normalizeEntries(raw, opts) {
50
+ const out = new Map();
51
+ let totalBytes = 0;
52
+ for (const key of Object.keys(raw)) {
53
+ if (key.endsWith('/'))
54
+ continue;
55
+ const body = raw[key];
56
+ totalBytes += body.byteLength;
57
+ if (totalBytes > opts.maxTotalBytes) {
58
+ throw new Error(`zip read failed: content exceeds limit (maxTotalBytes ${opts.maxTotalBytes})`);
59
+ }
60
+ out.set(key, body);
61
+ }
62
+ if (out.size > opts.maxEntries) {
63
+ throw new Error(`zip read failed: content exceeds limit (maxEntries ${opts.maxEntries})`);
64
+ }
65
+ return out;
66
+ }
67
+ function wrapReadError(err) {
68
+ const inner = err instanceof Error ? err.message : String(err);
69
+ const e = new Error(`zip read failed: ${inner}`);
70
+ e.cause = err;
71
+ throw e;
72
+ }
73
+ /**
74
+ * Unzip bytes to an entry table (directory entries filtered).
75
+ *
76
+ * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).
77
+ * @param opts - optional read caps (maxEntries / maxTotalBytes).
78
+ * @returns a map of archive path -> decompressed bytes.
79
+ * @throws on non-ZIP bytes or when caps are exceeded.
80
+ */
81
+ export function readZipEntries(data, opts = {}) {
82
+ let raw;
83
+ try {
84
+ raw = unzipSync(toBytes(data));
85
+ }
86
+ catch (err) {
87
+ wrapReadError(err);
88
+ }
89
+ return normalizeEntries(raw, resolveReadOptions(opts));
90
+ }
91
+ /**
92
+ * Zip an entry table into bytes.
93
+ *
94
+ * @param entries - archive path -> bytes to store.
95
+ * @param opts - optional compression level / ZIP comment.
96
+ * @returns the ZIP bytes.
97
+ * @throws on an empty entry table.
98
+ */
99
+ export function writeZipEntries(entries, opts) {
100
+ if (Object.keys(entries).length === 0) {
101
+ throw new Error('zip write failed: empty entry table');
102
+ }
103
+ return zipSync(entries, { level: opts?.level ?? DEFAULT_ZIP_LEVEL, comment: opts?.comment });
104
+ }
105
+ /** Async read: yields to the event loop between chunks (see plan §D8).
106
+ *
107
+ * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).
108
+ * @param opts - optional read caps (maxEntries / maxTotalBytes).
109
+ * @returns a promise of the entry map.
110
+ */
111
+ export function readZipEntriesAsync(data, opts = {}) {
112
+ return new Promise((resolve, reject) => {
113
+ unzip(toBytes(data), (err, raw) => {
114
+ if (err) {
115
+ reject(new Error(`zip read failed: ${err.message}`));
116
+ return;
117
+ }
118
+ try {
119
+ resolve(normalizeEntries(raw, resolveReadOptions(opts)));
120
+ }
121
+ catch (e) {
122
+ reject(e);
123
+ }
124
+ });
125
+ });
126
+ }
127
+ /** Zip an entry table into bytes, yielding between chunks.
128
+ *
129
+ * @param entries - archive path -> entry to store.
130
+ * @param opts - optional compression level / ZIP comment.
131
+ * @returns a promise of the ZIP bytes.
132
+ */
133
+ export function writeZipEntriesAsync(entries, opts) {
134
+ if (Object.keys(entries).length === 0) {
135
+ return Promise.reject(new Error('zip write failed: empty entry table'));
136
+ }
137
+ return new Promise((resolve, reject) => {
138
+ zip(entries, { level: opts?.level ?? DEFAULT_ZIP_LEVEL, comment: opts?.comment }, (err, out) => {
139
+ if (err) {
140
+ reject(new Error(`zip write failed: ${err.message}`));
141
+ return;
142
+ }
143
+ resolve(out);
144
+ });
145
+ });
146
+ }
147
+ //# sourceMappingURL=zip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/io/zip.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * io/zip — the single ZIP read/write entry for every faijs consumer.\n *\n * This is the one place faijs (and the host) reads and writes ZIP bytes. The\n * plan unifies two previously-divergent behaviours: reading uses fflate's\n * `unzipSync`, writing uses `zipSync`. Both surface as a plain entry map so\n * no caller ever touches fflate's `Unzlib` / `Zip` objects directly.\n *\n * Contract:\n * - Entries are keyed by the archive path (fflate normalises to forward\n * slashes). Directory entries (keys ending in `/`) are filtered out — they\n * are produced by fflate and are not data.\n * - Every function throws on failure; there is no degraded return value.\n * - A non-zip buffer throws `new Error('zip read failed: <msg>')`.\n * - `writeZipEntries` rejects an empty entry table (never produces an empty zip).\n *\n * Environment: plain pure functions usable in node, browser, worker and the\n * weapp worker — fflate's sync + async (callback) forms cover all of them\n * (see plan D8: the async forms let the event loop yield between chunks).\n */\nimport { zip, zipSync, unzip, unzipSync } from 'fflate'\n\n/** fflate's valid compression levels. */\nexport type ZipLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n\n/** Default compression level used by the sync/async writers. */\nexport const DEFAULT_ZIP_LEVEL: ZipLevel = 6\n\n/** Read-side caps bounding what a single read materialises. */\nexport interface ZipReadOptions {\n /** Max entry count; default `DEFAULT_MAX_ENTRIES` (9999). */\n maxEntries?: number\n /** Max total uncompressed bytes; default `DEFAULT_MAX_TOTAL_BYTES` (512 MiB). */\n maxTotalBytes?: number\n}\n\ntype RequiredReadOptions = Required<ZipReadOptions>\n\n/**\n * Default cap on the number of entries a single read materialises. Deliberately\n * generous: loading a project container is not the same magnitude as a user\n * picking an arbitrary file, and container members (byte-exact source shadows,\n * baked `.brp` payloads) scale with the source document.\n *\n * NOTE these caps are *post-decompression* checks — `unzipSync` has already\n * materialised the archive when they run, so they bound what a caller keeps\n * and walks, not peak allocation. They are a resource budget, NOT a\n * zip-bomb defence. Pre-decompression rejection would need fflate's\n * `filter` (per-entry `originalSize` accounting) and is tracked separately.\n */\nexport const DEFAULT_MAX_ENTRIES = 9999\n\n/** Default cap on total uncompressed bytes; same post-decompression caveat as {@link DEFAULT_MAX_ENTRIES}. */\nexport const DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024\n\nfunction toBytes(data: Uint8Array | ArrayBuffer): Uint8Array {\n return data instanceof Uint8Array ? data : new Uint8Array(data)\n}\n\nfunction resolveReadOptions(opts: ZipReadOptions): RequiredReadOptions {\n return {\n maxEntries: opts.maxEntries ?? DEFAULT_MAX_ENTRIES,\n maxTotalBytes: opts.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES,\n }\n}\n\n/** Strip directory entries (keys ending in `/`) and enforce size/entry caps. */\nfunction normalizeEntries(\n raw: Record<string, Uint8Array>,\n opts: RequiredReadOptions,\n): Map<string, Uint8Array> {\n const out = new Map<string, Uint8Array>()\n let totalBytes = 0\n for (const key of Object.keys(raw)) {\n if (key.endsWith('/')) continue\n const body = raw[key]\n totalBytes += body.byteLength\n if (totalBytes > opts.maxTotalBytes) {\n throw new Error(\n `zip read failed: content exceeds limit (maxTotalBytes ${opts.maxTotalBytes})`,\n )\n }\n out.set(key, body)\n }\n if (out.size > opts.maxEntries) {\n throw new Error(`zip read failed: content exceeds limit (maxEntries ${opts.maxEntries})`)\n }\n return out\n}\n\nfunction wrapReadError(err: unknown): never {\n const inner = err instanceof Error ? err.message : String(err)\n const e = new Error(`zip read failed: ${inner}`)\n ;(e as Error & { cause?: unknown }).cause = err\n throw e\n}\n\n/**\n * Unzip bytes to an entry table (directory entries filtered).\n *\n * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).\n * @param opts - optional read caps (maxEntries / maxTotalBytes).\n * @returns a map of archive path -> decompressed bytes.\n * @throws on non-ZIP bytes or when caps are exceeded.\n */\nexport function readZipEntries(\n data: Uint8Array | ArrayBuffer,\n opts: ZipReadOptions = {},\n): Map<string, Uint8Array> {\n let raw: Record<string, Uint8Array>\n try {\n raw = unzipSync(toBytes(data))\n } catch (err) {\n wrapReadError(err)\n }\n return normalizeEntries(raw, resolveReadOptions(opts))\n}\n\ntype EntryTable = Record<string, Uint8Array>\n\n/** Write-side options (compression level + advisory ZIP comment). */\nexport interface ZipWriteOptions {\n /** Compression level; default `DEFAULT_ZIP_LEVEL` (6). */\n level?: ZipLevel\n /** Optional ZIP comment (advisory — consumers read it via the EOCD record). */\n comment?: string\n}\n\n/**\n * Zip an entry table into bytes.\n *\n * @param entries - archive path -> bytes to store.\n * @param opts - optional compression level / ZIP comment.\n * @returns the ZIP bytes.\n * @throws on an empty entry table.\n */\nexport function writeZipEntries(entries: EntryTable, opts?: ZipWriteOptions): Uint8Array {\n if (Object.keys(entries).length === 0) {\n throw new Error('zip write failed: empty entry table')\n }\n return zipSync(entries, { level: opts?.level ?? DEFAULT_ZIP_LEVEL, comment: opts?.comment })\n}\n\n/** Async read: yields to the event loop between chunks (see plan §D8).\n *\n * @param data - the ZIP bytes to read (Uint8Array or ArrayBuffer).\n * @param opts - optional read caps (maxEntries / maxTotalBytes).\n * @returns a promise of the entry map.\n */\nexport function readZipEntriesAsync(\n data: Uint8Array | ArrayBuffer,\n opts: ZipReadOptions = {},\n): Promise<Map<string, Uint8Array>> {\n return new Promise((resolve, reject) => {\n unzip(toBytes(data), (err, raw) => {\n if (err) {\n reject(new Error(`zip read failed: ${err.message}`))\n return\n }\n try {\n resolve(normalizeEntries(raw, resolveReadOptions(opts)))\n } catch (e) {\n reject(e)\n }\n })\n })\n}\n\n/** Zip an entry table into bytes, yielding between chunks.\n *\n * @param entries - archive path -> entry to store.\n * @param opts - optional compression level / ZIP comment.\n * @returns a promise of the ZIP bytes.\n */\nexport function writeZipEntriesAsync(\n entries: EntryTable,\n opts?: ZipWriteOptions,\n): Promise<Uint8Array> {\n if (Object.keys(entries).length === 0) {\n return Promise.reject(new Error('zip write failed: empty entry table'))\n }\n return new Promise((resolve, reject) => {\n zip(entries, { level: opts?.level ?? DEFAULT_ZIP_LEVEL, comment: opts?.comment }, (err, out) => {\n if (err) {\n reject(new Error(`zip write failed: ${err.message}`))\n return\n }\n resolve(out)\n })\n })\n}"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * code-to-args — 单语句行 args 提取(编辑回填配套)
3
3
  *
4
- * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).
4
+ * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).
5
5
  *
6
6
  * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行
7
7
  * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * code-to-args — 单语句行 args 提取(编辑回填配套)
3
3
  *
4
- * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).
4
+ * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).
5
5
  *
6
6
  * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行
7
7
  * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),
@@ -1 +1 @@
1
- {"version":3,"file":"code-to-args.js","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * code-to-args — 单语句行 args 提取(编辑回填配套)\n *\n * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).\n *\n * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行\n * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),\n * 宿主不得用 acorn 自行解析(B3 修正)。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor 行级提取:\n * 单行文本经哨兵参数前置声明(与 MetadataExtractor looseLocalCalls 同构)\n * 交给 extractMetadata,取末条 op 行摘要的 positional/args。函数名、签名与\n * 返回契约(CodeToArgsResult)不变;HostArg 引用形态保真(A-5)。\n *\n * F1(表达式折叠):args 含计算表达式(binary/template/conditional/spread)时,\n * 与 parser 折叠语义一致地**求值后返回字面值**,不抛错。\n * 单行提取缺失参数真实值 → 前置声明用哨兵字面量 `let <id> = 0`(参数形态),\n * 使表达式可静态折叠;宿主用 StatementSummary.hasComputedArgs 判定只读降级,\n * 不得把折叠值写回源码(会丢失原表达式)。\n */\n\nimport type { HostArg } from './host-arg'\nimport { extractMetadata, type OpDimMap } from './metadata-extractor'\nimport { isHostRef } from './host-arg'\nimport { SCRIPT_UNIT_NAMES, UNIT_SCALE, UNIT_DIM, SCRIPT_UNIT_TO_NAME } from '../units'\nimport type { DimName, UnitName } from '../units'\n\n/**\n * 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):\n * parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的\n * 裸标识符参数引用)要求变量已声明,而单行提取天然缺失声明上下文。\n * 规则:提取行内全部标识符(剥掉字符串字面量后),为每个非 `cad`/关键字\n * 标识符前置一行 `let <id> = 0`(哨兵参数)。parser 对该形态只做语法\n * 检查、不查符号表;多余声明对 varToId 仅是\"可查到\",不影响目标行的\n * args 解析结果。F1 起用哨兵参数(而非 `cad.assembly({})` 语句)——\n * 参数值已知 → 表达式可静态折叠,满足\"参数为表达式时返回折叠字面值\"。\n */\nconst IDENT_RE = /[A-Za-z_$][\\w$]*/g\nconst STRING_RE = /'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"/g\nconst NON_DECL = new Set([\n 'cad', 'const', 'let', 'true', 'false', 'null', 'undefined',\n 'await', 'return', 'new', 'typeof', 'var', 'function',\n])\n\nfunction extractIdentifiers(line: string, namespaces?: Set<string>): string[] {\n const withoutStrings = line.replace(STRING_RE, \"''\")\n const declared = declaredByLine(withoutStrings)\n const ids = new Set<string>()\n for (const m of withoutStrings.matchAll(IDENT_RE)) {\n const id = m[0]\n // P7/D10.4: unit constants (MM, INCH, DEGREE, …) must NOT be pre-declared\n // as sentinel parameters (`let INCH = 0`), because that would shadow the\n // real global value and cause `10 * INCH` to fold to 0.\n if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id) || SCRIPT_UNIT_NAMES.has(id)) continue\n ids.add(id)\n }\n return [...ids]\n}\n\n/**\n * 行内自身声明的标识符(前置声明必须跳过,否则 acorn 重声明报错):\n * - `const/let x = ...` 的 x\n * - `const { k1: v1, k2 } = ...` 的绑定名 v1/k2(键名 k1 不是声明,仍需前置声明——无害)\n */\nfunction declaredByLine(line: string): Set<string> {\n const ids = new Set<string>()\n let m = /^\\s*(?:const|let)\\s+([A-Za-z_$][\\w$]*)\\s*=/.exec(line)\n if (m) ids.add(m[1])\n m = /^\\s*const\\s*\\{([^}]*)\\}\\s*=/.exec(line)\n if (m) {\n for (const prop of m[1].split(',')) {\n const bound = (prop.split(':')[1] ?? prop).trim()\n const id = /^([A-Za-z_$][\\w$]*)/.exec(bound)\n if (id) ids.add(id[1])\n }\n }\n return ids\n}\n\n/**\n * `codeToArgs` 的返回契约:位置实参槽 + 尾随选项对象(HostArg 形态,纯数据无 IR)。\n */\nexport interface CodeToArgsResult {\n positional: HostArg[]\n args: Record<string, HostArg>\n}\n\n/**\n * codeToArgs 选项。`opDims` 为 P4/P6 (unit-system D8) 透传:callee → 量纲声明,\n * 供单行回填路径的 dimension pass 消费(P6 落地前声明面透传即可,不影响解析结果)。\n */\nexport interface CodeToArgsOptions {\n /** 该脚本顶层 import 的绑定名(F2)。 */\n namespaces?: string[]\n /** callee → 量纲声明(unit-system D8,P6 消费)。 */\n opDims?: OpDimMap\n}\n\n/**\n * 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 IR 变体语义)。\n *\n * true-JS-subset §4.6.3 新契约:返回 `{ positional, args }`——\n * - `positional`: HostArg[],按调用顺序的位置实参(字面量原样;var-ref/\n * param-ref/call-ref/expr-ref 以 `{kind,...}` 标记对象呈现,宿主据此降级为\n * 只读编辑);宿主不接触内部类型(纯数据面)。\n * - `args`: 尾随选项对象(键值 HostArg 形态;无选项对象时为 `{}`)。\n * 旧契约(只返回对象槽)在位置形态下会静默丢弃非对象实参——本契约显式保留全部信息。\n *\n * 支持的行形态(与 parser 接受的语句一致):\n * - `const part0 = cad.box(10, 20, 30)`\n * - `part0 = cad.fai_drill(part0, { diameter: 5 })`(裸重赋值)\n * - `const { front: a, back: b } = cad.fai_split(part0, { normal: [0,0,1] })`(解构)\n * - `asm0.add_constraint({ ... })`(成员方法调用)\n * - 位置实参为字面量/变量引用/表达式(`cad.box(10, 20, 30)`、`cad.hem(p0.solid, {...})`)\n * - args 中的裸标识符参数引用(`cad.box(10, 20, height)`)\n * - args 中的计算表达式(`cad.box(10, 20, base + 20)`)→ 折叠为字面值返回\n *\n * @param codeLine 单条语句源码行\n * @param opts.namespaces 该脚本顶层 import 的绑定名(F2:`mech.makeHeadstock(...)`\n * 中 `mech` 不得被前置声明为变量)。L0 不感知注册表,由宿主从脚本 imports 提供。\n * @returns the extracted positional slot and trailing options object (both in\n * serialized JSON form).\n * @throws ParseError — 行文本不是合法语句时抛出(含行号)\n */\nexport function codeToArgs(codeLine: string, opts?: CodeToArgsOptions): CodeToArgsResult {\n const namespaces = new Set(opts?.namespaces ?? [])\n const decls = extractIdentifiers(codeLine, namespaces)\n .map((id) => `let ${id} = 0`)\n .join('\\n')\n const code = decls ? `${decls}\\n${codeLine}` : codeLine\n // 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;\n // 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,\n // 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。\n // opDims 透传给 dimension pass(P6 消费,P4 仅透传声明面)。\n const meta = extractMetadata(code, {\n namespaces: opts?.namespaces ?? [],\n looseLocalCalls: true,\n ...(opts?.opDims ? { opDims: opts.opDims } : {}),\n })\n const last = meta.lines[meta.lines.length - 1]\n if (!last) return { positional: [], args: {} }\n // 尾随纯对象(选项槽)从 positional 切出到 args(与现状 splitTrailingOptions\n // 同构:末位纯数据对象是选项槽;引用形态/字面量留在 positional)。\n const positional = [...last.positional]\n const lastArg = positional[positional.length - 1]\n if (\n lastArg !== null &&\n typeof lastArg === 'object' &&\n !Array.isArray(lastArg) &&\n !isHostRef(lastArg as HostArg)\n ) {\n positional.pop()\n return { positional, args: { ...(lastArg as Record<string, HostArg>) } }\n }\n return { positional, args: { ...last.args } }\n}\n\n// ── P7/D10: unit literal parsing ────────────────────────────────────────────\n\n/**\n * Reverse mapping: script-side constant name (UPPERCASE) → internal UnitName.\n */\nconst CONST_TO_UNIT: Readonly<Record<string, UnitName>> = Object.freeze(\n Object.fromEntries(\n (Object.keys(SCRIPT_UNIT_TO_NAME) as string[]).map(\n (k) => [k, SCRIPT_UNIT_TO_NAME[k]] as [string, UnitName],\n ),\n ),\n)\n\n/**\n * Parse a unit literal text expression (`n * UNIT`) into its base-unit value.\n *\n * P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like\n * `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.\n * Non-unit-literal expressions return `null` (host decides whether to\n * downgrade to read-only).\n *\n * @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).\n * @returns the parsed unit literal info, or `null` if not a unit literal.\n */\nexport function parseUnitLiteral(text: string): { base: number; dim: DimName; unitName: UnitName } | null {\n const match = /^\\s*(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)\\s*\\*\\s*([A-Z]+)\\s*$/.exec(text)\n if (!match) return null\n const n = Number(match[1])\n const constName = match[2]\n const unitName = CONST_TO_UNIT[constName]\n if (!unitName) return null\n const dim = UNIT_DIM[unitName]\n // toBase: n * UNIT_SCALE[unitName]\n const base = n * UNIT_SCALE[unitName]\n return { base, dim, unitName }\n}\n"]}
1
+ {"version":3,"file":"code-to-args.js","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * code-to-args — 单语句行 args 提取(编辑回填配套)\n *\n * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).\n *\n * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行\n * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),\n * 宿主不得用 acorn 自行解析(B3 修正)。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor 行级提取:\n * 单行文本经哨兵参数前置声明(与 MetadataExtractor looseLocalCalls 同构)\n * 交给 extractMetadata,取末条 op 行摘要的 positional/args。函数名、签名与\n * 返回契约(CodeToArgsResult)不变;HostArg 引用形态保真(A-5)。\n *\n * F1(表达式折叠):args 含计算表达式(binary/template/conditional/spread)时,\n * 与 parser 折叠语义一致地**求值后返回字面值**,不抛错。\n * 单行提取缺失参数真实值 → 前置声明用哨兵字面量 `let <id> = 0`(参数形态),\n * 使表达式可静态折叠;宿主用 StatementSummary.hasComputedArgs 判定只读降级,\n * 不得把折叠值写回源码(会丢失原表达式)。\n */\n\nimport type { HostArg } from './host-arg'\nimport { extractMetadata, type OpDimMap } from './metadata-extractor'\nimport { isHostRef } from './host-arg'\nimport { SCRIPT_UNIT_NAMES, UNIT_SCALE, UNIT_DIM, SCRIPT_UNIT_TO_NAME } from '../units'\nimport type { DimName, UnitName } from '../units'\n\n/**\n * 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):\n * parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的\n * 裸标识符参数引用)要求变量已声明,而单行提取天然缺失声明上下文。\n * 规则:提取行内全部标识符(剥掉字符串字面量后),为每个非 `cad`/关键字\n * 标识符前置一行 `let <id> = 0`(哨兵参数)。parser 对该形态只做语法\n * 检查、不查符号表;多余声明对 varToId 仅是\"可查到\",不影响目标行的\n * args 解析结果。F1 起用哨兵参数(而非 `cad.assembly({})` 语句)——\n * 参数值已知 → 表达式可静态折叠,满足\"参数为表达式时返回折叠字面值\"。\n */\nconst IDENT_RE = /[A-Za-z_$][\\w$]*/g\nconst STRING_RE = /'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"/g\nconst NON_DECL = new Set([\n 'cad', 'const', 'let', 'true', 'false', 'null', 'undefined',\n 'await', 'return', 'new', 'typeof', 'var', 'function',\n])\n\nfunction extractIdentifiers(line: string, namespaces?: Set<string>): string[] {\n const withoutStrings = line.replace(STRING_RE, \"''\")\n const declared = declaredByLine(withoutStrings)\n const ids = new Set<string>()\n for (const m of withoutStrings.matchAll(IDENT_RE)) {\n const id = m[0]\n // P7/D10.4: unit constants (MM, INCH, DEGREE, …) must NOT be pre-declared\n // as sentinel parameters (`let INCH = 0`), because that would shadow the\n // real global value and cause `10 * INCH` to fold to 0.\n if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id) || SCRIPT_UNIT_NAMES.has(id)) continue\n ids.add(id)\n }\n return [...ids]\n}\n\n/**\n * 行内自身声明的标识符(前置声明必须跳过,否则 acorn 重声明报错):\n * - `const/let x = ...` 的 x\n * - `const { k1: v1, k2 } = ...` 的绑定名 v1/k2(键名 k1 不是声明,仍需前置声明——无害)\n */\nfunction declaredByLine(line: string): Set<string> {\n const ids = new Set<string>()\n let m = /^\\s*(?:const|let)\\s+([A-Za-z_$][\\w$]*)\\s*=/.exec(line)\n if (m) ids.add(m[1])\n m = /^\\s*const\\s*\\{([^}]*)\\}\\s*=/.exec(line)\n if (m) {\n for (const prop of m[1].split(',')) {\n const bound = (prop.split(':')[1] ?? prop).trim()\n const id = /^([A-Za-z_$][\\w$]*)/.exec(bound)\n if (id) ids.add(id[1])\n }\n }\n return ids\n}\n\n/**\n * `codeToArgs` 的返回契约:位置实参槽 + 尾随选项对象(HostArg 形态,纯数据无 IR)。\n */\nexport interface CodeToArgsResult {\n positional: HostArg[]\n args: Record<string, HostArg>\n}\n\n/**\n * codeToArgs 选项。`opDims` 为 P4/P6 (unit-system D8) 透传:callee → 量纲声明,\n * 供单行回填路径的 dimension pass 消费(P6 落地前声明面透传即可,不影响解析结果)。\n */\nexport interface CodeToArgsOptions {\n /** 该脚本顶层 import 的绑定名(F2)。 */\n namespaces?: string[]\n /** callee → 量纲声明(unit-system D8,P6 消费)。 */\n opDims?: OpDimMap\n}\n\n/**\n * 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 IR 变体语义)。\n *\n * true-JS-subset §4.6.3 新契约:返回 `{ positional, args }`——\n * - `positional`: HostArg[],按调用顺序的位置实参(字面量原样;var-ref/\n * param-ref/call-ref/expr-ref 以 `{kind,...}` 标记对象呈现,宿主据此降级为\n * 只读编辑);宿主不接触内部类型(纯数据面)。\n * - `args`: 尾随选项对象(键值 HostArg 形态;无选项对象时为 `{}`)。\n * 旧契约(只返回对象槽)在位置形态下会静默丢弃非对象实参——本契约显式保留全部信息。\n *\n * 支持的行形态(与 parser 接受的语句一致):\n * - `const part0 = cad.box(10, 20, 30)`\n * - `part0 = cad.fai_drill(part0, { diameter: 5 })`(裸重赋值)\n * - `const { front: a, back: b } = cad.fai_split(part0, { normal: [0,0,1] })`(解构)\n * - `asm0.add_constraint({ ... })`(成员方法调用)\n * - 位置实参为字面量/变量引用/表达式(`cad.box(10, 20, 30)`、`cad.hem(p0.solid, {...})`)\n * - args 中的裸标识符参数引用(`cad.box(10, 20, height)`)\n * - args 中的计算表达式(`cad.box(10, 20, base + 20)`)→ 折叠为字面值返回\n *\n * @param codeLine 单条语句源码行\n * @param opts.namespaces 该脚本顶层 import 的绑定名(F2:`mech.makeHeadstock(...)`\n * 中 `mech` 不得被前置声明为变量)。L0 不感知注册表,由宿主从脚本 imports 提供。\n * @returns the extracted positional slot and trailing options object (both in\n * serialized JSON form).\n * @throws ParseError — 行文本不是合法语句时抛出(含行号)\n */\nexport function codeToArgs(codeLine: string, opts?: CodeToArgsOptions): CodeToArgsResult {\n const namespaces = new Set(opts?.namespaces ?? [])\n const decls = extractIdentifiers(codeLine, namespaces)\n .map((id) => `let ${id} = 0`)\n .join('\\n')\n const code = decls ? `${decls}\\n${codeLine}` : codeLine\n // 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;\n // 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,\n // 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。\n // opDims 透传给 dimension pass(P6 消费,P4 仅透传声明面)。\n const meta = extractMetadata(code, {\n namespaces: opts?.namespaces ?? [],\n looseLocalCalls: true,\n ...(opts?.opDims ? { opDims: opts.opDims } : {}),\n })\n const last = meta.lines[meta.lines.length - 1]\n if (!last) return { positional: [], args: {} }\n // 尾随纯对象(选项槽)从 positional 切出到 args(与现状 splitTrailingOptions\n // 同构:末位纯数据对象是选项槽;引用形态/字面量留在 positional)。\n const positional = [...last.positional]\n const lastArg = positional[positional.length - 1]\n if (\n lastArg !== null &&\n typeof lastArg === 'object' &&\n !Array.isArray(lastArg) &&\n !isHostRef(lastArg as HostArg)\n ) {\n positional.pop()\n return { positional, args: { ...(lastArg as Record<string, HostArg>) } }\n }\n return { positional, args: { ...last.args } }\n}\n\n// ── P7/D10: unit literal parsing ────────────────────────────────────────────\n\n/**\n * Reverse mapping: script-side constant name (UPPERCASE) → internal UnitName.\n */\nconst CONST_TO_UNIT: Readonly<Record<string, UnitName>> = Object.freeze(\n Object.fromEntries(\n (Object.keys(SCRIPT_UNIT_TO_NAME) as string[]).map(\n (k) => [k, SCRIPT_UNIT_TO_NAME[k]] as [string, UnitName],\n ),\n ),\n)\n\n/**\n * Parse a unit literal text expression (`n * UNIT`) into its base-unit value.\n *\n * P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like\n * `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.\n * Non-unit-literal expressions return `null` (host decides whether to\n * downgrade to read-only).\n *\n * @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).\n * @returns the parsed unit literal info, or `null` if not a unit literal.\n */\nexport function parseUnitLiteral(text: string): { base: number; dim: DimName; unitName: UnitName } | null {\n const match = /^\\s*(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)\\s*\\*\\s*([A-Z]+)\\s*$/.exec(text)\n if (!match) return null\n const n = Number(match[1])\n const constName = match[2]\n const unitName = CONST_TO_UNIT[constName]\n if (!unitName) return null\n const dim = UNIT_DIM[unitName]\n // toBase: n * UNIT_SCALE[unitName]\n const base = n * UNIT_SCALE[unitName]\n return { base, dim, unitName }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * statement-summary — 语句平铺摘要(宿主展示/编排用,非 IR 类型)
3
3
  *
4
- * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping).
4
+ * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping).
5
5
  *
6
6
  * `analyzeCode(code)` 是宿主消费语句信息的唯一形态(IR 已删除)。摘要只含展示/编排所需的标量字段:
7
7
  * Timeline 一行一节点、场景树分组推导、FeatureTree 识别、编辑回填定位。
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * statement-summary — 语句平铺摘要(宿主展示/编排用,非 IR 类型)
3
3
  *
4
- * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping).
4
+ * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping).
5
5
  *
6
6
  * `analyzeCode(code)` 是宿主消费语句信息的唯一形态(IR 已删除)。摘要只含展示/编排所需的标量字段:
7
7
  * Timeline 一行一节点、场景树分组推导、FeatureTree 识别、编辑回填定位。
@@ -1 +1 @@
1
- {"version":3,"file":"statement-summary.js","sourceRoot":"","sources":["../../src/lang/statement-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AA4DtD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,CAAA;AACpC,CAAC","sourcesContent":["/**\n * statement-summary — 语句平铺摘要(宿主展示/编排用,非 IR 类型)\n *\n * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping).\n *\n * `analyzeCode(code)` 是宿主消费语句信息的唯一形态(IR 已删除)。摘要只含展示/编排所需的标量字段:\n * Timeline 一行一节点、场景树分组推导、FeatureTree 识别、编辑回填定位。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor:lines 面直接\n * 产出 StatementSummary 原样(无投影层),与 MetadataExtractor 投影逐字相等\n * (A-16 对拍),仅 id = `'s' + lineNo` 语义变化(append 场景稳定,宿主按\n * 字符串使用不破裂)。\n */\n\nimport type { StmtId, PartName } from '../identity'\nimport type { HostArg } from './host-arg'\nimport { extractMetadata } from './metadata-extractor'\n\n/**\n * A flat scalar projection of one statement for host display and orchestration\n * (a non-IR type). Timeline rows, scene tree grouping, feature-tree\n * recognition, and edit-backfill navigation all consume this summary.\n */\nexport interface StatementSummary {\n /** 语句 id('s' + lineNo;append 场景行号稳定) */\n id: StmtId\n /** 调用名(<ns>.<callee> 或成员方法名) */\n callee: string\n /** 调用命名空间(F2:`mech.makeHeadstock(...)` → 'mech';缺省 cad 时为 undefined) */\n namespace?: string\n /** 本机函数调用(§3.4):callee 是脚本内函数名,namespace/packageName 缺省。\n * 宿主据此渲染「本机函数」节点(只读编辑,函数体不透明)。 */\n local?: boolean\n /** 命名空间对应的包名(F2:由顶层 import specifier 推导;cad 时为 undefined)。\n * timeline「带包名」标识 / 宿主 getFeatureByOp(packageName, op) 的依据。 */\n packageName?: string\n /** 成员方法调用接收者变量(asm1.do_assemble() → 'asm1') */\n receiver?: PartName\n /**\n * 位置实参槽(HostArg 形态,纯数据无 IR)。\n * 每个元素是 HostArg——字面量原样;var-ref/param-ref/call-ref/expr-ref\n * 以 `{kind, ...}` 形态呈现。宿主用 `isHostVarRef` 等守卫判定形态。\n */\n positional: HostArg[]\n /**\n * 尾随选项对象(HostArg 形态,纯数据无 IR)。\n * 键值经 HostArg 映射;无选项对象时为 `{}`。\n */\n args: Record<string, HostArg>\n /** 产出变量名(split 解构 = 多个;void 语句 = []) */\n outputs: PartName[]\n /** 解构键(const {front: a, back: b} → ['front','back']) */\n outputKeys?: string[]\n /** 语句引用的变量名集合(parser 收集) */\n refs?: string[]\n /** 是否有赋值(const/let 声明 = true;裸重赋值/成员调用 = false) */\n hasAssignment: boolean\n /** 参数是否含计算表达式(F1:parser 折叠时置位)。\n * true → 宿主编辑面板降级为只读/代码编辑,禁止表单写回(防表达式丢失)。 */\n hasComputedArgs: boolean\n /**\n * 装配相关语句标记(P2-f4):`cad.assembly` / `asmN.do_assemble` / `asmN.solve`\n * 行为语句。面板据此渲染装配节点;`assembly` 摘要字段只在 `cad.assembly`\n * 语句上存在(do_assemble/solve 行只有本标记)。\n */\n isAssembly?: boolean\n /** 装配语句摘要(仅 cad.assembly 语句;约束全文仍走 args 通道,此处只给类型名列表)。 */\n assembly?: {\n name?: string\n memberCount: number\n constraintTypes: string[]\n }\n /** 源码行号(1-based) */\n line: number\n}\n\n/**\n * 解析代码文本,返回语句平铺摘要(非 IR 类型)。\n *\n * 实现:MetadataExtractor.lines 直接产出(无投影层),与 MetadataExtractor\n * 投影逐字相等(A-16 对拍),id 语义 = `'s' + lineNo`。\n *\n * @param code - the faijs source text to parse and summarize.\n * @returns a flat statement summary for every parsed statement.\n * @throws ParseError — 含行号\n */\nexport function analyzeCode(code: string): StatementSummary[] {\n return extractMetadata(code).lines\n}\n"]}
1
+ {"version":3,"file":"statement-summary.js","sourceRoot":"","sources":["../../src/lang/statement-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AA4DtD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,CAAA;AACpC,CAAC","sourcesContent":["/**\n * statement-summary — 语句平铺摘要(宿主展示/编排用,非 IR 类型)\n *\n * See docs/language-design.md §3 (statement model ↔ StatementSummary mapping).\n *\n * `analyzeCode(code)` 是宿主消费语句信息的唯一形态(IR 已删除)。摘要只含展示/编排所需的标量字段:\n * Timeline 一行一节点、场景树分组推导、FeatureTree 识别、编辑回填定位。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor:lines 面直接\n * 产出 StatementSummary 原样(无投影层),与 MetadataExtractor 投影逐字相等\n * (A-16 对拍),仅 id = `'s' + lineNo` 语义变化(append 场景稳定,宿主按\n * 字符串使用不破裂)。\n */\n\nimport type { StmtId, PartName } from '../identity'\nimport type { HostArg } from './host-arg'\nimport { extractMetadata } from './metadata-extractor'\n\n/**\n * A flat scalar projection of one statement for host display and orchestration\n * (a non-IR type). Timeline rows, scene tree grouping, feature-tree\n * recognition, and edit-backfill navigation all consume this summary.\n */\nexport interface StatementSummary {\n /** 语句 id('s' + lineNo;append 场景行号稳定) */\n id: StmtId\n /** 调用名(<ns>.<callee> 或成员方法名) */\n callee: string\n /** 调用命名空间(F2:`mech.makeHeadstock(...)` → 'mech';缺省 cad 时为 undefined) */\n namespace?: string\n /** 本机函数调用(§3.4):callee 是脚本内函数名,namespace/packageName 缺省。\n * 宿主据此渲染「本机函数」节点(只读编辑,函数体不透明)。 */\n local?: boolean\n /** 命名空间对应的包名(F2:由顶层 import specifier 推导;cad 时为 undefined)。\n * timeline「带包名」标识 / 宿主 getFeatureByOp(packageName, op) 的依据。 */\n packageName?: string\n /** 成员方法调用接收者变量(asm1.do_assemble() → 'asm1') */\n receiver?: PartName\n /**\n * 位置实参槽(HostArg 形态,纯数据无 IR)。\n * 每个元素是 HostArg——字面量原样;var-ref/param-ref/call-ref/expr-ref\n * 以 `{kind, ...}` 形态呈现。宿主用 `isHostVarRef` 等守卫判定形态。\n */\n positional: HostArg[]\n /**\n * 尾随选项对象(HostArg 形态,纯数据无 IR)。\n * 键值经 HostArg 映射;无选项对象时为 `{}`。\n */\n args: Record<string, HostArg>\n /** 产出变量名(split 解构 = 多个;void 语句 = []) */\n outputs: PartName[]\n /** 解构键(const {front: a, back: b} → ['front','back']) */\n outputKeys?: string[]\n /** 语句引用的变量名集合(parser 收集) */\n refs?: string[]\n /** 是否有赋值(const/let 声明 = true;裸重赋值/成员调用 = false) */\n hasAssignment: boolean\n /** 参数是否含计算表达式(F1:parser 折叠时置位)。\n * true → 宿主编辑面板降级为只读/代码编辑,禁止表单写回(防表达式丢失)。 */\n hasComputedArgs: boolean\n /**\n * 装配相关语句标记(P2-f4):`cad.assembly` / `asmN.do_assemble` / `asmN.solve`\n * 行为语句。面板据此渲染装配节点;`assembly` 摘要字段只在 `cad.assembly`\n * 语句上存在(do_assemble/solve 行只有本标记)。\n */\n isAssembly?: boolean\n /** 装配语句摘要(仅 cad.assembly 语句;约束全文仍走 args 通道,此处只给类型名列表)。 */\n assembly?: {\n name?: string\n memberCount: number\n constraintTypes: string[]\n }\n /** 源码行号(1-based) */\n line: number\n}\n\n/**\n * 解析代码文本,返回语句平铺摘要(非 IR 类型)。\n *\n * 实现:MetadataExtractor.lines 直接产出(无投影层),与 MetadataExtractor\n * 投影逐字相等(A-16 对拍),id 语义 = `'s' + lineNo`。\n *\n * @param code - the faijs source text to parse and summarize.\n * @returns a flat statement summary for every parsed statement.\n * @throws ParseError — 含行号\n */\nexport function analyzeCode(code: string): StatementSummary[] {\n return extractMetadata(code).lines\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * faijs 文本层类型定义 — 保留类型(L0 零依赖)
3
3
  *
4
- * 设计文档:docs/syntax-design.md §3.1
4
+ * 设计文档:docs/language-design.md §3.1
5
5
  *
6
6
  * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的
7
7
  * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * faijs 文本层类型定义 — 保留类型(L0 零依赖)
3
3
  *
4
- * 设计文档:docs/syntax-design.md §3.1
4
+ * 设计文档:docs/language-design.md §3.1
5
5
  *
6
6
  * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的
7
7
  * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * faijs 文本层类型定义 — 保留类型(L0 零依赖)\n *\n * 设计文档:docs/syntax-design.md §3.1\n *\n * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的\n * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和\n * 基础值类型(Vec3 / JsonValue)。\n *\n * L0 边界:此文件仅依赖 TypeScript 内置类型 + identity(零依赖品牌模块)。\n */\n\nimport { type PartName } from '../identity'\n\n// ── 值与引用 ──\n\n/** A 3-component vector. */\nexport type Vec3 = [number, number, number]\n\n/** A JSON-serializable value, used for parameter literals and wire-shaped args. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [k: string]: JsonValue }\n\n// ── 参数表 ──\n\n/**\n * A parameter declaration (`const name = <literal>`), with its value and\n * optional schema metadata.\n */\nexport interface ParamDef {\n name: string\n type: 'number' | 'vec3' | 'bool' | 'enum'\n value: JsonValue\n default: JsonValue\n min?: number\n max?: number\n options?: string[]\n label?: string\n}\n\n// ── Part 脚本 ──\n\n/**\n * Scene-level model metadata (name and appearance) carried by a script.\n */\nexport interface ScriptMetaIR {\n name?: string\n appearance?: { color?: string; metalness?: number; roughness?: number }\n}\n\n/** 终端变量类型(keep-syntax 设计 §6:运行时登记,缺省 'shape')。 */\nexport type VarKind = 'shape' | 'compound' | 'value'\n\n/** 终端 shape:return 数组/DAG 叶子判定列出的最终输出(设计文档 §2.2 / §4.1) */\nexport interface TerminalShape {\n /** 终端左值变量名(PartName,如 'part0')——终端按变量名(outputs)标识,非语句 id */\n id: PartName\n /** 该终端 mesh 的独立 meta(name/appearance) */\n meta?: ScriptMetaIR\n /** 变量类型('shape' | 'compound' | 'value'),运行时登记,缺省 'shape' */\n kind?: VarKind\n /** 保留但 canvas 不渲染(keep-syntax 设计 §6),缺省 undefined → 可见 */\n hidden?: boolean\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * faijs 文本层类型定义 — 保留类型(L0 零依赖)\n *\n * 设计文档:docs/language-design.md §3.1\n *\n * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的\n * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和\n * 基础值类型(Vec3 / JsonValue)。\n *\n * L0 边界:此文件仅依赖 TypeScript 内置类型 + identity(零依赖品牌模块)。\n */\n\nimport { type PartName } from '../identity'\n\n// ── 值与引用 ──\n\n/** A 3-component vector. */\nexport type Vec3 = [number, number, number]\n\n/** A JSON-serializable value, used for parameter literals and wire-shaped args. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [k: string]: JsonValue }\n\n// ── 参数表 ──\n\n/**\n * A parameter declaration (`const name = <literal>`), with its value and\n * optional schema metadata.\n */\nexport interface ParamDef {\n name: string\n type: 'number' | 'vec3' | 'bool' | 'enum'\n value: JsonValue\n default: JsonValue\n min?: number\n max?: number\n options?: string[]\n label?: string\n}\n\n// ── Part 脚本 ──\n\n/**\n * Scene-level model metadata (name and appearance) carried by a script.\n */\nexport interface ScriptMetaIR {\n name?: string\n appearance?: { color?: string; metalness?: number; roughness?: number }\n}\n\n/** 终端变量类型(keep-syntax 设计 §6:运行时登记,缺省 'shape')。 */\nexport type VarKind = 'shape' | 'compound' | 'value'\n\n/** 终端 shape:return 数组/DAG 叶子判定列出的最终输出(设计文档 §2.2 / §4.1) */\nexport interface TerminalShape {\n /** 终端左值变量名(PartName,如 'part0')——终端按变量名(outputs)标识,非语句 id */\n id: PartName\n /** 该终端 mesh 的独立 meta(name/appearance) */\n meta?: ScriptMetaIR\n /** 变量类型('shape' | 'compound' | 'value'),运行时登记,缺省 'shape' */\n kind?: VarKind\n /** 保留但 canvas 不渲染(keep-syntax 设计 §6),缺省 undefined → 可见 */\n hidden?: boolean\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * mesh — 纯数据几何 API 统一入口
3
3
  *
4
- * See docs/api-contract.md §1 (architecture layers) and §10 (stdlib function catalog).
4
+ * See docs/api-contract.md §1 (architecture layers) and §10 (api function catalog).
5
5
  *
6
6
  * 原则(§5.1):
7
7
  * 1. 全部纯数据:输入输出是 Shape (ManifoldMeshData),不碰 THREE 场景、不读 store
@@ -69,6 +69,7 @@ export declare const cad: {
69
69
  solidToShape: typeof brepOps.solidToShape;
70
70
  };
71
71
  export type { Shape, Vec3, BoundingBox, FaceDescriptor } from './types.js';
72
+ export { guessStlUnit } from './stl-unit.js';
72
73
  export type { BoxParams, SphereParams, CylinderParams, ConeParams, WedgeParams, TextParams, SvgExtrudeParams, SdfParams, DrillParams, ExtrudeParams, EngraveParams, KnurlParams, SplitPlane, SplitResult, DovetailSplitParams, DowelSplitParams, TenonSplitParams, } from './types.js';
73
74
  export type { BrepChainState, DrillBrepParams, SplitBrepParams, SplitBrepResult, ExtrudeBrepParams, } from '../brep/index.js';
74
75
  export { createBrepChainState, initBrepChainState, releaseBrepChainState, solidToShape, isCadFormat, } from '../brep/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mesh/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,UAAU,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,MAAM,CAAA;AAI7B;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Df,CAAA;AAID,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACvE,YAAY,EACV,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAChE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EACvC,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EACtD,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,GACjF,MAAM,SAAS,CAAA;AAGhB,YAAY,EACV,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EACjE,iBAAiB,GAClB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,oBAAoB,EAAE,kBAAkB,EAAE,qBAAqB,EAC/D,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mesh/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,UAAU,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,MAAM,CAAA;AAI7B;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Df,CAAA;AAID,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,YAAY,EACV,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAChE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EACvC,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EACtD,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,GACjF,MAAM,SAAS,CAAA;AAGhB,YAAY,EACV,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EACjE,iBAAiB,GAClB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,oBAAoB,EAAE,kBAAkB,EAAE,qBAAqB,EAC/D,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * mesh — 纯数据几何 API 统一入口
3
3
  *
4
- * See docs/api-contract.md §1 (architecture layers) and §10 (stdlib function catalog).
4
+ * See docs/api-contract.md §1 (architecture layers) and §10 (api function catalog).
5
5
  *
6
6
  * 原则(§5.1):
7
7
  * 1. 全部纯数据:输入输出是 Shape (ManifoldMeshData),不碰 THREE 场景、不读 store
@@ -80,5 +80,6 @@ export const cad = {
80
80
  loadBrep: brepOps.loadBrep,
81
81
  solidToShape: brepOps.solidToShape,
82
82
  };
83
+ export { guessStlUnit } from './stl-unit.js';
83
84
  export { createBrepChainState, initBrepChainState, releaseBrepChainState, solidToShape, isCadFormat, } from '../brep/index.js';
84
85
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mesh/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,UAAU,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,MAAM,CAAA;AAE7B,sBAAsB;AAEtB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,cAAc;IACd,GAAG,EAAE,UAAU,CAAC,GAAG;IACnB,MAAM,EAAE,UAAU,CAAC,MAAM;IACzB,QAAQ,EAAE,UAAU,CAAC,QAAQ;IAC7B,IAAI,EAAE,UAAU,CAAC,IAAI;IACrB,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,GAAG,EAAE,UAAU,CAAC,GAAG;IAEnB,6BAA6B;IAC7B,OAAO,EAAE,cAAc,CAAC,OAAO;IAC/B,UAAU,EAAE,cAAc,CAAC,UAAU;IACrC,YAAY,EAAE,cAAc,CAAC,YAAY;IACzC,QAAQ,EAAE,cAAc,CAAC,QAAQ;IACjC,SAAS,EAAE,cAAc,CAAC,SAAS;IAEnC,KAAK;IACL,SAAS,EAAE,YAAY,CAAC,SAAS;IACjC,YAAY,EAAE,YAAY,CAAC,YAAY;IACvC,KAAK,EAAE,YAAY,CAAC,KAAK;IACzB,OAAO,EAAE,YAAY,CAAC,OAAO;IAC7B,eAAe,EAAE,YAAY,CAAC,eAAe;IAE7C,KAAK;IACL,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,QAAQ,EAAE,UAAU,CAAC,QAAQ;IAC7B,SAAS,EAAE,UAAU,CAAC,SAAS;IAE/B,KAAK;IACL,wDAAwD;IACxD,0EAA0E;IAE1E,KAAK;IACL,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,KAAK,EAAE,UAAU,CAAC,KAAK;IAEvB,KAAK;IACL,WAAW,EAAE,QAAQ,CAAC,WAAW;IACjC,UAAU,EAAE,QAAQ,CAAC,UAAU;IAC/B,MAAM,EAAE,QAAQ,CAAC,MAAM;IACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;IAEvB,KAAK;IACL,IAAI,EAAE,KAAK,CAAC,UAAU;IAEtB,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC,aAAa;IACpC,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;IACxB,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;IAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;CACnC,CAAA;AAiBD,OAAO,EACL,oBAAoB,EAAE,kBAAkB,EAAE,qBAAqB,EAC/D,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA","sourcesContent":["/**\n * mesh — 纯数据几何 API 统一入口\n *\n * See docs/api-contract.md §1 (architecture layers) and §10 (stdlib function catalog).\n *\n * 原则(§5.1):\n * 1. 全部纯数据:输入输出是 Shape (ManifoldMeshData),不碰 THREE 场景、不读 store\n * 2. 不可变:每个 API 返回新几何,不修改输入\n * 3. 同步签名、异步执行:API 签名同步(或 async);worker 边界由 ScriptEngine 处理\n * 4. 坐标系:右手系 +Z 向上、毫米、角度用度\n *\n * P1 阶段:mesh 是对现有纯函数的薄包装层,行为完全不变。\n * P3+ 阶段:mesh 将由 ScriptEngine 驱动,在 worker 中执行。\n */\n\nimport * as primitives from './primitives'\nimport * as brepPrimitives from '../brep/primitives-brep'\nimport * as brepOps from '../brep'\nimport * as booleanOps from './boolean'\nimport * as engraveOps from './engrave'\nimport * as transformOps from './transform'\nimport * as queryOps from './query'\nimport * as ioOps from './io'\n\n// ── 统一 cad API 对象 ──\n\n/**\n * Unified `cad` API object aggregating the pure-data mesh operations: mesh and\n * BREP primitives, transforms, booleans, engrave/knurl, geometry queries, file\n * IO, and BREP feature operations.\n *\n * D1(2026-09-23 扩展库拆分):`text` / `svgExtrude` / `fai_*` 键已随\n * `@faicad/faijs-extra` 迁出——它们的实现在扩展库的 mesh 面(`editorCad`)。\n */\nexport const cad = {\n // 创建(mesh 路径)\n box: primitives.box,\n sphere: primitives.sphere,\n cylinder: primitives.cylinder,\n cone: primitives.cone,\n wedge: primitives.wedge,\n screw: primitives.screw,\n sdf: primitives.sdf,\n\n // 创建(BREP 路径 — OCCT 精确实体三角化)\n boxBrep: brepPrimitives.boxBrep,\n sphereBrep: brepPrimitives.sphereBrep,\n cylinderBrep: brepPrimitives.cylinderBrep,\n coneBrep: brepPrimitives.coneBrep,\n wedgeBrep: brepPrimitives.wedgeBrep,\n\n // 变换\n translate: transformOps.translate,\n rotate_euler: transformOps.rotate_euler,\n scale: transformOps.scale,\n scale3d: transformOps.scale3d,\n transformMatrix: transformOps.transformMatrix,\n\n // 布尔\n union: booleanOps.union,\n subtract: booleanOps.subtract,\n intersect: booleanOps.intersect,\n\n // 分割\n // `fai_*` 键(编辑器消费面)已随扩展库迁出:@faicad/faijs-extra 的 mesh 面\n // 经 `mesh/fai_split.ts` / `mesh/fai_drill.ts` / `mesh/fai_extrude.ts` 提供。\n\n // 雕刻\n engrave: engraveOps.engrave,\n knurl: engraveOps.knurl,\n\n // 查询\n boundingBox: queryOps.boundingBox,\n bboxCenter: queryOps.bboxCenter,\n volume: queryOps.volume,\n faceAt: queryOps.faceAt,\n\n // IO\n load: ioOps.importFile,\n\n // BREP 特征操作(Phase 2 — OCCT 精确实体运算)\n translateBrep: brepOps.translateBrep,\n rotateBrep: brepOps.rotateBrep,\n scaleBrep: brepOps.scaleBrep,\n fuseBrep: brepOps.fuseBrep,\n cutBrep: brepOps.cutBrep,\n commonBrep: brepOps.commonBrep,\n drillBrep: brepOps.drillBrep,\n splitBrep: brepOps.splitBrep,\n extrudeBrep: brepOps.extrudeBrep,\n loadBrep: brepOps.loadBrep,\n solidToShape: brepOps.solidToShape,\n}\n\n// ── 类型导出 ──\n\nexport type { Shape, Vec3, BoundingBox, FaceDescriptor } from './types'\nexport type {\n BoxParams, SphereParams, CylinderParams, ConeParams, WedgeParams,\n TextParams, SvgExtrudeParams, SdfParams,\n DrillParams, ExtrudeParams, EngraveParams, KnurlParams,\n SplitPlane, SplitResult, DovetailSplitParams, DowelSplitParams, TenonSplitParams,\n} from './types'\n\n// BREP ops 类型导出\nexport type {\n BrepChainState, DrillBrepParams, SplitBrepParams, SplitBrepResult,\n ExtrudeBrepParams,\n} from '../brep'\nexport {\n createBrepChainState, initBrepChainState, releaseBrepChainState,\n solidToShape,\n isCadFormat,\n} from '../brep'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mesh/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,UAAU,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,MAAM,CAAA;AAE7B,sBAAsB;AAEtB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,cAAc;IACd,GAAG,EAAE,UAAU,CAAC,GAAG;IACnB,MAAM,EAAE,UAAU,CAAC,MAAM;IACzB,QAAQ,EAAE,UAAU,CAAC,QAAQ;IAC7B,IAAI,EAAE,UAAU,CAAC,IAAI;IACrB,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,GAAG,EAAE,UAAU,CAAC,GAAG;IAEnB,6BAA6B;IAC7B,OAAO,EAAE,cAAc,CAAC,OAAO;IAC/B,UAAU,EAAE,cAAc,CAAC,UAAU;IACrC,YAAY,EAAE,cAAc,CAAC,YAAY;IACzC,QAAQ,EAAE,cAAc,CAAC,QAAQ;IACjC,SAAS,EAAE,cAAc,CAAC,SAAS;IAEnC,KAAK;IACL,SAAS,EAAE,YAAY,CAAC,SAAS;IACjC,YAAY,EAAE,YAAY,CAAC,YAAY;IACvC,KAAK,EAAE,YAAY,CAAC,KAAK;IACzB,OAAO,EAAE,YAAY,CAAC,OAAO;IAC7B,eAAe,EAAE,YAAY,CAAC,eAAe;IAE7C,KAAK;IACL,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,QAAQ,EAAE,UAAU,CAAC,QAAQ;IAC7B,SAAS,EAAE,UAAU,CAAC,SAAS;IAE/B,KAAK;IACL,wDAAwD;IACxD,0EAA0E;IAE1E,KAAK;IACL,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,KAAK,EAAE,UAAU,CAAC,KAAK;IAEvB,KAAK;IACL,WAAW,EAAE,QAAQ,CAAC,WAAW;IACjC,UAAU,EAAE,QAAQ,CAAC,UAAU;IAC/B,MAAM,EAAE,QAAQ,CAAC,MAAM;IACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;IAEvB,KAAK;IACL,IAAI,EAAE,KAAK,CAAC,UAAU;IAEtB,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC,aAAa;IACpC,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;IACxB,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;IAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;IAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;CACnC,CAAA;AAKD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAazC,OAAO,EACL,oBAAoB,EAAE,kBAAkB,EAAE,qBAAqB,EAC/D,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA","sourcesContent":["/**\n * mesh — 纯数据几何 API 统一入口\n *\n * See docs/api-contract.md §1 (architecture layers) and §10 (api function catalog).\n *\n * 原则(§5.1):\n * 1. 全部纯数据:输入输出是 Shape (ManifoldMeshData),不碰 THREE 场景、不读 store\n * 2. 不可变:每个 API 返回新几何,不修改输入\n * 3. 同步签名、异步执行:API 签名同步(或 async);worker 边界由 ScriptEngine 处理\n * 4. 坐标系:右手系 +Z 向上、毫米、角度用度\n *\n * P1 阶段:mesh 是对现有纯函数的薄包装层,行为完全不变。\n * P3+ 阶段:mesh 将由 ScriptEngine 驱动,在 worker 中执行。\n */\n\nimport * as primitives from './primitives'\nimport * as brepPrimitives from '../brep/primitives-brep'\nimport * as brepOps from '../brep'\nimport * as booleanOps from './boolean'\nimport * as engraveOps from './engrave'\nimport * as transformOps from './transform'\nimport * as queryOps from './query'\nimport * as ioOps from './io'\n\n// ── 统一 cad API 对象 ──\n\n/**\n * Unified `cad` API object aggregating the pure-data mesh operations: mesh and\n * BREP primitives, transforms, booleans, engrave/knurl, geometry queries, file\n * IO, and BREP feature operations.\n *\n * D1(2026-09-23 扩展库拆分):`text` / `svgExtrude` / `fai_*` 键已随\n * `@faicad/faijs-extra` 迁出——它们的实现在扩展库的 mesh 面(`editorCad`)。\n */\nexport const cad = {\n // 创建(mesh 路径)\n box: primitives.box,\n sphere: primitives.sphere,\n cylinder: primitives.cylinder,\n cone: primitives.cone,\n wedge: primitives.wedge,\n screw: primitives.screw,\n sdf: primitives.sdf,\n\n // 创建(BREP 路径 — OCCT 精确实体三角化)\n boxBrep: brepPrimitives.boxBrep,\n sphereBrep: brepPrimitives.sphereBrep,\n cylinderBrep: brepPrimitives.cylinderBrep,\n coneBrep: brepPrimitives.coneBrep,\n wedgeBrep: brepPrimitives.wedgeBrep,\n\n // 变换\n translate: transformOps.translate,\n rotate_euler: transformOps.rotate_euler,\n scale: transformOps.scale,\n scale3d: transformOps.scale3d,\n transformMatrix: transformOps.transformMatrix,\n\n // 布尔\n union: booleanOps.union,\n subtract: booleanOps.subtract,\n intersect: booleanOps.intersect,\n\n // 分割\n // `fai_*` 键(编辑器消费面)已随扩展库迁出:@faicad/faijs-extra 的 mesh 面\n // 经 `mesh/fai_split.ts` / `mesh/fai_drill.ts` / `mesh/fai_extrude.ts` 提供。\n\n // 雕刻\n engrave: engraveOps.engrave,\n knurl: engraveOps.knurl,\n\n // 查询\n boundingBox: queryOps.boundingBox,\n bboxCenter: queryOps.bboxCenter,\n volume: queryOps.volume,\n faceAt: queryOps.faceAt,\n\n // IO\n load: ioOps.importFile,\n\n // BREP 特征操作(Phase 2 — OCCT 精确实体运算)\n translateBrep: brepOps.translateBrep,\n rotateBrep: brepOps.rotateBrep,\n scaleBrep: brepOps.scaleBrep,\n fuseBrep: brepOps.fuseBrep,\n cutBrep: brepOps.cutBrep,\n commonBrep: brepOps.commonBrep,\n drillBrep: brepOps.drillBrep,\n splitBrep: brepOps.splitBrep,\n extrudeBrep: brepOps.extrudeBrep,\n loadBrep: brepOps.loadBrep,\n solidToShape: brepOps.solidToShape,\n}\n\n// ── 类型导出 ──\n\nexport type { Shape, Vec3, BoundingBox, FaceDescriptor } from './types'\nexport { guessStlUnit } from './stl-unit'\nexport type {\n BoxParams, SphereParams, CylinderParams, ConeParams, WedgeParams,\n TextParams, SvgExtrudeParams, SdfParams,\n DrillParams, ExtrudeParams, EngraveParams, KnurlParams,\n SplitPlane, SplitResult, DovetailSplitParams, DowelSplitParams, TenonSplitParams,\n} from './types'\n\n// BREP ops 类型导出\nexport type {\n BrepChainState, DrillBrepParams, SplitBrepParams, SplitBrepResult,\n ExtrudeBrepParams,\n} from '../brep'\nexport {\n createBrepChainState, initBrepChainState, releaseBrepChainState,\n solidToShape,\n isCadFormat,\n} from '../brep'\n"]}
package/dist/mesh/io.d.ts CHANGED
@@ -25,6 +25,13 @@ export interface ImportFileResult {
25
25
  * null for declaration-less formats (STL) — the caller's opts.unit decided.
26
26
  */
27
27
  unit: UnitName | null;
28
+ /**
29
+ * Total parts the single file declared (e.g. 3MF `<build>` object count),
30
+ * present only when > 1. Single-part mesh (STL, single-object 3MF) omits it.
31
+ * When set, `shape` is only the FIRST part's geometry (feijs `load` op is
32
+ * single-part; the file was downgraded to its first part — §5.4).
33
+ */
34
+ multiPartCount?: number;
28
35
  }
29
36
  /**
30
37
  * Bounded scan window for `detectStepUnit`. Unit entities sit at the front of
@@ -1 +1 @@
1
- {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAM,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ;;;OAGG;IACH,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;CACtB;AAuBD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAa,CAAA;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBhE;AAeD;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,cAAc,CAAA;CAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAM,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ;;;OAGG;IACH,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAuBD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAa,CAAA;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,cAAc,CAAA;CAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAmC3B"}
package/dist/mesh/io.js CHANGED
@@ -86,18 +86,6 @@ export function detectStepUnit(stepText) {
86
86
  }
87
87
  return null;
88
88
  }
89
- /** Map a raw 3MF `<model unit>` attribute to a faijs UnitName (null when absent/unknown). */
90
- function threemfRawUnitToFaijs(raw) {
91
- switch (raw) {
92
- case 'micron': return 'micron';
93
- case 'millimeter': return 'mm';
94
- case 'centimeter': return 'cm';
95
- case 'inch': return 'inch';
96
- case 'foot': return 'foot';
97
- case 'meter': return 'm';
98
- default: return null;
99
- }
100
- }
101
89
  /**
102
90
  * Load geometry from raw file bytes (headless variant).
103
91
  *
@@ -113,11 +101,20 @@ function threemfRawUnitToFaijs(raw) {
113
101
  export async function importFile(buffer, format, opts) {
114
102
  const fmt = (format ?? 'stl').toLowerCase();
115
103
  if (fmt === '3mf' || fmt === 'threemf') {
116
- const mesh = await parseThreemf(buffer);
117
- const shape = { positions: mesh.positions, indices: mesh.indices };
118
- // parseThreemf already folded the declared unit into coordinates; surface
119
- // the raw declaration mapped to a faijs UnitName for metadata.
120
- return { shape, unit: threemfRawUnitToFaijs(mesh.sourceUnit) };
104
+ const archive = await parseThreemf(buffer);
105
+ // §5.4 单零件收敛:只取**第一个**对象实例(declaration order — `<build><item>`
106
+ // 序,见 threemf-loader)构造成单一 part;多对象文件记 multiPartCount 供上层
107
+ // 登记"多零件降级"警告。坐标已在 parseThreemf 里折算为 faijs 基准单位。
108
+ const first = archive.objects[0];
109
+ if (!first) {
110
+ throw new Error('[mesh/io] 3MF contains no objects');
111
+ }
112
+ const multiPartCount = archive.objects.length > 1 ? archive.objects.length : undefined;
113
+ const shape = {
114
+ positions: first.positions,
115
+ indices: first.indices,
116
+ };
117
+ return { shape, unit: archive.unit, multiPartCount };
121
118
  }
122
119
  if (fmt === 'stl') {
123
120
  const scale = (opts?.unit ?? mm).as(mm);