@faicad/faijs 0.19.0 → 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 (510) 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/brep-mirror/joinery-brep.d.ts.map +1 -1
  17. package/dist/api/brep-mirror/joinery-brep.js +3 -1
  18. package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
  19. package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
  20. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
  21. package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
  22. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
  23. package/dist/api/cadquery-selectors/edge.d.ts +40 -0
  24. package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
  25. package/dist/api/cadquery-selectors/edge.js +70 -0
  26. package/dist/api/cadquery-selectors/edge.js.map +1 -0
  27. package/dist/api/cadquery-selectors/entity.d.ts +121 -0
  28. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
  29. package/dist/api/cadquery-selectors/entity.js +167 -0
  30. package/dist/api/cadquery-selectors/entity.js.map +1 -0
  31. package/dist/api/cadquery-selectors/face.d.ts +33 -0
  32. package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
  33. package/dist/api/cadquery-selectors/face.js +353 -0
  34. package/dist/api/cadquery-selectors/face.js.map +1 -0
  35. package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
  36. package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
  37. package/dist/api/cadquery-selectors/grammar.js +345 -0
  38. package/dist/api/cadquery-selectors/grammar.js.map +1 -0
  39. package/dist/api/cadquery-selectors/index.d.ts +18 -0
  40. package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
  41. package/dist/api/cadquery-selectors/index.js +17 -0
  42. package/dist/api/cadquery-selectors/index.js.map +1 -0
  43. package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
  44. package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
  45. package/dist/api/cadquery-selectors/predicates.js +85 -0
  46. package/dist/api/cadquery-selectors/predicates.js.map +1 -0
  47. package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
  48. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
  49. package/dist/api/cadquery-selectors/resolve.js +243 -0
  50. package/dist/api/cadquery-selectors/resolve.js.map +1 -0
  51. package/dist/api/cadquery-selectors/types.d.ts +96 -0
  52. package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
  53. package/dist/api/cadquery-selectors/types.js +11 -0
  54. package/dist/api/cadquery-selectors/types.js.map +1 -0
  55. package/dist/api/chamfer.d.ts +13 -5
  56. package/dist/api/chamfer.d.ts.map +1 -1
  57. package/dist/api/chamfer.js +63 -7
  58. package/dist/api/chamfer.js.map +1 -1
  59. package/dist/api/compound-geom.d.ts +1 -1
  60. package/dist/api/compound-geom.js +1 -1
  61. package/dist/api/compound-geom.js.map +1 -1
  62. package/dist/api/draft.d.ts +1 -1
  63. package/dist/api/draft.js +1 -1
  64. package/dist/api/draft.js.map +1 -1
  65. package/dist/api/edge-ref.d.ts +1 -1
  66. package/dist/api/edge-ref.d.ts.map +1 -1
  67. package/dist/api/edge-ref.js +11 -3
  68. package/dist/api/edge-ref.js.map +1 -1
  69. package/dist/api/engrave.d.ts +1 -1
  70. package/dist/api/engrave.js +7 -7
  71. package/dist/api/engrave.js.map +1 -1
  72. package/dist/api/extrude.d.ts +6 -1
  73. package/dist/api/extrude.d.ts.map +1 -1
  74. package/dist/api/extrude.js +59 -5
  75. package/dist/api/extrude.js.map +1 -1
  76. package/dist/api/face-ref.d.ts +1 -1
  77. package/dist/api/face-ref.js +1 -1
  78. package/dist/api/face-ref.js.map +1 -1
  79. package/dist/api/feature-repair.d.ts +1 -1
  80. package/dist/api/feature-repair.js +1 -1
  81. package/dist/api/feature-repair.js.map +1 -1
  82. package/dist/api/fillet-variable.d.ts +1 -1
  83. package/dist/api/fillet-variable.js +1 -1
  84. package/dist/api/fillet-variable.js.map +1 -1
  85. package/dist/api/fillet.d.ts +28 -8
  86. package/dist/api/fillet.d.ts.map +1 -1
  87. package/dist/api/fillet.js +64 -9
  88. package/dist/api/fillet.js.map +1 -1
  89. package/dist/api/generated/script-face-manifest.d.ts +4 -0
  90. package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
  91. package/dist/api/generated/script-face-manifest.js.map +1 -1
  92. package/dist/api/geom.d.ts +1 -1
  93. package/dist/api/geom.js +1 -1
  94. package/dist/api/geom.js.map +1 -1
  95. package/dist/api/helix.d.ts +1 -1
  96. package/dist/api/helix.js +1 -1
  97. package/dist/api/helix.js.map +1 -1
  98. package/dist/api/import-brep.d.ts +20 -2
  99. package/dist/api/import-brep.d.ts.map +1 -1
  100. package/dist/api/import-brep.js +28 -3
  101. package/dist/api/import-brep.js.map +1 -1
  102. package/dist/api/import-step.d.ts +17 -2
  103. package/dist/api/import-step.d.ts.map +1 -1
  104. package/dist/api/import-step.js +23 -3
  105. package/dist/api/import-step.js.map +1 -1
  106. package/dist/api/index.d.ts +2 -1
  107. package/dist/api/index.d.ts.map +1 -1
  108. package/dist/api/index.js +5 -2
  109. package/dist/api/index.js.map +1 -1
  110. package/dist/api/internal/compat-op.js +1 -1
  111. package/dist/api/internal/compat-op.js.map +1 -1
  112. package/dist/api/internal/mesh-solid-op.d.ts +236 -0
  113. package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
  114. package/dist/api/internal/mesh-solid-op.js +352 -0
  115. package/dist/api/internal/mesh-solid-op.js.map +1 -0
  116. package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
  117. package/dist/api/internal/svg-asset-resolver.js +1 -1
  118. package/dist/api/internal/svg-asset-resolver.js.map +1 -1
  119. package/dist/api/knurl.d.ts +1 -1
  120. package/dist/api/knurl.d.ts.map +1 -1
  121. package/dist/api/knurl.js +3 -2
  122. package/dist/api/knurl.js.map +1 -1
  123. package/dist/api/loft.d.ts +1 -1
  124. package/dist/api/loft.js +1 -1
  125. package/dist/api/loft.js.map +1 -1
  126. package/dist/api/measurement/index.d.ts +9 -5
  127. package/dist/api/measurement/index.d.ts.map +1 -1
  128. package/dist/api/measurement/index.js +47 -20
  129. package/dist/api/measurement/index.js.map +1 -1
  130. package/dist/api/pattern.d.ts +5 -3
  131. package/dist/api/pattern.d.ts.map +1 -1
  132. package/dist/api/pattern.js +32 -4
  133. package/dist/api/pattern.js.map +1 -1
  134. package/dist/api/place.d.ts +1 -1
  135. package/dist/api/place.js +1 -1
  136. package/dist/api/place.js.map +1 -1
  137. package/dist/api/primitives.d.ts +5 -4
  138. package/dist/api/primitives.d.ts.map +1 -1
  139. package/dist/api/primitives.js +11 -5
  140. package/dist/api/primitives.js.map +1 -1
  141. package/dist/api/profile.d.ts +64 -8
  142. package/dist/api/profile.d.ts.map +1 -1
  143. package/dist/api/profile.js +61 -10
  144. package/dist/api/profile.js.map +1 -1
  145. package/dist/api/punch-hole.d.ts +3 -0
  146. package/dist/api/punch-hole.d.ts.map +1 -1
  147. package/dist/api/punch-hole.js.map +1 -1
  148. package/dist/api/reconcile.d.ts +1 -1
  149. package/dist/api/reconcile.js +1 -1
  150. package/dist/api/reconcile.js.map +1 -1
  151. package/dist/api/replicate.d.ts.map +1 -1
  152. package/dist/api/replicate.js +122 -1
  153. package/dist/api/replicate.js.map +1 -1
  154. package/dist/api/screw.d.ts +1 -1
  155. package/dist/api/screw.js +3 -3
  156. package/dist/api/screw.js.map +1 -1
  157. package/dist/api/sdf.d.ts +1 -1
  158. package/dist/api/sdf.js +2 -2
  159. package/dist/api/sdf.js.map +1 -1
  160. package/dist/api/section-by-plane.d.ts +1 -1
  161. package/dist/api/section-by-plane.d.ts.map +1 -1
  162. package/dist/api/section-by-plane.js +2 -1
  163. package/dist/api/section-by-plane.js.map +1 -1
  164. package/dist/api/shell.d.ts +11 -4
  165. package/dist/api/shell.d.ts.map +1 -1
  166. package/dist/api/shell.js +53 -7
  167. package/dist/api/shell.js.map +1 -1
  168. package/dist/api/sketch-on-face.d.ts +41 -0
  169. package/dist/api/sketch-on-face.d.ts.map +1 -1
  170. package/dist/api/sketch-on-face.js +100 -1
  171. package/dist/api/sketch-on-face.js.map +1 -1
  172. package/dist/api/sketch-on-plane.d.ts +17 -9
  173. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  174. package/dist/api/sketch-on-plane.js +12 -10
  175. package/dist/api/sketch-on-plane.js.map +1 -1
  176. package/dist/api/split-by-plane.d.ts +1 -1
  177. package/dist/api/split-by-plane.d.ts.map +1 -1
  178. package/dist/api/split-by-plane.js +2 -1
  179. package/dist/api/split-by-plane.js.map +1 -1
  180. package/dist/api/split.d.ts +1 -1
  181. package/dist/api/split.js +2 -2
  182. package/dist/api/split.js.map +1 -1
  183. package/dist/api/surface/arg-spec.d.ts +8 -0
  184. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  185. package/dist/api/surface/arg-spec.js.map +1 -1
  186. package/dist/api/sweep.d.ts +1 -1
  187. package/dist/api/sweep.js +1 -1
  188. package/dist/api/sweep.js.map +1 -1
  189. package/dist/api/thicken.d.ts +1 -1
  190. package/dist/api/thicken.js +1 -1
  191. package/dist/api/thicken.js.map +1 -1
  192. package/dist/api/topo-resolve.d.ts +74 -1
  193. package/dist/api/topo-resolve.d.ts.map +1 -1
  194. package/dist/api/topo-resolve.js +180 -2
  195. package/dist/api/topo-resolve.js.map +1 -1
  196. package/dist/api/transform.d.ts +10 -6
  197. package/dist/api/transform.d.ts.map +1 -1
  198. package/dist/api/transform.js +74 -21
  199. package/dist/api/transform.js.map +1 -1
  200. package/dist/api/wire.d.ts +1 -1
  201. package/dist/api/wire.js +1 -1
  202. package/dist/api/wire.js.map +1 -1
  203. package/dist/api/xml-dom.d.ts +27 -0
  204. package/dist/api/xml-dom.d.ts.map +1 -0
  205. package/dist/api/xml-dom.js +45 -0
  206. package/dist/api/xml-dom.js.map +1 -0
  207. package/dist/brep/brep-ops.d.ts +13 -11
  208. package/dist/brep/brep-ops.d.ts.map +1 -1
  209. package/dist/brep/brep-ops.js +31 -30
  210. package/dist/brep/brep-ops.js.map +1 -1
  211. package/dist/brep/brep-topology.d.ts +5 -4
  212. package/dist/brep/brep-topology.d.ts.map +1 -1
  213. package/dist/brep/brep-topology.js +9 -6
  214. package/dist/brep/brep-topology.js.map +1 -1
  215. package/dist/brep/effective-deflection.d.ts +35 -0
  216. package/dist/brep/effective-deflection.d.ts.map +1 -0
  217. package/dist/brep/effective-deflection.js +49 -0
  218. package/dist/brep/effective-deflection.js.map +1 -0
  219. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  220. package/dist/brep/engine/adapters/brep-mock.js +27 -0
  221. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  222. package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
  223. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  224. package/dist/brep/engine/adapters/brepkit.js +46 -1
  225. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  226. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  227. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  228. package/dist/brep/engine/adapters/occt.js +3 -1
  229. package/dist/brep/engine/adapters/occt.js.map +1 -1
  230. package/dist/brep/engine/primitives.d.ts +29 -7
  231. package/dist/brep/engine/primitives.d.ts.map +1 -1
  232. package/dist/brep/engine/primitives.js.map +1 -1
  233. package/dist/brep/engine/registry.d.ts +24 -1
  234. package/dist/brep/engine/registry.d.ts.map +1 -1
  235. package/dist/brep/engine/registry.js +24 -0
  236. package/dist/brep/engine/registry.js.map +1 -1
  237. package/dist/brep/engine/types.d.ts +54 -3
  238. package/dist/brep/engine/types.d.ts.map +1 -1
  239. package/dist/brep/engine/types.js +10 -0
  240. package/dist/brep/engine/types.js.map +1 -1
  241. package/dist/brep/export/export-model.d.ts +79 -0
  242. package/dist/brep/export/export-model.d.ts.map +1 -0
  243. package/dist/brep/export/export-model.js +336 -0
  244. package/dist/brep/export/export-model.js.map +1 -0
  245. package/dist/brep/face-evolution.d.ts +1 -1
  246. package/dist/brep/face-evolution.d.ts.map +1 -1
  247. package/dist/brep/face-evolution.js +20 -1
  248. package/dist/brep/face-evolution.js.map +1 -1
  249. package/dist/brep/handle-bridge.d.ts +1 -1
  250. package/dist/brep/handle-bridge.js +1 -1
  251. package/dist/brep/handle-bridge.js.map +1 -1
  252. package/dist/brep/mesh-solid.d.ts +218 -0
  253. package/dist/brep/mesh-solid.d.ts.map +1 -0
  254. package/dist/brep/mesh-solid.js +229 -0
  255. package/dist/brep/mesh-solid.js.map +1 -0
  256. package/dist/brep/primitives-brep.d.ts.map +1 -1
  257. package/dist/brep/primitives-brep.js +3 -1
  258. package/dist/brep/primitives-brep.js.map +1 -1
  259. package/dist/brep/text/fontRegistry.d.ts +32 -1
  260. package/dist/brep/text/fontRegistry.d.ts.map +1 -1
  261. package/dist/brep/text/fontRegistry.js +51 -1
  262. package/dist/brep/text/fontRegistry.js.map +1 -1
  263. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  264. package/dist/brep/text/text-to-solid.js +8 -3
  265. package/dist/brep/text/text-to-solid.js.map +1 -1
  266. package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
  267. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  268. package/dist/brepkit-kernel/brepkitKernel.js +453 -125
  269. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  270. package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
  271. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  272. package/dist/brepkit-kernel/brepkitWasm.js +10 -0
  273. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  274. package/dist/browser-host/browser-font-provider.d.ts +12 -0
  275. package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
  276. package/dist/browser-host/browser-font-provider.js +25 -0
  277. package/dist/browser-host/browser-font-provider.js.map +1 -1
  278. package/dist/browser.d.ts +6 -3
  279. package/dist/browser.d.ts.map +1 -1
  280. package/dist/browser.js +10 -3
  281. package/dist/browser.js.map +1 -1
  282. package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
  283. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  284. package/dist/cad-runtime/backend-dispatch.js +119 -4
  285. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  286. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  287. package/dist/cad-runtime/direct-executor.d.ts +19 -3
  288. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  289. package/dist/cad-runtime/direct-executor.js +49 -1
  290. package/dist/cad-runtime/direct-executor.js.map +1 -1
  291. package/dist/cad-runtime/ports.d.ts +3 -3
  292. package/dist/cad-runtime/ports.d.ts.map +1 -1
  293. package/dist/cad-runtime/ports.js.map +1 -1
  294. package/dist/cad-runtime/preview-exec.d.ts +4 -4
  295. package/dist/cad-runtime/preview-exec.js +2 -2
  296. package/dist/cad-runtime/preview-exec.js.map +1 -1
  297. package/dist/cad-runtime/runtime.d.ts +66 -8
  298. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  299. package/dist/cad-runtime/runtime.js +121 -8
  300. package/dist/cad-runtime/runtime.js.map +1 -1
  301. package/dist/define-op.d.ts +37 -1
  302. package/dist/define-op.d.ts.map +1 -1
  303. package/dist/define-op.js +25 -1
  304. package/dist/define-op.js.map +1 -1
  305. package/dist/env-agnostic.d.ts +7 -7
  306. package/dist/env-agnostic.d.ts.map +1 -1
  307. package/dist/env-agnostic.js +3 -3
  308. package/dist/env-agnostic.js.map +1 -1
  309. package/dist/geometry2d/adapt.d.ts +39 -4
  310. package/dist/geometry2d/adapt.d.ts.map +1 -1
  311. package/dist/geometry2d/adapt.js +14 -3
  312. package/dist/geometry2d/adapt.js.map +1 -1
  313. package/dist/geometry2d/blueprint.d.ts +2 -2
  314. package/dist/geometry2d/blueprint.js +2 -2
  315. package/dist/geometry2d/blueprint.js.map +1 -1
  316. package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
  317. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  318. package/dist/geometry2d/bridge/lift-on-plane.js +71 -12
  319. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  320. package/dist/geometry2d/bridge/plane.d.ts +17 -0
  321. package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
  322. package/dist/geometry2d/bridge/plane.js +22 -0
  323. package/dist/geometry2d/bridge/plane.js.map +1 -1
  324. package/dist/geometry2d/curve2d.d.ts +25 -0
  325. package/dist/geometry2d/curve2d.d.ts.map +1 -1
  326. package/dist/geometry2d/curve2d.js +41 -5
  327. package/dist/geometry2d/curve2d.js.map +1 -1
  328. package/dist/geometry2d/pen-sketcher.d.ts +25 -0
  329. package/dist/geometry2d/pen-sketcher.d.ts.map +1 -1
  330. package/dist/geometry2d/pen-sketcher.js +43 -0
  331. package/dist/geometry2d/pen-sketcher.js.map +1 -1
  332. package/dist/index.d.ts +6 -2
  333. package/dist/index.d.ts.map +1 -1
  334. package/dist/index.js +10 -3
  335. package/dist/index.js.map +1 -1
  336. package/dist/io/bytes-node.d.ts +11 -0
  337. package/dist/io/bytes-node.d.ts.map +1 -0
  338. package/dist/io/bytes-node.js +28 -0
  339. package/dist/io/bytes-node.js.map +1 -0
  340. package/dist/io/bytes.d.ts +33 -0
  341. package/dist/io/bytes.d.ts.map +1 -0
  342. package/dist/io/bytes.js +41 -0
  343. package/dist/io/bytes.js.map +1 -0
  344. package/dist/io/fai-zip/container-read.d.ts +102 -0
  345. package/dist/io/fai-zip/container-read.d.ts.map +1 -0
  346. package/dist/io/fai-zip/container-read.js +305 -0
  347. package/dist/io/fai-zip/container-read.js.map +1 -0
  348. package/dist/io/fai-zip/container-write.d.ts +70 -0
  349. package/dist/io/fai-zip/container-write.d.ts.map +1 -0
  350. package/dist/io/fai-zip/container-write.js +186 -0
  351. package/dist/io/fai-zip/container-write.js.map +1 -0
  352. package/dist/io/fai-zip/container.d.ts +107 -0
  353. package/dist/io/fai-zip/container.d.ts.map +1 -0
  354. package/dist/io/fai-zip/container.js +89 -0
  355. package/dist/io/fai-zip/container.js.map +1 -0
  356. package/dist/io/fai-zip/index.d.ts +18 -0
  357. package/dist/io/fai-zip/index.d.ts.map +1 -0
  358. package/dist/io/fai-zip/index.js +4 -0
  359. package/dist/io/fai-zip/index.js.map +1 -0
  360. package/dist/io/index.d.ts +10 -0
  361. package/dist/io/index.d.ts.map +1 -0
  362. package/dist/io/index.js +13 -0
  363. package/dist/io/index.js.map +1 -0
  364. package/dist/io/zip.d.ts +68 -0
  365. package/dist/io/zip.d.ts.map +1 -0
  366. package/dist/io/zip.js +147 -0
  367. package/dist/io/zip.js.map +1 -0
  368. package/dist/lang/code-to-args.d.ts +30 -4
  369. package/dist/lang/code-to-args.d.ts.map +1 -1
  370. package/dist/lang/code-to-args.js +42 -3
  371. package/dist/lang/code-to-args.js.map +1 -1
  372. package/dist/lang/codegen.d.ts +45 -1
  373. package/dist/lang/codegen.d.ts.map +1 -1
  374. package/dist/lang/codegen.js +135 -6
  375. package/dist/lang/codegen.js.map +1 -1
  376. package/dist/lang/host-arg.d.ts +6 -0
  377. package/dist/lang/host-arg.d.ts.map +1 -1
  378. package/dist/lang/host-arg.js.map +1 -1
  379. package/dist/lang/metadata-extractor.d.ts +25 -0
  380. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  381. package/dist/lang/metadata-extractor.js +289 -25
  382. package/dist/lang/metadata-extractor.js.map +1 -1
  383. package/dist/lang/parse-error.d.ts +7 -1
  384. package/dist/lang/parse-error.d.ts.map +1 -1
  385. package/dist/lang/parse-error.js.map +1 -1
  386. package/dist/lang/security-scanner.d.ts +9 -1
  387. package/dist/lang/security-scanner.d.ts.map +1 -1
  388. package/dist/lang/security-scanner.js +38 -1
  389. package/dist/lang/security-scanner.js.map +1 -1
  390. package/dist/lang/statement-summary.d.ts +1 -1
  391. package/dist/lang/statement-summary.js +1 -1
  392. package/dist/lang/statement-summary.js.map +1 -1
  393. package/dist/lang/types.d.ts +1 -1
  394. package/dist/lang/types.js +1 -1
  395. package/dist/lang/types.js.map +1 -1
  396. package/dist/mesh/index.d.ts +2 -1
  397. package/dist/mesh/index.d.ts.map +1 -1
  398. package/dist/mesh/index.js +2 -1
  399. package/dist/mesh/index.js.map +1 -1
  400. package/dist/mesh/io.d.ts +69 -9
  401. package/dist/mesh/io.d.ts.map +1 -1
  402. package/dist/mesh/io.js +121 -17
  403. package/dist/mesh/io.js.map +1 -1
  404. package/dist/mesh/reconcile.d.ts +1 -1
  405. package/dist/mesh/reconcile.js +1 -1
  406. package/dist/mesh/reconcile.js.map +1 -1
  407. package/dist/mesh/rigid-transform.d.ts +3 -3
  408. package/dist/mesh/rigid-transform.js +3 -3
  409. package/dist/mesh/rigid-transform.js.map +1 -1
  410. package/dist/mesh/stl-unit.d.ts +24 -0
  411. package/dist/mesh/stl-unit.d.ts.map +1 -0
  412. package/dist/mesh/stl-unit.js +17 -0
  413. package/dist/mesh/stl-unit.js.map +1 -0
  414. package/dist/mesh/threemf-bambu.d.ts +142 -0
  415. package/dist/mesh/threemf-bambu.d.ts.map +1 -0
  416. package/dist/mesh/threemf-bambu.js +334 -0
  417. package/dist/mesh/threemf-bambu.js.map +1 -0
  418. package/dist/mesh/threemf-loader.d.ts +50 -0
  419. package/dist/mesh/threemf-loader.d.ts.map +1 -0
  420. package/dist/mesh/threemf-loader.js +628 -0
  421. package/dist/mesh/threemf-loader.js.map +1 -0
  422. package/dist/mesh/threemf-view.d.ts +71 -0
  423. package/dist/mesh/threemf-view.d.ts.map +1 -0
  424. package/dist/mesh/threemf-view.js +100 -0
  425. package/dist/mesh/threemf-view.js.map +1 -0
  426. package/dist/mesh/transform.d.ts +2 -2
  427. package/dist/mesh/transform.d.ts.map +1 -1
  428. package/dist/mesh/transform.js +3 -3
  429. package/dist/mesh/transform.js.map +1 -1
  430. package/dist/mesh/types.d.ts +1 -1
  431. package/dist/mesh/types.d.ts.map +1 -1
  432. package/dist/mesh/types.js.map +1 -1
  433. package/dist/node-host/cli.d.ts +44 -6
  434. package/dist/node-host/cli.d.ts.map +1 -1
  435. package/dist/node-host/cli.js +127 -50
  436. package/dist/node-host/cli.js.map +1 -1
  437. package/dist/node-host/font-family-index.d.ts +93 -0
  438. package/dist/node-host/font-family-index.d.ts.map +1 -0
  439. package/dist/node-host/font-family-index.js +273 -0
  440. package/dist/node-host/font-family-index.js.map +1 -0
  441. package/dist/node-host/fs-asset-resolver.d.ts +8 -3
  442. package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
  443. package/dist/node-host/fs-asset-resolver.js +13 -5
  444. package/dist/node-host/fs-asset-resolver.js.map +1 -1
  445. package/dist/node-host/index.d.ts +8 -0
  446. package/dist/node-host/index.d.ts.map +1 -1
  447. package/dist/node-host/index.js +1 -0
  448. package/dist/node-host/index.js.map +1 -1
  449. package/dist/node-host/node-font-provider.d.ts +28 -0
  450. package/dist/node-host/node-font-provider.d.ts.map +1 -1
  451. package/dist/node-host/node-font-provider.js +49 -0
  452. package/dist/node-host/node-font-provider.js.map +1 -1
  453. package/dist/node.d.ts +1 -0
  454. package/dist/node.d.ts.map +1 -1
  455. package/dist/node.js +1 -0
  456. package/dist/node.js.map +1 -1
  457. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  458. package/dist/occt-kernel/occt-primitives.js +35 -2
  459. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  460. package/dist/occt-kernel/occtKernel.d.ts +18 -13
  461. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  462. package/dist/occt-kernel/occtKernel.js +20 -31
  463. package/dist/occt-kernel/occtKernel.js.map +1 -1
  464. package/dist/occt-kernel/stepColorParser.d.ts +18 -0
  465. package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
  466. package/dist/occt-kernel/stepColorParser.js +38 -0
  467. package/dist/occt-kernel/stepColorParser.js.map +1 -1
  468. package/dist/occt-kernel/topologyExt.d.ts +1 -1
  469. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  470. package/dist/occt-kernel/topologyExt.js +8 -6
  471. package/dist/occt-kernel/topologyExt.js.map +1 -1
  472. package/dist/primitives/text/cjk-font.d.ts +2 -15
  473. package/dist/primitives/text/cjk-font.d.ts.map +1 -1
  474. package/dist/primitives/text/cjk-font.js +13 -1
  475. package/dist/primitives/text/cjk-font.js.map +1 -1
  476. package/dist/runtime-state.d.ts +103 -9
  477. package/dist/runtime-state.d.ts.map +1 -1
  478. package/dist/runtime-state.js +95 -2
  479. package/dist/runtime-state.js.map +1 -1
  480. package/dist/sdk.d.ts +4 -4
  481. package/dist/sdk.d.ts.map +1 -1
  482. package/dist/sdk.js +6 -6
  483. package/dist/sdk.js.map +1 -1
  484. package/dist/shape.d.ts +97 -2
  485. package/dist/shape.d.ts.map +1 -1
  486. package/dist/shape.js +126 -1
  487. package/dist/shape.js.map +1 -1
  488. package/dist/tolerance.d.ts +38 -0
  489. package/dist/tolerance.d.ts.map +1 -0
  490. package/dist/tolerance.js +40 -0
  491. package/dist/tolerance.js.map +1 -0
  492. package/dist/topology/naming/lineage.d.ts +6 -0
  493. package/dist/topology/naming/lineage.d.ts.map +1 -1
  494. package/dist/topology/naming/lineage.js +8 -0
  495. package/dist/topology/naming/lineage.js.map +1 -1
  496. package/dist/topology/naming/resolve-edge.d.ts +20 -1
  497. package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
  498. package/dist/topology/naming/resolve-edge.js +54 -20
  499. package/dist/topology/naming/resolve-edge.js.map +1 -1
  500. package/dist/topology/naming/score.js +3 -3
  501. package/dist/topology/naming/score.js.map +1 -1
  502. package/dist/units.d.ts +248 -0
  503. package/dist/units.d.ts.map +1 -0
  504. package/dist/units.js +397 -0
  505. package/dist/units.js.map +1 -0
  506. package/dist/weapp.d.ts +6 -2
  507. package/dist/weapp.d.ts.map +1 -1
  508. package/dist/weapp.js +7 -1
  509. package/dist/weapp.js.map +1 -1
  510. package/package.json +28 -3
