@faicad/faijs 0.22.2 → 0.29.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/LICENSE +202 -28
  2. package/dist/api/api-namespace.d.ts +5 -5
  3. package/dist/api/api-namespace.d.ts.map +1 -1
  4. package/dist/api/api-namespace.js +4 -4
  5. package/dist/api/api-namespace.js.map +1 -1
  6. package/dist/api/assert.d.ts +2 -2
  7. package/dist/api/assert.js +8 -8
  8. package/dist/api/assert.js.map +1 -1
  9. package/dist/api/asset.d.ts +1 -1
  10. package/dist/api/asset.js +2 -2
  11. package/dist/api/asset.js.map +1 -1
  12. package/dist/api/boolean.d.ts +1 -1
  13. package/dist/api/boolean.d.ts.map +1 -1
  14. package/dist/api/boolean.js +128 -16
  15. package/dist/api/boolean.js.map +1 -1
  16. package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
  17. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
  18. package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
  19. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
  20. package/dist/api/cadquery-selectors/edge.d.ts +40 -0
  21. package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
  22. package/dist/api/cadquery-selectors/edge.js +70 -0
  23. package/dist/api/cadquery-selectors/edge.js.map +1 -0
  24. package/dist/api/cadquery-selectors/entity.d.ts +121 -0
  25. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
  26. package/dist/api/cadquery-selectors/entity.js +167 -0
  27. package/dist/api/cadquery-selectors/entity.js.map +1 -0
  28. package/dist/api/cadquery-selectors/face.d.ts +33 -0
  29. package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
  30. package/dist/api/cadquery-selectors/face.js +353 -0
  31. package/dist/api/cadquery-selectors/face.js.map +1 -0
  32. package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
  33. package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
  34. package/dist/api/cadquery-selectors/grammar.js +345 -0
  35. package/dist/api/cadquery-selectors/grammar.js.map +1 -0
  36. package/dist/api/cadquery-selectors/index.d.ts +18 -0
  37. package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
  38. package/dist/api/cadquery-selectors/index.js +17 -0
  39. package/dist/api/cadquery-selectors/index.js.map +1 -0
  40. package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
  41. package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
  42. package/dist/api/cadquery-selectors/predicates.js +85 -0
  43. package/dist/api/cadquery-selectors/predicates.js.map +1 -0
  44. package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
  45. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
  46. package/dist/api/cadquery-selectors/resolve.js +243 -0
  47. package/dist/api/cadquery-selectors/resolve.js.map +1 -0
  48. package/dist/api/cadquery-selectors/types.d.ts +96 -0
  49. package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
  50. package/dist/api/cadquery-selectors/types.js +11 -0
  51. package/dist/api/cadquery-selectors/types.js.map +1 -0
  52. package/dist/api/chamfer.d.ts +13 -5
  53. package/dist/api/chamfer.d.ts.map +1 -1
  54. package/dist/api/chamfer.js +63 -7
  55. package/dist/api/chamfer.js.map +1 -1
  56. package/dist/api/compound-geom.d.ts +1 -1
  57. package/dist/api/compound-geom.js +1 -1
  58. package/dist/api/compound-geom.js.map +1 -1
  59. package/dist/api/draft.d.ts +1 -1
  60. package/dist/api/draft.js +1 -1
  61. package/dist/api/draft.js.map +1 -1
  62. package/dist/api/edge-ref.d.ts +1 -1
  63. package/dist/api/edge-ref.d.ts.map +1 -1
  64. package/dist/api/edge-ref.js +11 -3
  65. package/dist/api/edge-ref.js.map +1 -1
  66. package/dist/api/engrave.d.ts +1 -1
  67. package/dist/api/engrave.js +7 -7
  68. package/dist/api/engrave.js.map +1 -1
  69. package/dist/api/extrude.d.ts +6 -1
  70. package/dist/api/extrude.d.ts.map +1 -1
  71. package/dist/api/extrude.js +59 -5
  72. package/dist/api/extrude.js.map +1 -1
  73. package/dist/api/face-ref.d.ts +1 -1
  74. package/dist/api/face-ref.js +1 -1
  75. package/dist/api/face-ref.js.map +1 -1
  76. package/dist/api/feature-repair.d.ts +1 -1
  77. package/dist/api/feature-repair.js +1 -1
  78. package/dist/api/feature-repair.js.map +1 -1
  79. package/dist/api/fillet-variable.d.ts +1 -1
  80. package/dist/api/fillet-variable.js +1 -1
  81. package/dist/api/fillet-variable.js.map +1 -1
  82. package/dist/api/fillet.d.ts +28 -8
  83. package/dist/api/fillet.d.ts.map +1 -1
  84. package/dist/api/fillet.js +64 -9
  85. package/dist/api/fillet.js.map +1 -1
  86. package/dist/api/geom.d.ts +1 -1
  87. package/dist/api/geom.js +1 -1
  88. package/dist/api/geom.js.map +1 -1
  89. package/dist/api/helix.d.ts +1 -1
  90. package/dist/api/helix.js +1 -1
  91. package/dist/api/helix.js.map +1 -1
  92. package/dist/api/import-brep.d.ts +20 -2
  93. package/dist/api/import-brep.d.ts.map +1 -1
  94. package/dist/api/import-brep.js +28 -3
  95. package/dist/api/import-brep.js.map +1 -1
  96. package/dist/api/import-step.d.ts +17 -2
  97. package/dist/api/import-step.d.ts.map +1 -1
  98. package/dist/api/import-step.js +23 -3
  99. package/dist/api/import-step.js.map +1 -1
  100. package/dist/api/index.d.ts +2 -1
  101. package/dist/api/index.d.ts.map +1 -1
  102. package/dist/api/index.js +5 -2
  103. package/dist/api/index.js.map +1 -1
  104. package/dist/api/internal/compat-op.js +1 -1
  105. package/dist/api/internal/compat-op.js.map +1 -1
  106. package/dist/api/internal/mesh-solid-op.d.ts +236 -0
  107. package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
  108. package/dist/api/internal/mesh-solid-op.js +352 -0
  109. package/dist/api/internal/mesh-solid-op.js.map +1 -0
  110. package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
  111. package/dist/api/internal/svg-asset-resolver.js +1 -1
  112. package/dist/api/internal/svg-asset-resolver.js.map +1 -1
  113. package/dist/api/knurl.d.ts +1 -1
  114. package/dist/api/knurl.js +2 -2
  115. package/dist/api/knurl.js.map +1 -1
  116. package/dist/api/loft.d.ts +1 -1
  117. package/dist/api/loft.js +1 -1
  118. package/dist/api/loft.js.map +1 -1
  119. package/dist/api/measurement/index.d.ts +9 -5
  120. package/dist/api/measurement/index.d.ts.map +1 -1
  121. package/dist/api/measurement/index.js +47 -20
  122. package/dist/api/measurement/index.js.map +1 -1
  123. package/dist/api/pattern.d.ts +5 -3
  124. package/dist/api/pattern.d.ts.map +1 -1
  125. package/dist/api/pattern.js +32 -4
  126. package/dist/api/pattern.js.map +1 -1
  127. package/dist/api/place.d.ts +1 -1
  128. package/dist/api/place.js +1 -1
  129. package/dist/api/place.js.map +1 -1
  130. package/dist/api/primitives.d.ts +1 -1
  131. package/dist/api/primitives.js +2 -2
  132. package/dist/api/primitives.js.map +1 -1
  133. package/dist/api/profile.d.ts +39 -12
  134. package/dist/api/profile.d.ts.map +1 -1
  135. package/dist/api/profile.js +4 -4
  136. package/dist/api/profile.js.map +1 -1
  137. package/dist/api/reconcile.d.ts +1 -1
  138. package/dist/api/reconcile.js +1 -1
  139. package/dist/api/reconcile.js.map +1 -1
  140. package/dist/api/replicate.d.ts.map +1 -1
  141. package/dist/api/replicate.js +122 -1
  142. package/dist/api/replicate.js.map +1 -1
  143. package/dist/api/screw.d.ts +1 -1
  144. package/dist/api/screw.js +3 -3
  145. package/dist/api/screw.js.map +1 -1
  146. package/dist/api/sdf.d.ts +1 -1
  147. package/dist/api/sdf.js +2 -2
  148. package/dist/api/sdf.js.map +1 -1
  149. package/dist/api/section-by-plane.d.ts +1 -1
  150. package/dist/api/section-by-plane.d.ts.map +1 -1
  151. package/dist/api/section-by-plane.js +2 -1
  152. package/dist/api/section-by-plane.js.map +1 -1
  153. package/dist/api/shell.d.ts +11 -4
  154. package/dist/api/shell.d.ts.map +1 -1
  155. package/dist/api/shell.js +53 -7
  156. package/dist/api/shell.js.map +1 -1
  157. package/dist/api/sketch-on-face.d.ts +41 -0
  158. package/dist/api/sketch-on-face.d.ts.map +1 -1
  159. package/dist/api/sketch-on-face.js +100 -1
  160. package/dist/api/sketch-on-face.js.map +1 -1
  161. package/dist/api/sketch-on-plane.d.ts +7 -5
  162. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  163. package/dist/api/sketch-on-plane.js +6 -7
  164. package/dist/api/sketch-on-plane.js.map +1 -1
  165. package/dist/api/split-by-plane.d.ts +1 -1
  166. package/dist/api/split-by-plane.d.ts.map +1 -1
  167. package/dist/api/split-by-plane.js +2 -1
  168. package/dist/api/split-by-plane.js.map +1 -1
  169. package/dist/api/split.d.ts +1 -1
  170. package/dist/api/split.js +2 -2
  171. package/dist/api/split.js.map +1 -1
  172. package/dist/api/sweep.d.ts +1 -1
  173. package/dist/api/sweep.js +1 -1
  174. package/dist/api/sweep.js.map +1 -1
  175. package/dist/api/thicken.d.ts +1 -1
  176. package/dist/api/thicken.js +1 -1
  177. package/dist/api/thicken.js.map +1 -1
  178. package/dist/api/topo-resolve.d.ts +74 -1
  179. package/dist/api/topo-resolve.d.ts.map +1 -1
  180. package/dist/api/topo-resolve.js +180 -2
  181. package/dist/api/topo-resolve.js.map +1 -1
  182. package/dist/api/transform.d.ts +5 -1
  183. package/dist/api/transform.d.ts.map +1 -1
  184. package/dist/api/transform.js +62 -11
  185. package/dist/api/transform.js.map +1 -1
  186. package/dist/api/wire.d.ts +1 -1
  187. package/dist/api/wire.js +1 -1
  188. package/dist/api/wire.js.map +1 -1
  189. package/dist/brep/brep-ops.d.ts +9 -7
  190. package/dist/brep/brep-ops.d.ts.map +1 -1
  191. package/dist/brep/brep-ops.js +23 -24
  192. package/dist/brep/brep-ops.js.map +1 -1
  193. package/dist/brep/brep-topology.d.ts +5 -4
  194. package/dist/brep/brep-topology.d.ts.map +1 -1
  195. package/dist/brep/brep-topology.js +6 -5
  196. package/dist/brep/brep-topology.js.map +1 -1
  197. package/dist/brep/effective-deflection.d.ts +35 -0
  198. package/dist/brep/effective-deflection.d.ts.map +1 -0
  199. package/dist/brep/effective-deflection.js +49 -0
  200. package/dist/brep/effective-deflection.js.map +1 -0
  201. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  202. package/dist/brep/engine/adapters/brep-mock.js +27 -0
  203. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  204. package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
  205. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  206. package/dist/brep/engine/adapters/brepkit.js +46 -1
  207. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  208. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  209. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  210. package/dist/brep/engine/adapters/occt.js +3 -1
  211. package/dist/brep/engine/adapters/occt.js.map +1 -1
  212. package/dist/brep/engine/primitives.d.ts +29 -7
  213. package/dist/brep/engine/primitives.d.ts.map +1 -1
  214. package/dist/brep/engine/primitives.js.map +1 -1
  215. package/dist/brep/engine/registry.d.ts +24 -1
  216. package/dist/brep/engine/registry.d.ts.map +1 -1
  217. package/dist/brep/engine/registry.js +24 -0
  218. package/dist/brep/engine/registry.js.map +1 -1
  219. package/dist/brep/engine/types.d.ts +54 -3
  220. package/dist/brep/engine/types.d.ts.map +1 -1
  221. package/dist/brep/engine/types.js +10 -0
  222. package/dist/brep/engine/types.js.map +1 -1
  223. package/dist/brep/export/export-model.d.ts.map +1 -1
  224. package/dist/brep/export/export-model.js +6 -5
  225. package/dist/brep/export/export-model.js.map +1 -1
  226. package/dist/brep/face-evolution.d.ts +1 -1
  227. package/dist/brep/face-evolution.d.ts.map +1 -1
  228. package/dist/brep/face-evolution.js +20 -1
  229. package/dist/brep/face-evolution.js.map +1 -1
  230. package/dist/brep/handle-bridge.d.ts +1 -1
  231. package/dist/brep/handle-bridge.js +1 -1
  232. package/dist/brep/handle-bridge.js.map +1 -1
  233. package/dist/brep/mesh-solid.d.ts +218 -0
  234. package/dist/brep/mesh-solid.d.ts.map +1 -0
  235. package/dist/brep/mesh-solid.js +229 -0
  236. package/dist/brep/mesh-solid.js.map +1 -0
  237. package/dist/brep/text/fontRegistry.d.ts +32 -1
  238. package/dist/brep/text/fontRegistry.d.ts.map +1 -1
  239. package/dist/brep/text/fontRegistry.js +51 -1
  240. package/dist/brep/text/fontRegistry.js.map +1 -1
  241. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  242. package/dist/brep/text/text-to-solid.js +8 -3
  243. package/dist/brep/text/text-to-solid.js.map +1 -1
  244. package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
  245. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  246. package/dist/brepkit-kernel/brepkitKernel.js +449 -123
  247. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  248. package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
  249. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  250. package/dist/brepkit-kernel/brepkitWasm.js +10 -0
  251. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  252. package/dist/browser-host/browser-font-provider.d.ts +12 -0
  253. package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
  254. package/dist/browser-host/browser-font-provider.js +25 -0
  255. package/dist/browser-host/browser-font-provider.js.map +1 -1
  256. package/dist/browser.d.ts +6 -3
  257. package/dist/browser.d.ts.map +1 -1
  258. package/dist/browser.js +10 -3
  259. package/dist/browser.js.map +1 -1
  260. package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
  261. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  262. package/dist/cad-runtime/backend-dispatch.js +119 -4
  263. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  264. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  265. package/dist/cad-runtime/direct-executor.d.ts +15 -3
  266. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  267. package/dist/cad-runtime/direct-executor.js +33 -1
  268. package/dist/cad-runtime/direct-executor.js.map +1 -1
  269. package/dist/cad-runtime/ports.d.ts +3 -3
  270. package/dist/cad-runtime/ports.d.ts.map +1 -1
  271. package/dist/cad-runtime/ports.js.map +1 -1
  272. package/dist/cad-runtime/preview-exec.d.ts +4 -4
  273. package/dist/cad-runtime/preview-exec.js +2 -2
  274. package/dist/cad-runtime/preview-exec.js.map +1 -1
  275. package/dist/cad-runtime/runtime.d.ts +42 -7
  276. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  277. package/dist/cad-runtime/runtime.js +68 -5
  278. package/dist/cad-runtime/runtime.js.map +1 -1
  279. package/dist/define-op.d.ts +15 -1
  280. package/dist/define-op.d.ts.map +1 -1
  281. package/dist/define-op.js +10 -1
  282. package/dist/define-op.js.map +1 -1
  283. package/dist/env-agnostic.d.ts +2 -2
  284. package/dist/env-agnostic.d.ts.map +1 -1
  285. package/dist/env-agnostic.js +1 -1
  286. package/dist/env-agnostic.js.map +1 -1
  287. package/dist/geometry2d/adapt.d.ts +39 -4
  288. package/dist/geometry2d/adapt.d.ts.map +1 -1
  289. package/dist/geometry2d/adapt.js +14 -3
  290. package/dist/geometry2d/adapt.js.map +1 -1
  291. package/dist/geometry2d/blueprint.d.ts +2 -2
  292. package/dist/geometry2d/blueprint.js +2 -2
  293. package/dist/geometry2d/blueprint.js.map +1 -1
  294. package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
  295. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  296. package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
  297. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  298. package/dist/geometry2d/bridge/plane.d.ts +17 -0
  299. package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
  300. package/dist/geometry2d/bridge/plane.js +22 -0
  301. package/dist/geometry2d/bridge/plane.js.map +1 -1
  302. package/dist/geometry2d/curve2d.d.ts +25 -0
  303. package/dist/geometry2d/curve2d.d.ts.map +1 -1
  304. package/dist/geometry2d/curve2d.js +41 -5
  305. package/dist/geometry2d/curve2d.js.map +1 -1
  306. package/dist/index.d.ts +6 -2
  307. package/dist/index.d.ts.map +1 -1
  308. package/dist/index.js +10 -3
  309. package/dist/index.js.map +1 -1
  310. package/dist/io/bytes-node.d.ts +11 -0
  311. package/dist/io/bytes-node.d.ts.map +1 -0
  312. package/dist/io/bytes-node.js +28 -0
  313. package/dist/io/bytes-node.js.map +1 -0
  314. package/dist/io/bytes.d.ts +33 -0
  315. package/dist/io/bytes.d.ts.map +1 -0
  316. package/dist/io/bytes.js +41 -0
  317. package/dist/io/bytes.js.map +1 -0
  318. package/dist/io/fai-zip/container-read.d.ts +102 -0
  319. package/dist/io/fai-zip/container-read.d.ts.map +1 -0
  320. package/dist/io/fai-zip/container-read.js +305 -0
  321. package/dist/io/fai-zip/container-read.js.map +1 -0
  322. package/dist/io/fai-zip/container-write.d.ts +70 -0
  323. package/dist/io/fai-zip/container-write.d.ts.map +1 -0
  324. package/dist/io/fai-zip/container-write.js +186 -0
  325. package/dist/io/fai-zip/container-write.js.map +1 -0
  326. package/dist/io/fai-zip/container.d.ts +107 -0
  327. package/dist/io/fai-zip/container.d.ts.map +1 -0
  328. package/dist/io/fai-zip/container.js +89 -0
  329. package/dist/io/fai-zip/container.js.map +1 -0
  330. package/dist/io/fai-zip/index.d.ts +18 -0
  331. package/dist/io/fai-zip/index.d.ts.map +1 -0
  332. package/dist/io/fai-zip/index.js +4 -0
  333. package/dist/io/fai-zip/index.js.map +1 -0
  334. package/dist/io/index.d.ts +10 -0
  335. package/dist/io/index.d.ts.map +1 -0
  336. package/dist/io/index.js +13 -0
  337. package/dist/io/index.js.map +1 -0
  338. package/dist/io/zip.d.ts +68 -0
  339. package/dist/io/zip.d.ts.map +1 -0
  340. package/dist/io/zip.js +147 -0
  341. package/dist/io/zip.js.map +1 -0
  342. package/dist/lang/code-to-args.d.ts +1 -1
  343. package/dist/lang/code-to-args.js +1 -1
  344. package/dist/lang/code-to-args.js.map +1 -1
  345. package/dist/lang/statement-summary.d.ts +1 -1
  346. package/dist/lang/statement-summary.js +1 -1
  347. package/dist/lang/statement-summary.js.map +1 -1
  348. package/dist/lang/types.d.ts +1 -1
  349. package/dist/lang/types.js +1 -1
  350. package/dist/lang/types.js.map +1 -1
  351. package/dist/mesh/index.d.ts +2 -1
  352. package/dist/mesh/index.d.ts.map +1 -1
  353. package/dist/mesh/index.js +2 -1
  354. package/dist/mesh/index.js.map +1 -1
  355. package/dist/mesh/io.d.ts +7 -0
  356. package/dist/mesh/io.d.ts.map +1 -1
  357. package/dist/mesh/io.js +14 -17
  358. package/dist/mesh/io.js.map +1 -1
  359. package/dist/mesh/reconcile.d.ts +1 -1
  360. package/dist/mesh/reconcile.js +1 -1
  361. package/dist/mesh/reconcile.js.map +1 -1
  362. package/dist/mesh/rigid-transform.d.ts +3 -3
  363. package/dist/mesh/rigid-transform.js +3 -3
  364. package/dist/mesh/rigid-transform.js.map +1 -1
  365. package/dist/mesh/stl-unit.d.ts +24 -0
  366. package/dist/mesh/stl-unit.d.ts.map +1 -0
  367. package/dist/mesh/stl-unit.js +17 -0
  368. package/dist/mesh/stl-unit.js.map +1 -0
  369. package/dist/mesh/threemf-bambu.d.ts +142 -0
  370. package/dist/mesh/threemf-bambu.d.ts.map +1 -0
  371. package/dist/mesh/threemf-bambu.js +334 -0
  372. package/dist/mesh/threemf-bambu.js.map +1 -0
  373. package/dist/mesh/threemf-loader.d.ts +42 -7
  374. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  375. package/dist/mesh/threemf-loader.js +565 -100
  376. package/dist/mesh/threemf-loader.js.map +1 -1
  377. package/dist/mesh/threemf-view.d.ts +71 -0
  378. package/dist/mesh/threemf-view.d.ts.map +1 -0
  379. package/dist/mesh/threemf-view.js +100 -0
  380. package/dist/mesh/threemf-view.js.map +1 -0
  381. package/dist/node-host/cli.d.ts +44 -6
  382. package/dist/node-host/cli.d.ts.map +1 -1
  383. package/dist/node-host/cli.js +76 -26
  384. package/dist/node-host/cli.js.map +1 -1
  385. package/dist/node-host/font-family-index.d.ts +93 -0
  386. package/dist/node-host/font-family-index.d.ts.map +1 -0
  387. package/dist/node-host/font-family-index.js +273 -0
  388. package/dist/node-host/font-family-index.js.map +1 -0
  389. package/dist/node-host/fs-asset-resolver.d.ts +8 -3
  390. package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
  391. package/dist/node-host/fs-asset-resolver.js +13 -5
  392. package/dist/node-host/fs-asset-resolver.js.map +1 -1
  393. package/dist/node-host/index.d.ts +8 -0
  394. package/dist/node-host/index.d.ts.map +1 -1
  395. package/dist/node-host/index.js +1 -0
  396. package/dist/node-host/index.js.map +1 -1
  397. package/dist/node-host/node-font-provider.d.ts +28 -0
  398. package/dist/node-host/node-font-provider.d.ts.map +1 -1
  399. package/dist/node-host/node-font-provider.js +49 -0
  400. package/dist/node-host/node-font-provider.js.map +1 -1
  401. package/dist/node.d.ts +1 -0
  402. package/dist/node.d.ts.map +1 -1
  403. package/dist/node.js +1 -0
  404. package/dist/node.js.map +1 -1
  405. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  406. package/dist/occt-kernel/occt-primitives.js +35 -2
  407. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  408. package/dist/occt-kernel/occtKernel.d.ts +18 -13
  409. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  410. package/dist/occt-kernel/occtKernel.js +18 -31
  411. package/dist/occt-kernel/occtKernel.js.map +1 -1
  412. package/dist/occt-kernel/stepColorParser.d.ts +18 -0
  413. package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
  414. package/dist/occt-kernel/stepColorParser.js +38 -0
  415. package/dist/occt-kernel/stepColorParser.js.map +1 -1
  416. package/dist/occt-kernel/topologyExt.d.ts +1 -1
  417. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  418. package/dist/occt-kernel/topologyExt.js +4 -5
  419. package/dist/occt-kernel/topologyExt.js.map +1 -1
  420. package/dist/primitives/text/cjk-font.d.ts +2 -15
  421. package/dist/primitives/text/cjk-font.d.ts.map +1 -1
  422. package/dist/primitives/text/cjk-font.js +13 -1
  423. package/dist/primitives/text/cjk-font.js.map +1 -1
  424. package/dist/runtime-state.d.ts +85 -9
  425. package/dist/runtime-state.d.ts.map +1 -1
  426. package/dist/runtime-state.js +72 -2
  427. package/dist/runtime-state.js.map +1 -1
  428. package/dist/sdk.d.ts +3 -3
  429. package/dist/sdk.d.ts.map +1 -1
  430. package/dist/sdk.js +5 -5
  431. package/dist/sdk.js.map +1 -1
  432. package/dist/shape.d.ts +97 -2
  433. package/dist/shape.d.ts.map +1 -1
  434. package/dist/shape.js +126 -1
  435. package/dist/shape.js.map +1 -1
  436. package/dist/topology/naming/lineage.d.ts +6 -0
  437. package/dist/topology/naming/lineage.d.ts.map +1 -1
  438. package/dist/topology/naming/lineage.js +8 -0
  439. package/dist/topology/naming/lineage.js.map +1 -1
  440. package/dist/topology/naming/resolve-edge.d.ts +20 -1
  441. package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
  442. package/dist/topology/naming/resolve-edge.js +54 -20
  443. package/dist/topology/naming/resolve-edge.js.map +1 -1
  444. package/dist/weapp.d.ts +6 -2
  445. package/dist/weapp.d.ts.map +1 -1
  446. package/dist/weapp.js +7 -1
  447. package/dist/weapp.js.map +1 -1
  448. package/package.json +18 -2
