@faicad/faijs 0.13.2 → 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.map +1 -1
- package/dist/api/edge-ref.js +7 -4
- 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.map +1 -1
- package/dist/api/internal/compat-op.js +2 -1
- 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/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 +8 -1
- package/dist/fcstd/attachment.d.ts.map +1 -1
- package/dist/fcstd/attachment.js +7 -1
- package/dist/fcstd/attachment.js.map +1 -1
- package/dist/fcstd/build-fai-zip.d.ts.map +1 -1
- package/dist/fcstd/build-fai-zip.js +12 -7
- package/dist/fcstd/build-fai-zip.js.map +1 -1
- package/dist/fcstd/codegen.d.ts +10 -1
- package/dist/fcstd/codegen.d.ts.map +1 -1
- package/dist/fcstd/codegen.js +150 -48
- package/dist/fcstd/codegen.js.map +1 -1
- package/dist/fcstd/contour.d.ts.map +1 -1
- package/dist/fcstd/contour.js +23 -24
- package/dist/fcstd/contour.js.map +1 -1
- package/dist/fcstd/convert.d.ts +2 -18
- package/dist/fcstd/convert.d.ts.map +1 -1
- package/dist/fcstd/convert.js +35 -53
- package/dist/fcstd/convert.js.map +1 -1
- package/dist/fcstd/external-geo.d.ts +12 -1
- package/dist/fcstd/external-geo.d.ts.map +1 -1
- package/dist/fcstd/external-geo.js +15 -1
- package/dist/fcstd/external-geo.js.map +1 -1
- package/dist/fcstd/feature-translate.d.ts +21 -1
- package/dist/fcstd/feature-translate.d.ts.map +1 -1
- package/dist/fcstd/feature-translate.js +108 -6
- package/dist/fcstd/feature-translate.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/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 +1 -1
- package/dist/weapp.d.ts.map +1 -1
- package/dist/weapp.js +1 -1
- package/dist/weapp.js.map +1 -1
- package/package.json +1 -1
|
@@ -34,13 +34,31 @@ import { computeContentKey, stableFingerprint } from './content-key.js';
|
|
|
34
34
|
export { computeContentKey } from './content-key.js';
|
|
35
35
|
export { stableFingerprint } from './content-key.js';
|
|
36
36
|
import { isCompoundLike, getSlot, ensureSlot } from '../shape.js';
|
|
37
|
-
import { buildPartNaming
|
|
37
|
+
import { buildPartNaming } from '../topology/naming/build-naming.js';
|
|
38
38
|
import { faceRowToHint } from '../topology/naming/geom-hint.js';
|
|
39
39
|
import { HASH_UPPER_BOUND } from '../brep/face-evolution.js';
|
|
40
|
+
import { scanDeterminism } from '../lang/determinism-scanner.js';
|
|
41
|
+
import { transform as sucraseTransform } from 'sucrase';
|
|
40
42
|
// 执行护栏超时错误(§6.3 / D8)定义在独立叶子文件 execution-limit-error.ts,
|
|
41
43
|
// DirectExecutor(direct 路径单元循环内检查)与本文件共用;此处 import + re-export
|
|
42
44
|
// 保持宿主 import 面不变(module 路径 runWithFailureHandling 的 Promise.race 使用)。
|
|
43
45
|
export { ExecutionLimitError } from './execution-limit-error.js';
|
|
46
|
+
import { RuntimeConcurrentError } from './runtime-concurrent-error.js';
|
|
47
|
+
export { RuntimeConcurrentError } from './runtime-concurrent-error.js';
|
|
48
|
+
/**
|
|
49
|
+
* 全局执行态锁(C1):进程内同一时刻只允许一个 runtime 处于执行态。
|
|
50
|
+
*
|
|
51
|
+
* 进程级单例(`setCurrentStmt` / backends / 内核)决定了并发执行多 runtime 不可支持;
|
|
52
|
+
* 旧行为是"互踩"(见 {@link CadRuntime.claimBackends} 文档),现在改为显式拒绝。
|
|
53
|
+
*
|
|
54
|
+
* **同实例的重入放行**:`update` 内部会经 `executeDirectText`/`appendDirectText` 落入
|
|
55
|
+
* 同一调用栈——那已被"同一栈上串行"保证,不构成并发。跨实例一律拒绝。
|
|
56
|
+
*/
|
|
57
|
+
let executingRuntimeId = null;
|
|
58
|
+
/** 执行态持有者(诊断用:错误信息里给出被谁挡住)。 */
|
|
59
|
+
let executingEntry = null;
|
|
60
|
+
/** runtime id 分配器(仅用于错误信息定位,不参与任何语义判定)。 */
|
|
61
|
+
let nextRuntimeId = 1;
|
|
44
62
|
/**
|
|
45
63
|
* Thrown by CadRuntime.append when a newly appended statement references a
|
|
46
64
|
* variable that is not in the persistent context — its producer was never
|
|
@@ -125,8 +143,14 @@ export class CadRuntime {
|
|
|
125
143
|
topologyCache = new Map();
|
|
126
144
|
/** 无 IR 执行器(DirectExecutor,T5 后唯一执行路径) */
|
|
127
145
|
directExecutor;
|
|
146
|
+
/** 实例 id(仅用于 C1 并发错误信息里的定位,不参与任何语义判定)。 */
|
|
147
|
+
runtimeId = nextRuntimeId++;
|
|
128
148
|
/** 安全策略档位(透传给 extractMetadata 与 DirectExecutor;缺省 'strict') */
|
|
129
149
|
securityPolicy;
|
|
150
|
+
/** 确定性扫描档位(缺省 'error';execute/append 前对源码做 B 档 taint 扫描)。 */
|
|
151
|
+
determinismPolicy;
|
|
152
|
+
/** warn 档位下收集的确定性警告,合并进最终 ExecutionResult.infos。 */
|
|
153
|
+
determinismWarnings = [];
|
|
130
154
|
/** 宿主注册库(含 cad:由根门面 createRuntime 包装注入;注入编译产物 fn 的第二参 ns) */
|
|
131
155
|
libs;
|
|
132
156
|
/** 库内容身份表 (binding → content hash),增量 key 用(B2,§7.3) */
|
|
@@ -177,9 +201,11 @@ export class CadRuntime {
|
|
|
177
201
|
// wrapping — DUAL_OP_META hangs on the function object with
|
|
178
202
|
// enumerable:false, and wrapping first would let bare functions silently
|
|
179
203
|
// skip the strict validation pass (R8).
|
|
204
|
+
// Phase 2.11-①: `options.naming` is the library-level provenance default;
|
|
205
|
+
// a bare function's own `fn.naming` wins over it (see admit-compat-lib.ts).
|
|
180
206
|
const lift = options?.autoLift ?? !hasDualOp(ns);
|
|
181
207
|
const admitted = lift
|
|
182
|
-
? admitCompatLib(ns)
|
|
208
|
+
? admitCompatLib(ns, { naming: options?.naming })
|
|
183
209
|
: ns;
|
|
184
210
|
this.libs[binding] = admitted;
|
|
185
211
|
this.libIds.set(binding, computeLibId(binding, ns));
|
|
@@ -201,6 +227,7 @@ export class CadRuntime {
|
|
|
201
227
|
this.libs = libs;
|
|
202
228
|
this.namespaces = { ...libs };
|
|
203
229
|
this.securityPolicy = options.security ?? 'strict';
|
|
230
|
+
this.determinismPolicy = options.determinism ?? 'error';
|
|
204
231
|
this.directExecutor = new DirectExecutor({
|
|
205
232
|
namespaces: this.namespaces,
|
|
206
233
|
setSolid: (partName, solid) => { this.solidCache.set(partName, solid); },
|
|
@@ -218,7 +245,11 @@ export class CadRuntime {
|
|
|
218
245
|
* 先前 runtime 的后续 execute 会被静默劫持(dispatch 走错槽、缓存键漂移、
|
|
219
246
|
* 顶替释放旧 BREP 句柄后拓扑重建撞上悬空句柄)。因此除构造外,每个执行入口
|
|
220
247
|
* (execute,所有执行路径的汇聚点)都必须先重新认领本实例的配置。
|
|
221
|
-
*
|
|
248
|
+
*
|
|
249
|
+
* ⚠️ 并发交错执行多个 runtime **仍会互踩**——这条限制现在由全局执行态锁强制
|
|
250
|
+
* ({@link withExecutionLock}):第二个 runtime 在他人执行态时抛
|
|
251
|
+
* {@link RuntimeConcurrentError}(E_RUNTIME_CONCURRENT),不再"尽力而为"。
|
|
252
|
+
* 用户已裁决不允许并发(开发计划 §4.7 C1)。
|
|
222
253
|
* ⚠️ getter 的 this 指向所在对象字面量,用箭头闭包捕获实例(避免 no-this-alias)。
|
|
223
254
|
*/
|
|
224
255
|
claimBackends() {
|
|
@@ -284,14 +315,48 @@ export class CadRuntime {
|
|
|
284
315
|
return this.brepChain;
|
|
285
316
|
}
|
|
286
317
|
// ── 公开入口:execute / append / update(输入一律是代码文本,IR 在引擎内部) ──
|
|
318
|
+
/**
|
|
319
|
+
* 取全局执行态锁并运行 `fn`(C1)。跨实例并发 → 抛 {@link RuntimeConcurrentError};
|
|
320
|
+
* 本实例重入(update 内部落到 executeDirectText/appendDirectText)放行。
|
|
321
|
+
*
|
|
322
|
+
* 刻意**同步**取锁(不在取锁前 await):这样 `runtimeA.execute(...)` 尚未 await 时
|
|
323
|
+
* 紧接着调 `runtimeB.execute(...)` 必然被拒绝,行为可确定、可测试。
|
|
324
|
+
* @param entry - 入口名(execute / append / update),仅用于错误信息。
|
|
325
|
+
* @param fn - 实际执行体。
|
|
326
|
+
* @returns fn 的结果;无论成功失败都释放锁(finally)。
|
|
327
|
+
*/
|
|
328
|
+
async withExecutionLock(entry, fn) {
|
|
329
|
+
if (executingRuntimeId !== null && executingRuntimeId !== this.runtimeId) {
|
|
330
|
+
throw new RuntimeConcurrentError(executingRuntimeId, this.runtimeId, entry);
|
|
331
|
+
}
|
|
332
|
+
const reentrant = executingRuntimeId === this.runtimeId;
|
|
333
|
+
if (!reentrant) {
|
|
334
|
+
executingRuntimeId = this.runtimeId;
|
|
335
|
+
executingEntry = entry;
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
return await fn();
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
if (!reentrant) {
|
|
342
|
+
executingRuntimeId = null;
|
|
343
|
+
executingEntry = null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/** 当前执行态持有者的入口名(诊断;无持有者时 null)。 */
|
|
348
|
+
static get executingEntry() {
|
|
349
|
+
return executingEntry;
|
|
350
|
+
}
|
|
287
351
|
/**
|
|
288
352
|
* Full execution from code text: parse → execute every statement.
|
|
289
353
|
* @param code - the .fai.js source text.
|
|
290
354
|
* @param opts - optional execution options.
|
|
291
355
|
* @returns promise resolving to the ExecutionResult.
|
|
356
|
+
* @throws {RuntimeConcurrentError} when another CadRuntime is already executing (C1).
|
|
292
357
|
*/
|
|
293
358
|
async execute(code, opts) {
|
|
294
|
-
return this.executeDirectText(code, opts);
|
|
359
|
+
return this.withExecutionLock('execute', () => this.executeDirectText(code, opts));
|
|
295
360
|
}
|
|
296
361
|
/**
|
|
297
362
|
* Append new statements (incremental execution): only execute the new code
|
|
@@ -300,9 +365,101 @@ export class CadRuntime {
|
|
|
300
365
|
* @param code - the new .fai.js source text to append.
|
|
301
366
|
* @param opts - optional execution options.
|
|
302
367
|
* @returns promise resolving to the ExecutionResult.
|
|
368
|
+
* @throws {RuntimeConcurrentError} when another CadRuntime is already executing (C1).
|
|
303
369
|
*/
|
|
304
370
|
async append(code, opts) {
|
|
305
|
-
return this.appendDirectText(code, opts);
|
|
371
|
+
return this.withExecutionLock('append', () => this.appendDirectText(code, opts));
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 确定性扫描门(B 档 taint):执行前对源码做静态扫描,违规按 determinismPolicy 处理。
|
|
375
|
+
*
|
|
376
|
+
* 扫描范围:主文件 + @faicad/* 库源码(经 libLoader.loadSource,若宿主提供)。
|
|
377
|
+
* 项目内相对 import 模块的扫描由 ModuleRegistry.load 内部完成(构造时传入 policy)。
|
|
378
|
+
*
|
|
379
|
+
* @returns ExecutionResult(违规 + policy='error' 时),null(通过或 warn/off)。
|
|
380
|
+
* warn 档位下警告收集到 this.determinismWarnings,由调用方合并进 infos。
|
|
381
|
+
*/
|
|
382
|
+
async runDeterminismGate(code, meta) {
|
|
383
|
+
if (this.determinismPolicy === 'off')
|
|
384
|
+
return null;
|
|
385
|
+
this.determinismWarnings = [];
|
|
386
|
+
const hints = this.extractDeterminismHints(meta);
|
|
387
|
+
const violations = scanDeterminism(code, {
|
|
388
|
+
defaultNs: this.defaultNsName,
|
|
389
|
+
extraNamespaces: hints.namespaces,
|
|
390
|
+
extraCallees: hints.callees,
|
|
391
|
+
}).violations;
|
|
392
|
+
// 库源码扫描(@faicad/* 非引擎;经 libLoader.loadSource,宿主未提供则跳过)
|
|
393
|
+
const loadSource = this.ports.libLoader?.loadSource;
|
|
394
|
+
if (loadSource) {
|
|
395
|
+
for (const imp of meta.imports ?? []) {
|
|
396
|
+
const spec = imp.packageName ?? imp.specifier ?? '';
|
|
397
|
+
if (!spec.startsWith('@faicad/'))
|
|
398
|
+
continue;
|
|
399
|
+
if (spec === '@faicad/faijs' || spec.startsWith('@faicad/faijs/'))
|
|
400
|
+
continue;
|
|
401
|
+
try {
|
|
402
|
+
const src = await loadSource(spec);
|
|
403
|
+
if (src) {
|
|
404
|
+
violations.push(...this.scanLibrarySource(src, hints).violations);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
// 库源码不可读 → 跳过(不阻断执行;库违规由库作者负责)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (violations.length === 0)
|
|
413
|
+
return null;
|
|
414
|
+
const formatted = violations.map((v) => `[determinism] line ${v.lineNo} [${v.source}]: ${v.message}`);
|
|
415
|
+
if (this.determinismPolicy === 'warn') {
|
|
416
|
+
this.determinismWarnings = formatted;
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
// 'error'
|
|
420
|
+
const first = violations[0];
|
|
421
|
+
return {
|
|
422
|
+
outputs: new Map(),
|
|
423
|
+
brepChain: this.brepChain,
|
|
424
|
+
terminals: [],
|
|
425
|
+
infos: [],
|
|
426
|
+
failedAt: {
|
|
427
|
+
index: -1,
|
|
428
|
+
callee: 'determinism',
|
|
429
|
+
message: formatted[0],
|
|
430
|
+
lineNo: first.lineNo,
|
|
431
|
+
code: 'E_DETERMINISM',
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
/** 从 meta.imports 提取扫描提示:namespace import → extraNamespaces,named import → extraCallees。 */
|
|
436
|
+
extractDeterminismHints(meta) {
|
|
437
|
+
const namespaces = [];
|
|
438
|
+
const callees = [];
|
|
439
|
+
for (const imp of meta.imports ?? []) {
|
|
440
|
+
if (imp.kind === 'namespace' && imp.localName)
|
|
441
|
+
namespaces.push(imp.localName);
|
|
442
|
+
if (imp.kind === 'named')
|
|
443
|
+
callees.push(...imp.bindings);
|
|
444
|
+
}
|
|
445
|
+
return { namespaces, callees };
|
|
446
|
+
}
|
|
447
|
+
/** 扫描库源码(可能含 TS 语法 → sucrase 脱后扫;失败则当 JS 直扫)。 */
|
|
448
|
+
scanLibrarySource(src, hints) {
|
|
449
|
+
let js = src;
|
|
450
|
+
try {
|
|
451
|
+
js = sucraseTransform(src, { transforms: ['typescript'] }).code;
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
// 非 TS 或 sucrase 转换失败 → 当 JS 直扫
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
violations: scanDeterminism(js, {
|
|
458
|
+
defaultNs: this.defaultNsName,
|
|
459
|
+
extraNamespaces: hints.namespaces,
|
|
460
|
+
extraCallees: hints.callees,
|
|
461
|
+
}).violations,
|
|
462
|
+
};
|
|
306
463
|
}
|
|
307
464
|
/**
|
|
308
465
|
* Direct-mode full execution: the code text runs on the DirectExecutor
|
|
@@ -315,6 +472,9 @@ export class CadRuntime {
|
|
|
315
472
|
this.claimBackends();
|
|
316
473
|
this.accumulatedCode = code;
|
|
317
474
|
const meta = extractMetadata(code, { defaultNs: this.defaultNsName, security: this.securityPolicy, namespaces: Object.keys(this.libs) });
|
|
475
|
+
const determinismFailure = await this.runDeterminismGate(code, meta);
|
|
476
|
+
if (determinismFailure)
|
|
477
|
+
return determinismFailure;
|
|
318
478
|
const libLoadFailure = await this.autoLoadLibsFromImports(meta.imports);
|
|
319
479
|
if (libLoadFailure)
|
|
320
480
|
return libLoadFailure;
|
|
@@ -340,6 +500,8 @@ export class CadRuntime {
|
|
|
340
500
|
return this.directFailedAtOrThrow(outcome.failedAt, meta);
|
|
341
501
|
}
|
|
342
502
|
const result = this.collectDirectResult(meta, opts);
|
|
503
|
+
if (this.determinismWarnings.length > 0)
|
|
504
|
+
result.infos.push(...this.determinismWarnings);
|
|
343
505
|
this.recordFingerprints(opts);
|
|
344
506
|
return result;
|
|
345
507
|
}
|
|
@@ -403,6 +565,9 @@ export class CadRuntime {
|
|
|
403
565
|
// A1 安全扫描需把 ctx 已有键 + 已注册命名空间都作为 knownNames(避免 SEC_FREE_IDENT 误杀 append 场景)。
|
|
404
566
|
const appendKnownNames = [...Object.keys(this.libs), ...de.listCtxKeys()];
|
|
405
567
|
const meta = extractMetadata(fullCode, { defaultNs: this.defaultNsName, looseVars: true, security: this.securityPolicy, namespaces: appendKnownNames, nsNames: Object.keys(this.libs) });
|
|
568
|
+
const determinismFailure = await this.runDeterminismGate(fullCode, meta);
|
|
569
|
+
if (determinismFailure)
|
|
570
|
+
return determinismFailure;
|
|
406
571
|
const libLoadFailure = await this.autoLoadLibsFromImports(meta.imports);
|
|
407
572
|
if (libLoadFailure)
|
|
408
573
|
return libLoadFailure;
|
|
@@ -427,6 +592,8 @@ export class CadRuntime {
|
|
|
427
592
|
return this.directFailedAtOrThrow(outcome.failedAt, meta);
|
|
428
593
|
}
|
|
429
594
|
const result = this.collectDirectResult(meta, opts);
|
|
595
|
+
if (this.determinismWarnings.length > 0)
|
|
596
|
+
result.infos.push(...this.determinismWarnings);
|
|
430
597
|
this.recordFingerprints(opts);
|
|
431
598
|
return result;
|
|
432
599
|
}
|
|
@@ -452,7 +619,7 @@ export class CadRuntime {
|
|
|
452
619
|
return { seed: {} };
|
|
453
620
|
if (!(meta.imports ?? []).some((imp) => isRelativeSpecifier(imp.specifier)))
|
|
454
621
|
return { seed: {} };
|
|
455
|
-
const registry = new ModuleRegistry(loader, (code, imports) => this.runDirectModule(code, imports), this.securityPolicy);
|
|
622
|
+
const registry = new ModuleRegistry(loader, (code, imports) => this.runDirectModule(code, imports), this.securityPolicy, this.determinismPolicy);
|
|
456
623
|
try {
|
|
457
624
|
const seed = await registry.resolveImports(meta.imports ?? [], baseKey);
|
|
458
625
|
return { seed };
|
|
@@ -523,9 +690,15 @@ export class CadRuntime {
|
|
|
523
690
|
const v = de.getCtxVar(String(name));
|
|
524
691
|
if (isShapeLike(v)) {
|
|
525
692
|
const shape = v;
|
|
693
|
+
// 非实体导入(C6 线框/面/壳)不携带显示网格——positions/indices 为
|
|
694
|
+
// undefined 是已知限制(load-nonsolid.test.ts),content key 退化为
|
|
695
|
+
// 占位值而不是崩溃。
|
|
696
|
+
const hasMesh = shape.positions instanceof Float32Array && shape.indices instanceof Uint32Array;
|
|
526
697
|
this.statementCache.set(name, {
|
|
527
698
|
statementKey: `direct:${String(name)}`,
|
|
528
|
-
outputContentKey:
|
|
699
|
+
outputContentKey: hasMesh
|
|
700
|
+
? computeContentKey(shape.positions, shape.indices)
|
|
701
|
+
: `direct:nomesh:${String(name)}`,
|
|
529
702
|
output: shape,
|
|
530
703
|
});
|
|
531
704
|
}
|
|
@@ -743,6 +916,7 @@ export class CadRuntime {
|
|
|
743
916
|
const resolved = imp.packageName ?? imp.specifier ?? '';
|
|
744
917
|
this.registerLib(imp.localName, ns, {
|
|
745
918
|
autoLift: this.ports.libLoader.options?.autoLiftFor?.(resolved) ?? this.ports.libLoader.options?.autoLift ?? !hasDualOp(ns),
|
|
919
|
+
naming: this.ports.libLoader.options?.namingFor?.(resolved),
|
|
746
920
|
packageName: imp.packageName,
|
|
747
921
|
});
|
|
748
922
|
}
|
|
@@ -777,8 +951,9 @@ export class CadRuntime {
|
|
|
777
951
|
};
|
|
778
952
|
}
|
|
779
953
|
if (partTopo.source === 'primitive') {
|
|
780
|
-
|
|
781
|
-
|
|
954
|
+
// Phase 1.8(D6):primitive 不再派生伪拓扑 role——拓扑身份是 BREP 专有能力,
|
|
955
|
+
// primitive/mesh 一致只填 hint(naming 行 origin/role 显式 null)。
|
|
956
|
+
return { source: partTopo.source, partName, faces, edges, edgeFaceOrdinals };
|
|
782
957
|
}
|
|
783
958
|
return { source: partTopo.source, partName, faces, edges, edgeFaceOrdinals };
|
|
784
959
|
}
|
|
@@ -822,9 +997,10 @@ export class CadRuntime {
|
|
|
822
997
|
* @param newCode - the .fai.js source text after the edit.
|
|
823
998
|
* @param opts - optional execution options.
|
|
824
999
|
* @returns promise resolving to the ExecutionResult.
|
|
1000
|
+
* @throws {RuntimeConcurrentError} when another CadRuntime is already executing (C1).
|
|
825
1001
|
*/
|
|
826
1002
|
async update(oldCode, newCode, opts) {
|
|
827
|
-
return this.updateIncremental(oldCode, newCode, opts);
|
|
1003
|
+
return this.withExecutionLock('update', () => this.updateIncremental(oldCode, newCode, opts));
|
|
828
1004
|
}
|
|
829
1005
|
// ── 公开:缓存访问 ──
|
|
830
1006
|
/**
|