@@ -1 +1 @@
1
- {"version":3,"file":"code-to-args.d.ts","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAqDzC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,gBAAgB,CA0B/F"}
1
+ {"version":3,"file":"code-to-args.d.ts","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAGrE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAsDjD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,QAAQ,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,gBAAgB,CA+BvF;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAWxG"}
@@ -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 语义一致),
@@ -20,6 +20,7 @@
20
20
  */
21
21
  import { extractMetadata } from './metadata-extractor.js';
22
22
  import { isHostRef } from './host-arg.js';
23
+ import { SCRIPT_UNIT_NAMES, UNIT_SCALE, UNIT_DIM, SCRIPT_UNIT_TO_NAME } from '../units.js';
23
24
  /**
24
25
  * 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):
25
26
  * parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的
@@ -42,7 +43,10 @@ function extractIdentifiers(line, namespaces) {
42
43
  const ids = new Set();
43
44
  for (const m of withoutStrings.matchAll(IDENT_RE)) {
44
45
  const id = m[0];
45
- if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id))
46
+ // P7/D10.4: unit constants (MM, INCH, DEGREE, …) must NOT be pre-declared
47
+ // as sentinel parameters (`let INCH = 0`), because that would shadow the
48
+ // real global value and cause `10 * INCH` to fold to 0.
49
+ if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id) || SCRIPT_UNIT_NAMES.has(id))
46
50
  continue;
47
51
  ids.add(id);
48
52
  }
@@ -104,7 +108,12 @@ export function codeToArgs(codeLine, opts) {
104
108
  // 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;
105
109
  // 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,
106
110
  // 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。
107
- const meta = extractMetadata(code, { namespaces: opts?.namespaces ?? [], looseLocalCalls: true });
111
+ // opDims 透传给 dimension pass(P6 消费,P4 仅透传声明面)。
112
+ const meta = extractMetadata(code, {
113
+ namespaces: opts?.namespaces ?? [],
114
+ looseLocalCalls: true,
115
+ ...(opts?.opDims ? { opDims: opts.opDims } : {}),
116
+ });
108
117
  const last = meta.lines[meta.lines.length - 1];
109
118
  if (!last)
110
119
  return { positional: [], args: {} };
@@ -121,4 +130,34 @@ export function codeToArgs(codeLine, opts) {
121
130
  }
122
131
  return { positional, args: { ...last.args } };
123
132
  }
133
+ // ── P7/D10: unit literal parsing ────────────────────────────────────────────
134
+ /**
135
+ * Reverse mapping: script-side constant name (UPPERCASE) → internal UnitName.
136
+ */
137
+ const CONST_TO_UNIT = Object.freeze(Object.fromEntries(Object.keys(SCRIPT_UNIT_TO_NAME).map((k) => [k, SCRIPT_UNIT_TO_NAME[k]])));
138
+ /**
139
+ * Parse a unit literal text expression (`n * UNIT`) into its base-unit value.
140
+ *
141
+ * P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like
142
+ * `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.
143
+ * Non-unit-literal expressions return `null` (host decides whether to
144
+ * downgrade to read-only).
145
+ *
146
+ * @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).
147
+ * @returns the parsed unit literal info, or `null` if not a unit literal.
148
+ */
149
+ export function parseUnitLiteral(text) {
150
+ const match = /^\s*(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s*\*\s*([A-Z]+)\s*$/.exec(text);
151
+ if (!match)
152
+ return null;
153
+ const n = Number(match[1]);
154
+ const constName = match[2];
155
+ const unitName = CONST_TO_UNIT[constName];
156
+ if (!unitName)
157
+ return null;
158
+ const dim = UNIT_DIM[unitName];
159
+ // toBase: n * UNIT_SCALE[unitName]
160
+ const base = n * UNIT_SCALE[unitName];
161
+ return { base, dim, unitName };
162
+ }
124
163
  //# sourceMappingURL=code-to-args.js.map
@@ -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 } from './metadata-extractor'\nimport { isHostRef } from './host-arg'\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 if (NON_DECL.has(id) || declared.has(id) || namespaces?.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 * 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 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?: { namespaces?: string[] }): 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 const meta = extractMetadata(code, { namespaces: opts?.namespaces ?? [], looseLocalCalls: true })\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"]}
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"]}
@@ -20,6 +20,7 @@
20
20
  * - 对象字面量 → `{key:value}`(冒号,合法 JS)