@@ -0,0 +1,93 @@
1
+ /**
2
+ * System-font family index (Node host only).
3
+ *
4
+ * CadQuery resolves `font="Arial"` through OCC's `Font_FontMgr`, which consults
5
+ * the operating system's installed fonts. faijs has no such service, so a
6
+ * name-based `font=` cannot be honoured unless the *host* provides one. This
7
+ * module is that provider for the Node host: it walks the OS font directories
8
+ * and maps a normalised family name to the font file, so
9
+ * `NodeFontProvider.resolveFont('Arial')` can return the bytes.
10
+ *
11
+ * Design notes
12
+ * ------------
13
+ * - **Only the `name` table is read.** Parsing a font with opentype.js costs
14
+ * milliseconds; a system font directory holds hundreds to thousands of files,
15
+ * so a full parse per file would add seconds to every first text call. The
16
+ * `name` table sits a few hundred bytes into the file, so a small `readSync`
17
+ * per file is enough.
18
+ * - **`.ttc`/`.woff`/`.woff2` are skipped**: TrueType collections need a
19
+ * per-face offset table and the WOFF formats are compressed — neither is a
20
+ * plain `name` table read.
21
+ * - Nothing here runs unless a caller explicitly asks for a font *by name*;
22
+ * the bundled default font stays the single source of truth for `default`.
23
+ */
24
+ /** Names of one font file. */
25
+ export interface FontFileNames {
26
+ /** Typographic family (name ID 16) when present, else family (name ID 1). */
27
+ family: string;
28
+ /** Subfamily (name ID 17 when present, else name ID 2), e.g. "Regular". */
29
+ subfamily: string;
30
+ }
31
+ /**
32
+ * Normalise a font name for matching: lower-case, letters/digits only.
33
+ *
34
+ * `"DejaVu Sans"`, `"DejaVuSans"` and `"dejavu-sans"` all collapse to
35
+ * `"dejavusans"`, which is what makes file-name based keys and real family
36
+ * names interchangeable.
37
+ *
38
+ * @param name - raw font name
39
+ * @returns the normalised comparison key
40
+ */
41
+ export declare function normalizeFontName(name: string): string;
42
+ /**
43
+ * Parse a `name` table that starts at `base` inside `buf`.
44
+ *
45
+ * Windows (platform 3) and Unicode (platform 0) records are UTF-16BE; Macintosh
46
+ * (platform 1) records are single-byte. Windows/en records win when a name is
47
+ * present more than once. Typographic names (16/17) win over legacy (1/2).
48
+ *
49
+ * @param buf - buffer containing the table
50
+ * @param base - offset of the table inside `buf`
51
+ * @returns the names, or null when the table is unreadable
52
+ */
53
+ export declare function parseNameTable(buf: Buffer, base: number): FontFileNames | null;
54
+ /**
55
+ * Read the family/subfamily names out of a complete font file buffer.
56
+ *
57
+ * @param buf - the whole font file
58
+ * @returns the names, or null when the file has no readable `name` table
59
+ */
60
+ export declare function readFontFileNames(buf: Buffer): FontFileNames | null;
61
+ /** Locate a font file whose `name` table names it `family`. */
62
+ export interface FontFamilyMatch {
63
+ /** Absolute path of the best (Regular-preferred) file for the family. */
64
+ path: string;
65
+ }
66
+ /**
67
+ * The OS font directories to scan, in search order (Windows / macOS / Linux).
68
+ *
69
+ * @returns the platform's standard font directories present in the environment,
70
+ * with unavailable ones filtered out (may be empty on a stripped-down host)
71
+ */
72
+ export declare function defaultSystemFontDirs(): string[];
73
+ /** normalized family name -> best file path found so far. */
74
+ export type FontFamilyIndex = Map<string, string>;
75
+ /**
76
+ * Build a normalised-family → file-path index for the given directories.
77
+ *
78
+ * When a family has several files (Regular/Bold/Italic…), the Regular one wins;
79
+ * otherwise the first file seen is kept. Also indexes each file's *file stem*,
80
+ * so a host pointed at a bare directory of renamed files still resolves them.
81
+ *
82
+ * @param dirs - font directories to scan (missing directories are skipped)
83
+ * @returns the index (empty when nothing readable was found)
84
+ */
85
+ export declare function buildFontFamilyIndex(dirs: readonly string[]): FontFamilyIndex;
86
+ /**
87
+ * PATH-style helper: split a user-supplied directory list.
88
+ *
89
+ * @param dirs - a path-delimiter-separated directory list (`;` on Windows, `:` elsewhere)
90
+ * @returns the non-empty entries, in the order given
91
+ */
92
+ export declare function splitDirList(dirs: string): string[];
93
+ //# sourceMappingURL=font-family-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-family-index.d.ts","sourceRoot":"","sources":["../../src/node-host/font-family-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAWH,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAkCD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAyC9E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAInE;AA6BD,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAwBhD;AA2BD,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEjD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,CAgB7E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * System-font family index (Node host only).
3
+ *
4
+ * CadQuery resolves `font="Arial"` through OCC's `Font_FontMgr`, which consults
5
+ * the operating system's installed fonts. faijs has no such service, so a
6
+ * name-based `font=` cannot be honoured unless the *host* provides one. This
7
+ * module is that provider for the Node host: it walks the OS font directories
8
+ * and maps a normalised family name to the font file, so
9
+ * `NodeFontProvider.resolveFont('Arial')` can return the bytes.
10
+ *
11
+ * Design notes
12
+ * ------------
13
+ * - **Only the `name` table is read.** Parsing a font with opentype.js costs
14
+ * milliseconds; a system font directory holds hundreds to thousands of files,
15
+ * so a full parse per file would add seconds to every first text call. The
16
+ * `name` table sits a few hundred bytes into the file, so a small `readSync`
17
+ * per file is enough.
18
+ * - **`.ttc`/`.woff`/`.woff2` are skipped**: TrueType collections need a
19
+ * per-face offset table and the WOFF formats are compressed — neither is a
20
+ * plain `name` table read.
21
+ * - Nothing here runs unless a caller explicitly asks for a font *by name*;
22
+ * the bundled default font stays the single source of truth for `default`.
23
+ */
24
+ import { readdirSync, readSync, openSync, closeSync, statSync, existsSync } from 'node:fs';
25
+ import { join, extname, delimiter } from 'node:path';
26
+ /** A file we can index by reading its `name` table directly. */
27
+ const INDEXABLE_EXT = new Set(['.ttf', '.otf']);
28
+ /** sfnt version tags that start with a standard table directory. */
29
+ const SFNT_TRUE_TYPE = 0x00010000;
30
+ /**
31
+ * Normalise a font name for matching: lower-case, letters/digits only.
32
+ *
33
+ * `"DejaVu Sans"`, `"DejaVuSans"` and `"dejavu-sans"` all collapse to
34
+ * `"dejavusans"`, which is what makes file-name based keys and real family
35
+ * names interchangeable.
36
+ *
37
+ * @param name - raw font name
38
+ * @returns the normalised comparison key
39
+ */
40
+ export function normalizeFontName(name) {
41
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, '');
42
+ }
43
+ /** Decode a UTF-16BE string out of `buf` (Node has no utf16be codec). */
44
+ function utf16beToString(buf, start, byteLength) {
45
+ const chars = [];
46
+ for (let i = 0; i + 1 < byteLength; i += 2) {
47
+ chars.push(String.fromCharCode(buf.readUInt16BE(start + i)));
48
+ }
49
+ return chars.join('');
50
+ }
51
+ /**
52
+ * Locate the `name` table inside a font's table directory.
53
+ *
54
+ * @param buf - buffer holding at least the sfnt header + table directory
55
+ * @returns the table's byte offset and length, or null for an unsupported file
56
+ */
57
+ function findNameTable(buf) {
58
+ if (buf.length < 12)
59
+ return null;
60
+ const sfnt = buf.readUInt32BE(0);
61
+ const tag = buf.toString('latin1', 0, 4);
62
+ if (sfnt !== SFNT_TRUE_TYPE && tag !== 'OTTO' && tag !== 'true' && tag !== 'typ1')
63
+ return null;
64
+ const numTables = buf.readUInt16BE(4);
65
+ for (let i = 0; i < numTables; i++) {
66
+ const rec = 12 + i * 16;
67
+ if (rec + 16 > buf.length)
68
+ break;
69
+ if (buf.toString('latin1', rec, rec + 4) === 'name') {
70
+ return { offset: buf.readUInt32BE(rec + 8), length: buf.readUInt32BE(rec + 12) };
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ /**
76
+ * Parse a `name` table that starts at `base` inside `buf`.
77
+ *
78
+ * Windows (platform 3) and Unicode (platform 0) records are UTF-16BE; Macintosh
79
+ * (platform 1) records are single-byte. Windows/en records win when a name is
80
+ * present more than once. Typographic names (16/17) win over legacy (1/2).
81
+ *
82
+ * @param buf - buffer containing the table
83
+ * @param base - offset of the table inside `buf`
84
+ * @returns the names, or null when the table is unreadable
85
+ */
86
+ export function parseNameTable(buf, base) {
87
+ if (base + 6 > buf.length)
88
+ return null;
89
+ const count = buf.readUInt16BE(base + 2);
90
+ const storage = base + buf.readUInt16BE(base + 4);
91
+ // nameID -> best (highest-priority) decoded value
92
+ const best = new Map();
93
+ for (let i = 0; i < count; i++) {
94
+ const rec = base + 6 + i * 12;
95
+ if (rec + 12 > buf.length)
96
+ break;
97
+ const platform = buf.readUInt16BE(rec);
98
+ const language = buf.readUInt16BE(rec + 4);
99
+ const nameId = buf.readUInt16BE(rec + 6);
100
+ const len = buf.readUInt16BE(rec + 8);
101
+ const off = buf.readUInt16BE(rec + 10);
102
+ if (len === 0 || (nameId !== 1 && nameId !== 2 && nameId !== 16 && nameId !== 17))
103
+ continue;
104
+ const start = storage + off;
105
+ if (start + len > buf.length)
106
+ continue;
107
+ let value = null;
108
+ let score = 0;
109
+ if (platform === 3 || platform === 0) {
110
+ value = utf16beToString(buf, start, len);
111
+ score = platform === 3 ? (language === 0x0409 ? 3 : 2) : 1;
112
+ }
113
+ else if (platform === 1) {
114
+ value = buf.toString('latin1', start, start + len);
115
+ score = 1;
116
+ }
117
+ if (value === null)
118
+ continue;
119
+ value = value.replace(/\0/g, '').trim();
120
+ if (!value)
121
+ continue;
122
+ const prior = best.get(nameId);
123
+ if (!prior || score > prior.score)
124
+ best.set(nameId, { score, value });
125
+ }
126
+ const family = best.get(16)?.value ?? best.get(1)?.value;
127
+ if (!family)
128
+ return null;
129
+ return {
130
+ family,
131
+ subfamily: best.get(17)?.value ?? best.get(2)?.value ?? '',
132
+ };
133
+ }
134
+ /**
135
+ * Read the family/subfamily names out of a complete font file buffer.
136
+ *
137
+ * @param buf - the whole font file
138
+ * @returns the names, or null when the file has no readable `name` table
139
+ */
140
+ export function readFontFileNames(buf) {
141
+ const table = findNameTable(buf);
142
+ if (!table || table.offset + 6 > buf.length)
143
+ return null;
144
+ return parseNameTable(buf, table.offset);
145
+ }
146
+ /**
147
+ * Scan one font file and return its names (null when unreadable).
148
+ *
149
+ * Two-phase read: the sfnt header + table directory first, then exactly the
150
+ * `name` table. Reading a fixed head window is not enough — in a large font
151
+ * (`glyf`/`loca` are megabytes) the `name` table sits far past any small prefix
152
+ * (Arial's is at ~0x0F0000), which silently made the whole system index miss.
153
+ */
154
+ function namesOf(path) {
155
+ let fd;
156
+ try {
157
+ fd = openSync(path, 'r');
158
+ const size = statSync(path).size;
159
+ const head = Buffer.alloc(Math.min(size, 4096));
160
+ readSync(fd, head, 0, head.length, 0);
161
+ const table = findNameTable(head);
162
+ if (!table || table.length === 0 || table.offset + table.length > size)
163
+ return null;
164
+ const tbl = Buffer.alloc(table.length);
165
+ readSync(fd, tbl, 0, table.length, table.offset);
166
+ return parseNameTable(tbl, 0);
167
+ }
168
+ catch {
169
+ return null;
170
+ }
171
+ finally {
172
+ if (fd !== undefined)
173
+ closeSync(fd);
174
+ }
175
+ }
176
+ /**
177
+ * The OS font directories to scan, in search order (Windows / macOS / Linux).
178
+ *
179
+ * @returns the platform's standard font directories present in the environment,
180
+ * with unavailable ones filtered out (may be empty on a stripped-down host)
181
+ */
182
+ export function defaultSystemFontDirs() {
183
+ const win = process.env.WINDIR || process.env.SystemRoot;
184
+ if (process.platform === 'win32') {
185
+ return [
186
+ win ? join(win, 'Fonts') : '',
187
+ process.env.LOCALAPPDATA ? join(process.env.LOCALAPPDATA, 'Microsoft', 'Windows', 'Fonts') : '',
188
+ ].filter(Boolean);
189
+ }
190
+ if (process.platform === 'darwin') {
191
+ return [
192
+ '/System/Library/Fonts',
193
+ '/Library/Fonts',
194
+ process.env.HOME ? join(process.env.HOME, 'Library', 'Fonts') : '',
195
+ ].filter(Boolean);
196
+ }
197
+ // Linux / other unix: fontconfig's usual roots.
198
+ const xdg = process.env.XDG_DATA_HOME;
199
+ return [
200
+ '/usr/share/fonts',
201
+ '/usr/local/share/fonts',
202
+ xdg ? join(xdg, 'fonts') : '',
203
+ process.env.HOME ? join(process.env.HOME, '.fonts') : '',
204
+ process.env.HOME ? join(process.env.HOME, '.local', 'share', 'fonts') : '',
205
+ ].filter(Boolean);
206
+ }
207
+ /** Every indexable font file under `dir`, depth-first and depth-capped. */
208
+ function* walkFontFiles(dir, depth = 4) {
209
+ if (depth <= 0 || !existsSync(dir))
210
+ return;
211
+ let entries;
212
+ try {
213
+ entries = readdirSync(dir);
214
+ }
215
+ catch {
216
+ return;
217
+ }
218
+ for (const entry of entries) {
219
+ const p = join(dir, entry);
220
+ let st;
221
+ try {
222
+ st = statSync(p);
223
+ }
224
+ catch {
225
+ continue;
226
+ }
227
+ if (st.isDirectory()) {
228
+ yield* walkFontFiles(p, depth - 1);
229
+ }
230
+ else if (INDEXABLE_EXT.has(extname(entry).toLowerCase())) {
231
+ yield p;
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * Build a normalised-family → file-path index for the given directories.
237
+ *
238
+ * When a family has several files (Regular/Bold/Italic…), the Regular one wins;
239
+ * otherwise the first file seen is kept. Also indexes each file's *file stem*,
240
+ * so a host pointed at a bare directory of renamed files still resolves them.
241
+ *
242
+ * @param dirs - font directories to scan (missing directories are skipped)
243
+ * @returns the index (empty when nothing readable was found)
244
+ */
245
+ export function buildFontFamilyIndex(dirs) {
246
+ const index = new Map();
247
+ for (const dir of dirs) {
248
+ for (const file of walkFontFiles(dir)) {
249
+ const names = namesOf(file);
250
+ if (!names)
251
+ continue;
252
+ const key = normalizeFontName(names.family);
253
+ const isRegular = normalizeFontName(names.subfamily) === 'regular';
254
+ if (key && (!index.has(key) || isRegular))
255
+ index.set(key, file);
256
+ // Also allow lookup by file stem ("arial" -> arial.ttf).
257
+ const stem = normalizeFontName(file.replace(/^.*[\\/]/, '').replace(/\.[^.]+$/, ''));
258
+ if (stem && !index.has(stem))
259
+ index.set(stem, file);
260
+ }
261
+ }
262
+ return index;
263
+ }
264
+ /**
265
+ * PATH-style helper: split a user-supplied directory list.
266
+ *
267
+ * @param dirs - a path-delimiter-separated directory list (`;` on Windows, `:` elsewhere)
268
+ * @returns the non-empty entries, in the order given
269
+ */
270
+ export function splitDirList(dirs) {
271
+ return dirs.split(delimiter).filter(Boolean);
272
+ }
273
+ //# sourceMappingURL=font-family-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-family-index.js","sourceRoot":"","sources":["../../src/node-host/font-family-index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System-font family index (Node host only).\n *\n * CadQuery resolves `font=\"Arial\"` through OCC's `Font_FontMgr`, which consults\n * the operating system's installed fonts. faijs has no such service, so a\n * name-based `font=` cannot be honoured unless the *host* provides one. This\n * module is that provider for the Node host: it walks the OS font directories\n * and maps a normalised family name to the font file, so\n * `NodeFontProvider.resolveFont('Arial')` can return the bytes.\n *\n * Design notes\n * ------------\n * - **Only the `name` table is read.** Parsing a font with opentype.js costs\n * milliseconds; a system font directory holds hundreds to thousands of files,\n * so a full parse per file would add seconds to every first text call. The\n * `name` table sits a few hundred bytes into the file, so a small `readSync`\n * per file is enough.\n * - **`.ttc`/`.woff`/`.woff2` are skipped**: TrueType collections need a\n * per-face offset table and the WOFF formats are compressed — neither is a\n * plain `name` table read.\n * - Nothing here runs unless a caller explicitly asks for a font *by name*;\n * the bundled default font stays the single source of truth for `default`.\n */\n\nimport { readdirSync, readSync, openSync, closeSync, statSync, existsSync } from 'node:fs'\nimport { join, extname, delimiter } from 'node:path'\n\n/** A file we can index by reading its `name` table directly. */\nconst INDEXABLE_EXT = new Set(['.ttf', '.otf'])\n\n/** sfnt version tags that start with a standard table directory. */\nconst SFNT_TRUE_TYPE = 0x00010000\n\n/** Names of one font file. */\nexport interface FontFileNames {\n /** Typographic family (name ID 16) when present, else family (name ID 1). */\n family: string\n /** Subfamily (name ID 17 when present, else name ID 2), e.g. \"Regular\". */\n subfamily: string\n}\n\n/**\n * Normalise a font name for matching: lower-case, letters/digits only.\n *\n * `\"DejaVu Sans\"`, `\"DejaVuSans\"` and `\"dejavu-sans\"` all collapse to\n * `\"dejavusans\"`, which is what makes file-name based keys and real family\n * names interchangeable.\n *\n * @param name - raw font name\n * @returns the normalised comparison key\n */\nexport function normalizeFontName(name: string): string {\n return name.toLowerCase().replace(/[^a-z0-9]+/g, '')\n}\n\n/** Decode a UTF-16BE string out of `buf` (Node has no utf16be codec). */\nfunction utf16beToString(buf: Buffer, start: number, byteLength: number): string {\n const chars: string[] = []\n for (let i = 0; i + 1 < byteLength; i += 2) {\n chars.push(String.fromCharCode(buf.readUInt16BE(start + i)))\n }\n return chars.join('')\n}\n\n/**\n * Locate the `name` table inside a font's table directory.\n *\n * @param buf - buffer holding at least the sfnt header + table directory\n * @returns the table's byte offset and length, or null for an unsupported file\n */\nfunction findNameTable(buf: Buffer): { offset: number; length: number } | null {\n if (buf.length < 12) return null\n const sfnt = buf.readUInt32BE(0)\n const tag = buf.toString('latin1', 0, 4)\n if (sfnt !== SFNT_TRUE_TYPE && tag !== 'OTTO' && tag !== 'true' && tag !== 'typ1') return null\n\n const numTables = buf.readUInt16BE(4)\n for (let i = 0; i < numTables; i++) {\n const rec = 12 + i * 16\n if (rec + 16 > buf.length) break\n if (buf.toString('latin1', rec, rec + 4) === 'name') {\n return { offset: buf.readUInt32BE(rec + 8), length: buf.readUInt32BE(rec + 12) }\n }\n }\n return null\n}\n\n/**\n * Parse a `name` table that starts at `base` inside `buf`.\n *\n * Windows (platform 3) and Unicode (platform 0) records are UTF-16BE; Macintosh\n * (platform 1) records are single-byte. Windows/en records win when a name is\n * present more than once. Typographic names (16/17) win over legacy (1/2).\n *\n * @param buf - buffer containing the table\n * @param base - offset of the table inside `buf`\n * @returns the names, or null when the table is unreadable\n */\nexport function parseNameTable(buf: Buffer, base: number): FontFileNames | null {\n if (base + 6 > buf.length) return null\n const count = buf.readUInt16BE(base + 2)\n const storage = base + buf.readUInt16BE(base + 4)\n\n // nameID -> best (highest-priority) decoded value\n const best = new Map<number, { score: number; value: string }>()\n for (let i = 0; i < count; i++) {\n const rec = base + 6 + i * 12\n if (rec + 12 > buf.length) break\n const platform = buf.readUInt16BE(rec)\n const language = buf.readUInt16BE(rec + 4)\n const nameId = buf.readUInt16BE(rec + 6)\n const len = buf.readUInt16BE(rec + 8)\n const off = buf.readUInt16BE(rec + 10)\n if (len === 0 || (nameId !== 1 && nameId !== 2 && nameId !== 16 && nameId !== 17)) continue\n const start = storage + off\n if (start + len > buf.length) continue\n\n let value: string | null = null\n let score = 0\n if (platform === 3 || platform === 0) {\n value = utf16beToString(buf, start, len)\n score = platform === 3 ? (language === 0x0409 ? 3 : 2) : 1\n } else if (platform === 1) {\n value = buf.toString('latin1', start, start + len)\n score = 1\n }\n if (value === null) continue\n value = value.replace(/\\0/g, '').trim()\n if (!value) continue\n const prior = best.get(nameId)\n if (!prior || score > prior.score) best.set(nameId, { score, value })\n }\n\n const family = best.get(16)?.value ?? best.get(1)?.value\n if (!family) return null\n return {\n family,\n subfamily: best.get(17)?.value ?? best.get(2)?.value ?? '',\n }\n}\n\n/**\n * Read the family/subfamily names out of a complete font file buffer.\n *\n * @param buf - the whole font file\n * @returns the names, or null when the file has no readable `name` table\n */\nexport function readFontFileNames(buf: Buffer): FontFileNames | null {\n const table = findNameTable(buf)\n if (!table || table.offset + 6 > buf.length) return null\n return parseNameTable(buf, table.offset)\n}\n\n/**\n * Scan one font file and return its names (null when unreadable).\n *\n * Two-phase read: the sfnt header + table directory first, then exactly the\n * `name` table. Reading a fixed head window is not enough — in a large font\n * (`glyf`/`loca` are megabytes) the `name` table sits far past any small prefix\n * (Arial's is at ~0x0F0000), which silently made the whole system index miss.\n */\nfunction namesOf(path: string): FontFileNames | null {\n let fd: number | undefined\n try {\n fd = openSync(path, 'r')\n const size = statSync(path).size\n const head = Buffer.alloc(Math.min(size, 4096))\n readSync(fd, head, 0, head.length, 0)\n const table = findNameTable(head)\n if (!table || table.length === 0 || table.offset + table.length > size) return null\n const tbl = Buffer.alloc(table.length)\n readSync(fd, tbl, 0, table.length, table.offset)\n return parseNameTable(tbl, 0)\n } catch {\n return null\n } finally {\n if (fd !== undefined) closeSync(fd)\n }\n}\n\n/** Locate a font file whose `name` table names it `family`. */\nexport interface FontFamilyMatch {\n /** Absolute path of the best (Regular-preferred) file for the family. */\n path: string\n}\n\n/**\n * The OS font directories to scan, in search order (Windows / macOS / Linux).\n *\n * @returns the platform's standard font directories present in the environment,\n * with unavailable ones filtered out (may be empty on a stripped-down host)\n */\nexport function defaultSystemFontDirs(): string[] {\n const win = process.env.WINDIR || process.env.SystemRoot\n if (process.platform === 'win32') {\n return [\n win ? join(win, 'Fonts') : '',\n process.env.LOCALAPPDATA ? join(process.env.LOCALAPPDATA, 'Microsoft', 'Windows', 'Fonts') : '',\n ].filter(Boolean)\n }\n if (process.platform === 'darwin') {\n return [\n '/System/Library/Fonts',\n '/Library/Fonts',\n process.env.HOME ? join(process.env.HOME, 'Library', 'Fonts') : '',\n ].filter(Boolean)\n }\n // Linux / other unix: fontconfig's usual roots.\n const xdg = process.env.XDG_DATA_HOME\n return [\n '/usr/share/fonts',\n '/usr/local/share/fonts',\n xdg ? join(xdg, 'fonts') : '',\n process.env.HOME ? join(process.env.HOME, '.fonts') : '',\n process.env.HOME ? join(process.env.HOME, '.local', 'share', 'fonts') : '',\n ].filter(Boolean)\n}\n\n/** Every indexable font file under `dir`, depth-first and depth-capped. */\nfunction* walkFontFiles(dir: string, depth = 4): Generator<string> {\n if (depth <= 0 || !existsSync(dir)) return\n let entries: string[]\n try {\n entries = readdirSync(dir)\n } catch {\n return\n }\n for (const entry of entries) {\n const p = join(dir, entry)\n let st\n try {\n st = statSync(p)\n } catch {\n continue\n }\n if (st.isDirectory()) {\n yield* walkFontFiles(p, depth - 1)\n } else if (INDEXABLE_EXT.has(extname(entry).toLowerCase())) {\n yield p\n }\n }\n}\n\n/** normalized family name -> best file path found so far. */\nexport type FontFamilyIndex = Map<string, string>\n\n/**\n * Build a normalised-family → file-path index for the given directories.\n *\n * When a family has several files (Regular/Bold/Italic…), the Regular one wins;\n * otherwise the first file seen is kept. Also indexes each file's *file stem*,\n * so a host pointed at a bare directory of renamed files still resolves them.\n *\n * @param dirs - font directories to scan (missing directories are skipped)\n * @returns the index (empty when nothing readable was found)\n */\nexport function buildFontFamilyIndex(dirs: readonly string[]): FontFamilyIndex {\n const index: FontFamilyIndex = new Map()\n for (const dir of dirs) {\n for (const file of walkFontFiles(dir)) {\n const names = namesOf(file)\n if (!names) continue\n const key = normalizeFontName(names.family)\n const isRegular = normalizeFontName(names.subfamily) === 'regular'\n if (key && (!index.has(key) || isRegular)) index.set(key, file)\n\n // Also allow lookup by file stem (\"arial\" -> arial.ttf).\n const stem = normalizeFontName(file.replace(/^.*[\\\\/]/, '').replace(/\\.[^.]+$/, ''))\n if (stem && !index.has(stem)) index.set(stem, file)\n }\n }\n return index\n}\n\n/**\n * PATH-style helper: split a user-supplied directory list.\n *\n * @param dirs - a path-delimiter-separated directory list (`;` on Windows, `:` elsewhere)\n * @returns the non-empty entries, in the order given\n */\nexport function splitDirList(dirs: string): string[] {\n return dirs.split(delimiter).filter(Boolean)\n}\n"]}
@@ -13,7 +13,7 @@
13
13
  * "logo_svg_key": { "path": "assets/logo.svg", "format": "svg" }
14
14
  * }
15
15
  *
16
- * 或简单目录模式(无 manifest):key = 文件名(不含扩展名)
16
+ * 或简单目录模式(无 manifest):key = 完整文件名(含扩展名,P8 资产按文件名注册)
17
17
  */
18
18
  import type { AssetResolver } from '../cad-runtime/ports.js';
19
19
  /** Options for constructing an FsAssetResolver. */
@@ -37,13 +37,18 @@ export interface FsAssetResolverOptions {
37
37
  * "logo_svg_key": { "path": "assets/logo.svg", "format": "svg" }
38
38
  * }
39
39
  *
40
- * Or a plain directory mode (no manifest): key = file name without extension.
40
+ * Or a plain directory mode (no manifest): key = full file name (with extension, P8: assets are registered by file name).
41
41
  */
42
42
  export declare class FsAssetResolver implements AssetResolver {
43
43
  private assetsDir;
44
44
  private manifest;
45
45
  constructor(opts?: FsAssetResolverOptions);
46
- /** 扫描目录,按文件名(不含扩展名)注册 key */
46
+ /**
47
+ * 扫描目录,注册两种 key(同一文件的两个命名空间,非内部逻辑回退):
48
+ * - 完整文件名(含扩展名):P8 起 `cad.load({ file })` 的寻址载体;
49
+ * - 无扩展名 basename:`cad.import_brep({ asset })` 的平台 BREP 资产约定
50
+ * (asset 引用 `<stem>.brp` 的 `<stem>`,容器资产名)。
51
+ */
47
52
  private scanDirectory;
48
53
  resolveByKey(key: string): Promise<{
49
54
  bytes: ArrayBuffer;
@@ -1 +1 @@
1
- {"version":3,"file":"fs-asset-resolver.d.ts","sourceRoot":"","sources":["../../src/node-host/fs-asset-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAwBzD,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,eAAgB,YAAW,aAAa;IACnD,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,QAAQ,CAAe;gBAEnB,IAAI,CAAC,EAAE,sBAAsB;IAezC,6BAA6B;IAC7B,OAAO,CAAC,aAAa;IAWf,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAmB3E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ/C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAOpD"}
1
+ {"version":3,"file":"fs-asset-resolver.d.ts","sourceRoot":"","sources":["../../src/node-host/fs-asset-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAwBzD,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,eAAgB,YAAW,aAAa;IACnD,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,QAAQ,CAAe;gBAEnB,IAAI,CAAC,EAAE,sBAAsB;IAezC;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAcf,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAmB3E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ/C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAOpD"}
@@ -13,7 +13,7 @@
13
13
  * "logo_svg_key": { "path": "assets/logo.svg", "format": "svg" }
14
14
  * }
15
15
  *
16
- * 或简单目录模式(无 manifest):key = 文件名(不含扩展名)
16
+ * 或简单目录模式(无 manifest):key = 完整文件名(含扩展名,P8 资产按文件名注册)
17
17
  */
18
18
  import { readFileSync, existsSync, statSync, readdirSync } from 'node:fs';
19
19
  import { resolve, extname, basename } from 'node:path';
@@ -46,7 +46,7 @@ function inferFormat(filePath) {
46
46
  * "logo_svg_key": { "path": "assets/logo.svg", "format": "svg" }
47
47
  * }
48
48
  *
49
- * Or a plain directory mode (no manifest): key = file name without extension.
49
+ * Or a plain directory mode (no manifest): key = full file name (with extension, P8: assets are registered by file name).
50
50
  */
51
51
  export class FsAssetResolver {
52
52
  assetsDir;
@@ -63,14 +63,22 @@ export class FsAssetResolver {
63
63
  this.scanDirectory(this.assetsDir);
64
64
  }
65
65
  }
66
- /** 扫描目录,按文件名(不含扩展名)注册 key */
66
+ /**
67
+ * 扫描目录,注册两种 key(同一文件的两个命名空间,非内部逻辑回退):
68
+ * - 完整文件名(含扩展名):P8 起 `cad.load({ file })` 的寻址载体;
69
+ * - 无扩展名 basename:`cad.import_brep({ asset })` 的平台 BREP 资产约定
70
+ * (asset 引用 `<stem>.brp` 的 `<stem>`,容器资产名)。
71
+ */
67
72
  scanDirectory(dir) {
68
73
  const files = readdirSync(dir);
69
74
  for (const file of files) {
70
75
  const fullPath = resolve(dir, file);
71
76
  if (statSync(fullPath).isFile()) {
72
- const key = basename(file, extname(file));
73
- this.manifest[key] = { path: fullPath, format: inferFormat(fullPath) };
77
+ this.manifest[file] = { path: fullPath, format: inferFormat(fullPath) };
78
+ const stem = basename(file, extname(file));
79
+ if (stem !== file) {
80
+ this.manifest[stem] = { path: fullPath, format: inferFormat(fullPath) };
81
+ }
74
82
  }
75
83
  }
76
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fs-asset-resolver.js","sourceRoot":"","sources":["../../src/node-host/fs-asset-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * FsAssetResolver — Node 端资产解析(fs 目录/manifest)\n *\n *\n * 实现 AssetResolver 接口:\n * - resolveByKey(key): 从 --assets 目录/manifest 解析 key → 文件路径 → ArrayBuffer\n * - resolveFile(path): 直接读取本地文件\n * - resolveUrl(url): fetch(Node 18+ 内置 fetch)\n *\n * manifest 格式(JSON):\n * {\n * \"file_abc123\": { \"path\": \"models/box.step\", \"format\": \"step\" },\n * \"logo_svg_key\": { \"path\": \"assets/logo.svg\", \"format\": \"svg\" }\n * }\n *\n * 或简单目录模式(无 manifest):key = 文件名(不含扩展名)\n */\n\nimport { readFileSync, existsSync, statSync, readdirSync } from 'node:fs'\nimport { resolve, extname, basename } from 'node:path'\nimport type { AssetResolver } from '../cad-runtime/ports'\n\ninterface ManifestEntry {\n path: string\n format?: string\n}\n\ntype Manifest = Record<string, ManifestEntry>\n\n/** 从文件扩展名推断格式 */\nfunction inferFormat(filePath: string): string | undefined {\n if (filePath.toLowerCase().endsWith('.fai.js')) return 'faijs'\n const ext = extname(filePath).toLowerCase().slice(1)\n const formatMap: Record<string, string> = {\n step: 'step',\n stp: 'step',\n '3mf': '3mf',\n stl: 'stl',\n obj: 'obj',\n svg: 'svg',\n }\n return formatMap[ext]\n}\n\n/** Options for constructing an FsAssetResolver. */\nexport interface FsAssetResolverOptions {\n /** Asset root directory. */\n assetsDir?: string\n /** Manifest file path (JSON, key -> {path, format?}). */\n manifestPath?: string\n}\n\n/**\n * Node-side asset resolver backed by the filesystem (directory/manifest).\n *\n * Implements the AssetResolver interface:\n * - resolveByKey(key): resolve a key from the --assets directory/manifest to a file path and return its bytes\n * - resolveFile(path): read a local file directly\n * - resolveUrl(url): fetch a URL (Node 18+ built-in fetch)\n *\n * Manifest format (JSON):\n * {\n * \"file_abc123\": { \"path\": \"models/box.step\", \"format\": \"step\" },\n * \"logo_svg_key\": { \"path\": \"assets/logo.svg\", \"format\": \"svg\" }\n * }\n *\n * Or a plain directory mode (no manifest): key = file name without extension.\n */\nexport class FsAssetResolver implements AssetResolver {\n private assetsDir: string | undefined\n private manifest: Manifest = {}\n\n constructor(opts?: FsAssetResolverOptions) {\n this.assetsDir = opts?.assetsDir\n const manifestPath = opts?.manifestPath ?? (this.assetsDir ? resolve(this.assetsDir, 'manifest.json') : undefined)\n\n if (manifestPath && existsSync(manifestPath)) {\n const raw = readFileSync(manifestPath, 'utf-8')\n this.manifest = JSON.parse(raw) as Manifest\n }\n\n // 如果没有 manifest 但有 assetsDir,自动扫描目录\n if (Object.keys(this.manifest).length === 0 && this.assetsDir && existsSync(this.assetsDir)) {\n this.scanDirectory(this.assetsDir)\n }\n }\n\n /** 扫描目录,按文件名(不含扩展名)注册 key */\n private scanDirectory(dir: string): void {\n const files = readdirSync(dir)\n for (const file of files) {\n const fullPath = resolve(dir, file)\n if (statSync(fullPath).isFile()) {\n const key = basename(file, extname(file))\n this.manifest[key] = { path: fullPath, format: inferFormat(fullPath) }\n }\n }\n }\n\n async resolveByKey(key: string): Promise<{ bytes: ArrayBuffer; format?: string }> {\n const entry = this.manifest[key]\n if (!entry) {\n throw new Error(`[FsAssetResolver] asset key \"${key}\" not found in manifest or directory`)\n }\n\n const fullPath = this.assetsDir\n ? resolve(this.assetsDir, entry.path)\n : entry.path\n\n if (!existsSync(fullPath)) {\n throw new Error(`[FsAssetResolver] asset file not found: ${fullPath}`)\n }\n\n const buf = readFileSync(fullPath)\n const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n return { bytes: arrayBuffer, format: entry.format ?? inferFormat(fullPath) }\n }\n\n async resolveFile(path: string): Promise<ArrayBuffer> {\n if (!existsSync(path)) {\n throw new Error(`[FsAssetResolver] file not found: ${path}`)\n }\n const buf = readFileSync(path)\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n }\n\n async resolveUrl(url: string): Promise<ArrayBuffer> {\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`[FsAssetResolver] fetch failed: ${url} (${response.status} ${response.statusText})`)\n }\n return response.arrayBuffer()\n }\n}\n"]}
1
+ {"version":3,"file":"fs-asset-resolver.js","sourceRoot":"","sources":["../../src/node-host/fs-asset-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * FsAssetResolver — Node 端资产解析(fs 目录/manifest)\n *\n *\n * 实现 AssetResolver 接口:\n * - resolveByKey(key): 从 --assets 目录/manifest 解析 key → 文件路径 → ArrayBuffer\n * - resolveFile(path): 直接读取本地文件\n * - resolveUrl(url): fetch(Node 18+ 内置 fetch)\n *\n * manifest 格式(JSON):\n * {\n * \"file_abc123\": { \"path\": \"models/box.step\", \"format\": \"step\" },\n * \"logo_svg_key\": { \"path\": \"assets/logo.svg\", \"format\": \"svg\" }\n * }\n *\n * 或简单目录模式(无 manifest):key = 完整文件名(含扩展名,P8 资产按文件名注册)\n */\n\nimport { readFileSync, existsSync, statSync, readdirSync } from 'node:fs'\nimport { resolve, extname, basename } from 'node:path'\nimport type { AssetResolver } from '../cad-runtime/ports'\n\ninterface ManifestEntry {\n path: string\n format?: string\n}\n\ntype Manifest = Record<string, ManifestEntry>\n\n/** 从文件扩展名推断格式 */\nfunction inferFormat(filePath: string): string | undefined {\n if (filePath.toLowerCase().endsWith('.fai.js')) return 'faijs'\n const ext = extname(filePath).toLowerCase().slice(1)\n const formatMap: Record<string, string> = {\n step: 'step',\n stp: 'step',\n '3mf': '3mf',\n stl: 'stl',\n obj: 'obj',\n svg: 'svg',\n }\n return formatMap[ext]\n}\n\n/** Options for constructing an FsAssetResolver. */\nexport interface FsAssetResolverOptions {\n /** Asset root directory. */\n assetsDir?: string\n /** Manifest file path (JSON, key -> {path, format?}). */\n manifestPath?: string\n}\n\n/**\n * Node-side asset resolver backed by the filesystem (directory/manifest).\n *\n * Implements the AssetResolver interface:\n * - resolveByKey(key): resolve a key from the --assets directory/manifest to a file path and return its bytes\n * - resolveFile(path): read a local file directly\n * - resolveUrl(url): fetch a URL (Node 18+ built-in fetch)\n *\n * Manifest format (JSON):\n * {\n * \"file_abc123\": { \"path\": \"models/box.step\", \"format\": \"step\" },\n * \"logo_svg_key\": { \"path\": \"assets/logo.svg\", \"format\": \"svg\" }\n * }\n *\n * Or a plain directory mode (no manifest): key = full file name (with extension, P8: assets are registered by file name).\n */\nexport class FsAssetResolver implements AssetResolver {\n private assetsDir: string | undefined\n private manifest: Manifest = {}\n\n constructor(opts?: FsAssetResolverOptions) {\n this.assetsDir = opts?.assetsDir\n const manifestPath = opts?.manifestPath ?? (this.assetsDir ? resolve(this.assetsDir, 'manifest.json') : undefined)\n\n if (manifestPath && existsSync(manifestPath)) {\n const raw = readFileSync(manifestPath, 'utf-8')\n this.manifest = JSON.parse(raw) as Manifest\n }\n\n // 如果没有 manifest 但有 assetsDir,自动扫描目录\n if (Object.keys(this.manifest).length === 0 && this.assetsDir && existsSync(this.assetsDir)) {\n this.scanDirectory(this.assetsDir)\n }\n }\n\n /**\n * 扫描目录,注册两种 key(同一文件的两个命名空间,非内部逻辑回退):\n * - 完整文件名(含扩展名):P8 起 `cad.load({ file })` 的寻址载体;\n * - 无扩展名 basename:`cad.import_brep({ asset })` 的平台 BREP 资产约定\n * (asset 引用 `<stem>.brp` 的 `<stem>`,容器资产名)。\n */\n private scanDirectory(dir: string): void {\n const files = readdirSync(dir)\n for (const file of files) {\n const fullPath = resolve(dir, file)\n if (statSync(fullPath).isFile()) {\n this.manifest[file] = { path: fullPath, format: inferFormat(fullPath) }\n const stem = basename(file, extname(file))\n if (stem !== file) {\n this.manifest[stem] = { path: fullPath, format: inferFormat(fullPath) }\n }\n }\n }\n }\n\n async resolveByKey(key: string): Promise<{ bytes: ArrayBuffer; format?: string }> {\n const entry = this.manifest[key]\n if (!entry) {\n throw new Error(`[FsAssetResolver] asset key \"${key}\" not found in manifest or directory`)\n }\n\n const fullPath = this.assetsDir\n ? resolve(this.assetsDir, entry.path)\n : entry.path\n\n if (!existsSync(fullPath)) {\n throw new Error(`[FsAssetResolver] asset file not found: ${fullPath}`)\n }\n\n const buf = readFileSync(fullPath)\n const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n return { bytes: arrayBuffer, format: entry.format ?? inferFormat(fullPath) }\n }\n\n async resolveFile(path: string): Promise<ArrayBuffer> {\n if (!existsSync(path)) {\n throw new Error(`[FsAssetResolver] file not found: ${path}`)\n }\n const buf = readFileSync(path)\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n }\n\n async resolveUrl(url: string): Promise<ArrayBuffer> {\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`[FsAssetResolver] fetch failed: ${url} (${response.status} ${response.statusText})`)\n }\n return response.arrayBuffer()\n }\n}\n"]}
@@ -25,6 +25,14 @@ export interface CreateNodePortsOptions {
25
25
  fontsDir?: string;
26
26
  /** Default font path (falls back to the project single source of truth when omitted). */
27
27
  defaultFontPath?: string;
28
+ /**
29
+ * Look up font *family names* in the OS font directories (default `true`).
30
+ *
31
+ * This is what makes `text(font: 'Arial')` behave like CadQuery, whose
32
+ * `Font_FontMgr` resolves names against the installed fonts. Set `false` for a
33
+ * hermetic host: name lookups then miss and fall back to the default font.
34
+ */
35
+ systemFonts?: boolean;
28
36
  }
29
37
  /**
30
38
  * Create Node-side HostPorts (for injecting into CadRuntime).
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node-host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAQrD,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAqBxE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node-host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAQrD,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAsBxE"}
@@ -38,6 +38,7 @@ export function createNodePorts(opts) {
38
38
  const fontProvider = new NodeFontProvider({
39
39
  defaultFontPath: opts?.defaultFontPath,
40
40
  fontsDir: opts?.fontsDir,
41
+ systemFonts: opts?.systemFonts,
41
42
  });
42
43
  // 连接 NodeFontProvider 到 fontRegistry
43
44
  setFontLoader(fontProvider);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node-host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAczD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAA6B;IAC3D,MAAM,YAAY,GAAG,IAAI,gBAAgB,CAAC;QACxC,eAAe,EAAE,IAAI,EAAE,eAAe;QACtC,QAAQ,EAAE,IAAI,EAAE,QAAQ;KACzB,CAAC,CAAA;IAEF,qCAAqC;IACrC,aAAa,CAAC,YAAY,CAAC,CAAA;IAE3B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,SAAS,EAAE,IAAI,EAAE,SAAS;QAC1B,YAAY,EAAE,IAAI,EAAE,YAAY;KACjC,CAAC,CAAA;IAEF,OAAO;QACL,GAAG,EAAE,IAAI,gBAAgB,EAAE;QAC3B,GAAG,EAAE,IAAI,gBAAgB,EAAE;QAC3B,KAAK,EAAE,YAAY;QACnB,MAAM;QACN,MAAM,EAAE,IAAI,YAAY,EAAE;KAC3B,CAAA;AACH,CAAC","sourcesContent":["/**\n * node-host — L3 Node host 公开 API\n *\n *\n * Node host 负责:\n * - 创建 CadRuntime 实例(注入 node Ports:InlineCsgBackend / InlineSdfBackend / ...)\n * - 连接 NodeFontProvider 到 fontRegistry\n * - CLI 入口\n */\n\nexport { InlineCsgBackend } from '../browser-host/inline-csg-backend'\nexport { InlineSdfBackend } from '../browser-host/inline-sdf-backend'\nexport { NodeFontProvider } from './node-font-provider'\nexport type { NodeFontProviderOptions } from './node-font-provider'\nexport { FsAssetResolver } from './fs-asset-resolver'\nexport type { FsAssetResolverOptions } from './fs-asset-resolver'\nexport { CliEventSink } from './cli-event-sink'\n\nimport type { HostPorts } from '../cad-runtime/ports'\nimport { InlineCsgBackend } from '../browser-host/inline-csg-backend'\nimport { InlineSdfBackend } from '../browser-host/inline-sdf-backend'\nimport { NodeFontProvider } from './node-font-provider'\nimport { FsAssetResolver } from './fs-asset-resolver'\nimport { CliEventSink } from './cli-event-sink'\nimport { setFontLoader } from '../brep/text/fontRegistry'\n\n/** Options for creating Node host ports. */\nexport interface CreateNodePortsOptions {\n /** Asset directory (used by FsAssetResolver). */\n assetsDir?: string\n /** Manifest file path. */\n manifestPath?: string\n /** Extra fonts directory. */\n fontsDir?: string\n /** Default font path (falls back to the project single source of truth when omitted). */\n defaultFontPath?: string\n}\n\n/**\n * Create Node-side HostPorts (for injecting into CadRuntime).\n *\n * Assembles all inline backends into HostPorts:\n * - csg: InlineCsgBackend (runs manifold-3d directly on the main thread)\n * - sdf: InlineSdfBackend (runs directly on the main thread)\n * - fonts: NodeFontProvider (fs font loading)\n * - assets: FsAssetResolver (fs asset resolution)\n * - events: CliEventSink (writes to stderr + collects)\n *\n * Also connects the NodeFontProvider to fontRegistry (setFontLoader), so that\n * brep/text's ensureDefaultFont() can load fonts via the filesystem.\n *\n * @param opts - options controlling the ports (assets/fonts directories, default font path)\n * @returns the assembled HostPorts\n */\nexport function createNodePorts(opts?: CreateNodePortsOptions): HostPorts {\n const fontProvider = new NodeFontProvider({\n defaultFontPath: opts?.defaultFontPath,\n fontsDir: opts?.fontsDir,\n })\n\n // 连接 NodeFontProvider 到 fontRegistry\n setFontLoader(fontProvider)\n\n const assets = new FsAssetResolver({\n assetsDir: opts?.assetsDir,\n manifestPath: opts?.manifestPath,\n })\n\n return {\n csg: new InlineCsgBackend(),\n sdf: new InlineSdfBackend(),\n fonts: fontProvider,\n assets,\n events: new CliEventSink(),\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node-host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAsBzD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAA6B;IAC3D,MAAM,YAAY,GAAG,IAAI,gBAAgB,CAAC;QACxC,eAAe,EAAE,IAAI,EAAE,eAAe;QACtC,QAAQ,EAAE,IAAI,EAAE,QAAQ;QACxB,WAAW,EAAE,IAAI,EAAE,WAAW;KAC/B,CAAC,CAAA;IAEF,qCAAqC;IACrC,aAAa,CAAC,YAAY,CAAC,CAAA;IAE3B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,SAAS,EAAE,IAAI,EAAE,SAAS;QAC1B,YAAY,EAAE,IAAI,EAAE,YAAY;KACjC,CAAC,CAAA;IAEF,OAAO;QACL,GAAG,EAAE,IAAI,gBAAgB,EAAE;QAC3B,GAAG,EAAE,IAAI,gBAAgB,EAAE;QAC3B,KAAK,EAAE,YAAY;QACnB,MAAM;QACN,MAAM,EAAE,IAAI,YAAY,EAAE;KAC3B,CAAA;AACH,CAAC","sourcesContent":["/**\n * node-host — L3 Node host 公开 API\n *\n *\n * Node host 负责:\n * - 创建 CadRuntime 实例(注入 node Ports:InlineCsgBackend / InlineSdfBackend / ...)\n * - 连接 NodeFontProvider 到 fontRegistry\n * - CLI 入口\n */\n\nexport { InlineCsgBackend } from '../browser-host/inline-csg-backend'\nexport { InlineSdfBackend } from '../browser-host/inline-sdf-backend'\nexport { NodeFontProvider } from './node-font-provider'\nexport type { NodeFontProviderOptions } from './node-font-provider'\nexport { FsAssetResolver } from './fs-asset-resolver'\nexport type { FsAssetResolverOptions } from './fs-asset-resolver'\nexport { CliEventSink } from './cli-event-sink'\n\nimport type { HostPorts } from '../cad-runtime/ports'\nimport { InlineCsgBackend } from '../browser-host/inline-csg-backend'\nimport { InlineSdfBackend } from '../browser-host/inline-sdf-backend'\nimport { NodeFontProvider } from './node-font-provider'\nimport { FsAssetResolver } from './fs-asset-resolver'\nimport { CliEventSink } from './cli-event-sink'\nimport { setFontLoader } from '../brep/text/fontRegistry'\n\n/** Options for creating Node host ports. */\nexport interface CreateNodePortsOptions {\n /** Asset directory (used by FsAssetResolver). */\n assetsDir?: string\n /** Manifest file path. */\n manifestPath?: string\n /** Extra fonts directory. */\n fontsDir?: string\n /** Default font path (falls back to the project single source of truth when omitted). */\n defaultFontPath?: string\n /**\n * Look up font *family names* in the OS font directories (default `true`).\n *\n * This is what makes `text(font: 'Arial')` behave like CadQuery, whose\n * `Font_FontMgr` resolves names against the installed fonts. Set `false` for a\n * hermetic host: name lookups then miss and fall back to the default font.\n */\n systemFonts?: boolean\n}\n\n/**\n * Create Node-side HostPorts (for injecting into CadRuntime).\n *\n * Assembles all inline backends into HostPorts:\n * - csg: InlineCsgBackend (runs manifold-3d directly on the main thread)\n * - sdf: InlineSdfBackend (runs directly on the main thread)\n * - fonts: NodeFontProvider (fs font loading)\n * - assets: FsAssetResolver (fs asset resolution)\n * - events: CliEventSink (writes to stderr + collects)\n *\n * Also connects the NodeFontProvider to fontRegistry (setFontLoader), so that\n * brep/text's ensureDefaultFont() can load fonts via the filesystem.\n *\n * @param opts - options controlling the ports (assets/fonts directories, default font path)\n * @returns the assembled HostPorts\n */\nexport function createNodePorts(opts?: CreateNodePortsOptions): HostPorts {\n const fontProvider = new NodeFontProvider({\n defaultFontPath: opts?.defaultFontPath,\n fontsDir: opts?.fontsDir,\n systemFonts: opts?.systemFonts,\n })\n\n // 连接 NodeFontProvider 到 fontRegistry\n setFontLoader(fontProvider)\n\n const assets = new FsAssetResolver({\n assetsDir: opts?.assetsDir,\n manifestPath: opts?.manifestPath,\n })\n\n return {\n csg: new InlineCsgBackend(),\n sdf: new InlineSdfBackend(),\n fonts: fontProvider,\n assets,\n events: new CliEventSink(),\n }\n}\n"]}
@@ -18,6 +18,18 @@ export interface NodeFontProviderOptions {
18
18
  defaultFontPath?: string;
19
19
  /** Extra fonts directory: all .ttf/.otf files are registered by file name (without extension) as keys. */
20
20
  fontsDir?: string;
21
+ /**
22
+ * Enable name-based lookup against the OS font directories (default `true`).
23
+ *
24
+ * Needed to honour a font *family name* (`resolveFont('Arial')`) the way
25
+ * CadQuery's `font=` does through OCC's system font manager. Only consulted
26
+ * when a caller names a font that is not already registered, so the bundled
27
+ * default font path is unaffected. Set `false` to keep the host fully
28
+ * hermetic (name lookups then always miss and fall back to the default).
29
+ */
30
+ systemFonts?: boolean;
31
+ /** Override the system font directories to scan (PATH-separated string or array). */
32
+ systemFontDirs?: string[] | string;
21
33
  }
22
34
  /**
23
35
  * Node-side font provider (fs loading).
@@ -37,6 +49,10 @@ export declare class NodeFontProvider implements FontProvider, FontLoader {
37
49
  private keyToPath;
38
50
  /** 缓存的 ArrayBuffer(避免重复读磁盘) */
39
51
  private cache;
52
+ /** System font dirs to scan for a font *family name* (empty ⇒ disabled). */
53
+ private systemFontDirs;
54
+ /** Lazily built normalized-family → path index (null until first name miss). */
55
+ private familyIndex;
40
56
  constructor(opts?: NodeFontProviderOptions);
41
57
  /** FontProvider.loadFont: load font bytes by key. */
42
58
  loadFont(key: string): Promise<ArrayBuffer>;
@@ -44,6 +60,18 @@ export declare class NodeFontProvider implements FontProvider, FontLoader {
44
60
  loadDefaultFont(): Promise<ArrayBuffer>;
45
61
  /** FontProvider.listFonts: list the available font keys. */
46
62
  listFonts(): string[];
63
+ /**
64
+ * FontLoader.resolveFont: resolve a font family name or a file path.
65
+ *
66
+ * Order: an existing file path wins, then a registered key (exact, then
67
+ * normalised so `"Arial"` matches the `arial.ttf` stem), then the OS font
68
+ * family index. Returns `null` — never throws — when nothing matches, so the
69
+ * caller can fall back to the default font the way OCC does.
70
+ *
71
+ * @param nameOrPath - font family name or font file path
72
+ * @returns the font bytes, or null when the name cannot be resolved here
73
+ */
74
+ resolveFont(nameOrPath: string): Promise<ArrayBuffer | null>;
47
75
  /** 读取文件并缓存 */
48
76
  private loadFile;
49
77
  }