@faicad/faijs 0.13.1 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +30 -4
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/boolean.d.ts +19 -0
- package/dist/api/boolean.d.ts.map +1 -1
- package/dist/api/boolean.js +51 -10
- package/dist/api/boolean.js.map +1 -1
- package/dist/api/chamfer.d.ts.map +1 -1
- package/dist/api/chamfer.js +8 -7
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/compound-geom.d.ts +45 -0
- package/dist/api/compound-geom.d.ts.map +1 -0
- package/dist/api/compound-geom.js +85 -0
- package/dist/api/compound-geom.js.map +1 -0
- package/dist/api/compound.d.ts +2 -0
- package/dist/api/compound.d.ts.map +1 -1
- package/dist/api/compound.js +2 -0
- package/dist/api/compound.js.map +1 -1
- package/dist/api/copy.d.ts +1 -0
- package/dist/api/copy.d.ts.map +1 -1
- package/dist/api/copy.js +4 -2
- package/dist/api/copy.js.map +1 -1
- package/dist/api/edge-ref.d.ts +3 -2
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +10 -6
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/engrave.d.ts.map +1 -1
- package/dist/api/engrave.js +1 -0
- package/dist/api/engrave.js.map +1 -1
- package/dist/api/extrude.d.ts.map +1 -1
- package/dist/api/extrude.js +131 -3
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/face-ref.d.ts.map +1 -1
- package/dist/api/face-ref.js +7 -4
- package/dist/api/face-ref.js.map +1 -1
- package/dist/api/fai_drill.d.ts +1 -1
- package/dist/api/fai_drill.d.ts.map +1 -1
- package/dist/api/fai_drill.js +31 -18
- package/dist/api/fai_drill.js.map +1 -1
- package/dist/api/fai_extrude.d.ts +1 -1
- package/dist/api/fai_extrude.d.ts.map +1 -1
- package/dist/api/fai_extrude.js +2 -1
- package/dist/api/fai_extrude.js.map +1 -1
- package/dist/api/fai_split.d.ts +1 -1
- package/dist/api/fai_split.d.ts.map +1 -1
- package/dist/api/fai_split.js +2 -1
- package/dist/api/fai_split.js.map +1 -1
- package/dist/api/fillet.d.ts.map +1 -1
- package/dist/api/fillet.js +6 -5
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/generated/operations.js +16 -16
- package/dist/api/generated/operations.js.map +1 -1
- package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
- package/dist/api/generated/script-face-manifest.js +0 -1
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/generated/script-face.d.ts +1 -4
- package/dist/api/generated/script-face.d.ts.map +1 -1
- package/dist/api/generated/script-face.js +2 -3
- package/dist/api/generated/script-face.js.map +1 -1
- package/dist/api/generated/sketching.js +1 -1
- package/dist/api/generated/sketching.js.map +1 -1
- package/dist/api/generated/topology.d.ts +0 -48
- package/dist/api/generated/topology.d.ts.map +1 -1
- package/dist/api/generated/topology.js +20 -62
- package/dist/api/generated/topology.js.map +1 -1
- package/dist/api/import-brep.d.ts +36 -0
- package/dist/api/import-brep.d.ts.map +1 -0
- package/dist/api/import-brep.js +72 -0
- package/dist/api/import-brep.js.map +1 -0
- package/dist/api/import-step.d.ts +28 -0
- package/dist/api/import-step.d.ts.map +1 -0
- package/dist/api/import-step.js +57 -0
- package/dist/api/import-step.js.map +1 -0
- package/dist/api/index.d.ts +7 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +19 -5
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/compat-op.d.ts +2 -0
- package/dist/api/internal/compat-op.d.ts.map +1 -1
- package/dist/api/internal/compat-op.js +10 -2
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/knurl.d.ts.map +1 -1
- package/dist/api/knurl.js +1 -0
- package/dist/api/knurl.js.map +1 -1
- package/dist/api/load.d.ts +3 -1
- package/dist/api/load.d.ts.map +1 -1
- package/dist/api/load.js +3 -1
- package/dist/api/load.js.map +1 -1
- package/dist/api/pattern.d.ts +32 -0
- package/dist/api/pattern.d.ts.map +1 -0
- package/dist/api/pattern.js +121 -0
- package/dist/api/pattern.js.map +1 -0
- package/dist/api/place.d.ts +35 -0
- package/dist/api/place.d.ts.map +1 -0
- package/dist/api/place.js +113 -0
- package/dist/api/place.js.map +1 -0
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +10 -3
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/screw.d.ts.map +1 -1
- package/dist/api/screw.js +1 -0
- package/dist/api/screw.js.map +1 -1
- package/dist/api/sdf.d.ts.map +1 -1
- package/dist/api/sdf.js +1 -0
- package/dist/api/sdf.js.map +1 -1
- package/dist/api/sketch.d.ts.map +1 -1
- package/dist/api/sketch.js +1 -0
- package/dist/api/sketch.js.map +1 -1
- package/dist/api/split.d.ts +31 -0
- package/dist/api/split.d.ts.map +1 -0
- package/dist/api/split.js +96 -0
- package/dist/api/split.js.map +1 -0
- package/dist/api/surface/arg-spec.d.ts +9 -0
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js +49 -30
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/svgExtrude.d.ts.map +1 -1
- package/dist/api/svgExtrude.js +1 -0
- package/dist/api/svgExtrude.js.map +1 -1
- package/dist/api/text.d.ts.map +1 -1
- package/dist/api/text.js +1 -0
- package/dist/api/text.js.map +1 -1
- package/dist/api/topo-resolve.d.ts.map +1 -1
- package/dist/api/topo-resolve.js +65 -3
- package/dist/api/topo-resolve.js.map +1 -1
- package/dist/api/transform.d.ts +4 -0
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +44 -12
- package/dist/api/transform.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +34 -1
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +62 -22
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +8 -0
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brepkit.js +6 -1
- package/dist/brep/engine/adapters/brepkit.js.map +1 -1
- package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
- package/dist/brep/engine/adapters/occt.js +24 -1
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +17 -0
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/engine/types.d.ts +49 -6
- package/dist/brep/engine/types.d.ts.map +1 -1
- package/dist/brep/engine/types.js.map +1 -1
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +6 -1
- package/dist/brep/export/step.js.map +1 -1
- package/dist/brep/face-evolution.d.ts +78 -8
- package/dist/brep/face-evolution.d.ts.map +1 -1
- package/dist/brep/face-evolution.js +130 -17
- package/dist/brep/face-evolution.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +27 -1
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/browser.d.ts +0 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/admit-compat-lib.d.ts +19 -1
- package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
- package/dist/cad-runtime/admit-compat-lib.js +21 -1
- package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
- package/dist/cad-runtime/backend-dispatch.d.ts +44 -3
- package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
- package/dist/cad-runtime/backend-dispatch.js +46 -3
- package/dist/cad-runtime/backend-dispatch.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.d.ts +2 -0
- package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.js +9 -1
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +14 -4
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/module-registry.d.ts +3 -1
- package/dist/cad-runtime/module-registry.d.ts.map +1 -1
- package/dist/cad-runtime/module-registry.js +13 -1
- package/dist/cad-runtime/module-registry.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +7 -0
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/runtime-concurrent-error.d.ts +38 -0
- package/dist/cad-runtime/runtime-concurrent-error.d.ts.map +1 -0
- package/dist/cad-runtime/runtime-concurrent-error.js +43 -0
- package/dist/cad-runtime/runtime-concurrent-error.js.map +1 -0
- package/dist/cad-runtime/runtime.d.ts +54 -2
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +186 -10
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +22 -0
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +82 -12
- package/dist/define-op.js.map +1 -1
- package/dist/fcstd/attachment.d.ts +72 -0
- package/dist/fcstd/attachment.d.ts.map +1 -0
- package/dist/fcstd/attachment.js +93 -0
- package/dist/fcstd/attachment.js.map +1 -0
- package/dist/fcstd/build-fai-zip.d.ts +11 -0
- package/dist/fcstd/build-fai-zip.d.ts.map +1 -1
- package/dist/fcstd/build-fai-zip.js +21 -8
- package/dist/fcstd/build-fai-zip.js.map +1 -1
- package/dist/fcstd/cli.d.ts +3 -0
- package/dist/fcstd/cli.d.ts.map +1 -0
- package/dist/fcstd/cli.js +37 -0
- package/dist/fcstd/cli.js.map +1 -0
- package/dist/fcstd/codegen.d.ts +23 -1
- package/dist/fcstd/codegen.d.ts.map +1 -1
- package/dist/fcstd/codegen.js +159 -48
- package/dist/fcstd/codegen.js.map +1 -1
- package/dist/fcstd/container.d.ts +16 -1
- package/dist/fcstd/container.d.ts.map +1 -1
- package/dist/fcstd/container.js +12 -1
- package/dist/fcstd/container.js.map +1 -1
- package/dist/fcstd/contour.d.ts +9 -1
- package/dist/fcstd/contour.d.ts.map +1 -1
- package/dist/fcstd/contour.js +28 -18
- package/dist/fcstd/contour.js.map +1 -1
- package/dist/fcstd/convert.d.ts +31 -2
- package/dist/fcstd/convert.d.ts.map +1 -1
- package/dist/fcstd/convert.js +73 -22
- package/dist/fcstd/convert.js.map +1 -1
- package/dist/fcstd/document.d.ts +8 -1
- package/dist/fcstd/document.d.ts.map +1 -1
- package/dist/fcstd/document.js +4 -1
- package/dist/fcstd/document.js.map +1 -1
- package/dist/fcstd/expressions.d.ts +14 -1
- package/dist/fcstd/expressions.d.ts.map +1 -1
- package/dist/fcstd/expressions.js +11 -1
- package/dist/fcstd/expressions.js.map +1 -1
- package/dist/fcstd/external-geo.d.ts +27 -2
- package/dist/fcstd/external-geo.d.ts.map +1 -1
- package/dist/fcstd/external-geo.js +23 -2
- package/dist/fcstd/external-geo.js.map +1 -1
- package/dist/fcstd/feature-translate.d.ts +85 -3
- package/dist/fcstd/feature-translate.d.ts.map +1 -1
- package/dist/fcstd/feature-translate.js +189 -9
- package/dist/fcstd/feature-translate.js.map +1 -1
- package/dist/fcstd/index.d.ts +23 -0
- package/dist/fcstd/index.d.ts.map +1 -0
- package/dist/fcstd/index.js +19 -0
- package/dist/fcstd/index.js.map +1 -0
- package/dist/fcstd/placement.d.ts +49 -6
- package/dist/fcstd/placement.d.ts.map +1 -1
- package/dist/fcstd/placement.js +46 -6
- package/dist/fcstd/placement.js.map +1 -1
- package/dist/fcstd/planegcs-backend.d.ts +16 -1
- package/dist/fcstd/planegcs-backend.d.ts.map +1 -1
- package/dist/fcstd/planegcs-backend.js +16 -1
- package/dist/fcstd/planegcs-backend.js.map +1 -1
- package/dist/fcstd/sketch-parse.d.ts +43 -0
- package/dist/fcstd/sketch-parse.d.ts.map +1 -1
- package/dist/fcstd/sketch-parse.js +26 -0
- package/dist/fcstd/sketch-parse.js.map +1 -1
- package/dist/fcstd/sketch-solver.d.ts +20 -2
- package/dist/fcstd/sketch-solver.d.ts.map +1 -1
- package/dist/fcstd/sketch-solver.js +6 -1
- package/dist/fcstd/sketch-solver.js.map +1 -1
- package/dist/fcstd/sketch-verify.d.ts +19 -1
- package/dist/fcstd/sketch-verify.d.ts.map +1 -1
- package/dist/fcstd/sketch-verify.js +14 -1
- package/dist/fcstd/sketch-verify.js.map +1 -1
- package/dist/fcstd/structural-types.d.ts +83 -0
- package/dist/fcstd/structural-types.d.ts.map +1 -0
- package/dist/fcstd/structural-types.js +116 -0
- package/dist/fcstd/structural-types.js.map +1 -0
- package/dist/fcstd/unpack.d.ts +21 -2
- package/dist/fcstd/unpack.d.ts.map +1 -1
- package/dist/fcstd/unpack.js +11 -2
- package/dist/fcstd/unpack.js.map +1 -1
- package/dist/fcstd-convert.d.ts +30 -0
- package/dist/fcstd-convert.d.ts.map +1 -0
- package/dist/fcstd-convert.js +27 -0
- package/dist/fcstd-convert.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lang/determinism-scanner.d.ts +62 -0
- package/dist/lang/determinism-scanner.d.ts.map +1 -0
- package/dist/lang/determinism-scanner.js +619 -0
- package/dist/lang/determinism-scanner.js.map +1 -0
- package/dist/lang/symbol-table.generated.d.ts +7 -3
- package/dist/lang/symbol-table.generated.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.js +7 -3
- package/dist/lang/symbol-table.generated.js.map +1 -1
- package/dist/mesh/index.d.ts.map +1 -1
- package/dist/mesh/index.js +3 -2
- package/dist/mesh/index.js.map +1 -1
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +56 -2
- package/dist/node-host/cli.js.map +1 -1
- package/dist/runtime-state.d.ts +18 -6
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +9 -1
- package/dist/runtime-state.js.map +1 -1
- package/dist/shape.d.ts +15 -0
- package/dist/shape.d.ts.map +1 -1
- package/dist/shape.js +26 -3
- package/dist/shape.js.map +1 -1
- package/dist/topology/naming/build-naming.d.ts +14 -30
- package/dist/topology/naming/build-naming.d.ts.map +1 -1
- package/dist/topology/naming/build-naming.js +21 -54
- package/dist/topology/naming/build-naming.js.map +1 -1
- package/dist/topology/naming/capture-topo-ref.d.ts.map +1 -1
- package/dist/topology/naming/capture-topo-ref.js +5 -0
- package/dist/topology/naming/capture-topo-ref.js.map +1 -1
- package/dist/topology/naming/index.d.ts +3 -0
- package/dist/topology/naming/index.d.ts.map +1 -1
- package/dist/topology/naming/index.js +3 -0
- package/dist/topology/naming/index.js.map +1 -1
- package/dist/topology/naming/lineage-resolve.d.ts +80 -0
- package/dist/topology/naming/lineage-resolve.d.ts.map +1 -0
- package/dist/topology/naming/lineage-resolve.js +120 -0
- package/dist/topology/naming/lineage-resolve.js.map +1 -0
- package/dist/topology/naming/lineage.d.ts +349 -0
- package/dist/topology/naming/lineage.d.ts.map +1 -0
- package/dist/topology/naming/lineage.js +398 -0
- package/dist/topology/naming/lineage.js.map +1 -0
- package/dist/topology/naming/migrate.d.ts +41 -0
- package/dist/topology/naming/migrate.d.ts.map +1 -0
- package/dist/topology/naming/migrate.js +88 -0
- package/dist/topology/naming/migrate.js.map +1 -0
- package/dist/topology/naming/role-name.d.ts +176 -0
- package/dist/topology/naming/role-name.d.ts.map +1 -0
- package/dist/topology/naming/role-name.js +344 -0
- package/dist/topology/naming/role-name.js.map +1 -0
- package/dist/topology/naming/roles.d.ts +20 -22
- package/dist/topology/naming/roles.d.ts.map +1 -1
- package/dist/topology/naming/roles.js +51 -49
- package/dist/topology/naming/roles.js.map +1 -1
- package/dist/topology/naming/types.d.ts +65 -18
- package/dist/topology/naming/types.d.ts.map +1 -1
- package/dist/topology/naming/types.js.map +1 -1
- package/dist/weapp.d.ts +22 -0
- package/dist/weapp.d.ts.map +1 -0
- package/dist/weapp.js +23 -0
- package/dist/weapp.js.map +1 -0
- package/package.json +18 -5
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* role-name.ts — `RoleName` 契约与序列化(计划 §4.2)。
|
|
3
|
+
*
|
|
4
|
+
* 一条语句对自己产出的每个面起的**局部名**。作用域 = 那条语句;
|
|
5
|
+
* 全局唯一性由 `(origin, role)` 提供(`origin` 是 `StmtId`,见 `types.ts`)。
|
|
6
|
+
*
|
|
7
|
+
* ## 为什么 role 不能是一个裸字符串
|
|
8
|
+
*
|
|
9
|
+
* 旧实现在位置兜底时产出 `box:top` / `extrude:face_3` / `cylinder:lateral`
|
|
10
|
+
* ——**名字里塞了 origin**。这带来两个后果,都是致命的:
|
|
11
|
+
* 1. 同一个 role 在不同语句下**不是同一个名字**(`box:top` vs `extrude:top`),
|
|
12
|
+
* 于是「role 词汇表」无法按 op 封闭枚举,生成器无法把词汇表产出到 `.d.ts`;
|
|
13
|
+
* 2. 前缀是**位置兜底**的伪装——`extrude:face_3` 有名字却不承载任何设计意图,
|
|
14
|
+
* 按「有名/无名」统计会得出假的"全覆盖"(Phase 0.8 基线实测)。
|
|
15
|
+
*
|
|
16
|
+
* ⇒ role 只描述**在那条语句内的局部语义**,origin 由 `(StmtId)` 单独承载。
|
|
17
|
+
*
|
|
18
|
+
* ## 七个 kind 是封闭集
|
|
19
|
+
*
|
|
20
|
+
* `semantic`(op 词汇表封闭)/ `wall`(profile 第 i 条边扫出)/ `hole`(内环子结构)/
|
|
21
|
+
* `replica`(pattern 第 k 份)/ `splinter`(split 第 j 片)/ `generated`(倒角过渡面)/
|
|
22
|
+
* `imported`(import_brep 原始面序)。**新增 kind = 破坏性变更,须版本化。**
|
|
23
|
+
*
|
|
24
|
+
* ## 四条约束(分析文档 §5.1.1 R1–R4)
|
|
25
|
+
*
|
|
26
|
+
* 局部唯一 / 封闭可枚举 / **抗参数变化** / 结构化可分解。
|
|
27
|
+
* 第三、四条正是本文件的序列化设计目标:`wall:3` 在 profile 边数变化后**仍然是第 3 条边**
|
|
28
|
+
* (不是"第 3 张面"这种随面序漂移的地址),且 `replica[2]/hole:1/wall:3` 可逐层分解回结构。
|
|
29
|
+
*
|
|
30
|
+
* ## 序列化(进 `.fai.js` 的参数)
|
|
31
|
+
*
|
|
32
|
+
* ```
|
|
33
|
+
* semantic top (裸名)
|
|
34
|
+
* wall wall:3
|
|
35
|
+
* hole hole:1/wall:2 (前缀包裹 inner)
|
|
36
|
+
* replica replica[2]/wall:3 (前缀包裹 inner)
|
|
37
|
+
* splinter splinter(top)#1 (包裹 inner + 后缀)
|
|
38
|
+
* generated gen:fillet:0
|
|
39
|
+
* imported imported:5
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* `parseRoleName` 与 `formatRoleName` **互为逆**(值级 round-trip),
|
|
43
|
+
* 且 `parseRoleName` 是**单射**的(不接受前导零、不接受保留字作 semantic)——
|
|
44
|
+
* 否则两个不同的 RoleName 会序列化成同一个串,`.fai.js` 里的引用会静默指向错的面。
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* 一条语句对某个产出面的局部名(计划 §4.2)。
|
|
48
|
+
*
|
|
49
|
+
* - `semantic`:op 声明的封闭词汇(`top` / `bottom` / `lateral` / `start` / `end` …)
|
|
50
|
+
* - `wall`:由输入 profile 第 `index` 条边扫出/旋出的侧面
|
|
51
|
+
* - `hole`:第 `index` 个内环下的同名子结构(`inner` 递归该内环下的局部名)
|
|
52
|
+
* - `replica`:pattern 的第 `k` 份(`inner` 递归该份内的局部名)
|
|
53
|
+
* - `splinter`:split 的第 `index` 片(`inner` 递归原面的局部名)
|
|
54
|
+
* - `generated`:`op` 造出的过渡面(`fillet` / `chamfer`)第 `index` 张
|
|
55
|
+
* - `imported`:`import_brep` 的原始面序第 `index` 张
|
|
56
|
+
*/
|
|
57
|
+
export type RoleName = {
|
|
58
|
+
readonly kind: 'semantic';
|
|
59
|
+
readonly name: string;
|
|
60
|
+
} | {
|
|
61
|
+
readonly kind: 'wall';
|
|
62
|
+
readonly index: number;
|
|
63
|
+
} | {
|
|
64
|
+
readonly kind: 'hole';
|
|
65
|
+
readonly index: number;
|
|
66
|
+
readonly inner: RoleName;
|
|
67
|
+
} | {
|
|
68
|
+
readonly kind: 'replica';
|
|
69
|
+
readonly k: number;
|
|
70
|
+
readonly inner: RoleName;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: 'splinter';
|
|
73
|
+
readonly inner: RoleName;
|
|
74
|
+
readonly index: number;
|
|
75
|
+
} | {
|
|
76
|
+
readonly kind: 'generated';
|
|
77
|
+
readonly op: string;
|
|
78
|
+
readonly index: number;
|
|
79
|
+
} | {
|
|
80
|
+
readonly kind: 'imported';
|
|
81
|
+
readonly index: number;
|
|
82
|
+
};
|
|
83
|
+
/** 七个 kind 的名字,供审计测试枚举(`RoleName` 是封闭集,新增 kind 必须同步此处)。 */
|
|
84
|
+
export declare const ROLE_NAME_KINDS: readonly ["semantic", "wall", "hole", "replica", "splinter", "generated", "imported"];
|
|
85
|
+
/** `ROLE_NAME_KINDS` 的元素类型。 */
|
|
86
|
+
export type RoleNameKind = (typeof ROLE_NAME_KINDS)[number];
|
|
87
|
+
/** RoleName 序列化/校验失败(格式不合法、保留字冲突、索引非法)。 */
|
|
88
|
+
export declare class RoleNameError extends Error {
|
|
89
|
+
/** 稳定的错误码(供 args 校验与宿主识别)。 */
|
|
90
|
+
readonly code = "E_TOPO_ROLE_INVALID";
|
|
91
|
+
/**
|
|
92
|
+
* @param message - what is wrong with the role name.
|
|
93
|
+
*/
|
|
94
|
+
constructor(message: string);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 把一个 `RoleName` 序列化成进 `.fai.js` 的串。
|
|
98
|
+
*
|
|
99
|
+
* 结果**不含 origin**:身份是 `(StmtId, RoleName)` 两元组,串只承载后半。
|
|
100
|
+
*
|
|
101
|
+
* @param role - the role name to serialize.
|
|
102
|
+
* @returns the wire form (e.g. `top`, `wall:3`, `replica[2]/wall:3`).
|
|
103
|
+
* @throws RoleNameError when the value violates the contract (reserved name, bad index).
|
|
104
|
+
*/
|
|
105
|
+
export declare function formatRoleName(role: RoleName): string;
|
|
106
|
+
/**
|
|
107
|
+
* 把串解析回 `RoleName`(`formatRoleName` 的逆)。非法输入返回 `null`,不抛错。
|
|
108
|
+
*
|
|
109
|
+
* 只返回 `null` 而不抛错,是因为解析发生在读 `.fai.js` 参数时:
|
|
110
|
+
* 调用方需要区分「这不是一个 role 串」(→ 走迁移器/报缺失)与「这是坏的 role 串」。
|
|
111
|
+
*
|
|
112
|
+
* @param text - the wire form.
|
|
113
|
+
* @returns the parsed role, or null when the text is not a valid RoleName.
|
|
114
|
+
*/
|
|
115
|
+
export declare function parseRoleName(text: string): RoleName | null;
|
|
116
|
+
/**
|
|
117
|
+
* 造一个 `semantic` role(op 声明的封闭词汇)。
|
|
118
|
+
*
|
|
119
|
+
* @param name - the op's closed-vocabulary name.
|
|
120
|
+
* @returns the role.
|
|
121
|
+
* @throws RoleNameError when the name is malformed or shadows a structural keyword.
|
|
122
|
+
*/
|
|
123
|
+
export declare function semantic(name: string): RoleName;
|
|
124
|
+
/**
|
|
125
|
+
* 造一个 `wall` role(输入 profile 第 i 条边扫出/旋出的侧面)。
|
|
126
|
+
*
|
|
127
|
+
* @param index - zero-based profile-edge index.
|
|
128
|
+
* @returns the role.
|
|
129
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
130
|
+
*/
|
|
131
|
+
export declare function wall(index: number): RoleName;
|
|
132
|
+
/**
|
|
133
|
+
* 造一个 `hole` role(第 j 个内环下的同名子结构)。
|
|
134
|
+
*
|
|
135
|
+
* @param index - zero-based inner-loop index.
|
|
136
|
+
* @param inner - the local role inside that loop.
|
|
137
|
+
* @returns the role.
|
|
138
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
139
|
+
*/
|
|
140
|
+
export declare function hole(index: number, inner: RoleName): RoleName;
|
|
141
|
+
/**
|
|
142
|
+
* 造一个 `replica` role(pattern 的第 k 份)。
|
|
143
|
+
*
|
|
144
|
+
* @param k - zero-based replica index.
|
|
145
|
+
* @param inner - the local role inside that replica.
|
|
146
|
+
* @returns the role.
|
|
147
|
+
* @throws RoleNameError when k is not a non-negative integer.
|
|
148
|
+
*/
|
|
149
|
+
export declare function replica(k: number, inner: RoleName): RoleName;
|
|
150
|
+
/**
|
|
151
|
+
* 造一个 `splinter` role(split 的第 j 片)。
|
|
152
|
+
*
|
|
153
|
+
* @param inner - the local role of the face being split.
|
|
154
|
+
* @param index - zero-based splinter index.
|
|
155
|
+
* @returns the role.
|
|
156
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
157
|
+
*/
|
|
158
|
+
export declare function splinter(inner: RoleName, index: number): RoleName;
|
|
159
|
+
/**
|
|
160
|
+
* 造一个 `generated` role(fillet/chamfer 过渡面)。
|
|
161
|
+
*
|
|
162
|
+
* @param op - the producing op ('fillet' / 'chamfer').
|
|
163
|
+
* @param index - zero-based index among that op's generated faces.
|
|
164
|
+
* @returns the role.
|
|
165
|
+
* @throws RoleNameError when op or index violates the contract.
|
|
166
|
+
*/
|
|
167
|
+
export declare function generated(op: string, index: number): RoleName;
|
|
168
|
+
/**
|
|
169
|
+
* 造一个 `imported` role(`import_brep` 的原始面序)。
|
|
170
|
+
*
|
|
171
|
+
* @param index - zero-based face index in the imported shape's enumeration order.
|
|
172
|
+
* @returns the role.
|
|
173
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
174
|
+
*/
|
|
175
|
+
export declare function imported(index: number): RoleName;
|
|
176
|
+
//# sourceMappingURL=role-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-name.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/role-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAqBH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAChB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC3E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,2DAA2D;AAC3D,eAAO,MAAM,eAAe,uFAQlB,CAAA;AAEV,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE3D,2CAA2C;AAC3C,qBAAa,aAAc,SAAQ,KAAK;IACtC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,yBAAwB;IAErC;;OAEG;gBACS,OAAO,EAAE,MAAM;CAI5B;AAsCD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAyBrD;AAqCD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA0D3D;AAQD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAG/C;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAG5C;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAG7D;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAG5D;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAGjE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAI7D;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAGhD"}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* role-name.ts — `RoleName` 契约与序列化(计划 §4.2)。
|
|
3
|
+
*
|
|
4
|
+
* 一条语句对自己产出的每个面起的**局部名**。作用域 = 那条语句;
|
|
5
|
+
* 全局唯一性由 `(origin, role)` 提供(`origin` 是 `StmtId`,见 `types.ts`)。
|
|
6
|
+
*
|
|
7
|
+
* ## 为什么 role 不能是一个裸字符串
|
|
8
|
+
*
|
|
9
|
+
* 旧实现在位置兜底时产出 `box:top` / `extrude:face_3` / `cylinder:lateral`
|
|
10
|
+
* ——**名字里塞了 origin**。这带来两个后果,都是致命的:
|
|
11
|
+
* 1. 同一个 role 在不同语句下**不是同一个名字**(`box:top` vs `extrude:top`),
|
|
12
|
+
* 于是「role 词汇表」无法按 op 封闭枚举,生成器无法把词汇表产出到 `.d.ts`;
|
|
13
|
+
* 2. 前缀是**位置兜底**的伪装——`extrude:face_3` 有名字却不承载任何设计意图,
|
|
14
|
+
* 按「有名/无名」统计会得出假的"全覆盖"(Phase 0.8 基线实测)。
|
|
15
|
+
*
|
|
16
|
+
* ⇒ role 只描述**在那条语句内的局部语义**,origin 由 `(StmtId)` 单独承载。
|
|
17
|
+
*
|
|
18
|
+
* ## 七个 kind 是封闭集
|
|
19
|
+
*
|
|
20
|
+
* `semantic`(op 词汇表封闭)/ `wall`(profile 第 i 条边扫出)/ `hole`(内环子结构)/
|
|
21
|
+
* `replica`(pattern 第 k 份)/ `splinter`(split 第 j 片)/ `generated`(倒角过渡面)/
|
|
22
|
+
* `imported`(import_brep 原始面序)。**新增 kind = 破坏性变更,须版本化。**
|
|
23
|
+
*
|
|
24
|
+
* ## 四条约束(分析文档 §5.1.1 R1–R4)
|
|
25
|
+
*
|
|
26
|
+
* 局部唯一 / 封闭可枚举 / **抗参数变化** / 结构化可分解。
|
|
27
|
+
* 第三、四条正是本文件的序列化设计目标:`wall:3` 在 profile 边数变化后**仍然是第 3 条边**
|
|
28
|
+
* (不是"第 3 张面"这种随面序漂移的地址),且 `replica[2]/hole:1/wall:3` 可逐层分解回结构。
|
|
29
|
+
*
|
|
30
|
+
* ## 序列化(进 `.fai.js` 的参数)
|
|
31
|
+
*
|
|
32
|
+
* ```
|
|
33
|
+
* semantic top (裸名)
|
|
34
|
+
* wall wall:3
|
|
35
|
+
* hole hole:1/wall:2 (前缀包裹 inner)
|
|
36
|
+
* replica replica[2]/wall:3 (前缀包裹 inner)
|
|
37
|
+
* splinter splinter(top)#1 (包裹 inner + 后缀)
|
|
38
|
+
* generated gen:fillet:0
|
|
39
|
+
* imported imported:5
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* `parseRoleName` 与 `formatRoleName` **互为逆**(值级 round-trip),
|
|
43
|
+
* 且 `parseRoleName` 是**单射**的(不接受前导零、不接受保留字作 semantic)——
|
|
44
|
+
* 否则两个不同的 RoleName 会序列化成同一个串,`.fai.js` 里的引用会静默指向错的面。
|
|
45
|
+
*/
|
|
46
|
+
/** 结构关键字:出现在串首即被解释成结构 kind,故不得作为 semantic 名。 */
|
|
47
|
+
const RESERVED_KEYWORDS = ['wall', 'hole', 'replica', 'splinter', 'gen', 'imported'];
|
|
48
|
+
/**
|
|
49
|
+
* semantic 名的合法形态。
|
|
50
|
+
*
|
|
51
|
+
* 限成 `[A-Za-z_][A-Za-z0-9_]*`:op 词汇表是**封闭可枚举**的
|
|
52
|
+
* (`top` / `bottom` / `lateral` / `start` / `end` …),不需要更宽的字符集;
|
|
53
|
+
* 收紧后串首不会与任何结构关键字歧义。
|
|
54
|
+
*/
|
|
55
|
+
const SEMANTIC_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
56
|
+
/** 非负整数,**禁止前导零**(`0` 合法,`01` 不合法)——保证 format/parse 单射。 */
|
|
57
|
+
const INDEX_SOURCE = '0|[1-9][0-9]*';
|
|
58
|
+
const LEADING_INDEX_RE = new RegExp(`^(${INDEX_SOURCE})$`);
|
|
59
|
+
/** `generated` 的 op 名:与 semantic 同字符集,保证 `gen:<op>:<i>` 无歧义。 */
|
|
60
|
+
const OP_NAME_RE = SEMANTIC_NAME_RE;
|
|
61
|
+
/** 七个 kind 的名字,供审计测试枚举(`RoleName` 是封闭集,新增 kind 必须同步此处)。 */
|
|
62
|
+
export const ROLE_NAME_KINDS = [
|
|
63
|
+
'semantic',
|
|
64
|
+
'wall',
|
|
65
|
+
'hole',
|
|
66
|
+
'replica',
|
|
67
|
+
'splinter',
|
|
68
|
+
'generated',
|
|
69
|
+
'imported',
|
|
70
|
+
];
|
|
71
|
+
/** RoleName 序列化/校验失败(格式不合法、保留字冲突、索引非法)。 */
|
|
72
|
+
export class RoleNameError extends Error {
|
|
73
|
+
/** 稳定的错误码(供 args 校验与宿主识别)。 */
|
|
74
|
+
code = 'E_TOPO_ROLE_INVALID';
|
|
75
|
+
/**
|
|
76
|
+
* @param message - what is wrong with the role name.
|
|
77
|
+
*/
|
|
78
|
+
constructor(message) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = 'RoleNameError';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** 校验非负整数索引。 @throws RoleNameError when out of contract. */
|
|
84
|
+
function assertIndex(value, what) {
|
|
85
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
86
|
+
throw new RoleNameError(`${what} must be a non-negative integer, got ${String(value)}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 校验 semantic 名:形态合法且不与结构关键字冲突。
|
|
91
|
+
*
|
|
92
|
+
* @param name - the candidate semantic name.
|
|
93
|
+
* @throws RoleNameError when empty, malformed, or shadowing a structural keyword.
|
|
94
|
+
*/
|
|
95
|
+
function assertSemanticName(name) {
|
|
96
|
+
if (!SEMANTIC_NAME_RE.test(name)) {
|
|
97
|
+
throw new RoleNameError(`semantic name must match ${SEMANTIC_NAME_RE.source}, got ${JSON.stringify(name)}`);
|
|
98
|
+
}
|
|
99
|
+
if (RESERVED_KEYWORDS.includes(name)) {
|
|
100
|
+
throw new RoleNameError(`semantic name ${JSON.stringify(name)} is a structural keyword; ` +
|
|
101
|
+
`serializing it would parse back as kind '${name}' (use the structural kind instead)`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** 校验 generated 的 op 名(保证 `gen:<op>:<i>` 三段可切)。 */
|
|
105
|
+
function assertOpName(op) {
|
|
106
|
+
if (!OP_NAME_RE.test(op)) {
|
|
107
|
+
throw new RoleNameError(`generated op must match ${OP_NAME_RE.source}, got ${JSON.stringify(op)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 把一个 `RoleName` 序列化成进 `.fai.js` 的串。
|
|
112
|
+
*
|
|
113
|
+
* 结果**不含 origin**:身份是 `(StmtId, RoleName)` 两元组,串只承载后半。
|
|
114
|
+
*
|
|
115
|
+
* @param role - the role name to serialize.
|
|
116
|
+
* @returns the wire form (e.g. `top`, `wall:3`, `replica[2]/wall:3`).
|
|
117
|
+
* @throws RoleNameError when the value violates the contract (reserved name, bad index).
|
|
118
|
+
*/
|
|
119
|
+
export function formatRoleName(role) {
|
|
120
|
+
switch (role.kind) {
|
|
121
|
+
case 'semantic':
|
|
122
|
+
assertSemanticName(role.name);
|
|
123
|
+
return role.name;
|
|
124
|
+
case 'wall':
|
|
125
|
+
assertIndex(role.index, 'wall index');
|
|
126
|
+
return `wall:${role.index}`;
|
|
127
|
+
case 'hole':
|
|
128
|
+
assertIndex(role.index, 'hole index');
|
|
129
|
+
return `hole:${role.index}/${formatRoleName(role.inner)}`;
|
|
130
|
+
case 'replica':
|
|
131
|
+
assertIndex(role.k, 'replica k');
|
|
132
|
+
return `replica[${role.k}]/${formatRoleName(role.inner)}`;
|
|
133
|
+
case 'splinter':
|
|
134
|
+
assertIndex(role.index, 'splinter index');
|
|
135
|
+
return `splinter(${formatRoleName(role.inner)})#${role.index}`;
|
|
136
|
+
case 'generated':
|
|
137
|
+
assertOpName(role.op);
|
|
138
|
+
assertIndex(role.index, 'generated index');
|
|
139
|
+
return `gen:${role.op}:${role.index}`;
|
|
140
|
+
case 'imported':
|
|
141
|
+
assertIndex(role.index, 'imported index');
|
|
142
|
+
return `imported:${role.index}`;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 读一个非负整数前缀(禁止前导零)。
|
|
147
|
+
*
|
|
148
|
+
* @param text - the candidate integer text.
|
|
149
|
+
* @returns the parsed value, or null when it is not a canonical non-negative integer.
|
|
150
|
+
*/
|
|
151
|
+
function readIndex(text) {
|
|
152
|
+
if (!LEADING_INDEX_RE.test(text))
|
|
153
|
+
return null;
|
|
154
|
+
return Number(text);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 切出 balanced 的 `(...)` 段:返回内层文本与剩余文本。
|
|
158
|
+
*
|
|
159
|
+
* `splinter` 的 inner 自身可能含括号(`splinter(splinter(top)#1)#2`),
|
|
160
|
+
* 故不能用最后一个 `)` 定位。
|
|
161
|
+
*
|
|
162
|
+
* @param text - text starting with `(`.
|
|
163
|
+
* @returns the inner text and the remainder after the matching `)`, or null when unbalanced.
|
|
164
|
+
*/
|
|
165
|
+
function readBalancedParen(text) {
|
|
166
|
+
if (!text.startsWith('('))
|
|
167
|
+
return null;
|
|
168
|
+
let depth = 0;
|
|
169
|
+
for (let i = 0; i < text.length; i++) {
|
|
170
|
+
const ch = text[i];
|
|
171
|
+
if (ch === '(')
|
|
172
|
+
depth++;
|
|
173
|
+
else if (ch === ')') {
|
|
174
|
+
depth--;
|
|
175
|
+
if (depth === 0)
|
|
176
|
+
return { inner: text.slice(1, i), rest: text.slice(i + 1) };
|
|
177
|
+
if (depth < 0)
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 把串解析回 `RoleName`(`formatRoleName` 的逆)。非法输入返回 `null`,不抛错。
|
|
185
|
+
*
|
|
186
|
+
* 只返回 `null` 而不抛错,是因为解析发生在读 `.fai.js` 参数时:
|
|
187
|
+
* 调用方需要区分「这不是一个 role 串」(→ 走迁移器/报缺失)与「这是坏的 role 串」。
|
|
188
|
+
*
|
|
189
|
+
* @param text - the wire form.
|
|
190
|
+
* @returns the parsed role, or null when the text is not a valid RoleName.
|
|
191
|
+
*/
|
|
192
|
+
export function parseRoleName(text) {
|
|
193
|
+
if (text === '')
|
|
194
|
+
return null;
|
|
195
|
+
if (text.startsWith('wall:')) {
|
|
196
|
+
const index = readIndex(text.slice('wall:'.length));
|
|
197
|
+
return index === null ? null : { kind: 'wall', index };
|
|
198
|
+
}
|
|
199
|
+
if (text.startsWith('imported:')) {
|
|
200
|
+
const index = readIndex(text.slice('imported:'.length));
|
|
201
|
+
return index === null ? null : { kind: 'imported', index };
|
|
202
|
+
}
|
|
203
|
+
if (text.startsWith('gen:')) {
|
|
204
|
+
const parts = text.split(':');
|
|
205
|
+
if (parts.length !== 3)
|
|
206
|
+
return null;
|
|
207
|
+
const op = parts[1];
|
|
208
|
+
if (!OP_NAME_RE.test(op))
|
|
209
|
+
return null;
|
|
210
|
+
const index = readIndex(parts[2]);
|
|
211
|
+
return index === null ? null : { kind: 'generated', op, index };
|
|
212
|
+
}
|
|
213
|
+
if (text.startsWith('splinter(')) {
|
|
214
|
+
const balanced = readBalancedParen(text.slice('splinter'.length));
|
|
215
|
+
if (!balanced)
|
|
216
|
+
return null;
|
|
217
|
+
const inner = parseRoleName(balanced.inner);
|
|
218
|
+
if (!inner)
|
|
219
|
+
return null;
|
|
220
|
+
if (!balanced.rest.startsWith('#'))
|
|
221
|
+
return null;
|
|
222
|
+
const index = readIndex(balanced.rest.slice(1));
|
|
223
|
+
return index === null ? null : { kind: 'splinter', inner, index };
|
|
224
|
+
}
|
|
225
|
+
if (text.startsWith('hole:')) {
|
|
226
|
+
// `hole:<i>/<inner>`:先切 index,再整体递归 inner(inner 内还可有 `/`)。
|
|
227
|
+
const remainder = text.slice('hole:'.length);
|
|
228
|
+
const slash = remainder.indexOf('/');
|
|
229
|
+
if (slash < 0)
|
|
230
|
+
return null;
|
|
231
|
+
const index = readIndex(remainder.slice(0, slash));
|
|
232
|
+
if (index === null)
|
|
233
|
+
return null;
|
|
234
|
+
const inner = parseRoleName(remainder.slice(slash + 1));
|
|
235
|
+
return inner ? { kind: 'hole', index, inner } : null;
|
|
236
|
+
}
|
|
237
|
+
if (text.startsWith('replica[')) {
|
|
238
|
+
const close = text.indexOf(']');
|
|
239
|
+
if (close < 0)
|
|
240
|
+
return null;
|
|
241
|
+
const k = readIndex(text.slice('replica['.length, close));
|
|
242
|
+
if (k === null)
|
|
243
|
+
return null;
|
|
244
|
+
const rest = text.slice(close + 1);
|
|
245
|
+
if (!rest.startsWith('/'))
|
|
246
|
+
return null;
|
|
247
|
+
const inner = parseRoleName(rest.slice(1));
|
|
248
|
+
return inner ? { kind: 'replica', k, inner } : null;
|
|
249
|
+
}
|
|
250
|
+
// 兜底:semantic(保留字已在上面被结构分支吃掉,故此处不会歧义)
|
|
251
|
+
if (!SEMANTIC_NAME_RE.test(text))
|
|
252
|
+
return null;
|
|
253
|
+
if (RESERVED_KEYWORDS.includes(text))
|
|
254
|
+
return null;
|
|
255
|
+
return { kind: 'semantic', name: text };
|
|
256
|
+
}
|
|
257
|
+
// ── 构造子(七个 kind 各一个)──
|
|
258
|
+
//
|
|
259
|
+
// 存在理由:把「契约校验」收在一处。调用点直接写字面量会绕过 `assertIndex` /
|
|
260
|
+
// `assertSemanticName`,于是不合法的 role 在 `formatRoleName` 才炸——
|
|
261
|
+
// 那时已经离出错点很远(可能跨了一次执行)。构造子让非法值**在产生点**就报错。
|
|
262
|
+
/**
|
|
263
|
+
* 造一个 `semantic` role(op 声明的封闭词汇)。
|
|
264
|
+
*
|
|
265
|
+
* @param name - the op's closed-vocabulary name.
|
|
266
|
+
* @returns the role.
|
|
267
|
+
* @throws RoleNameError when the name is malformed or shadows a structural keyword.
|
|
268
|
+
*/
|
|
269
|
+
export function semantic(name) {
|
|
270
|
+
assertSemanticName(name);
|
|
271
|
+
return { kind: 'semantic', name };
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 造一个 `wall` role(输入 profile 第 i 条边扫出/旋出的侧面)。
|
|
275
|
+
*
|
|
276
|
+
* @param index - zero-based profile-edge index.
|
|
277
|
+
* @returns the role.
|
|
278
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
279
|
+
*/
|
|
280
|
+
export function wall(index) {
|
|
281
|
+
assertIndex(index, 'wall index');
|
|
282
|
+
return { kind: 'wall', index };
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 造一个 `hole` role(第 j 个内环下的同名子结构)。
|
|
286
|
+
*
|
|
287
|
+
* @param index - zero-based inner-loop index.
|
|
288
|
+
* @param inner - the local role inside that loop.
|
|
289
|
+
* @returns the role.
|
|
290
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
291
|
+
*/
|
|
292
|
+
export function hole(index, inner) {
|
|
293
|
+
assertIndex(index, 'hole index');
|
|
294
|
+
return { kind: 'hole', index, inner };
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 造一个 `replica` role(pattern 的第 k 份)。
|
|
298
|
+
*
|
|
299
|
+
* @param k - zero-based replica index.
|
|
300
|
+
* @param inner - the local role inside that replica.
|
|
301
|
+
* @returns the role.
|
|
302
|
+
* @throws RoleNameError when k is not a non-negative integer.
|
|
303
|
+
*/
|
|
304
|
+
export function replica(k, inner) {
|
|
305
|
+
assertIndex(k, 'replica k');
|
|
306
|
+
return { kind: 'replica', k, inner };
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* 造一个 `splinter` role(split 的第 j 片)。
|
|
310
|
+
*
|
|
311
|
+
* @param inner - the local role of the face being split.
|
|
312
|
+
* @param index - zero-based splinter index.
|
|
313
|
+
* @returns the role.
|
|
314
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
315
|
+
*/
|
|
316
|
+
export function splinter(inner, index) {
|
|
317
|
+
assertIndex(index, 'splinter index');
|
|
318
|
+
return { kind: 'splinter', inner, index };
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* 造一个 `generated` role(fillet/chamfer 过渡面)。
|
|
322
|
+
*
|
|
323
|
+
* @param op - the producing op ('fillet' / 'chamfer').
|
|
324
|
+
* @param index - zero-based index among that op's generated faces.
|
|
325
|
+
* @returns the role.
|
|
326
|
+
* @throws RoleNameError when op or index violates the contract.
|
|
327
|
+
*/
|
|
328
|
+
export function generated(op, index) {
|
|
329
|
+
assertOpName(op);
|
|
330
|
+
assertIndex(index, 'generated index');
|
|
331
|
+
return { kind: 'generated', op, index };
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* 造一个 `imported` role(`import_brep` 的原始面序)。
|
|
335
|
+
*
|
|
336
|
+
* @param index - zero-based face index in the imported shape's enumeration order.
|
|
337
|
+
* @returns the role.
|
|
338
|
+
* @throws RoleNameError when the index is not a non-negative integer.
|
|
339
|
+
*/
|
|
340
|
+
export function imported(index) {
|
|
341
|
+
assertIndex(index, 'imported index');
|
|
342
|
+
return { kind: 'imported', index };
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=role-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-name.js","sourceRoot":"","sources":["../../../src/topology/naming/role-name.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * role-name.ts — `RoleName` 契约与序列化(计划 §4.2)。\n *\n * 一条语句对自己产出的每个面起的**局部名**。作用域 = 那条语句;\n * 全局唯一性由 `(origin, role)` 提供(`origin` 是 `StmtId`,见 `types.ts`)。\n *\n * ## 为什么 role 不能是一个裸字符串\n *\n * 旧实现在位置兜底时产出 `box:top` / `extrude:face_3` / `cylinder:lateral`\n * ——**名字里塞了 origin**。这带来两个后果,都是致命的:\n * 1. 同一个 role 在不同语句下**不是同一个名字**(`box:top` vs `extrude:top`),\n * 于是「role 词汇表」无法按 op 封闭枚举,生成器无法把词汇表产出到 `.d.ts`;\n * 2. 前缀是**位置兜底**的伪装——`extrude:face_3` 有名字却不承载任何设计意图,\n * 按「有名/无名」统计会得出假的\"全覆盖\"(Phase 0.8 基线实测)。\n *\n * ⇒ role 只描述**在那条语句内的局部语义**,origin 由 `(StmtId)` 单独承载。\n *\n * ## 七个 kind 是封闭集\n *\n * `semantic`(op 词汇表封闭)/ `wall`(profile 第 i 条边扫出)/ `hole`(内环子结构)/\n * `replica`(pattern 第 k 份)/ `splinter`(split 第 j 片)/ `generated`(倒角过渡面)/\n * `imported`(import_brep 原始面序)。**新增 kind = 破坏性变更,须版本化。**\n *\n * ## 四条约束(分析文档 §5.1.1 R1–R4)\n *\n * 局部唯一 / 封闭可枚举 / **抗参数变化** / 结构化可分解。\n * 第三、四条正是本文件的序列化设计目标:`wall:3` 在 profile 边数变化后**仍然是第 3 条边**\n * (不是\"第 3 张面\"这种随面序漂移的地址),且 `replica[2]/hole:1/wall:3` 可逐层分解回结构。\n *\n * ## 序列化(进 `.fai.js` 的参数)\n *\n * ```\n * semantic top (裸名)\n * wall wall:3\n * hole hole:1/wall:2 (前缀包裹 inner)\n * replica replica[2]/wall:3 (前缀包裹 inner)\n * splinter splinter(top)#1 (包裹 inner + 后缀)\n * generated gen:fillet:0\n * imported imported:5\n * ```\n *\n * `parseRoleName` 与 `formatRoleName` **互为逆**(值级 round-trip),\n * 且 `parseRoleName` 是**单射**的(不接受前导零、不接受保留字作 semantic)——\n * 否则两个不同的 RoleName 会序列化成同一个串,`.fai.js` 里的引用会静默指向错的面。\n */\n\n/** 结构关键字:出现在串首即被解释成结构 kind,故不得作为 semantic 名。 */\nconst RESERVED_KEYWORDS = ['wall', 'hole', 'replica', 'splinter', 'gen', 'imported'] as const\n\n/**\n * semantic 名的合法形态。\n *\n * 限成 `[A-Za-z_][A-Za-z0-9_]*`:op 词汇表是**封闭可枚举**的\n * (`top` / `bottom` / `lateral` / `start` / `end` …),不需要更宽的字符集;\n * 收紧后串首不会与任何结构关键字歧义。\n */\nconst SEMANTIC_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/** 非负整数,**禁止前导零**(`0` 合法,`01` 不合法)——保证 format/parse 单射。 */\nconst INDEX_SOURCE = '0|[1-9][0-9]*'\nconst LEADING_INDEX_RE = new RegExp(`^(${INDEX_SOURCE})$`)\n\n/** `generated` 的 op 名:与 semantic 同字符集,保证 `gen:<op>:<i>` 无歧义。 */\nconst OP_NAME_RE = SEMANTIC_NAME_RE\n\n/**\n * 一条语句对某个产出面的局部名(计划 §4.2)。\n *\n * - `semantic`:op 声明的封闭词汇(`top` / `bottom` / `lateral` / `start` / `end` …)\n * - `wall`:由输入 profile 第 `index` 条边扫出/旋出的侧面\n * - `hole`:第 `index` 个内环下的同名子结构(`inner` 递归该内环下的局部名)\n * - `replica`:pattern 的第 `k` 份(`inner` 递归该份内的局部名)\n * - `splinter`:split 的第 `index` 片(`inner` 递归原面的局部名)\n * - `generated`:`op` 造出的过渡面(`fillet` / `chamfer`)第 `index` 张\n * - `imported`:`import_brep` 的原始面序第 `index` 张\n */\nexport type RoleName =\n | { readonly kind: 'semantic'; readonly name: string }\n | { readonly kind: 'wall'; readonly index: number }\n | { readonly kind: 'hole'; readonly index: number; readonly inner: RoleName }\n | { readonly kind: 'replica'; readonly k: number; readonly inner: RoleName }\n | { readonly kind: 'splinter'; readonly inner: RoleName; readonly index: number }\n | { readonly kind: 'generated'; readonly op: string; readonly index: number }\n | { readonly kind: 'imported'; readonly index: number }\n\n/** 七个 kind 的名字,供审计测试枚举(`RoleName` 是封闭集,新增 kind 必须同步此处)。 */\nexport const ROLE_NAME_KINDS = [\n 'semantic',\n 'wall',\n 'hole',\n 'replica',\n 'splinter',\n 'generated',\n 'imported',\n] as const\n\n/** `ROLE_NAME_KINDS` 的元素类型。 */\nexport type RoleNameKind = (typeof ROLE_NAME_KINDS)[number]\n\n/** RoleName 序列化/校验失败(格式不合法、保留字冲突、索引非法)。 */\nexport class RoleNameError extends Error {\n /** 稳定的错误码(供 args 校验与宿主识别)。 */\n readonly code = 'E_TOPO_ROLE_INVALID'\n\n /**\n * @param message - what is wrong with the role name.\n */\n constructor(message: string) {\n super(message)\n this.name = 'RoleNameError'\n }\n}\n\n/** 校验非负整数索引。 @throws RoleNameError when out of contract. */\nfunction assertIndex(value: number, what: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new RoleNameError(`${what} must be a non-negative integer, got ${String(value)}`)\n }\n}\n\n/**\n * 校验 semantic 名:形态合法且不与结构关键字冲突。\n *\n * @param name - the candidate semantic name.\n * @throws RoleNameError when empty, malformed, or shadowing a structural keyword.\n */\nfunction assertSemanticName(name: string): void {\n if (!SEMANTIC_NAME_RE.test(name)) {\n throw new RoleNameError(\n `semantic name must match ${SEMANTIC_NAME_RE.source}, got ${JSON.stringify(name)}`,\n )\n }\n if ((RESERVED_KEYWORDS as readonly string[]).includes(name)) {\n throw new RoleNameError(\n `semantic name ${JSON.stringify(name)} is a structural keyword; ` +\n `serializing it would parse back as kind '${name}' (use the structural kind instead)`,\n )\n }\n}\n\n/** 校验 generated 的 op 名(保证 `gen:<op>:<i>` 三段可切)。 */\nfunction assertOpName(op: string): void {\n if (!OP_NAME_RE.test(op)) {\n throw new RoleNameError(\n `generated op must match ${OP_NAME_RE.source}, got ${JSON.stringify(op)}`,\n )\n }\n}\n\n/**\n * 把一个 `RoleName` 序列化成进 `.fai.js` 的串。\n *\n * 结果**不含 origin**:身份是 `(StmtId, RoleName)` 两元组,串只承载后半。\n *\n * @param role - the role name to serialize.\n * @returns the wire form (e.g. `top`, `wall:3`, `replica[2]/wall:3`).\n * @throws RoleNameError when the value violates the contract (reserved name, bad index).\n */\nexport function formatRoleName(role: RoleName): string {\n switch (role.kind) {\n case 'semantic':\n assertSemanticName(role.name)\n return role.name\n case 'wall':\n assertIndex(role.index, 'wall index')\n return `wall:${role.index}`\n case 'hole':\n assertIndex(role.index, 'hole index')\n return `hole:${role.index}/${formatRoleName(role.inner)}`\n case 'replica':\n assertIndex(role.k, 'replica k')\n return `replica[${role.k}]/${formatRoleName(role.inner)}`\n case 'splinter':\n assertIndex(role.index, 'splinter index')\n return `splinter(${formatRoleName(role.inner)})#${role.index}`\n case 'generated':\n assertOpName(role.op)\n assertIndex(role.index, 'generated index')\n return `gen:${role.op}:${role.index}`\n case 'imported':\n assertIndex(role.index, 'imported index')\n return `imported:${role.index}`\n }\n}\n\n/**\n * 读一个非负整数前缀(禁止前导零)。\n *\n * @param text - the candidate integer text.\n * @returns the parsed value, or null when it is not a canonical non-negative integer.\n */\nfunction readIndex(text: string): number | null {\n if (!LEADING_INDEX_RE.test(text)) return null\n return Number(text)\n}\n\n/**\n * 切出 balanced 的 `(...)` 段:返回内层文本与剩余文本。\n *\n * `splinter` 的 inner 自身可能含括号(`splinter(splinter(top)#1)#2`),\n * 故不能用最后一个 `)` 定位。\n *\n * @param text - text starting with `(`.\n * @returns the inner text and the remainder after the matching `)`, or null when unbalanced.\n */\nfunction readBalancedParen(text: string): { inner: string; rest: string } | null {\n if (!text.startsWith('(')) return null\n let depth = 0\n for (let i = 0; i < text.length; i++) {\n const ch = text[i]\n if (ch === '(') depth++\n else if (ch === ')') {\n depth--\n if (depth === 0) return { inner: text.slice(1, i), rest: text.slice(i + 1) }\n if (depth < 0) return null\n }\n }\n return null\n}\n\n/**\n * 把串解析回 `RoleName`(`formatRoleName` 的逆)。非法输入返回 `null`,不抛错。\n *\n * 只返回 `null` 而不抛错,是因为解析发生在读 `.fai.js` 参数时:\n * 调用方需要区分「这不是一个 role 串」(→ 走迁移器/报缺失)与「这是坏的 role 串」。\n *\n * @param text - the wire form.\n * @returns the parsed role, or null when the text is not a valid RoleName.\n */\nexport function parseRoleName(text: string): RoleName | null {\n if (text === '') return null\n\n if (text.startsWith('wall:')) {\n const index = readIndex(text.slice('wall:'.length))\n return index === null ? null : { kind: 'wall', index }\n }\n\n if (text.startsWith('imported:')) {\n const index = readIndex(text.slice('imported:'.length))\n return index === null ? null : { kind: 'imported', index }\n }\n\n if (text.startsWith('gen:')) {\n const parts = text.split(':')\n if (parts.length !== 3) return null\n const op = parts[1]\n if (!OP_NAME_RE.test(op)) return null\n const index = readIndex(parts[2])\n return index === null ? null : { kind: 'generated', op, index }\n }\n\n if (text.startsWith('splinter(')) {\n const balanced = readBalancedParen(text.slice('splinter'.length))\n if (!balanced) return null\n const inner = parseRoleName(balanced.inner)\n if (!inner) return null\n if (!balanced.rest.startsWith('#')) return null\n const index = readIndex(balanced.rest.slice(1))\n return index === null ? null : { kind: 'splinter', inner, index }\n }\n\n if (text.startsWith('hole:')) {\n // `hole:<i>/<inner>`:先切 index,再整体递归 inner(inner 内还可有 `/`)。\n const remainder = text.slice('hole:'.length)\n const slash = remainder.indexOf('/')\n if (slash < 0) return null\n const index = readIndex(remainder.slice(0, slash))\n if (index === null) return null\n const inner = parseRoleName(remainder.slice(slash + 1))\n return inner ? { kind: 'hole', index, inner } : null\n }\n\n if (text.startsWith('replica[')) {\n const close = text.indexOf(']')\n if (close < 0) return null\n const k = readIndex(text.slice('replica['.length, close))\n if (k === null) return null\n const rest = text.slice(close + 1)\n if (!rest.startsWith('/')) return null\n const inner = parseRoleName(rest.slice(1))\n return inner ? { kind: 'replica', k, inner } : null\n }\n\n // 兜底:semantic(保留字已在上面被结构分支吃掉,故此处不会歧义)\n if (!SEMANTIC_NAME_RE.test(text)) return null\n if ((RESERVED_KEYWORDS as readonly string[]).includes(text)) return null\n return { kind: 'semantic', name: text }\n}\n\n// ── 构造子(七个 kind 各一个)──\n//\n// 存在理由:把「契约校验」收在一处。调用点直接写字面量会绕过 `assertIndex` /\n// `assertSemanticName`,于是不合法的 role 在 `formatRoleName` 才炸——\n// 那时已经离出错点很远(可能跨了一次执行)。构造子让非法值**在产生点**就报错。\n\n/**\n * 造一个 `semantic` role(op 声明的封闭词汇)。\n *\n * @param name - the op's closed-vocabulary name.\n * @returns the role.\n * @throws RoleNameError when the name is malformed or shadows a structural keyword.\n */\nexport function semantic(name: string): RoleName {\n assertSemanticName(name)\n return { kind: 'semantic', name }\n}\n\n/**\n * 造一个 `wall` role(输入 profile 第 i 条边扫出/旋出的侧面)。\n *\n * @param index - zero-based profile-edge index.\n * @returns the role.\n * @throws RoleNameError when the index is not a non-negative integer.\n */\nexport function wall(index: number): RoleName {\n assertIndex(index, 'wall index')\n return { kind: 'wall', index }\n}\n\n/**\n * 造一个 `hole` role(第 j 个内环下的同名子结构)。\n *\n * @param index - zero-based inner-loop index.\n * @param inner - the local role inside that loop.\n * @returns the role.\n * @throws RoleNameError when the index is not a non-negative integer.\n */\nexport function hole(index: number, inner: RoleName): RoleName {\n assertIndex(index, 'hole index')\n return { kind: 'hole', index, inner }\n}\n\n/**\n * 造一个 `replica` role(pattern 的第 k 份)。\n *\n * @param k - zero-based replica index.\n * @param inner - the local role inside that replica.\n * @returns the role.\n * @throws RoleNameError when k is not a non-negative integer.\n */\nexport function replica(k: number, inner: RoleName): RoleName {\n assertIndex(k, 'replica k')\n return { kind: 'replica', k, inner }\n}\n\n/**\n * 造一个 `splinter` role(split 的第 j 片)。\n *\n * @param inner - the local role of the face being split.\n * @param index - zero-based splinter index.\n * @returns the role.\n * @throws RoleNameError when the index is not a non-negative integer.\n */\nexport function splinter(inner: RoleName, index: number): RoleName {\n assertIndex(index, 'splinter index')\n return { kind: 'splinter', inner, index }\n}\n\n/**\n * 造一个 `generated` role(fillet/chamfer 过渡面)。\n *\n * @param op - the producing op ('fillet' / 'chamfer').\n * @param index - zero-based index among that op's generated faces.\n * @returns the role.\n * @throws RoleNameError when op or index violates the contract.\n */\nexport function generated(op: string, index: number): RoleName {\n assertOpName(op)\n assertIndex(index, 'generated index')\n return { kind: 'generated', op, index }\n}\n\n/**\n * 造一个 `imported` role(`import_brep` 的原始面序)。\n *\n * @param index - zero-based face index in the imported shape's enumeration order.\n * @returns the role.\n * @throws RoleNameError when the index is not a non-negative integer.\n */\nexport function imported(index: number): RoleName {\n assertIndex(index, 'imported index')\n return { kind: 'imported', index }\n}\n"]}
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
import type { BrepEngineApi } from '../../brep/engine/primitives.js';
|
|
13
13
|
import type { BrepHandle } from '../../brep/engine/types.js';
|
|
14
14
|
import type { HashEvolution } from '../../brep/face-evolution.js';
|
|
15
|
-
import type {
|
|
15
|
+
import type { StmtId } from '../../identity.js';
|
|
16
16
|
import type { RoleTable } from './types.js';
|
|
17
|
+
import { type RoleName } from './role-name.js';
|
|
17
18
|
/** 主轴判定阈值:abs(component) > 0.9 视为轴对齐。 */
|
|
18
19
|
export declare const AXIS_THRESHOLD = 0.9;
|
|
19
20
|
/** Re-export:hash 键演化(decodeHashEvolution 产出,见 brep/face-evolution.ts §2.4)。 */
|
|
@@ -22,19 +23,24 @@ export type { HashEvolution };
|
|
|
22
23
|
* box 面:按外法向主轴给语义名。
|
|
23
24
|
*
|
|
24
25
|
* @param n - the outward normal of the face (unit length expected).
|
|
25
|
-
* @returns the cardinal role ('
|
|
26
|
+
* @returns the cardinal role (semantic 'top' etc.), or undefined when no axis dominates.
|
|
26
27
|
*/
|
|
27
|
-
export declare function boxRoleFromNormal(n: readonly [number, number, number]):
|
|
28
|
+
export declare function boxRoleFromNormal(n: readonly [number, number, number]): RoleName | undefined;
|
|
28
29
|
/**
|
|
29
|
-
* 给链根 shape 建
|
|
30
|
+
* 给链根 shape 建 role 子表(单 origin;§3.2)。
|
|
30
31
|
*
|
|
31
|
-
*
|
|
32
|
+
* 语义命名优先;**位置兜底已删**(Phase 1.7,计划 §4.2 R3:`${opType}:face_${i}`
|
|
33
|
+
* 里的 index 是 OCCT 枚举序号,OCCT 不承诺面序稳定,改参即漂——真正抗重放的
|
|
34
|
+
* 只有语义 role)。无语义名的面**不进表**:缺身份是显式状态(naming 行 role=null),
|
|
35
|
+
* 不是可伪造的名字。R1(局部唯一)由构造保证:同语句内一个 role 只指一个面。
|
|
36
|
+
*
|
|
37
|
+
* assign 时只保留 hash + hint,不保留面句柄
|
|
32
38
|
* (避免 wasm 句柄生命周期泄漏——读完几何量即弃)。
|
|
33
39
|
*
|
|
34
40
|
* @param kernel - the OCCT kernel.
|
|
35
41
|
* @param shape - the chain-root solid (primitive / load STEP 产物).
|
|
36
|
-
* @param opType - the chain-root operation type ('box'/'cylinder'/...
|
|
37
|
-
* @returns
|
|
42
|
+
* @param opType - the chain-root operation type ('box'/'cylinder'/...)。
|
|
43
|
+
* @returns role → hash 子表(role 为 RoleName 线格式串;仅语义命中的面)。
|
|
38
44
|
*/
|
|
39
45
|
export declare function assignRoles(kernel: BrepEngineApi, shape: BrepHandle, opType: string): Map<string, number[]>;
|
|
40
46
|
/**
|
|
@@ -57,7 +63,7 @@ export declare function nextHashes(hashes: readonly number[], evolution: HashEvo
|
|
|
57
63
|
* @param evolution - the hash-keyed evolution record for this op.
|
|
58
64
|
* @returns a NEW RoleTable with the origin's roles advanced (immutable style).
|
|
59
65
|
*/
|
|
60
|
-
export declare function propagateRoles(roles: RoleTable, origin:
|
|
66
|
+
export declare function propagateRoles(roles: RoleTable, origin: StmtId, evolution: HashEvolution): RoleTable;
|
|
61
67
|
/**
|
|
62
68
|
* 沿一次 hash 演化推进 RoleTable 的**所有** origin(单父 op 用,§3.3)。
|
|
63
69
|
*
|
|
@@ -73,27 +79,19 @@ export declare function propagateAllOrigins(roles: RoleTable, evolution: HashEvo
|
|
|
73
79
|
* 布尔合流:合并两个来源的 role 表(§3.4,faijs 对 brepjs 的必要扩展)。
|
|
74
80
|
*
|
|
75
81
|
* 对 A、B 两张 hash 演化分别传播各自的表后合并;布尔新生成的缝面/刃面
|
|
76
|
-
*
|
|
82
|
+
* 以本次布尔**语句的 StmtId** 为新 origin(Phase 1.6:不再用 LHS 变量名)。
|
|
83
|
+
* 缝面**不再给位置名**(Phase 1.7:位置兜底已删)——登记空子表占位,
|
|
84
|
+
* 面身份待 Phase 3 的 kernel/byAdjacency 词汇补齐;naming 行将显式 role=null。
|
|
77
85
|
*
|
|
78
86
|
* @param targetTable - the target part's role table.
|
|
79
87
|
* @param targetEvo - the target-side hash evolution (A 的 inHash 去向).
|
|
80
88
|
* @param toolTable - the tool part's role table.
|
|
81
89
|
* @param toolEvo - the tool-side hash evolution (B 的 inHash 去向).
|
|
82
|
-
* @param
|
|
83
|
-
* @param seamCount - how many seam/generated faces to
|
|
90
|
+
* @param outStmt - the boolean statement's StmtId (new origin for seam faces).
|
|
91
|
+
* @param seamCount - how many seam/generated faces to register (0 表示不登记).
|
|
84
92
|
* @returns the merged RoleTable.
|
|
85
93
|
*/
|
|
86
|
-
export declare function mergeRoleTables(targetTable: RoleTable, targetEvo: HashEvolution, toolTable: RoleTable, toolEvo: HashEvolution,
|
|
87
|
-
/**
|
|
88
|
-
* 布尔缝面/刃面的位置名角色表(§3.4:以本次语句 LHS 为新 origin)。
|
|
89
|
-
* 缝面的 hash 来自结果形状的 subShapeHashes(按生成序),此处仅分配 role 名——
|
|
90
|
-
* hash 由调用方在拿到结果 shape 后填入(seam 面 hash 需结果 subShapeHashes 对照)。
|
|
91
|
-
*
|
|
92
|
-
* @param outPart - the boolean statement's LHS variable name.
|
|
93
|
-
* @param count - the number of seam faces to name.
|
|
94
|
-
* @returns a single-origin role map with positional roles.
|
|
95
|
-
*/
|
|
96
|
-
export declare function assignGeneratedPositionalRoles(outPart: string, count: number): Map<string, number[]>;
|
|
94
|
+
export declare function mergeRoleTables(targetTable: RoleTable, targetEvo: HashEvolution, toolTable: RoleTable, toolEvo: HashEvolution, outStmt: StmtId, seamCount: number): RoleTable;
|
|
97
95
|
/**
|
|
98
96
|
* 序号 → role 反查(§3.7 生成 ExecutionResult.naming 用)。
|
|
99
97
|
*
|