21
21
  */
22
22
  import type { HostArg } from './host-arg.js';
23
+ import type { DimName, UnitName, UnitContext } from '../units.js';
23
24
  /**
24
25
  * Format a number as text: integers emit as-is; decimals retain at most 6
25
26
  * significant fractional digits with trailing zeros stripped.
@@ -27,6 +28,43 @@ import type { HostArg } from './host-arg.js';
27
28
  * @returns the formatted text representation.
28
29
  */
29
30
  export declare function fmtNum(n: number): string;
31
+ /**
32
+ * Format a unit literal number using JS shortest-round-trip representation.
33
+ *
34
+ * P7/D10.3 rule 5: unit literal numbers MUST use `String(n)` (e.g.
35
+ * `0.39370078740157477`), NEVER `fmtNum` (which truncates to 6 decimal
36
+ * places and would silently zero out `1e-7`).
37
+ * @param n - the number to format.
38
+ * @returns the shortest JS round-trip text representation.
39
+ */
40
+ export declare function fmtUnitNum(n: number): string;
41
+ /**
42
+ * Format a base-unit value as a unit literal expression (`n * UNIT`).
43
+ *
44
+ * P7/D10.3: `base` is the base-unit (mm/degree) value; `dim` determines which
45
+ * system display unit to use; `unitName` is the target display unit.
46
+ * The number is formatted with `fmtUnitNum` (not `fmtNum`).
47
+ * @param base - the base-unit numeric value.
48
+ * @param dim - the dimension of the value.
49
+ * @param unitName - the display unit to express the value in.
50
+ * @returns text like `10 * INCH` or `0.39370078740157477 * INCH`.
51
+ */
52
+ export declare function formatUnitLiteral(base: number, dim: DimName, unitName: UnitName): string;
53
+ /**
54
+ * P7/D10.3: Options for unit-aware serialization of `formatCodeLine`.
55
+ *
56
+ * When provided, dimensioned parameters are emitted as unit literals
57
+ * (`n * UNIT`). When absent, output is byte-identical to the pre-P7 behavior.
58
+ */
59
+ export interface UnitSerializeOptions {
60
+ /** System display unit; defaults to base (mm / degree). */
61
+ units?: UnitContext;
62
+ /** Parameter dimension declarations (host provides from op paramDims + slotMap). */
63
+ dims?: {
64
+ positional?: (DimName | null)[];
65
+ byKey?: Record<string, DimName>;
66
+ };
67
+ }
30
68
  /**
31
69
  * Pure-data input for printing one faijs source line, decoupled from IR types.
32
70
  *
@@ -65,8 +103,14 @@ export interface FormatCodeLineInput {
65
103
  * 从纯数据(非 IR 类型)打印一行 faijs 源代码。
66
104
  *
67
105
  * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
106
+ *
107
+ * P7/D10: when `opts` is provided, dimensioned parameters are serialized as
108
+ * unit literals (`n * UNIT`). When `opts` is absent, output is byte-identical
109
+ * to the pre-P7 behavior (zero-impact regression guarantee).
110
+ *
68
111
  * @param input - the pure-data line description.
112
+ * @param opts - optional unit serialization options (P7/D10).
69
113
  * @returns the printed single-line code text.
70
114
  */
71
- export declare function formatCodeLine(input: FormatCodeLineInput): string;
115
+ export declare function formatCodeLine(input: FormatCodeLineInput, opts?: UnitSerializeOptions): string;
72
116
  //# sourceMappingURL=codegen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAKzC;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxC;AAmDD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,YAAY;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAOD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAoDjE"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAK9D;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxC;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAcD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAIxF;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAC5E;AA0BD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,YAAY;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAyFD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,MAAM,CA4D9F"}
@@ -20,6 +20,7 @@
20
20
  * - 对象字面量 → `{key:value}`(冒号,合法 JS)
21
21
  */
22
22
  import { isHostVarRef, isHostParamRef, isHostCallRef, isHostExprRef, isHostRef } from './host-arg.js';
23
+ import { unitFor, fromBase } from '../units.js';
23
24
  // ── 数值格式化 ──
24
25
  /**
25
26
  * Format a number as text: integers emit as-is; decimals retain at most 6
@@ -57,6 +58,45 @@ function escapeStr(s) {
57
58
  }
58
59
  return out;
59
60
  }
61
+ /**
62
+ * Format a unit literal number using JS shortest-round-trip representation.
63
+ *
64
+ * P7/D10.3 rule 5: unit literal numbers MUST use `String(n)` (e.g.
65
+ * `0.39370078740157477`), NEVER `fmtNum` (which truncates to 6 decimal
66
+ * places and would silently zero out `1e-7`).
67
+ * @param n - the number to format.
68
+ * @returns the shortest JS round-trip text representation.
69
+ */
70
+ export function fmtUnitNum(n) {
71
+ return String(n);
72
+ }
73
+ /**
74
+ * Reverse lookup: find the script-side unit constant name for a given
75
+ * `UnitName`. Returns the UPPERCASE constant name (e.g. `INCH` for `'inch'`).
76
+ */
77
+ const NAME_TO_CONST = {
78
+ mm: 'MM', cm: 'CM', m: 'METER', micron: 'MICRON',
79
+ inch: 'INCH', foot: 'FOOT', yard: 'YARD',
80
+ degree: 'DEGREE', radian: 'RADIAN',
81
+ gram: 'GRAM', kilogram: 'KILOGRAM',
82
+ second: 'SECOND',
83
+ };
84
+ /**
85
+ * Format a base-unit value as a unit literal expression (`n * UNIT`).
86
+ *
87
+ * P7/D10.3: `base` is the base-unit (mm/degree) value; `dim` determines which
88
+ * system display unit to use; `unitName` is the target display unit.
89
+ * The number is formatted with `fmtUnitNum` (not `fmtNum`).
90
+ * @param base - the base-unit numeric value.
91
+ * @param dim - the dimension of the value.
92
+ * @param unitName - the display unit to express the value in.
93
+ * @returns text like `10 * INCH` or `0.39370078740157477 * INCH`.
94
+ */
95
+ export function formatUnitLiteral(base, dim, unitName) {
96
+ const displayValue = fromBase(base, unitName, dim);
97
+ const constName = NAME_TO_CONST[unitName];
98
+ return `${fmtUnitNum(displayValue)} * ${constName}`;
99
+ }
60
100
  /** 参数值 → 文本(递归,HostArg 面) */
61
101
  function fmtValue(value) {
62
102
  if (value === null)
@@ -77,7 +117,7 @@ function fmtValue(value) {
77
117
  return `${namespace ?? 'cad'}.${callee}(${inner})`;
78
118
  }
79
119
  if (isHostExprRef(value))
80
- return `(${value.text})`;
120
+ return value.bare ? value.text : `(${value.text})`;
81
121
  if (Array.isArray(value))
82
122
  return `[${value.map(fmtValue).join(',')}]`;
83
123
  if (typeof value === 'object') {
@@ -91,13 +131,34 @@ function isPlainObjArg(arg) {
91
131
  return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && !isHostRef(arg);
92
132
  }
93
133
  /**
94
- * 从纯数据(非 IR 类型)打印一行 faijs 源代码。
134
+ * Recursively format a HostArg value, applying unit wrapping to numbers inside
135
+ * arrays (vec3) and plain objects when a dimension is declared.
136
+ */
137
+ function fmtValueWithDim(value, dim, opts) {
138
+ if (opts && dim) {
139
+ // Number → unit literal
140
+ if (typeof value === 'number') {
141
+ const unitName = unitFor(dim, opts.units);
142
+ return formatUnitLiteral(value, dim, unitName);
143
+ }
144
+ // Array (vec3) → element-wise
145
+ if (Array.isArray(value)) {
146
+ return `[${value.map((el) => fmtValueWithDim(el, dim, opts)).join(',')}]`;
147
+ }
148
+ // Bare expr-ref already containing a unit literal → keep as-is
149
+ if (isHostExprRef(value) && value.bare)
150
+ return value.text;
151
+ }
152
+ return fmtValue(value);
153
+ }
154
+ /**
155
+ * Original `formatCodeLine` body without unit support (P7 fast path).
95
156
  *
96
- * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
97
- * @param input - the pure-data line description.
98
- * @returns the printed single-line code text.
157
+ * This is the byte-identical pre-P7 implementation, called when `opts` is
158
+ * absent or has no `dims` field. Kept as a separate function so the
159
+ * unit-aware path can be tested independently.
99
160
  */
100
- export function formatCodeLine(input) {
161
+ function formatCodeLineRaw(input) {
101
162
  const positional = input.positional;
102
163
  const argsInput = input.args ?? {};
103
164
  // 位置实参按序打印
@@ -145,4 +206,72 @@ export function formatCodeLine(input) {
145
206
  return `${out} = ${nsExpr}(${callArgs})`;
146
207
  return `let ${out} = ${nsExpr}(${callArgs})`;
147
208
  }
209
+ /**
210
+ * 从纯数据(非 IR 类型)打印一行 faijs 源代码。
211
+ *
212
+ * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
213
+ *
214
+ * P7/D10: when `opts` is provided, dimensioned parameters are serialized as
215
+ * unit literals (`n * UNIT`). When `opts` is absent, output is byte-identical
216
+ * to the pre-P7 behavior (zero-impact regression guarantee).
217
+ *
218
+ * @param input - the pure-data line description.
219
+ * @param opts - optional unit serialization options (P7/D10).
220
+ * @returns the printed single-line code text.
221
+ */
222
+ export function formatCodeLine(input, opts) {
223
+ // Fast path: no unit options → original behavior (byte-identical)
224
+ if (!opts || !opts.dims) {
225
+ return formatCodeLineRaw(input);
226
+ }
227
+ const positional = input.positional;
228
+ const argsInput = input.args ?? {};
229
+ const posDims = opts.dims.positional ?? [];
230
+ const keyDims = opts.dims.byKey ?? {};
231
+ // Positional args with per-index dimension
232
+ const positionalParts = positional.map((arg, i) => {
233
+ const dim = posDims[i] ?? null;
234
+ if (isPlainObjArg(arg)) {
235
+ const entries = Object.entries(arg);
236
+ return `{ ${entries.map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`).join(', ')} }`;
237
+ }
238
+ return fmtValueWithDim(arg, dim, opts);
239
+ });
240
+ // args slot (transitional compat: appended as trailing option when last positional is not a plain object)
241
+ const argsParts = Object.entries(argsInput).map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`);
242
+ const lastIsPlainObject = positional.length > 0 && isPlainObjArg(positional[positional.length - 1]);
243
+ let callArgs;
244
+ if (positionalParts.length > 0) {
245
+ callArgs = positionalParts.join(', ');
246
+ if (!lastIsPlainObject && argsParts.length > 0) {
247
+ callArgs = [...positionalParts, `{ ${argsParts.join(', ')} }`].join(', ');
248
+ }
249
+ }
250
+ else if (input.receiver) {
251
+ callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '';
252
+ }
253
+ else {
254
+ callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '{}';
255
+ }
256
+ // F2:命名空间前缀(缺省 cad);本机函数调用 callee 无命名空间前缀
257
+ const nsExpr = input.namespace === undefined ? `cad.${input.callee}` : `${input.namespace}.${input.callee}`;
258
+ // 1) 解构:outputKeys + outputs 一一对应
259
+ if (input.outputKeys && input.outputKeys.length > 0) {
260
+ const destructure = input.outputKeys.map((k, i) => `${k}: ${input.outputs[i]}`).join(', ');
261
+ return `const { ${destructure} } = ${nsExpr}(${callArgs})`;
262
+ }
263
+ // 2) 成员调用
264
+ if (input.receiver) {
265
+ return `${input.receiver}.${input.callee}(${callArgs})`;
266
+ }
267
+ // 3) 无赋值调用
268
+ if (input.outputs.length === 0) {
269
+ return `${nsExpr}(${callArgs})`;
270
+ }
271
+ // 4) 赋值:outputDeclared → 裸重赋值;否则 let 声明
272
+ const out = input.outputs[0];
273
+ if (input.outputDeclared)
274
+ return `${out} = ${nsExpr}(${callArgs})`;
275
+ return `let ${out} = ${nsExpr}(${callArgs})`;
276
+ }
148
277
  //# sourceMappingURL=codegen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * codegen — 纯数据 → 文本 打印工具(宿主编辑器/测试用;L0,仅依赖 host-arg)\n *\n * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。\n * 输入是纯数据(HostArg 面),不依赖任何 IR 类型。\n *\n * 扁平代码格式(无 export/async/await/return/参数声明):\n * ```js\n * let part0 = cad.box(10, 20, 30)\n * part0 = cad.translate(part0, { offset: [1, 2, 3] })\n * ```\n *\n * 值格式约定(确定性输出):\n * - vec3 → `[1,2,3]`(紧凑无空格)\n * - 数字 → 整数直出;小数最多保留 6 位有效小数并去尾零\n * - 字符串 → 单引号包裹\n * - HostVarRef → 裸变量名(members 元素)\n * - HostCallRef → `cad.faceNormal(part0)`(嵌套调用)\n * - HostExprRef → `(expr text)`(原文加括号)\n * - 对象字面量 → `{key:value}`(冒号,合法 JS)\n */\n\nimport type { HostArg } from './host-arg'\nimport { isHostVarRef, isHostParamRef, isHostCallRef, isHostExprRef, isHostRef } from './host-arg'\n\n// ── 数值格式化 ──\n\n/**\n * Format a number as text: integers emit as-is; decimals retain at most 6\n * significant fractional digits with trailing zeros stripped.\n * @param n - the number to format.\n * @returns the formatted text representation.\n */\nexport function fmtNum(n: number): string {\n if (!Number.isFinite(n)) return String(n)\n if (Number.isInteger(n)) return String(n)\n const s = n.toFixed(6)\n return s.replace(/\\.?0+$/, '')\n}\n\n// ── 字符串转义 ──\n\n/** 字符串转义:转义反斜杠、单引号与控制字符(多行 SDF code 等字符串参数用)。\n * 逐一字符映射(避开 regex 控制字符字面量,满足 eslint no-control-regex),\n * 保证 fmtValue ⇄ analyzeCode 往返一致:嵌入 '…' 后仍是合法 JS,可被精确还原。 */\nconst STRING_ESCAPES: Record<string, string> = {\n '\\\\': '\\\\\\\\',\n \"'\": \"\\\\'\",\n '\\u0008': '\\\\b', // backspace\n '\\u000C': '\\\\f', // form feed\n '\\u000A': '\\\\n', // line feed\n '\\u000D': '\\\\r', // carriage return\n '\\u0009': '\\\\t', // tab\n '\\u000B': '\\\\v', // vertical tab\n}\n\nfunction escapeStr(s: string): string {\n let out = ''\n for (let i = 0; i < s.length; i++) {\n const esc = STRING_ESCAPES[s[i]]\n out += esc ?? s[i]\n }\n return out\n}\n\n/** 参数值 → 文本(递归,HostArg 面) */\nfunction fmtValue(value: HostArg): string {\n if (value === null) return 'null'\n if (typeof value === 'number') return fmtNum(value)\n if (typeof value === 'boolean') return String(value)\n if (typeof value === 'string') return `'${escapeStr(value)}'`\n if (isHostVarRef(value)) return value.name\n if (isHostParamRef(value)) return value.name\n if (isHostCallRef(value)) {\n const { callee, args, namespace } = value\n const inner = args.map(fmtValue).join(', ')\n return `${namespace ?? 'cad'}.${callee}(${inner})`\n }\n if (isHostExprRef(value)) return `(${value.text})`\n if (Array.isArray(value)) return `[${value.map(fmtValue).join(',')}]`\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, HostArg>)\n return `{${entries.map(([k, v]) => `${k}:${fmtValue(v)}`).join(', ')}}`\n }\n return String(value)\n}\n\n// ── 纯数据 → 代码行(宿主代码生成入口) ──\n\n/**\n * Pure-data input for printing one faijs source line, decoupled from IR types.\n *\n * `positional` and `args` use `HostArg` (host-friendly types with `kind`-based\n * discrimination).\n */\nexport interface FormatCodeLineInput {\n callee: string\n /** 成员方法调用接收者变量名 */\n receiver?: string\n /**\n * 位置实参槽(HostArg 形态):宿主可传字面量、\n * 变量引用(`{kind:'var-ref',name}`)、参数引用(`{kind:'param-ref',name}`)、\n * 嵌套调用(`{kind:'call-ref',callee,args,namespace?}`)、\n * 表达式(`{kind:'expr-ref',text,refs,params}`)或纯 JsonValue,按序打印。\n */\n positional: HostArg[]\n /** 产出变量名 */\n outputs: string[]\n /** 解构键(与 outputs 一一对应) */\n outputKeys?: string[]\n /**\n * (过渡兼容)选项对象:positional 末位不是纯对象时追加为尾随选项对象。\n * 新代码应把选项对象直接放进 positional。\n */\n args?: Record<string, HostArg>\n /** 调用命名空间(F2:第三方库 `mech.makeHeadstock(...)` → 'mech';缺省 'cad') */\n namespace?: string\n /**\n * outputs[0] 是否已在代码中声明:true → 裸重赋值(`part0 = ...`),\n * false/省略 → let 声明;解构/成员调用/无输出时忽略。\n */\n outputDeclared?: boolean\n}\n\n/** 检测 HostArg 是否为纯数据对象(非引用形态)。 */\nfunction isPlainObjArg(arg: HostArg): boolean {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && !isHostRef(arg)\n}\n\n/**\n * 从纯数据(非 IR 类型)打印一行 faijs 源代码。\n *\n * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。\n * @param input - the pure-data line description.\n * @returns the printed single-line code text.\n */\nexport function formatCodeLine(input: FormatCodeLineInput): string {\n const positional = input.positional\n const argsInput: Record<string, HostArg> = input.args ?? {}\n\n // 位置实参按序打印\n const positionalParts = positional.map((arg) => {\n if (isPlainObjArg(arg)) {\n const entries = Object.entries(arg as Record<string, HostArg>)\n return `{ ${entries.map(([k, v]) => `${k}:${fmtValue(v)}`).join(', ')} }`\n }\n return fmtValue(arg)\n })\n\n // args 槽(过渡兼容:positional 末位非纯对象时追加为独立选项槽)\n const argsParts = Object.entries(argsInput).map(([k, v]) => `${k}:${fmtValue(v)}`)\n const lastIsPlainObject = positional.length > 0 && isPlainObjArg(positional[positional.length - 1])\n\n let callArgs: string\n if (positionalParts.length > 0) {\n callArgs = positionalParts.join(', ')\n if (!lastIsPlainObject && argsParts.length > 0) {\n callArgs = [...positionalParts, `{ ${argsParts.join(', ')} }`].join(', ')\n }\n } else if (input.receiver) {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : ''\n } else {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '{}'\n }\n\n // F2:命名空间前缀(缺省 cad);本机函数调用 callee 无命名空间前缀\n const nsExpr = input.namespace === undefined ? `cad.${input.callee}` : `${input.namespace}.${input.callee}`\n\n // 1) 解构:outputKeys + outputs 一一对应\n if (input.outputKeys && input.outputKeys.length > 0) {\n const destructure = input.outputKeys.map((k, i) => `${k}: ${input.outputs[i]}`).join(', ')\n return `const { ${destructure} } = ${nsExpr}(${callArgs})`\n }\n\n // 2) 成员调用\n if (input.receiver) {\n return `${input.receiver}.${input.callee}(${callArgs})`\n }\n\n // 3) 无赋值调用\n if (input.outputs.length === 0) {\n return `${nsExpr}(${callArgs})`\n }\n\n // 4) 赋值:outputDeclared → 裸重赋值;否则 let 声明\n const out = input.outputs[0]\n if (input.outputDeclared) return `${out} = ${nsExpr}(${callArgs})`\n return `let ${out} = ${nsExpr}(${callArgs})`\n}\n"]}
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * codegen — 纯数据 → 文本 打印工具(宿主编辑器/测试用;L0,仅依赖 host-arg)\n *\n * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。\n * 输入是纯数据(HostArg 面),不依赖任何 IR 类型。\n *\n * 扁平代码格式(无 export/async/await/return/参数声明):\n * ```js\n * let part0 = cad.box(10, 20, 30)\n * part0 = cad.translate(part0, { offset: [1, 2, 3] })\n * ```\n *\n * 值格式约定(确定性输出):\n * - vec3 → `[1,2,3]`(紧凑无空格)\n * - 数字 → 整数直出;小数最多保留 6 位有效小数并去尾零\n * - 字符串 → 单引号包裹\n * - HostVarRef → 裸变量名(members 元素)\n * - HostCallRef → `cad.faceNormal(part0)`(嵌套调用)\n * - HostExprRef → `(expr text)`(原文加括号)\n * - 对象字面量 → `{key:value}`(冒号,合法 JS)\n */\n\nimport type { HostArg } from './host-arg'\nimport { isHostVarRef, isHostParamRef, isHostCallRef, isHostExprRef, isHostRef } from './host-arg'\nimport type { DimName, UnitName, UnitContext } from '../units'\nimport { unitFor, fromBase } from '../units'\n\n// ── 数值格式化 ──\n\n/**\n * Format a number as text: integers emit as-is; decimals retain at most 6\n * significant fractional digits with trailing zeros stripped.\n * @param n - the number to format.\n * @returns the formatted text representation.\n */\nexport function fmtNum(n: number): string {\n if (!Number.isFinite(n)) return String(n)\n if (Number.isInteger(n)) return String(n)\n const s = n.toFixed(6)\n return s.replace(/\\.?0+$/, '')\n}\n\n// ── 字符串转义 ──\n\n/** 字符串转义:转义反斜杠、单引号与控制字符(多行 SDF code 等字符串参数用)。\n * 逐一字符映射(避开 regex 控制字符字面量,满足 eslint no-control-regex),\n * 保证 fmtValue ⇄ analyzeCode 往返一致:嵌入 '…' 后仍是合法 JS,可被精确还原。 */\nconst STRING_ESCAPES: Record<string, string> = {\n '\\\\': '\\\\\\\\',\n \"'\": \"\\\\'\",\n '\\u0008': '\\\\b', // backspace\n '\\u000C': '\\\\f', // form feed\n '\\u000A': '\\\\n', // line feed\n '\\u000D': '\\\\r', // carriage return\n '\\u0009': '\\\\t', // tab\n '\\u000B': '\\\\v', // vertical tab\n}\n\nfunction escapeStr(s: string): string {\n let out = ''\n for (let i = 0; i < s.length; i++) {\n const esc = STRING_ESCAPES[s[i]]\n out += esc ?? s[i]\n }\n return out\n}\n\n/**\n * Format a unit literal number using JS shortest-round-trip representation.\n *\n * P7/D10.3 rule 5: unit literal numbers MUST use `String(n)` (e.g.\n * `0.39370078740157477`), NEVER `fmtNum` (which truncates to 6 decimal\n * places and would silently zero out `1e-7`).\n * @param n - the number to format.\n * @returns the shortest JS round-trip text representation.\n */\nexport function fmtUnitNum(n: number): string {\n return String(n)\n}\n\n/**\n * Reverse lookup: find the script-side unit constant name for a given\n * `UnitName`. Returns the UPPERCASE constant name (e.g. `INCH` for `'inch'`).\n */\nconst NAME_TO_CONST: Readonly<Record<UnitName, string>> = {\n mm: 'MM', cm: 'CM', m: 'METER', micron: 'MICRON',\n inch: 'INCH', foot: 'FOOT', yard: 'YARD',\n degree: 'DEGREE', radian: 'RADIAN',\n gram: 'GRAM', kilogram: 'KILOGRAM',\n second: 'SECOND',\n}\n\n/**\n * Format a base-unit value as a unit literal expression (`n * UNIT`).\n *\n * P7/D10.3: `base` is the base-unit (mm/degree) value; `dim` determines which\n * system display unit to use; `unitName` is the target display unit.\n * The number is formatted with `fmtUnitNum` (not `fmtNum`).\n * @param base - the base-unit numeric value.\n * @param dim - the dimension of the value.\n * @param unitName - the display unit to express the value in.\n * @returns text like `10 * INCH` or `0.39370078740157477 * INCH`.\n */\nexport function formatUnitLiteral(base: number, dim: DimName, unitName: UnitName): string {\n const displayValue = fromBase(base, unitName, dim)\n const constName = NAME_TO_CONST[unitName]\n return `${fmtUnitNum(displayValue)} * ${constName}`\n}\n\n/**\n * P7/D10.3: Options for unit-aware serialization of `formatCodeLine`.\n *\n * When provided, dimensioned parameters are emitted as unit literals\n * (`n * UNIT`). When absent, output is byte-identical to the pre-P7 behavior.\n */\nexport interface UnitSerializeOptions {\n /** System display unit; defaults to base (mm / degree). */\n units?: UnitContext\n /** Parameter dimension declarations (host provides from op paramDims + slotMap). */\n dims?: { positional?: (DimName | null)[]; byKey?: Record<string, DimName> }\n}\n\n/** 参数值 → 文本(递归,HostArg 面) */\nfunction fmtValue(value: HostArg): string {\n if (value === null) return 'null'\n if (typeof value === 'number') return fmtNum(value)\n if (typeof value === 'boolean') return String(value)\n if (typeof value === 'string') return `'${escapeStr(value)}'`\n if (isHostVarRef(value)) return value.name\n if (isHostParamRef(value)) return value.name\n if (isHostCallRef(value)) {\n const { callee, args, namespace } = value\n const inner = args.map(fmtValue).join(', ')\n return `${namespace ?? 'cad'}.${callee}(${inner})`\n }\n if (isHostExprRef(value)) return value.bare ? value.text : `(${value.text})`\n if (Array.isArray(value)) return `[${value.map(fmtValue).join(',')}]`\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, HostArg>)\n return `{${entries.map(([k, v]) => `${k}:${fmtValue(v)}`).join(', ')}}`\n }\n return String(value)\n}\n\n// ── 纯数据 → 代码行(宿主代码生成入口) ──\n\n/**\n * Pure-data input for printing one faijs source line, decoupled from IR types.\n *\n * `positional` and `args` use `HostArg` (host-friendly types with `kind`-based\n * discrimination).\n */\nexport interface FormatCodeLineInput {\n callee: string\n /** 成员方法调用接收者变量名 */\n receiver?: string\n /**\n * 位置实参槽(HostArg 形态):宿主可传字面量、\n * 变量引用(`{kind:'var-ref',name}`)、参数引用(`{kind:'param-ref',name}`)、\n * 嵌套调用(`{kind:'call-ref',callee,args,namespace?}`)、\n * 表达式(`{kind:'expr-ref',text,refs,params}`)或纯 JsonValue,按序打印。\n */\n positional: HostArg[]\n /** 产出变量名 */\n outputs: string[]\n /** 解构键(与 outputs 一一对应) */\n outputKeys?: string[]\n /**\n * (过渡兼容)选项对象:positional 末位不是纯对象时追加为尾随选项对象。\n * 新代码应把选项对象直接放进 positional。\n */\n args?: Record<string, HostArg>\n /** 调用命名空间(F2:第三方库 `mech.makeHeadstock(...)` → 'mech';缺省 'cad') */\n namespace?: string\n /**\n * outputs[0] 是否已在代码中声明:true → 裸重赋值(`part0 = ...`),\n * false/省略 → let 声明;解构/成员调用/无输出时忽略。\n */\n outputDeclared?: boolean\n}\n\n/** 检测 HostArg 是否为纯数据对象(非引用形态)。 */\nfunction isPlainObjArg(arg: HostArg): boolean {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && !isHostRef(arg)\n}\n\n/**\n * Recursively format a HostArg value, applying unit wrapping to numbers inside\n * arrays (vec3) and plain objects when a dimension is declared.\n */\nfunction fmtValueWithDim(value: HostArg, dim: DimName | null | undefined, opts: UnitSerializeOptions | undefined): string {\n if (opts && dim) {\n // Number → unit literal\n if (typeof value === 'number') {\n const unitName = unitFor(dim, opts.units)\n return formatUnitLiteral(value, dim, unitName)\n }\n // Array (vec3) → element-wise\n if (Array.isArray(value)) {\n return `[${value.map((el) => fmtValueWithDim(el, dim, opts)).join(',')}]`\n }\n // Bare expr-ref already containing a unit literal → keep as-is\n if (isHostExprRef(value) && value.bare) return value.text\n }\n return fmtValue(value)\n}\n\n/**\n * Original `formatCodeLine` body without unit support (P7 fast path).\n *\n * This is the byte-identical pre-P7 implementation, called when `opts` is\n * absent or has no `dims` field. Kept as a separate function so the\n * unit-aware path can be tested independently.\n */\nfunction formatCodeLineRaw(input: FormatCodeLineInput): string {\n const positional = input.positional\n const argsInput: Record<string, HostArg> = input.args ?? {}\n\n // 位置实参按序打印\n const positionalParts = positional.map((arg) => {\n if (isPlainObjArg(arg)) {\n const entries = Object.entries(arg as Record<string, HostArg>)\n return `{ ${entries.map(([k, v]) => `${k}:${fmtValue(v)}`).join(', ')} }`\n }\n return fmtValue(arg)\n })\n\n // args 槽(过渡兼容:positional 末位非纯对象时追加为独立选项槽)\n const argsParts = Object.entries(argsInput).map(([k, v]) => `${k}:${fmtValue(v)}`)\n const lastIsPlainObject = positional.length > 0 && isPlainObjArg(positional[positional.length - 1])\n\n let callArgs: string\n if (positionalParts.length > 0) {\n callArgs = positionalParts.join(', ')\n if (!lastIsPlainObject && argsParts.length > 0) {\n callArgs = [...positionalParts, `{ ${argsParts.join(', ')} }`].join(', ')\n }\n } else if (input.receiver) {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : ''\n } else {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '{}'\n }\n\n // F2:命名空间前缀(缺省 cad);本机函数调用 callee 无命名空间前缀\n const nsExpr = input.namespace === undefined ? `cad.${input.callee}` : `${input.namespace}.${input.callee}`\n\n // 1) 解构:outputKeys + outputs 一一对应\n if (input.outputKeys && input.outputKeys.length > 0) {\n const destructure = input.outputKeys.map((k, i) => `${k}: ${input.outputs[i]}`).join(', ')\n return `const { ${destructure} } = ${nsExpr}(${callArgs})`\n }\n\n // 2) 成员调用\n if (input.receiver) {\n return `${input.receiver}.${input.callee}(${callArgs})`\n }\n\n // 3) 无赋值调用\n if (input.outputs.length === 0) {\n return `${nsExpr}(${callArgs})`\n }\n\n // 4) 赋值:outputDeclared → 裸重赋值;否则 let 声明\n const out = input.outputs[0]\n if (input.outputDeclared) return `${out} = ${nsExpr}(${callArgs})`\n return `let ${out} = ${nsExpr}(${callArgs})`\n}\n\n/**\n * 从纯数据(非 IR 类型)打印一行 faijs 源代码。\n *\n * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。\n *\n * P7/D10: when `opts` is provided, dimensioned parameters are serialized as\n * unit literals (`n * UNIT`). When `opts` is absent, output is byte-identical\n * to the pre-P7 behavior (zero-impact regression guarantee).\n *\n * @param input - the pure-data line description.\n * @param opts - optional unit serialization options (P7/D10).\n * @returns the printed single-line code text.\n */\nexport function formatCodeLine(input: FormatCodeLineInput, opts?: UnitSerializeOptions): string {\n // Fast path: no unit options → original behavior (byte-identical)\n if (!opts || !opts.dims) {\n return formatCodeLineRaw(input)\n }\n\n const positional = input.positional\n const argsInput: Record<string, HostArg> = input.args ?? {}\n const posDims = opts.dims.positional ?? []\n const keyDims = opts.dims.byKey ?? {}\n\n // Positional args with per-index dimension\n const positionalParts = positional.map((arg, i) => {\n const dim = posDims[i] ?? null\n if (isPlainObjArg(arg)) {\n const entries = Object.entries(arg as Record<string, HostArg>)\n return `{ ${entries.map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`).join(', ')} }`\n }\n return fmtValueWithDim(arg, dim, opts)\n })\n\n // args slot (transitional compat: appended as trailing option when last positional is not a plain object)\n const argsParts = Object.entries(argsInput).map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`)\n const lastIsPlainObject = positional.length > 0 && isPlainObjArg(positional[positional.length - 1])\n\n let callArgs: string\n if (positionalParts.length > 0) {\n callArgs = positionalParts.join(', ')\n if (!lastIsPlainObject && argsParts.length > 0) {\n callArgs = [...positionalParts, `{ ${argsParts.join(', ')} }`].join(', ')\n }\n } else if (input.receiver) {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : ''\n } else {\n callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '{}'\n }\n\n // F2:命名空间前缀(缺省 cad);本机函数调用 callee 无命名空间前缀\n const nsExpr = input.namespace === undefined ? `cad.${input.callee}` : `${input.namespace}.${input.callee}`\n\n // 1) 解构:outputKeys + outputs 一一对应\n if (input.outputKeys && input.outputKeys.length > 0) {\n const destructure = input.outputKeys.map((k, i) => `${k}: ${input.outputs[i]}`).join(', ')\n return `const { ${destructure} } = ${nsExpr}(${callArgs})`\n }\n\n // 2) 成员调用\n if (input.receiver) {\n return `${input.receiver}.${input.callee}(${callArgs})`\n }\n\n // 3) 无赋值调用\n if (input.outputs.length === 0) {\n return `${nsExpr}(${callArgs})`\n }\n\n // 4) 赋值:outputDeclared → 裸重赋值;否则 let 声明\n const out = input.outputs[0]\n if (input.outputDeclared) return `${out} = ${nsExpr}(${callArgs})`\n return `let ${out} = ${nsExpr}(${callArgs})`\n}\n"]}
@@ -66,6 +66,12 @@ export interface HostExprRef {
66
66
  text: string;
67
67
  refs: string[];
68
68
  params: string[];
69
+ /**
70
+ * P7/D10: when `true`, `fmtValue` emits the text without surrounding
71
+ * parentheses. Used by machine-generated unit literals (`10 * INCH`)
72
+ * to avoid the visually noisy `(10 * INCH)` form.
73
+ */
74
+ bare?: boolean;
69
75
  }
70
76
  /** Union of all host-visible reference shapes. */
71
77
  export type HostRef = HostVarRef | HostParamRef | HostCallRef | HostExprRef;
@@ -1 +1 @@
1
- {"version":3,"file":"host-arg.d.ts","sourceRoot":"","sources":["../../src/lang/host-arg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAIxC,wGAAwG;AACxG,UAAU,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAA;CAAE;AACnC,yDAAyD;AACzD,UAAU,UAAU;IAAG,MAAM,EAAE,MAAM,CAAA;CAAE;AACvC,sEAAsE;AACtE,UAAU,SAAS;IAAG,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE;AACtF,uEAAuE;AACvE,UAAU,SAAS;IAAG,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAAE;AAEjF,iGAAiG;AACjG,KAAK,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAA;AAiBtE,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,kDAAkD;AAClD,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,CAAA;AAE3E;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,OAAO,CAAA;AAEzC,qFAAqF;AACrF,eAAO,MAAM,cAAc,2DAA4D,CAAA;AACvF,0EAA0E;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AA6BzD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,UAAU,CAExD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,YAAY,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAO1D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAQ1D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,CAElD;AAID;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAuBjD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CAwB/C;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAUrD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAG/D"}
1
+ {"version":3,"file":"host-arg.d.ts","sourceRoot":"","sources":["../../src/lang/host-arg.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"host-arg.js","sourceRoot":"","sources":["../../src/lang/host-arg.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * host-arg — 宿主友好位置参数类型(IR 屏蔽层)\n *\n * 宿主(3d_editor 等)只接触 `HostArg`,不 import 任何 IR 类型。\n *\n * IR→Host 方向(`argIRToHost`):只认 `$` 前缀标记键(`$ref`/`$param`/`$call`/`$expr`),\n * 不认 `kind`,因此 parser 从 `.fai.js` 源码产生的字面量对象不会被误判。\n *\n * Host→IR 方向(`hostArgToIR`):按 `kind` 字段 + 形状守卫判定。\n *\n * **保留字规则(确定性裁决)**:普通对象若 `kind` 字段的值 ∈ `HOST_REF_KINDS`\n * 且完整匹配对应变体形状,一律按引用处理。即:字面量参数对象中禁止出现\n * 这 4 个 `kind` 值。此约束写入 JSDoc 与 `docs/api-contract.md`。\n *\n * 注意:`HostRef` 在结构上是 `JsonValue` 的子类型,因此 `HostArg` 在 TS 层面\n * 约等于 `JsonValue`,判别依赖运行时守卫而非类型系统——这是有意为之。\n */\n\nimport type { JsonValue } from './types'\n\n// ── 内联 IR 守卫(原 types.ts 的 IR 类型已删除,守卫逻辑内联于此) ──\n\n/** IR marker: variable reference `{$ref: string}` (legacy IR form, still recognized by argIRToHost). */\ninterface IRVarRef { $ref: string }\n/** IR marker: parameter reference `{$param: string}`. */\ninterface IRParamRef { $param: string }\n/** IR marker: nested call `{$call: { callee, args, namespace? }}`. */\ninterface IRCallRef { $call: { callee: string; args: unknown[]; namespace?: string } }\n/** IR marker: runtime expression `{$expr: { text, refs, params }}`. */\ninterface IRExprRef { $expr: { text: string; refs: string[]; params: string[] } }\n\n/** Union of legacy IR marker shapes (used by argIRToHost for backward-compatible conversion). */\ntype ArgIR = JsonValue | IRVarRef | IRParamRef | IRCallRef | IRExprRef\n\nfunction isIRVarRef(arg: unknown): arg is IRVarRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$ref' in arg\n}\nfunction isIRParamRef(arg: unknown): arg is IRParamRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$param' in arg\n}\nfunction isIRCallRef(arg: unknown): arg is IRCallRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$call' in arg\n}\nfunction isIRExprRef(arg: unknown): arg is IRExprRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$expr' in arg\n}\n\n// ── 宿主友好位置参数类型 ──\n\n/** Variable reference: a reference to a declared shape variable (e.g. `part0`). */\nexport interface HostVarRef {\n kind: 'var-ref'\n name: string\n}\n\n/** Parameter reference: a reference to a script parameter (e.g. `hole_diameter`). */\nexport interface HostParamRef {\n kind: 'param-ref'\n name: string\n}\n\n/** Nested call reference: a `cad.<callee>(...)` or `<ns>.<callee>(...)` embedded in args. */\nexport interface HostCallRef {\n kind: 'call-ref'\n callee: string\n args: HostArg[]\n /** Calling namespace (e.g. `mech.helper(...)` → 'mech'; absent = 'cad'). */\n namespace?: string\n}\n\n/** Runtime expression reference: an expression that could not be statically folded. */\nexport interface HostExprRef {\n kind: 'expr-ref'\n text: string\n refs: string[]\n params: string[]\n}\n\n/** Union of all host-visible reference shapes. */\nexport type HostRef = HostVarRef | HostParamRef | HostCallRef | HostExprRef\n\n/**\n * A host-friendly argument value: either a JSON literal or a host reference shape.\n *\n * **Discrimination relies on runtime guards** (`isHostRef` etc.), not the TS type system —\n * `HostRef` is structurally a subtype of `JsonValue`. This is intentional.\n * Literal parameter objects must not use `kind` values from `HOST_REF_KINDS`.\n */\nexport type HostArg = JsonValue | HostRef\n\n/** The set of `kind` values that identify host reference shapes (reserved words). */\nexport const HOST_REF_KINDS = ['var-ref', 'param-ref', 'call-ref', 'expr-ref'] as const\n/** The `kind` string literal type derived from {@link HOST_REF_KINDS}. */\nexport type HostRefKind = (typeof HOST_REF_KINDS)[number]\n\n// ── 辅助:普通对象检测 ──\n\n/**\n * Check whether a value is a non-null, non-array plain object.\n * @param a - the value to test.\n * @returns true when the value is a plain object (not null, not array).\n */\nfunction isPlainObject(a: unknown): a is Record<string, unknown> {\n return a !== null && typeof a === 'object' && !Array.isArray(a)\n}\n\n/**\n * Map all values of a plain object through a transform function (shallow key copy).\n * @param obj - the plain object to map.\n * @param fn - the transform function applied to each value.\n * @returns a new object with the same keys and transformed values.\n */\nfunction mapValues<T, U>(obj: Record<string, T>, fn: (v: T) => U): Record<string, U> {\n const out: Record<string, U> = {}\n for (const [k, v] of Object.entries(obj)) {\n out[k] = fn(v)\n }\n return out\n}\n\n// ── 守卫 ──\n\n/**\n * Type guard: is the value a `HostVarRef`?\n *\n * Checks `kind === 'var-ref'` and `name: string`. This is the Host→IR direction guard.\n * @param a - the argument value to test.\n * @returns true when the value is a `HostVarRef`.\n */\nexport function isHostVarRef(a: HostArg): a is HostVarRef {\n return isPlainObject(a) && a.kind === 'var-ref' && typeof a.name === 'string'\n}\n\n/**\n * Type guard: is the value a `HostParamRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostParamRef`.\n */\nexport function isHostParamRef(a: HostArg): a is HostParamRef {\n return isPlainObject(a) && a.kind === 'param-ref' && typeof a.name === 'string'\n}\n\n/**\n * Type guard: is the value a `HostCallRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostCallRef`.\n */\nexport function isHostCallRef(a: HostArg): a is HostCallRef {\n return (\n isPlainObject(a) &&\n a.kind === 'call-ref' &&\n typeof a.callee === 'string' &&\n Array.isArray(a.args)\n )\n}\n\n/**\n * Type guard: is the value a `HostExprRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostExprRef`.\n */\nexport function isHostExprRef(a: HostArg): a is HostExprRef {\n return (\n isPlainObject(a) &&\n a.kind === 'expr-ref' &&\n typeof a.text === 'string' &&\n Array.isArray(a.refs) &&\n Array.isArray(a.params)\n )\n}\n\n/**\n * Type guard: is the value any host reference shape?\n * @param a - the argument value to test.\n * @returns true when the value is one of `HostVarRef`/`HostParamRef`/`HostCallRef`/`HostExprRef`.\n */\nexport function isHostRef(a: HostArg): a is HostRef {\n return isHostVarRef(a) || isHostParamRef(a) || isHostCallRef(a) || isHostExprRef(a)\n}\n\n// ── 递归双向转换(core 内部,不导出) ──\n\n/**\n * Convert a legacy IR marker argument (`$`-prefixed) to a `HostArg` (host-friendly).\n *\n * Recursively transforms arrays and plain objects. Recognizes `$`-prefixed\n * marker keys only — `kind` fields are not checked in this direction.\n * @param arg - the IR argument to convert.\n * @returns the host-friendly argument.\n */\nexport function argIRToHost(arg: unknown): HostArg {\n if (isIRVarRef(arg)) return { kind: 'var-ref', name: arg.$ref }\n if (isIRParamRef(arg)) return { kind: 'param-ref', name: arg.$param }\n if (isIRCallRef(arg)) {\n const { callee, args, namespace } = arg.$call\n return {\n kind: 'call-ref',\n callee,\n args: args.map(argIRToHost) as HostArg[],\n ...(namespace !== undefined ? { namespace } : {}),\n }\n }\n if (isIRExprRef(arg)) {\n return {\n kind: 'expr-ref',\n text: arg.$expr.text,\n refs: [...arg.$expr.refs],\n params: [...arg.$expr.params],\n }\n }\n if (Array.isArray(arg)) return arg.map(argIRToHost) as unknown as HostArg\n if (isPlainObject(arg)) return mapValues(arg, argIRToHost) as unknown as HostArg\n return arg as HostArg\n}\n\n/**\n * Convert a `HostArg` (host-friendly) back to a legacy IR marker (`$`-prefixed).\n *\n * Uses `kind`-based guards to identify reference shapes. Literal objects\n * that don't match any reference kind are recursively transformed as plain data.\n * @param arg - the host-friendly argument.\n * @returns the IR marker argument.\n */\nexport function hostArgToIR(arg: HostArg): ArgIR {\n if (isHostVarRef(arg)) return { $ref: arg.name }\n if (isHostParamRef(arg)) return { $param: arg.name }\n if (isHostCallRef(arg)) {\n return {\n $call: {\n callee: arg.callee,\n args: arg.args.map(hostArgToIR) as unknown[],\n ...(arg.namespace !== undefined ? { namespace: arg.namespace } : {}),\n },\n }\n }\n if (isHostExprRef(arg)) {\n return {\n $expr: {\n text: arg.text,\n refs: [...arg.refs],\n params: [...arg.params],\n },\n }\n }\n if (Array.isArray(arg)) return arg.map(hostArgToIR) as unknown as ArgIR\n if (isPlainObject(arg)) return mapValues(arg as Record<string, HostArg>, hostArgToIR) as unknown as ArgIR\n return arg\n}\n\n// ── 导出辅助函数 ──\n\n/**\n * Render a `HostArg` to a human-readable display string (for timeline labels, read-only fields).\n *\n * - Primitives → `String(arg)`\n * - Arrays → `[a, b, …]` (recursive)\n * - var-ref/param-ref → `name`\n * - call-ref → `callee(a, b, …)` (recursive)\n * - expr-ref → `text`\n * - Plain objects → `JSON.stringify`\n * @param arg - the host argument to display.\n * @returns a human-readable string representation.\n */\nexport function hostArgToDisplay(arg: HostArg): string {\n if (isHostVarRef(arg) || isHostParamRef(arg)) return arg.name\n if (isHostCallRef(arg)) {\n const inner = arg.args.map(hostArgToDisplay).join(', ')\n return `${arg.callee}(${inner})`\n }\n if (isHostExprRef(arg)) return arg.text\n if (Array.isArray(arg)) return `[${arg.map(hostArgToDisplay).join(', ')}]`\n if (isPlainObject(arg)) return JSON.stringify(arg)\n return String(arg)\n}\n\n/**\n * Extract the literal value from a `HostArg`, returning `null` for reference shapes.\n * @param arg - the host argument.\n * @returns the literal value if `arg` is not a reference, otherwise `null`.\n */\nexport function hostArgToLiteral(arg: HostArg): JsonValue | null {\n if (isHostRef(arg)) return null\n return arg\n}\n"]}
1
+ {"version":3,"file":"host-arg.js","sourceRoot":"","sources":["../../src/lang/host-arg.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * host-arg — 宿主友好位置参数类型(IR 屏蔽层)\n *\n * 宿主(3d_editor 等)只接触 `HostArg`,不 import 任何 IR 类型。\n *\n * IR→Host 方向(`argIRToHost`):只认 `$` 前缀标记键(`$ref`/`$param`/`$call`/`$expr`),\n * 不认 `kind`,因此 parser 从 `.fai.js` 源码产生的字面量对象不会被误判。\n *\n * Host→IR 方向(`hostArgToIR`):按 `kind` 字段 + 形状守卫判定。\n *\n * **保留字规则(确定性裁决)**:普通对象若 `kind` 字段的值 ∈ `HOST_REF_KINDS`\n * 且完整匹配对应变体形状,一律按引用处理。即:字面量参数对象中禁止出现\n * 这 4 个 `kind` 值。此约束写入 JSDoc 与 `docs/api-contract.md`。\n *\n * 注意:`HostRef` 在结构上是 `JsonValue` 的子类型,因此 `HostArg` 在 TS 层面\n * 约等于 `JsonValue`,判别依赖运行时守卫而非类型系统——这是有意为之。\n */\n\nimport type { JsonValue } from './types'\n\n// ── 内联 IR 守卫(原 types.ts 的 IR 类型已删除,守卫逻辑内联于此) ──\n\n/** IR marker: variable reference `{$ref: string}` (legacy IR form, still recognized by argIRToHost). */\ninterface IRVarRef { $ref: string }\n/** IR marker: parameter reference `{$param: string}`. */\ninterface IRParamRef { $param: string }\n/** IR marker: nested call `{$call: { callee, args, namespace? }}`. */\ninterface IRCallRef { $call: { callee: string; args: unknown[]; namespace?: string } }\n/** IR marker: runtime expression `{$expr: { text, refs, params }}`. */\ninterface IRExprRef { $expr: { text: string; refs: string[]; params: string[] } }\n\n/** Union of legacy IR marker shapes (used by argIRToHost for backward-compatible conversion). */\ntype ArgIR = JsonValue | IRVarRef | IRParamRef | IRCallRef | IRExprRef\n\nfunction isIRVarRef(arg: unknown): arg is IRVarRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$ref' in arg\n}\nfunction isIRParamRef(arg: unknown): arg is IRParamRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$param' in arg\n}\nfunction isIRCallRef(arg: unknown): arg is IRCallRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$call' in arg\n}\nfunction isIRExprRef(arg: unknown): arg is IRExprRef {\n return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && '$expr' in arg\n}\n\n// ── 宿主友好位置参数类型 ──\n\n/** Variable reference: a reference to a declared shape variable (e.g. `part0`). */\nexport interface HostVarRef {\n kind: 'var-ref'\n name: string\n}\n\n/** Parameter reference: a reference to a script parameter (e.g. `hole_diameter`). */\nexport interface HostParamRef {\n kind: 'param-ref'\n name: string\n}\n\n/** Nested call reference: a `cad.<callee>(...)` or `<ns>.<callee>(...)` embedded in args. */\nexport interface HostCallRef {\n kind: 'call-ref'\n callee: string\n args: HostArg[]\n /** Calling namespace (e.g. `mech.helper(...)` → 'mech'; absent = 'cad'). */\n namespace?: string\n}\n\n/** Runtime expression reference: an expression that could not be statically folded. */\nexport interface HostExprRef {\n kind: 'expr-ref'\n text: string\n refs: string[]\n params: string[]\n /**\n * P7/D10: when `true`, `fmtValue` emits the text without surrounding\n * parentheses. Used by machine-generated unit literals (`10 * INCH`)\n * to avoid the visually noisy `(10 * INCH)` form.\n */\n bare?: boolean\n}\n\n/** Union of all host-visible reference shapes. */\nexport type HostRef = HostVarRef | HostParamRef | HostCallRef | HostExprRef\n\n/**\n * A host-friendly argument value: either a JSON literal or a host reference shape.\n *\n * **Discrimination relies on runtime guards** (`isHostRef` etc.), not the TS type system —\n * `HostRef` is structurally a subtype of `JsonValue`. This is intentional.\n * Literal parameter objects must not use `kind` values from `HOST_REF_KINDS`.\n */\nexport type HostArg = JsonValue | HostRef\n\n/** The set of `kind` values that identify host reference shapes (reserved words). */\nexport const HOST_REF_KINDS = ['var-ref', 'param-ref', 'call-ref', 'expr-ref'] as const\n/** The `kind` string literal type derived from {@link HOST_REF_KINDS}. */\nexport type HostRefKind = (typeof HOST_REF_KINDS)[number]\n\n// ── 辅助:普通对象检测 ──\n\n/**\n * Check whether a value is a non-null, non-array plain object.\n * @param a - the value to test.\n * @returns true when the value is a plain object (not null, not array).\n */\nfunction isPlainObject(a: unknown): a is Record<string, unknown> {\n return a !== null && typeof a === 'object' && !Array.isArray(a)\n}\n\n/**\n * Map all values of a plain object through a transform function (shallow key copy).\n * @param obj - the plain object to map.\n * @param fn - the transform function applied to each value.\n * @returns a new object with the same keys and transformed values.\n */\nfunction mapValues<T, U>(obj: Record<string, T>, fn: (v: T) => U): Record<string, U> {\n const out: Record<string, U> = {}\n for (const [k, v] of Object.entries(obj)) {\n out[k] = fn(v)\n }\n return out\n}\n\n// ── 守卫 ──\n\n/**\n * Type guard: is the value a `HostVarRef`?\n *\n * Checks `kind === 'var-ref'` and `name: string`. This is the Host→IR direction guard.\n * @param a - the argument value to test.\n * @returns true when the value is a `HostVarRef`.\n */\nexport function isHostVarRef(a: HostArg): a is HostVarRef {\n return isPlainObject(a) && a.kind === 'var-ref' && typeof a.name === 'string'\n}\n\n/**\n * Type guard: is the value a `HostParamRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostParamRef`.\n */\nexport function isHostParamRef(a: HostArg): a is HostParamRef {\n return isPlainObject(a) && a.kind === 'param-ref' && typeof a.name === 'string'\n}\n\n/**\n * Type guard: is the value a `HostCallRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostCallRef`.\n */\nexport function isHostCallRef(a: HostArg): a is HostCallRef {\n return (\n isPlainObject(a) &&\n a.kind === 'call-ref' &&\n typeof a.callee === 'string' &&\n Array.isArray(a.args)\n )\n}\n\n/**\n * Type guard: is the value a `HostExprRef`?\n * @param a - the argument value to test.\n * @returns true when the value is a `HostExprRef`.\n */\nexport function isHostExprRef(a: HostArg): a is HostExprRef {\n return (\n isPlainObject(a) &&\n a.kind === 'expr-ref' &&\n typeof a.text === 'string' &&\n Array.isArray(a.refs) &&\n Array.isArray(a.params)\n )\n}\n\n/**\n * Type guard: is the value any host reference shape?\n * @param a - the argument value to test.\n * @returns true when the value is one of `HostVarRef`/`HostParamRef`/`HostCallRef`/`HostExprRef`.\n */\nexport function isHostRef(a: HostArg): a is HostRef {\n return isHostVarRef(a) || isHostParamRef(a) || isHostCallRef(a) || isHostExprRef(a)\n}\n\n// ── 递归双向转换(core 内部,不导出) ──\n\n/**\n * Convert a legacy IR marker argument (`$`-prefixed) to a `HostArg` (host-friendly).\n *\n * Recursively transforms arrays and plain objects. Recognizes `$`-prefixed\n * marker keys only — `kind` fields are not checked in this direction.\n * @param arg - the IR argument to convert.\n * @returns the host-friendly argument.\n */\nexport function argIRToHost(arg: unknown): HostArg {\n if (isIRVarRef(arg)) return { kind: 'var-ref', name: arg.$ref }\n if (isIRParamRef(arg)) return { kind: 'param-ref', name: arg.$param }\n if (isIRCallRef(arg)) {\n const { callee, args, namespace } = arg.$call\n return {\n kind: 'call-ref',\n callee,\n args: args.map(argIRToHost) as HostArg[],\n ...(namespace !== undefined ? { namespace } : {}),\n }\n }\n if (isIRExprRef(arg)) {\n return {\n kind: 'expr-ref',\n text: arg.$expr.text,\n refs: [...arg.$expr.refs],\n params: [...arg.$expr.params],\n }\n }\n if (Array.isArray(arg)) return arg.map(argIRToHost) as unknown as HostArg\n if (isPlainObject(arg)) return mapValues(arg, argIRToHost) as unknown as HostArg\n return arg as HostArg\n}\n\n/**\n * Convert a `HostArg` (host-friendly) back to a legacy IR marker (`$`-prefixed).\n *\n * Uses `kind`-based guards to identify reference shapes. Literal objects\n * that don't match any reference kind are recursively transformed as plain data.\n * @param arg - the host-friendly argument.\n * @returns the IR marker argument.\n */\nexport function hostArgToIR(arg: HostArg): ArgIR {\n if (isHostVarRef(arg)) return { $ref: arg.name }\n if (isHostParamRef(arg)) return { $param: arg.name }\n if (isHostCallRef(arg)) {\n return {\n $call: {\n callee: arg.callee,\n args: arg.args.map(hostArgToIR) as unknown[],\n ...(arg.namespace !== undefined ? { namespace: arg.namespace } : {}),\n },\n }\n }\n if (isHostExprRef(arg)) {\n return {\n $expr: {\n text: arg.text,\n refs: [...arg.refs],\n params: [...arg.params],\n },\n }\n }\n if (Array.isArray(arg)) return arg.map(hostArgToIR) as unknown as ArgIR\n if (isPlainObject(arg)) return mapValues(arg as Record<string, HostArg>, hostArgToIR) as unknown as ArgIR\n return arg\n}\n\n// ── 导出辅助函数 ──\n\n/**\n * Render a `HostArg` to a human-readable display string (for timeline labels, read-only fields).\n *\n * - Primitives → `String(arg)`\n * - Arrays → `[a, b, …]` (recursive)\n * - var-ref/param-ref → `name`\n * - call-ref → `callee(a, b, …)` (recursive)\n * - expr-ref → `text`\n * - Plain objects → `JSON.stringify`\n * @param arg - the host argument to display.\n * @returns a human-readable string representation.\n */\nexport function hostArgToDisplay(arg: HostArg): string {\n if (isHostVarRef(arg) || isHostParamRef(arg)) return arg.name\n if (isHostCallRef(arg)) {\n const inner = arg.args.map(hostArgToDisplay).join(', ')\n return `${arg.callee}(${inner})`\n }\n if (isHostExprRef(arg)) return arg.text\n if (Array.isArray(arg)) return `[${arg.map(hostArgToDisplay).join(', ')}]`\n if (isPlainObject(arg)) return JSON.stringify(arg)\n return String(arg)\n}\n\n/**\n * Extract the literal value from a `HostArg`, returning `null` for reference shapes.\n * @param arg - the host argument.\n * @returns the literal value if `arg` is not a reference, otherwise `null`.\n */\nexport function hostArgToLiteral(arg: HostArg): JsonValue | null {\n if (isHostRef(arg)) return null\n return arg\n}\n"]}
@@ -18,6 +18,7 @@ import type { StatementSummary } from './statement-summary.js';
18
18
  import type { ScriptMetaIR, TerminalShape } from './types.js';
19
19
  import { type StmtId } from '../identity.js';
20
20
  import { type SecurityPolicy } from './security-scanner.js';
21
+ import type { DimName } from '../units.js';
21
22
  /** 参数表条目(参数面板:const X = <字面量> → 名字/值/是否计算表达式) */
22
23
  export interface ParamEntry {
23
24
  name: string;
@@ -179,7 +180,31 @@ export interface ExtractMetadataOptions {
179
180
  security?: SecurityPolicy;
180
181
  /** S7 命名空间保护名(缺省 = namespaces;append 场景可指定更小集合仅命名空间名) */
181
182
  nsNames?: string[];
183
+ /**
184
+ * P4/P6 (unit-system D8): callee → 量纲声明的映射,供 dimension pass 做静态
185
+ * 量纲校验。调用方从 op 注册表取出透传(lang 不碰 op 注册表铁律)。
186
+ */
187
+ opDims?: OpDimMap;
188
+ }
189
+ /**
190
+ * P4/P6 (unit-system D8): 一个 op 的脚本面量纲声明,供静态 dimension 检查使用。
191
+ * 由调用方(CadRuntime/CLI/codeToArgs)从 op 注册表取出透传,`lang/` 本身不碰
192
+ * op 注册表(铁律:lang 不得依赖 op 注册表)。
193
+ */
194
+ export interface OpDimDecl {
195
+ /** 参数名 → 量纲;缺省键视为无量纲。 */
196
+ paramDims?: Record<string, DimName>;
197
+ /** 函数调用结果的量纲。 */
198
+ retDim?: DimName;
199
+ /** D11 slot-map(positional→object 装箱表);位置形态校验用。 */
200
+ slotMap?: {
201
+ keys: string[];
202
+ vec3Keys?: string[];
203
+ shapeArity?: number;
204
+ };
182
205
  }
206
+ /** P4/P6: callee 名 → 量纲声明(供 extractMetadata 的 dimension pass 消费)。 */
207
+ export type OpDimMap = Record<string, OpDimDecl>;
183
208
  /**
184
209
  * 从源码文本提取 UI 通道元数据(UiMetadata)。
185
210
  *