geospec 0.1.0-beta.2 → 0.1.0-beta.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.
- package/agent/doctrine.md +8 -0
- package/agent/geospec-authoring/SKILL.md +19 -20
- package/agent/geospec-authoring/api-constants.md +11 -1
- package/agent/geospec-authoring/api-functions.md +9 -1
- package/agent/geospec-authoring/api-index.md +22 -7
- package/agent/geospec-authoring/api-types.md +91 -3
- package/agent/geospec-authoring/public-api-constants.md +33 -1
- package/agent/geospec-authoring/public-api-functions.md +21 -2
- package/agent/geospec-authoring/public-api-index.md +57 -20
- package/agent/geospec-authoring/public-api-types-2.md +267 -220
- package/agent/geospec-authoring/public-api-types-3.md +217 -0
- package/agent/geospec-authoring/public-api-types.md +37 -137
- package/agent/resources.js +14 -13
- package/agent/skills.json +3 -2
- package/dist/assertion-client/client.d.mts +12 -2
- package/dist/assertion-client/client.mjs +2 -2
- package/dist/assertion-client/index.d.mts +2 -2
- package/dist/assertion-client/index.mjs +1 -1
- package/dist/config/tau-project-artifact.mjs +1 -1
- package/dist/create-geospec.d.mts +3 -2
- package/dist/create-geospec.mjs +1 -1
- package/dist/engine/client.d.mts +21 -1
- package/dist/engine/client.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/model/export-intent.d.mts +17 -1
- package/dist/model/export-intent.mjs +1 -1
- package/dist/model/index.d.mts +4 -3
- package/dist/model/index.mjs +1 -1
- package/dist/model/native-model-loader.d.mts +30 -7
- package/dist/model/native-model-loader.mjs +1 -1
- package/dist/model/region-scope.d.mts +23 -0
- package/dist/model/region-scope.mjs +1 -0
- package/dist/model/subject-assertions.mjs +1 -1
- package/dist/model/types.d.mts +50 -3
- package/dist/runner/collector.d.mts +4 -2
- package/dist/runner/collector.mjs +2 -2
- package/dist/runner/index.d.mts +3 -2
- package/dist/runner/index.mjs +1 -1
- package/dist/runner/native/native-serial-runner.mjs +1 -1
- package/dist/runner/run-geospec-module.mjs +2 -2
- package/dist/runner/timeout-codes.d.mts +45 -0
- package/dist/runner/timeout-codes.mjs +1 -0
- package/dist/runner/types.d.mts +34 -1
- package/dist/runner/worker/runner-types.d.mts +24 -3
- package/dist/runner/worker/serial-runner.mjs +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "../mesh/types.mjs";
|
|
2
|
+
import "./types.mjs";
|
|
3
|
+
import { GeoSpecAssertion } from "../runner/types.mjs";
|
|
4
|
+
//#region src/model/region-scope.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The claims a region-cropped subject answers: measurements of the cropped geometry itself. Each
|
|
7
|
+
* verdict holds for the region only, and the assertion records the region it stands for.
|
|
8
|
+
*
|
|
9
|
+
* Every other kind quantifies over the whole model (component counts, all-components
|
|
10
|
+
* interference, occurrences, watertightness, integrity, topology, diagnostics) or relates parts the
|
|
11
|
+
* crop may have cut, so a crop can neither prove nor disprove it.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
declare const geoSpecRegionScopedKinds: ReadonlySet<GeoSpecAssertion['kind']>;
|
|
16
|
+
/**
|
|
17
|
+
* Diagnostic code of a whole-model claim made on a region-cropped subject.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
declare const geoSpecRegionWholeModelClaimCode = "GEOSPEC_REGION_WHOLE_MODEL_CLAIM";
|
|
22
|
+
//#endregion
|
|
23
|
+
export { geoSpecRegionScopedKinds, geoSpecRegionWholeModelClaimCode };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=new Set([`boundingBox`,`volume`,`surfaceArea`,`mass`,`centerOfMass`]),t=`GEOSPEC_REGION_WHOLE_MODEL_CLAIM`,n=(n,r)=>n===void 0||e.has(r)?void 0:{code:t,severity:`error`,message:`A '${r}' claim is about the whole model, and this subject is cropped to the region min [${n.min.join(`, `)}] max [${n.max.join(`, `)}] mm, so the claim cannot be decided on it.`,suggestion:`Keep the claim and make it on a whole-model load (loadModel without region). If the whole model exceeds a host limit, provision more resources (host admission limits or workUnitLimit) and report the claim as not decided at this capacity. A region load answers only bounding box, volume, surface area, mass and center of mass of that region.`,details:{kind:r,region:{min:[...n.min],max:[...n.max]},regionScopedKinds:[...e]}};export{e as geoSpecRegionScopedKinds,t as geoSpecRegionWholeModelClaimCode,n as regionScopeRefusal};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolveGeoSpecSubject as e}from"./subject.mjs";import{createGeoSpecMatcherMethods as t}from"../assertion-client/client.mjs";import{diagnosticForTransport as n,geometryDiagnosticSchema as r}from"./errors.mjs";const
|
|
1
|
+
import{resolveGeoSpecSubject as e}from"./subject.mjs";import{createGeoSpecMatcherMethods as t}from"../assertion-client/client.mjs";import{diagnosticForTransport as n,geometryDiagnosticSchema as r}from"./errors.mjs";import{regionScopeRefusal as i}from"./region-scope.mjs";const a=(a,o)=>{let s=e(a),c=o?.workUnitLimit??s.load?.workUnitLimit,l=s.client.expectGeo(s.identity,c===void 0?void 0:{workUnitLimit:c}),u=o=>t({subject:a,polarity:o?`negative`:`positive`,invoke:t=>{e(a);let c=s.load?.region,u=c===void 0?void 0:{min:[...c.min],max:[...c.max]},d=u===void 0?{}:{region:u},f=i(c,t.kind);if(f!==void 0)return{kind:t.kind,subject:s.identity,...s.load===void 0?{}:{loadId:s.load.loadId},...d,expected:t.expected,passed:!1,diagnostics:[f]};let p=o?l.not:l,m=Reflect.apply(p[t.matcher],p,t.arguments),h=m.diagnostics.map(e=>n(r.parse(e)));return{kind:t.kind,subject:s.identity,...s.load===void 0?{}:{loadId:s.load.loadId},...d,expected:t.expected,passed:m.status===`passed`,diagnostics:h,report:m}}});return Object.assign(u(!1),{not:u(!0)})};export{a as expectGeoSubject};
|
package/dist/model/types.d.mts
CHANGED
|
@@ -36,11 +36,13 @@ type GeoSpecModelFormat = MeshFileFormat | 'step' | 'stp';
|
|
|
36
36
|
* small so typed runtime clients do not have to widen their full generic
|
|
37
37
|
* method surface to GeoSpec's testing DSL. A client with `shutdown` is awaited
|
|
38
38
|
* through it when GeoSpec releases an owned runtime, so its host resources are
|
|
39
|
-
* closed before the caller (for example a worker thread) exits.
|
|
39
|
+
* closed before the caller (for example a worker thread) exits. A client with
|
|
40
|
+
* `snapshotSource` lets one run reuse an identical file load after confirming
|
|
41
|
+
* that the source closure it exported is unchanged.
|
|
40
42
|
*
|
|
41
43
|
* @public
|
|
42
44
|
*/
|
|
43
|
-
type GeoSpecRuntimeClient = Pick<RuntimeClient, 'connect' | 'terminate'> & Partial<Pick<RuntimeClient, 'shutdown'>> & {
|
|
45
|
+
type GeoSpecRuntimeClient = Pick<RuntimeClient, 'connect' | 'terminate'> & Partial<Pick<RuntimeClient, 'shutdown' | 'snapshotSource' | 'describe'>> & {
|
|
44
46
|
open: (input: Pick<Parameters<RuntimeClient['open']>[0], 'source' | 'parameters' | 'stage' | 'watch' | 'signal'>) => Pick<ReturnType<RuntimeClient['open']>, 'export' | 'close'>;
|
|
45
47
|
on?(event: 'telemetry', handler: (batch: {
|
|
46
48
|
readonly entries: ReadonlyArray<{
|
|
@@ -71,6 +73,15 @@ type GeoSpecRuntimeSourceAdapter = {
|
|
|
71
73
|
file?: string;
|
|
72
74
|
}): Promise<GeoSpecRuntimeClient>;
|
|
73
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Axis-aligned crop box in canonical Z-up millimetres; every `min` axis is below its `max` axis.
|
|
78
|
+
*
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
type GeoSpecLoadRegion = {
|
|
82
|
+
readonly min: readonly [number, number, number];
|
|
83
|
+
readonly max: readonly [number, number, number];
|
|
84
|
+
};
|
|
74
85
|
/**
|
|
75
86
|
* Direct geometry-source model load options.
|
|
76
87
|
*
|
|
@@ -102,6 +113,12 @@ type LoadModelSourceOptions = {
|
|
|
102
113
|
meshLinearTolerance?: number;
|
|
103
114
|
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
104
115
|
meshAngularToleranceDegrees?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Default work-unit budget for every claim on this subject: a positive integer no greater than
|
|
118
|
+
* the host's maximum (default `geoSpecMaximumWorkUnitLimit`, 512 000 000). `expectGeo(subject, { workUnitLimit })` overrides
|
|
119
|
+
* it per chain. Recorded in the load evidence; it never changes the exported or admitted bytes.
|
|
120
|
+
*/
|
|
121
|
+
workUnitLimit?: number;
|
|
105
122
|
};
|
|
106
123
|
/**
|
|
107
124
|
* Inline code-CAD model load options.
|
|
@@ -131,6 +148,21 @@ type LoadModelCodeOptions<Code extends Record<string, string> = Record<string, s
|
|
|
131
148
|
meshLinearTolerance?: number;
|
|
132
149
|
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
133
150
|
meshAngularToleranceDegrees?: number;
|
|
151
|
+
/**
|
|
152
|
+
* Default work-unit budget for every claim on this subject: a positive integer no greater than
|
|
153
|
+
* the host's maximum (default `geoSpecMaximumWorkUnitLimit`, 512 000 000). `expectGeo(subject, { workUnitLimit })` overrides
|
|
154
|
+
* it per chain. Recorded in the load evidence; it never changes the exported or admitted bytes.
|
|
155
|
+
*/
|
|
156
|
+
workUnitLimit?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Axis-aligned millimetre box the kernel crops the model to before export, so a large mesh model
|
|
159
|
+
* can be checked region by region. Only kernels whose direct GLB export declares a `region` option
|
|
160
|
+
* honor it; any other kernel, a STEP load or a crop the kernel does not confirm refuses with a typed
|
|
161
|
+
* diagnostic instead of loading the whole model. The cropped subject is a different subject: its
|
|
162
|
+
* admission carries the kernel's crop notice and its load evidence records `region`, so a claim on
|
|
163
|
+
* it never stands for the whole model.
|
|
164
|
+
*/
|
|
165
|
+
region?: GeoSpecLoadRegion;
|
|
134
166
|
};
|
|
135
167
|
/**
|
|
136
168
|
* Filesystem-backed model load options.
|
|
@@ -158,6 +190,21 @@ type LoadModelFileOptions = {
|
|
|
158
190
|
meshLinearTolerance?: number;
|
|
159
191
|
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
160
192
|
meshAngularToleranceDegrees?: number;
|
|
193
|
+
/**
|
|
194
|
+
* Default work-unit budget for every claim on this subject: a positive integer no greater than
|
|
195
|
+
* the host's maximum (default `geoSpecMaximumWorkUnitLimit`, 512 000 000). `expectGeo(subject, { workUnitLimit })` overrides
|
|
196
|
+
* it per chain. Recorded in the load evidence; it never changes the exported or admitted bytes.
|
|
197
|
+
*/
|
|
198
|
+
workUnitLimit?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Axis-aligned millimetre box the kernel crops the model to before export, so a large mesh model
|
|
201
|
+
* can be checked region by region. Only kernels whose direct GLB export declares a `region` option
|
|
202
|
+
* honor it; any other kernel, a STEP load or a crop the kernel does not confirm refuses with a typed
|
|
203
|
+
* diagnostic instead of loading the whole model. The cropped subject is a different subject: its
|
|
204
|
+
* admission carries the kernel's crop notice and its load evidence records `region`, so a claim on
|
|
205
|
+
* it never stands for the whole model.
|
|
206
|
+
*/
|
|
207
|
+
region?: GeoSpecLoadRegion;
|
|
161
208
|
};
|
|
162
209
|
/**
|
|
163
210
|
* Options accepted by {@link import('./load-model.js').loadModel}.
|
|
@@ -204,4 +251,4 @@ type CreateModelLoaderOptions = {
|
|
|
204
251
|
meshAngularToleranceDegrees?: number;
|
|
205
252
|
};
|
|
206
253
|
//#endregion
|
|
207
|
-
export { CreateModelLoaderOptions, GeoSpecModelFormat, GeoSpecModelLoader, GeoSpecRuntimeClient, GeoSpecRuntimeClientFactory, GeoSpecRuntimeSourceAdapter, LoadModelCodeOptions, LoadModelFileOptions, LoadModelOptions, LoadModelSourceOptions, ManagedGeoSpecModelLoader, MeshBufferSource, MeshSource };
|
|
254
|
+
export { CreateModelLoaderOptions, GeoSpecLoadRegion, GeoSpecModelFormat, GeoSpecModelLoader, GeoSpecRuntimeClient, GeoSpecRuntimeClientFactory, GeoSpecRuntimeSourceAdapter, LoadModelCodeOptions, LoadModelFileOptions, LoadModelOptions, LoadModelSourceOptions, ManagedGeoSpecModelLoader, MeshBufferSource, MeshSource };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GeometryDiagnostic } from "../mesh/types.mjs";
|
|
2
|
-
import { GeoSpecMatcher, GeoSpecTestCase } from "./types.mjs";
|
|
2
|
+
import { GeoSpecExpectOptions, GeoSpecMatcher, GeoSpecTestCase, GeoSpecTestEvent } from "./types.mjs";
|
|
3
3
|
import { GeoSpecAssertionClientOptions } from "../assertion-client/client.mjs";
|
|
4
4
|
import "../assertion-client/index.mjs";
|
|
5
5
|
import { GeoSpecTestNamePattern } from "./filter.mjs";
|
|
@@ -17,7 +17,7 @@ type GeoSpecCollector = {
|
|
|
17
17
|
describeSkip(name: string, _function?: GeoSpecTestFunction): void;
|
|
18
18
|
it(name: string, function_: GeoSpecTestFunction): void;
|
|
19
19
|
itSkip(name: string, _function?: GeoSpecTestFunction): void;
|
|
20
|
-
expectGeo(subject: unknown): GeoSpecMatcher;
|
|
20
|
+
expectGeo(subject: unknown, options?: GeoSpecExpectOptions): GeoSpecMatcher;
|
|
21
21
|
waitForCompletion(testTimeout?: number, testNamePattern?: GeoSpecTestNamePattern): Promise<void>;
|
|
22
22
|
};
|
|
23
23
|
/** Per-module collector configuration; native subject/engine lifetime stays with the host. @public */
|
|
@@ -25,6 +25,8 @@ type GeoSpecCollectorOptions = {
|
|
|
25
25
|
matcherWallBackstop?: number;
|
|
26
26
|
forensic?: boolean;
|
|
27
27
|
nativeAssertions: GeoSpecAssertionClientOptions;
|
|
28
|
+
/** Observes each selected test as it starts and settles, for host progress reporting. */
|
|
29
|
+
onTestEvent?: (event: GeoSpecTestEvent) => void;
|
|
28
30
|
};
|
|
29
31
|
/**
|
|
30
32
|
* Assertion error thrown by GeoSpec matchers when an expectation does not hold.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)||`GeoSpec assertion failed.`),this.name=`GeoSpecAssertionError`,this.diagnostics=Object.freeze([...e])}};const
|
|
1
|
+
import{assertGeoSpecAuthoredWorkUnitLimit as e}from"../engine/client.mjs";import{resolveGeoSpecSubject as t}from"../model/subject.mjs";import{GeoSpecAssertionError as n,createGeoSpecAssertionClient as r,createGeoSpecMatcherMethods as i}from"../assertion-client/client.mjs";import{diagnosticForTransport as a,geometryDiagnosticSchema as o}from"../model/errors.mjs";import{matchesGeoSpecTestName as s}from"./filter.mjs";import{geoSpecTimeoutCode as c}from"./timeout-codes.mjs";import{regionScopeRefusal as l}from"../model/region-scope.mjs";const u=`__GEOSPEC_COLLECTOR__`,d=globalThis,f=e=>typeof e==`object`&&!!e&&`then`in e&&typeof e.then==`function`;var p=class extends Error{diagnostics;constructor(e){super(e.map(e=>e.message).join(`
|
|
2
|
+
`)||`GeoSpec assertion failed.`),this.name=`GeoSpecAssertionError`,this.diagnostics=Object.freeze([...e])}},m=class extends Error{testTimeout;constructor(e){super(`GeoSpec test timed out after ${e}ms.`),this.name=`GeoSpecTestTimeoutError`,this.testTimeout=e}};const h=e=>{if(e instanceof p)return[...e.diagnostics];if(e instanceof m)return[{code:c.test,severity:`error`,message:`${e.message} The test still ran to completion before the run moved on; this is a wall-clock timeout, not a geometry verdict.`,suggestion:`Keep the assertion and the model as designed. Raise testTimeout (CLI --test-timeout) so the requirement can finish; if this host cannot give it the time, report it as not decided at this capacity.`,details:{testTimeout:e.testTimeout}}];if(typeof e==`object`&&e&&Reflect.get(e,`name`)===`GeoSpecModelLoadError`){let t=Reflect.get(e,`diagnostics`);if(Array.isArray(t)&&t.length>0)try{return t.map(e=>a(g(e)))}catch{}}let t=typeof e==`object`&&e&&typeof Reflect.get(e,`message`)==`string`?String(Reflect.get(e,`message`)):String(e),{details:n}=a({code:`TEST_FAILED`,severity:`error`,message:t,details:e});return t.includes(`model.volume is not a function`)?[{code:`GEOSPEC_SUBJECT_API_MISUSE`,severity:`error`,message:`GeoSpec GeometrySubject does not expose model.volume().`,suggestion:`Use expectGeo(model).toHaveVolume({ value, tolerance }) instead of reading model.volume().`,details:n}]:/Cannot read properties of undefined \(reading 'bounds'\)/u.test(t)?[{code:`GEOSPEC_SUBJECT_API_MISUSE`,severity:`error`,message:`GeoSpec GeometrySubject does not expose model.boundingBox.bounds.`,suggestion:`Use expectGeo(model).toHaveBoundingBox({ min, max, size, center, tolerance }) instead of reading model.boundingBox.`,details:n}]:[{code:`TEST_FAILED`,severity:`error`,message:t,details:n}]},g=e=>o.parse(e),_=(e,t)=>{if(e.passed=t.length===0,e.diagnostics=t,t.length>0)throw new p(t);return e},v=async(e,t)=>{if(t===void 0)return e;let n;try{return await Promise.race([e,new Promise((e,r)=>{n=setTimeout(()=>{r(new m(t))},t)})])}finally{n!==void 0&&clearTimeout(n)}},y=(e,t)=>{for(let n of e)n.status===`rejected`&&t(n.reason)},b=()=>{let e=d[u];if(!x(e))throw Error(`GeoSpec collector is not active. Run the module through runGeoSpecModule().`);return e},x=e=>typeof e==`object`&&!!e&&`describe`in e&&`it`in e&&`expectGeo`in e&&`tests`in e,S=e=>typeof e==`object`&&!!e&&`suite`in e&&`name`in e&&`assertions`in e;function C(o){let c=r(o.nativeAssertions),u=[],d=[],m=[],b=[],x=new WeakSet,C,w=!1,T=(e,t)=>{try{o.onTestEvent?.({type:e,test:t})}catch{}},E=(e,t)=>{m.push((async()=>{try{await e}catch(e){t.onError(e)}finally{t.onFinally()}})())},D=e=>{d.push({ordinal:d.length,suite:[...u],name:e,assertions:[],status:`skipped`,diagnostics:[]})},O=(e,r)=>{if(!S(C))throw Error(`expectGeo() must be called inside it().`);let i={kind:e.kind,subject:null,expected:e.expected};C.assertions.push(i);let s=performance.now();try{let s=t(e.subject,o.nativeAssertions.engine);i.subject=s.identity,s.load!==void 0&&(i.loadId=s.load.loadId);let u=s.load?.region;u!==void 0&&(i.region={min:[...u.min],max:[...u.max]});let d=l(u,e.kind);if(d!==void 0)return _(i,[d]);let f=r?.workUnitLimit??s.load?.workUnitLimit,p=c.expectGeo(s.identity,f===void 0?void 0:{workUnitLimit:f}),m=(e.polarity===`negative`?p.not:p)[e.matcher],h;try{h=m(...e.arguments)}catch(e){if(!(e instanceof n))throw e;h=e.report}if(i.report=h,h.status===`passed`)return _(i,[]);let v=h.diagnostics.map(e=>a(g(e)));return _(i,v.length>0?v:[{code:`GEOSPEC_NATIVE_ASSERTION_FAILED`,severity:`error`,message:`Native claim '${h.claimId}' ended with status '${h.status}'.`,details:{claimId:h.claimId,status:h.status}}])}catch(e){throw e instanceof p&&i.report!==void 0&&x.add(e),i.passed=!1,i.diagnostics??=h(e),e}finally{i.durationMs=performance.now()-s}};return{describe(e,t){u.push(e);try{let n=t();if(f(n)){let t=[...u];E(n,{onError(n){d.push({ordinal:d.length,suite:t,name:e,assertions:[],status:`failed`,diagnostics:h(n)})},onFinally(){u.pop()}});return}}catch(t){d.push({ordinal:d.length,suite:[...u],name:e,assertions:[],status:`failed`,diagnostics:h(t)})}u.pop()},describeSkip(e){D(e)},it(e,t){let n={ordinal:d.length,suite:[...u],name:e,assertions:[],status:`not-run`,diagnostics:[]};d.push(n),b.push({test:n,function_:t})},itSkip(e){D(e)},expectGeo(t,n){e(n?.workUnitLimit,`expectGeo workUnitLimit`,o.nativeAssertions.maximumWorkUnitLimit);let r=e=>O(e,n);return Object.assign(i({invoke:r,polarity:`positive`,subject:t}),{not:i({invoke:r,polarity:`negative`,subject:t})})},async waitForCompletion(e,t){if(w)return;w=!0;let n=Promise.allSettled(m);try{await v(n,e)}catch(e){throw await n,e}for(let n of b){if(!s(n.test,t))continue;let r=C;C=n.test,n.test.status=`passed`,T(`test-start`,n.test);let i=performance.now(),a=[],o=e=>{a.some(t=>Object.is(t,e))||a.push(e)};try{let t;try{t=Promise.resolve(n.function_()),await v(t,e)}catch(e){o(e)}if(t!==void 0&&y(await Promise.allSettled([t]),o),a.length>0||n.test.assertions.some(e=>e.passed===!1)){n.test.status=`failed`;for(let e of a)n.test.diagnostics.push(...h(e));let{assertions:e}=n.test;if(!(a.some(e=>!(e instanceof p)||!x.has(e))||e.some(e=>e.passed===!1&&(e.report===void 0||e.report.status===`invalid`||e.report.status===`engine-error`)))){let t=e.map(e=>e.report?.status);n.test.status=t.includes(`failed`)?`failed`:t.some(e=>e!==void 0&&e!==`passed`&&e!==`unsupported`)?`inconclusive`:t.includes(`unsupported`)?`unsupported`:`failed`}}}finally{C=r,n.test.durationMs=performance.now()-i,T(`test-complete`,n.test)}}},tests:d}}const w=()=>{Reflect.deleteProperty(d,u)},T=e=>{d[u]=e};export{p as GeoSpecAssertionError,w as clearCollectorGlobals,u as collectorGlobalKey,C as createCollector,b as getCollector,T as installCollector};
|
package/dist/runner/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { GeoSpecAssemblyOccurrenceExpectation, GeoSpecAssemblyOccurrencesExpectation, GeoSpecAssertion, GeoSpecAxisExpectation, GeoSpecBoundingBoxExpectation, GeoSpecCenterOfMassExpectation, GeoSpecChamferFeatureExpectation, GeoSpecCircularHoleExpectation, GeoSpecCircularHolePatternExpectation, GeoSpecComponentInterferenceAllowance, GeoSpecComponentInterferenceExpectation, GeoSpecComponentInterferencePairExpectation, GeoSpecConnectedComponentsExpectation, GeoSpecCylindricalFaceExpectation, GeoSpecFilletFeatureExpectation, GeoSpecGeometrySelector, GeoSpecMassExpectation, GeoSpecMatcher, GeoSpecMeshIntegrityExpectation, GeoSpecMinimumWallThicknessExpectation, GeoSpecModuleBundleCache, GeoSpecNumericExpectation, GeoSpecPlanarFaceExpectation, GeoSpecPointExpectation, GeoSpecProductStructureExpectation, GeoSpecRunFailure, GeoSpecRunResult, GeoSpecRunSuccess, GeoSpecSpatialRelationshipExpectation, GeoSpecSpatialRelationshipsExpectation, GeoSpecStepUnitsExpectation, GeoSpecSurfaceAreaExpectation, GeoSpecTestCase, GeoSpecTestStatus, GeoSpecTopologyCountsExpectation, GeoSpecValidBrepExpectation, GeoSpecVolumeExpectation, RunGeoSpecModuleOptions } from "./types.mjs";
|
|
1
|
+
import { GeoSpecAssemblyOccurrenceExpectation, GeoSpecAssemblyOccurrencesExpectation, GeoSpecAssertion, GeoSpecAxisExpectation, GeoSpecBoundingBoxExpectation, GeoSpecCenterOfMassExpectation, GeoSpecChamferFeatureExpectation, GeoSpecCircularHoleExpectation, GeoSpecCircularHolePatternExpectation, GeoSpecComponentInterferenceAllowance, GeoSpecComponentInterferenceExpectation, GeoSpecComponentInterferencePairExpectation, GeoSpecConnectedComponentsExpectation, GeoSpecCylindricalFaceExpectation, GeoSpecFilletFeatureExpectation, GeoSpecGeometrySelector, GeoSpecMassExpectation, GeoSpecMatcher, GeoSpecMeshIntegrityExpectation, GeoSpecMinimumWallThicknessExpectation, GeoSpecModuleBundleCache, GeoSpecNumericExpectation, GeoSpecPlanarFaceExpectation, GeoSpecPointExpectation, GeoSpecProductStructureExpectation, GeoSpecRunFailure, GeoSpecRunResult, GeoSpecRunSuccess, GeoSpecSpatialRelationshipExpectation, GeoSpecSpatialRelationshipsExpectation, GeoSpecStepUnitsExpectation, GeoSpecSurfaceAreaExpectation, GeoSpecTestCase, GeoSpecTestEvent, GeoSpecTestStatus, GeoSpecTopologyCountsExpectation, GeoSpecValidBrepExpectation, GeoSpecVolumeExpectation, RunGeoSpecModuleOptions } from "./types.mjs";
|
|
2
2
|
import { GeoSpecTestNamePattern, compileGeoSpecTestNamePattern, filterGeoSpecTests, matchesGeoSpecTestName } from "./filter.mjs";
|
|
3
3
|
import { GeoSpecAssertionError, GeoSpecCollector, GeoSpecCollectorOptions, clearCollectorGlobals, createCollector, installCollector } from "./collector.mjs";
|
|
4
4
|
import { DiscoverGeoSpecFilesOptions, GeoSpecDiscoveryFileKind, GeoSpecDiscoveryFileStat, GeoSpecDiscoveryFileSystem, GeoSpecDiscoveryResult, defaultGeoSpecIgnoredDirectories, defaultGeoSpecInclude, discoverGeoSpecFiles, isGeoSpecTestFile } from "./discovery.mjs";
|
|
5
5
|
import { runGeoSpecModule } from "./run-geospec-module.mjs";
|
|
6
|
-
|
|
6
|
+
import { GeoSpecTimeoutCode, geoSpecTimeoutCode, isGeoSpecTimeoutCode } from "./timeout-codes.mjs";
|
|
7
|
+
export { type DiscoverGeoSpecFilesOptions, type GeoSpecAssemblyOccurrenceExpectation, type GeoSpecAssemblyOccurrencesExpectation, type GeoSpecAssertion, GeoSpecAssertionError, type GeoSpecAxisExpectation, type GeoSpecBoundingBoxExpectation, type GeoSpecCenterOfMassExpectation, type GeoSpecChamferFeatureExpectation, type GeoSpecCircularHoleExpectation, type GeoSpecCircularHolePatternExpectation, type GeoSpecCollector, type GeoSpecCollectorOptions, type GeoSpecComponentInterferenceAllowance, type GeoSpecComponentInterferenceExpectation, type GeoSpecComponentInterferencePairExpectation, type GeoSpecConnectedComponentsExpectation, type GeoSpecCylindricalFaceExpectation, type GeoSpecDiscoveryFileKind, type GeoSpecDiscoveryFileStat, type GeoSpecDiscoveryFileSystem, type GeoSpecDiscoveryResult, type GeoSpecFilletFeatureExpectation, type GeoSpecGeometrySelector, type GeoSpecMassExpectation, type GeoSpecMatcher, type GeoSpecMeshIntegrityExpectation, type GeoSpecMinimumWallThicknessExpectation, type GeoSpecModuleBundleCache, type GeoSpecNumericExpectation, type GeoSpecPlanarFaceExpectation, type GeoSpecPointExpectation, type GeoSpecProductStructureExpectation, type GeoSpecRunFailure, type GeoSpecRunResult, type GeoSpecRunSuccess, type GeoSpecSpatialRelationshipExpectation, type GeoSpecSpatialRelationshipsExpectation, type GeoSpecStepUnitsExpectation, type GeoSpecSurfaceAreaExpectation, type GeoSpecTestCase, type GeoSpecTestEvent, type GeoSpecTestNamePattern, type GeoSpecTestStatus, type GeoSpecTimeoutCode, type GeoSpecTopologyCountsExpectation, type GeoSpecValidBrepExpectation, type GeoSpecVolumeExpectation, type RunGeoSpecModuleOptions, clearCollectorGlobals, compileGeoSpecTestNamePattern, createCollector, defaultGeoSpecIgnoredDirectories, defaultGeoSpecInclude, discoverGeoSpecFiles, filterGeoSpecTests, geoSpecTimeoutCode, installCollector, isGeoSpecTestFile, isGeoSpecTimeoutCode, matchesGeoSpecTestName, runGeoSpecModule };
|
package/dist/runner/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{compileGeoSpecTestNamePattern as e,filterGeoSpecTests as t,matchesGeoSpecTestName as n}from"./filter.mjs";import{
|
|
1
|
+
import{compileGeoSpecTestNamePattern as e,filterGeoSpecTests as t,matchesGeoSpecTestName as n}from"./filter.mjs";import{geoSpecTimeoutCode as r,isGeoSpecTimeoutCode as i}from"./timeout-codes.mjs";import{GeoSpecAssertionError as a,clearCollectorGlobals as o,createCollector as s,installCollector as c}from"./collector.mjs";import{defaultGeoSpecIgnoredDirectories as l,defaultGeoSpecInclude as u,discoverGeoSpecFiles as d,isGeoSpecTestFile as f}from"./discovery.mjs";import{runGeoSpecModule as p}from"./run-geospec-module.mjs";export{a as GeoSpecAssertionError,o as clearCollectorGlobals,e as compileGeoSpecTestNamePattern,s as createCollector,l as defaultGeoSpecIgnoredDirectories,u as defaultGeoSpecInclude,d as discoverGeoSpecFiles,t as filterGeoSpecTests,r as geoSpecTimeoutCode,c as installCollector,f as isGeoSpecTestFile,i as isGeoSpecTimeoutCode,n as matchesGeoSpecTestName,p as runGeoSpecModule};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createGeoSpecNativeModelLoader as e}from"../../model/native-model-loader.mjs";import{createSerialGeoSpecRunner as t}from"../worker/serial-runner.mjs";const n=new TextDecoder(`utf-8`,{fatal:!0}),r=(e,t)=>{let r=JSON.parse(n.decode(e));if(typeof r!=`object`||!r||!(`plan`in r))throw TypeError(`Native GeoSpec assertion requires a plan with admitted subjects.`);let{plan:i}=r;if(typeof i!=`object`||!i||!(`subjects`in i)||!Array.isArray(i.subjects)||i.subjects.length===0)throw TypeError(`Native GeoSpec assertion requires admitted subjects.`);for(let e of i.subjects){if(typeof e!=`object`||!e)throw TypeError(`Native GeoSpec assertion requires admitted subjects.`);let n=`subjectHash`in e;if(n===`contentHash`in e)throw TypeError(`Native GeoSpec assertion requires one admitted subject identity.`);let r=n?e.subjectHash:`contentHash`in e?e.contentHash:void 0;if(typeof r!=`string`||!t.has(r))throw TypeError(`Native GeoSpec subject was not admitted by this run.`)}},i=i=>{let a=i.nativeModelLoader??e({...i.model,engine:i.nativeAssertions.engine}),o=new Set,s=Object.assign(async e=>{let t=await a(e);return o.add(t.subjectHash),t},{async releaseAll(){try{await a.releaseAll()}finally{o.clear()}}}),c=i.nativeAssertions.engine,l={evaluateClaim(e){return r(e,o),c.evaluateClaim(e)},processRequest(e){let t=JSON.parse(n.decode(e));return typeof t==`object`&&t&&`method`in t&&t.method===`submitClaims`&&r(e,o),c.processRequest(e)},ingestSubject:(e,t,n)=>c.ingestSubject(e,t,n),subjectHandle:e=>c.subjectHandle(e),releaseSubject:e=>c.releaseSubject(e)},u=t({filesystem:i.filesystem,nativeAssertions:{...i.nativeAssertions,engine:l},nativeModelLoader:s,...i.builtinModules===void 0?{}:{builtinModules:i.builtinModules}});return{...u,async close(){try{await u.close()}finally{o.clear()}}}};export{i as createNativeGeoSpecRunner};
|
|
1
|
+
import{createGeoSpecNativeModelLoader as e}from"../../model/native-model-loader.mjs";import{createSerialGeoSpecRunner as t}from"../worker/serial-runner.mjs";const n=new TextDecoder(`utf-8`,{fatal:!0}),r=(e,t)=>{let r=JSON.parse(n.decode(e));if(typeof r!=`object`||!r||!(`plan`in r))throw TypeError(`Native GeoSpec assertion requires a plan with admitted subjects.`);let{plan:i}=r;if(typeof i!=`object`||!i||!(`subjects`in i)||!Array.isArray(i.subjects)||i.subjects.length===0)throw TypeError(`Native GeoSpec assertion requires admitted subjects.`);for(let e of i.subjects){if(typeof e!=`object`||!e)throw TypeError(`Native GeoSpec assertion requires admitted subjects.`);let n=`subjectHash`in e;if(n===`contentHash`in e)throw TypeError(`Native GeoSpec assertion requires one admitted subject identity.`);let r=n?e.subjectHash:`contentHash`in e?e.contentHash:void 0;if(typeof r!=`string`||!t.has(r))throw TypeError(`Native GeoSpec subject was not admitted by this run.`)}},i=i=>{let a=i.nativeModelLoader??e({...i.model,engine:i.nativeAssertions.engine,...i.nativeAssertions.maximumWorkUnitLimit===void 0?{}:{maximumWorkUnitLimit:i.nativeAssertions.maximumWorkUnitLimit}}),o=new Set,s=Object.assign(async e=>{let t=await a(e);return o.add(t.subjectHash),t},{async releaseAll(){try{await a.releaseAll()}finally{o.clear()}}}),c=i.nativeAssertions.engine,l={evaluateClaim(e){return r(e,o),c.evaluateClaim(e)},processRequest(e){let t=JSON.parse(n.decode(e));return typeof t==`object`&&t&&`method`in t&&t.method===`submitClaims`&&r(e,o),c.processRequest(e)},ingestSubject:(e,t,n)=>c.ingestSubject(e,t,n),subjectHandle:e=>c.subjectHandle(e),releaseSubject:e=>c.releaseSubject(e)},u=t({filesystem:i.filesystem,nativeAssertions:{...i.nativeAssertions,engine:l},nativeModelLoader:s,...i.builtinModules===void 0?{}:{builtinModules:i.builtinModules}});return{...u,async close(){try{await u.close()}finally{o.clear()}}}};export{i as createNativeGeoSpecRunner};
|
|
@@ -16,7 +16,7 @@ export const it = (name, fn) => getRunBinding().collector.it(name, fn);
|
|
|
16
16
|
it.skip = (name, fn) => getRunBinding().collector.itSkip(name, fn);
|
|
17
17
|
|
|
18
18
|
export const test = it;
|
|
19
|
-
export const expectGeo = (subject) => getRunBinding().collector.expectGeo(subject);
|
|
19
|
+
export const expectGeo = (subject, options) => getRunBinding().collector.expectGeo(subject, options);
|
|
20
20
|
`,C=e=>`
|
|
21
21
|
${x(e)}
|
|
22
22
|
export const GeoSpecModelLoadError = getRunBinding().geoSpecModelLoadError;
|
|
@@ -44,4 +44,4 @@ export const createModelLoader = (defaults = {}) => {
|
|
|
44
44
|
}
|
|
45
45
|
return factory(defaults);
|
|
46
46
|
};
|
|
47
|
-
`;async function w(m){let h=a(m.testNamePattern);if(!h.success)return{success:!1,issues:[h.issue]};let g=v(m.filesystem),_=await l({filesystem:g.filesystem}),x=s({...m.matcherWallBackstop===void 0?{}:{matcherWallBackstop:m.matcherWallBackstop},...m.forensic===void 0?{}:{forensic:m.forensic},nativeAssertions:m.nativeAssertions}),w=await y(m),T=f(),E=b(),D=new Set,O=[],k=async()=>{do{let e=[...D];await Promise.allSettled(e);for(let t of e)D.delete(t)}while(D.size>0)},A=m.nativeModelLoader,j=r(m.nativeAssertions),M=!0,N=A===void 0?void 0:n=>{let r=O.length,a=`${T}:load:${r+1}`;O.push({loadId:a,status:`unavailable`});let o=(async()=>{try{let i=await A(n),{load:o,...s}=i,c=t(i),l=o===void 0?void 0:{...structuredClone(o),loadId:a};return O[r]={loadId:a,status:l?.status??`unavailable`,subject:s,...l===void 0?{}:{evidence:l}},e({engine:m.nativeAssertions.engine,client:j,identity:s,...l===void 0?{}:{load:l},isLive:()=>M,...c===void 0?{}:{ensureResident:c}})}catch(e){throw O[r]={loadId:a,status:`failed`,error:e instanceof Error?e.message:String(e),...e instanceof i?{diagnostics:e.diagnostics}:{}},e}})();return D.add(o.catch(()=>void 0)),D.add(o),o};E.set(T,{collector:x,geoSpecModelLoadError:i,...N?{nativeModelLoader:N}:{},...N?{createModelLoader:t=>{if(t.engine!==void 0||t.readSource!==void 0)throw TypeError(`Authored VM model defaults cannot replace the admitting host.`);let r=0,i=new Set,a=new Set,o,s=async i=>{let o=r,s=await N({...t,...i}),c=n(s);return c.lease!==void 0&&a.add(c.lease),e({...c,isLive:()=>c.isLive()&&r===o})},c=e=>{let t=s(e);return i.add(t),t},l=async()=>{do{let e=[...i];await Promise.allSettled(e);for(let t of e)i.delete(t)}while(i.size>0);r+=1;let e=[];for(let t of a)try{t.dispose(),a.delete(t)}catch(t){e.push(t)}if(e.length>0)throw AggregateError(e,`GeoSpec model scope disposal failed.`)};return Object.assign(c,{dispose(){return o??=l().finally(()=>{o=void 0}),o}})}}:{}}),_.registerModule(`geospec`,{version:`0.0.0-poc`,code:S(T)}),_.registerModule(`geospec/model`,{version:`0.0.0-poc`,code:C(T)});for(let[e,t]of Object.entries(m.builtinModules??{}))_.registerModule(e,t);try{let e=w?.bundle??await _.bundle(m.entryPath);if(!e.success)return{success:!1,issues:e.issues,bundle:e};let t=g.reads();m.bundleCache!==void 0&&w===void 0&&t!==void 0&&m.bundleCache.set(m.entryPath,{builtinIdentity:p(m),runToken:T,bundle:e,bundlerReads:t});let n=await _.execute(w===void 0?e.code:e.code.replaceAll(w.runToken,T)),r=async()=>{let t={},n=g.reads()!==void 0;for(let e of w?.bundlerReads??g.observed()){if(e.question===`exists`||typeof e.answer==`boolean`)continue;let r=await c(typeof e.answer==`string`?new TextEncoder().encode(e.answer):e.answer);n&&=t[e.path]===void 0||t[e.path]===`sha256:${r}`,t[e.path]=`sha256:${r}`}let r=new Map(Object.entries(t));for(let e of O){let{evidence:t}=e;for(let e of t?.exportOptions===void 0?t?.artifacts??[]:[])if(e.sourcePath!==void 0){let t=`sha256:${e.sha256}`;n&&=!r.has(e.sourcePath)||r.get(e.sourcePath)===t,r.set(e.sourcePath,t)}if(t?.sourcePath!==void 0&&t.exportOptions===void 0){let e=t.artifacts[0];if(e!==void 0){let i=`sha256:${e.sha256}`;n&&=!r.has(t.sourcePath)||r.get(t.sourcePath)===i,r.set(t.sourcePath,i)}}for(let[t,i]of Object.entries(e.evidence?.sourceRevision?.files??{}))n&&=!r.has(t)||r.get(t)===i,r.set(t,i)}return{status:n?O.some(e=>e.status!==`complete`)?`unavailable`:`complete`:`mixed`,modules:[{entryPath:m.entryPath,bundleSha256:await c(new TextEncoder().encode(w===void 0?e.code:e.code.replaceAll(w.runToken,T))),files:t,consistent:n}],loads:O}},i=e=>({discovered:x.tests.length,selected:e,completed:x.tests.filter(e=>e.status!==`not-run`&&e.status!==`skipped`).length,passed:x.tests.filter(e=>e.status===`passed`).length,failed:x.tests.filter(e=>e.status===`failed`).length,unsupported:x.tests.filter(e=>e.status===`unsupported`).length,inconclusive:x.tests.filter(e=>e.status===`inconclusive`).length,skipped:x.tests.filter(e=>e.status===`skipped`).length,notRun:x.tests.filter(e=>e.status===`not-run`).length});if(!n.success)return await k(),{success:!1,issues:n.issues,bundle:e,tests:x.tests,accounting:i(0),lineage:await r()};if(m.collectOnly===!0)return await x.waitForCompletion(m.testTimeout,/(?!)/u),await k(),{success:!0,passed:!1,tests:x.tests,bundle:e,accounting:i(0),lineage:await r()};await x.waitForCompletion(m.testTimeout,h.pattern),await k();let a=o(x.tests,h.pattern),s=await r();return{success:!0,passed:s.status===`complete`&&a.every(e=>e.status===`passed`||e.status===`skipped`),tests:a,bundle:e,accounting:i(a.length),lineage:s}}finally{await k(),M=!1,E.delete(T),E.size===0&&Reflect.deleteProperty(d,u),_.dispose()}}export{w as runGeoSpecModule};
|
|
47
|
+
`;async function w(m){let h=a(m.testNamePattern);if(!h.success)return{success:!1,issues:[h.issue]};let g=v(m.filesystem),_=await l({filesystem:g.filesystem}),x=s({...m.matcherWallBackstop===void 0?{}:{matcherWallBackstop:m.matcherWallBackstop},...m.forensic===void 0?{}:{forensic:m.forensic},...m.onTestEvent===void 0?{}:{onTestEvent:m.onTestEvent},nativeAssertions:m.nativeAssertions}),w=await y(m),T=f(),E=b(),D=new Set,O=[],k=async()=>{do{let e=[...D];await Promise.allSettled(e);for(let t of e)D.delete(t)}while(D.size>0)},A=m.nativeModelLoader,j=r(m.nativeAssertions),M=!0,N=A===void 0?void 0:n=>{let r=O.length,a=`${T}:load:${r+1}`;O.push({loadId:a,status:`unavailable`});let o=(async()=>{try{let i=await A(n),{load:o,...s}=i,c=t(i),l=o===void 0?void 0:{...structuredClone(o),loadId:a};return O[r]={loadId:a,status:l?.status??`unavailable`,subject:s,...l===void 0?{}:{evidence:l}},e({engine:m.nativeAssertions.engine,client:j,identity:s,...l===void 0?{}:{load:l},isLive:()=>M,...c===void 0?{}:{ensureResident:c}})}catch(e){throw O[r]={loadId:a,status:`failed`,error:e instanceof Error?e.message:String(e),...e instanceof i?{diagnostics:e.diagnostics}:{}},e}})();return D.add(o.catch(()=>void 0)),D.add(o),o};E.set(T,{collector:x,geoSpecModelLoadError:i,...N?{nativeModelLoader:N}:{},...N?{createModelLoader:t=>{if(t.engine!==void 0||t.readSource!==void 0)throw TypeError(`Authored VM model defaults cannot replace the admitting host.`);let r=0,i=new Set,a=new Set,o,s=async i=>{let o=r,s=await N({...t,...i}),c=n(s);return c.lease!==void 0&&a.add(c.lease),e({...c,isLive:()=>c.isLive()&&r===o})},c=e=>{let t=s(e);return i.add(t),t},l=async()=>{do{let e=[...i];await Promise.allSettled(e);for(let t of e)i.delete(t)}while(i.size>0);r+=1;let e=[];for(let t of a)try{t.dispose(),a.delete(t)}catch(t){e.push(t)}if(e.length>0)throw AggregateError(e,`GeoSpec model scope disposal failed.`)};return Object.assign(c,{dispose(){return o??=l().finally(()=>{o=void 0}),o}})}}:{}}),_.registerModule(`geospec`,{version:`0.0.0-poc`,code:S(T)}),_.registerModule(`geospec/model`,{version:`0.0.0-poc`,code:C(T)});for(let[e,t]of Object.entries(m.builtinModules??{}))_.registerModule(e,t);try{let e=w?.bundle??await _.bundle(m.entryPath);if(!e.success)return{success:!1,issues:e.issues,bundle:e};let t=g.reads();m.bundleCache!==void 0&&w===void 0&&t!==void 0&&m.bundleCache.set(m.entryPath,{builtinIdentity:p(m),runToken:T,bundle:e,bundlerReads:t});let n=await _.execute(w===void 0?e.code:e.code.replaceAll(w.runToken,T)),r=async()=>{let t={},n=g.reads()!==void 0;for(let e of w?.bundlerReads??g.observed()){if(e.question===`exists`||typeof e.answer==`boolean`)continue;let r=await c(typeof e.answer==`string`?new TextEncoder().encode(e.answer):e.answer);n&&=t[e.path]===void 0||t[e.path]===`sha256:${r}`,t[e.path]=`sha256:${r}`}let r=new Map(Object.entries(t));for(let e of O){let{evidence:t}=e;for(let e of t?.exportOptions===void 0?t?.artifacts??[]:[])if(e.sourcePath!==void 0){let t=`sha256:${e.sha256}`;n&&=!r.has(e.sourcePath)||r.get(e.sourcePath)===t,r.set(e.sourcePath,t)}if(t?.sourcePath!==void 0&&t.exportOptions===void 0){let e=t.artifacts[0];if(e!==void 0){let i=`sha256:${e.sha256}`;n&&=!r.has(t.sourcePath)||r.get(t.sourcePath)===i,r.set(t.sourcePath,i)}}for(let[t,i]of Object.entries(e.evidence?.sourceRevision?.files??{}))n&&=!r.has(t)||r.get(t)===i,r.set(t,i)}return{status:n?O.some(e=>e.status!==`complete`)?`unavailable`:`complete`:`mixed`,modules:[{entryPath:m.entryPath,bundleSha256:await c(new TextEncoder().encode(w===void 0?e.code:e.code.replaceAll(w.runToken,T))),files:t,consistent:n}],loads:O}},i=e=>({discovered:x.tests.length,selected:e,completed:x.tests.filter(e=>e.status!==`not-run`&&e.status!==`skipped`).length,passed:x.tests.filter(e=>e.status===`passed`).length,failed:x.tests.filter(e=>e.status===`failed`).length,unsupported:x.tests.filter(e=>e.status===`unsupported`).length,inconclusive:x.tests.filter(e=>e.status===`inconclusive`).length,skipped:x.tests.filter(e=>e.status===`skipped`).length,notRun:x.tests.filter(e=>e.status===`not-run`).length});if(!n.success)return await k(),{success:!1,issues:n.issues,bundle:e,tests:x.tests,accounting:i(0),lineage:await r()};if(m.collectOnly===!0)return await x.waitForCompletion(m.testTimeout,/(?!)/u),await k(),{success:!0,passed:!1,tests:x.tests,bundle:e,accounting:i(0),lineage:await r()};await x.waitForCompletion(m.testTimeout,h.pattern),await k();let a=o(x.tests,h.pattern),s=await r();return{success:!0,passed:s.status===`complete`&&a.every(e=>e.status===`passed`||e.status===`skipped`),tests:a,bundle:e,accounting:i(a.length),lineage:s}}finally{await k(),M=!1,E.delete(T),E.size===0&&Reflect.deleteProperty(d,u),_.dispose()}}export{w as runGeoSpecModule};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/runner/timeout-codes.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* One timeout vocabulary for every GeoSpec host.
|
|
4
|
+
*
|
|
5
|
+
* GeoSpec has three wall-clock bounds, and each host reports the ones it
|
|
6
|
+
* applies with the same code, so a spec that times out reads the same whether
|
|
7
|
+
* it ran in the browser worker, the Node pool or the CLI:
|
|
8
|
+
*
|
|
9
|
+
* | Code | Bound | Set by | Hosts |
|
|
10
|
+
* | ----------------------- | --------------------------------------------- | --------------------------------------------- | --------------------- |
|
|
11
|
+
* | `GEOSPEC_TEST_TIMEOUT` | One test's async body | `test_model.testTimeout`, CLI `--test-timeout` | Every host |
|
|
12
|
+
* | `GEOSPEC_SHARD_TIMEOUT` | One pool shard; its worker is terminated | CLI `--shard-timeout`, pool `shardTimeout` | Node pool |
|
|
13
|
+
* | `GEOSPEC_RUN_TIMEOUT` | One whole run; completed requirements survive | The host's run budget | Browser worker runner |
|
|
14
|
+
*
|
|
15
|
+
* None of them is a geometry verdict: a timed-out requirement is never a pass,
|
|
16
|
+
* and the deterministic work-unit budget inside the engine (`MATCHER_TIMEOUT`)
|
|
17
|
+
* is a separate, non-wall-clock refusal.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Codes for GeoSpec wall-clock timeouts, one per bound.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
declare const geoSpecTimeoutCode: {
|
|
27
|
+
/** A test's async body outlived `testTimeout` / `--test-timeout`. */
|
|
28
|
+
readonly test: "GEOSPEC_TEST_TIMEOUT";
|
|
29
|
+
/** A pool shard outlived the non-verdict `--shard-timeout` watchdog. */
|
|
30
|
+
readonly shard: "GEOSPEC_SHARD_TIMEOUT";
|
|
31
|
+
/** A whole run outlived its host run budget. */
|
|
32
|
+
readonly run: "GEOSPEC_RUN_TIMEOUT";
|
|
33
|
+
};
|
|
34
|
+
/** One GeoSpec timeout code. @public */
|
|
35
|
+
type GeoSpecTimeoutCode = (typeof geoSpecTimeoutCode)[keyof typeof geoSpecTimeoutCode];
|
|
36
|
+
/**
|
|
37
|
+
* Whether a diagnostic or issue code belongs to the GeoSpec timeout family.
|
|
38
|
+
*
|
|
39
|
+
* @param code - Any diagnostic or issue code.
|
|
40
|
+
* @returns True for {@link geoSpecTimeoutCode} values.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
declare const isGeoSpecTimeoutCode: (code: string) => code is GeoSpecTimeoutCode;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { GeoSpecTimeoutCode, geoSpecTimeoutCode, isGeoSpecTimeoutCode };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={test:`GEOSPEC_TEST_TIMEOUT`,shard:`GEOSPEC_SHARD_TIMEOUT`,run:`GEOSPEC_RUN_TIMEOUT`},t=new Set(Object.values(e)),n=e=>t.has(e);export{e as geoSpecTimeoutCode,n as isGeoSpecTimeoutCode};
|
package/dist/runner/types.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GeometryDiagnostic, Vec3 } from "../mesh/types.mjs";
|
|
2
2
|
import { GeometrySelector } from "../selector/types.mjs";
|
|
3
|
+
import { GeoSpecLoadRegion } from "../model/types.mjs";
|
|
3
4
|
import { GeoSpecModelLoadEvidence, GeoSpecNativeModelLoader } from "../model/native-model-loader.mjs";
|
|
4
5
|
import { GeoSpecCanonicalClaimReport, GeoSpecNativeSubject } from "../engine/client.mjs";
|
|
5
6
|
import { GeoSpecAssertionClientOptions } from "../assertion-client/client.mjs";
|
|
@@ -132,6 +133,20 @@ type GeoSpecMassExpectation = {
|
|
|
132
133
|
density?: number;
|
|
133
134
|
tolerance?: number;
|
|
134
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Per-chain options accepted by `expectGeo(subject, options)`.
|
|
138
|
+
*
|
|
139
|
+
* @public
|
|
140
|
+
*/
|
|
141
|
+
type GeoSpecExpectOptions = {
|
|
142
|
+
/**
|
|
143
|
+
* Deterministic work-unit budget for every claim in this chain: a positive integer no
|
|
144
|
+
* greater than the host's maximum (default `geoSpecMaximumWorkUnitLimit`, 512 000 000). Omitted uses the subject's
|
|
145
|
+
* `loadModel` budget, then the host's, then the engine default. Raise it to retry a
|
|
146
|
+
* `MATCHER_TIMEOUT` refusal whose `details.used` exceeded `details.limit`.
|
|
147
|
+
*/
|
|
148
|
+
readonly workUnitLimit?: number;
|
|
149
|
+
};
|
|
135
150
|
/**
|
|
136
151
|
* Center-of-mass expectation accepted by
|
|
137
152
|
* `expectGeo(...).toHaveCenterOfMass(...)`.
|
|
@@ -139,6 +154,7 @@ type GeoSpecMassExpectation = {
|
|
|
139
154
|
* @public
|
|
140
155
|
*/
|
|
141
156
|
type GeoSpecCenterOfMassExpectation = {
|
|
157
|
+
/** Exact expected point in millimetres; per-axis ranges such as `{ greaterThan }` are not supported. */
|
|
142
158
|
point: GeoSpecPointExpectation;
|
|
143
159
|
tolerance?: number;
|
|
144
160
|
};
|
|
@@ -579,6 +595,11 @@ type GeoSpecAssertion = {
|
|
|
579
595
|
report?: GeoSpecCanonicalClaimReport;
|
|
580
596
|
/** The host load which admitted this assertion's subject; independent of equal geometry hashes. */
|
|
581
597
|
loadId?: string;
|
|
598
|
+
/**
|
|
599
|
+
* The crop this assertion's subject was loaded with. Present only for a region load: the verdict
|
|
600
|
+
* holds for this millimetre box, never for the whole model.
|
|
601
|
+
*/
|
|
602
|
+
region?: GeoSpecLoadRegion;
|
|
582
603
|
/** Wall-clock cost of matcher evaluation in milliseconds (R1: budgeted matchers only). */
|
|
583
604
|
durationMs?: number;
|
|
584
605
|
};
|
|
@@ -665,6 +686,16 @@ type GeoSpecTestCase = {
|
|
|
665
686
|
/** Wall-clock cost of the test body plus its pending assertions, in milliseconds (R1). */
|
|
666
687
|
durationMs?: number;
|
|
667
688
|
};
|
|
689
|
+
/**
|
|
690
|
+
* A selected test starting or settling inside a module run. Observers see the
|
|
691
|
+
* live test case; an observer error never changes its verdict.
|
|
692
|
+
*
|
|
693
|
+
* @public
|
|
694
|
+
*/
|
|
695
|
+
type GeoSpecTestEvent = {
|
|
696
|
+
readonly type: 'test-start' | 'test-complete';
|
|
697
|
+
readonly test: GeoSpecTestCase;
|
|
698
|
+
};
|
|
668
699
|
/**
|
|
669
700
|
* Options for executing a GeoSpec ESM test module.
|
|
670
701
|
*
|
|
@@ -683,6 +714,8 @@ type RunGeoSpecModuleOptions = {
|
|
|
683
714
|
matcherWallBackstop?: number;
|
|
684
715
|
/** Emit structured forensic events for this run. */
|
|
685
716
|
forensic?: boolean;
|
|
717
|
+
/** Observes each selected test as it starts and settles, for host progress reporting. */
|
|
718
|
+
onTestEvent?: (event: GeoSpecTestEvent) => void;
|
|
686
719
|
/**
|
|
687
720
|
* Host-provided protocol-3 compiled assertion client. The host owns engine and
|
|
688
721
|
* admitted subject lifetimes and supplies bindings through builtinModules;
|
|
@@ -740,4 +773,4 @@ type GeoSpecRunFailure = {
|
|
|
740
773
|
*/
|
|
741
774
|
type GeoSpecRunResult = GeoSpecRunSuccess | GeoSpecRunFailure;
|
|
742
775
|
//#endregion
|
|
743
|
-
export { GeoSpecAssemblyOccurrenceExpectation, GeoSpecAssemblyOccurrencesExpectation, GeoSpecAssertion, GeoSpecAxisExpectation, GeoSpecBoundingBoxExpectation, GeoSpecCenterOfMassExpectation, GeoSpecChamferFeatureExpectation, GeoSpecCircularHoleExpectation, GeoSpecCircularHolePatternExpectation, GeoSpecComponentInterferenceAllowance, GeoSpecComponentInterferenceExpectation, GeoSpecComponentInterferencePairExpectation, GeoSpecComponentSelector, GeoSpecConnectedComponentsExpectation, GeoSpecCylindricalFaceExpectation, GeoSpecFilletFeatureExpectation, GeoSpecGeometrySelector, GeoSpecMassExpectation, GeoSpecMatcher, GeoSpecMeshIntegrityExpectation, GeoSpecMinimumWallThicknessExpectation, GeoSpecModuleBundleCache, GeoSpecNoDiagnosticsExpectation, GeoSpecNumericExpectation, GeoSpecPlanarFaceExpectation, GeoSpecPointExpectation, GeoSpecProductStructureExpectation, GeoSpecRunFailure, GeoSpecRunLineage, GeoSpecRunResult, GeoSpecRunSuccess, GeoSpecSpatialRelationshipExpectation, GeoSpecSpatialRelationshipsExpectation, GeoSpecStepUnitsExpectation, GeoSpecSurfaceAreaExpectation, GeoSpecTestAccounting, GeoSpecTestCase, GeoSpecTestStatus, GeoSpecTopologyCountsExpectation, GeoSpecValidBrepExpectation, GeoSpecVoidContinuityExpectation, GeoSpecVoidWaypoint, GeoSpecVolumeExpectation, RunGeoSpecModuleOptions };
|
|
776
|
+
export { GeoSpecAssemblyOccurrenceExpectation, GeoSpecAssemblyOccurrencesExpectation, GeoSpecAssertion, GeoSpecAxisExpectation, GeoSpecBoundingBoxExpectation, GeoSpecCenterOfMassExpectation, GeoSpecChamferFeatureExpectation, GeoSpecCircularHoleExpectation, GeoSpecCircularHolePatternExpectation, GeoSpecComponentInterferenceAllowance, GeoSpecComponentInterferenceExpectation, GeoSpecComponentInterferencePairExpectation, GeoSpecComponentSelector, GeoSpecConnectedComponentsExpectation, GeoSpecCylindricalFaceExpectation, GeoSpecExpectOptions, GeoSpecFilletFeatureExpectation, GeoSpecGeometrySelector, GeoSpecMassExpectation, GeoSpecMatcher, GeoSpecMeshIntegrityExpectation, GeoSpecMinimumWallThicknessExpectation, GeoSpecModuleBundleCache, GeoSpecNoDiagnosticsExpectation, GeoSpecNumericExpectation, GeoSpecPlanarFaceExpectation, GeoSpecPointExpectation, GeoSpecProductStructureExpectation, GeoSpecRunFailure, GeoSpecRunLineage, GeoSpecRunResult, GeoSpecRunSuccess, GeoSpecSpatialRelationshipExpectation, GeoSpecSpatialRelationshipsExpectation, GeoSpecStepUnitsExpectation, GeoSpecSurfaceAreaExpectation, GeoSpecTestAccounting, GeoSpecTestCase, GeoSpecTestEvent, GeoSpecTestStatus, GeoSpecTopologyCountsExpectation, GeoSpecValidBrepExpectation, GeoSpecVoidContinuityExpectation, GeoSpecVoidWaypoint, GeoSpecVolumeExpectation, RunGeoSpecModuleOptions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ManagedGeoSpecNativeModelLoader } from "../../model/native-model-loader.mjs";
|
|
2
|
-
import { GeoSpecRunResult, GeoSpecTestAccounting, RunGeoSpecModuleOptions } from "../types.mjs";
|
|
2
|
+
import { GeoSpecRunResult, GeoSpecTestAccounting, GeoSpecTestCase, RunGeoSpecModuleOptions } from "../types.mjs";
|
|
3
3
|
import { VmFileSystem, VmIssue } from "@taucad/esbuild/vm";
|
|
4
4
|
//#region src/runner/worker/runner-types.d.ts
|
|
5
5
|
/**
|
|
@@ -53,8 +53,15 @@ type GeoSpecRunnerAccounting = GeoSpecTestAccounting & {
|
|
|
53
53
|
cancelled: boolean;
|
|
54
54
|
bailed: boolean;
|
|
55
55
|
};
|
|
56
|
+
/** Identity of a test that has started but not settled. @public */
|
|
57
|
+
type GeoSpecRunnerTestRef = {
|
|
58
|
+
readonly suite: readonly string[];
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly ordinal?: number;
|
|
61
|
+
};
|
|
56
62
|
/**
|
|
57
|
-
* Lifecycle event emitted by GeoSpec worker-style runners.
|
|
63
|
+
* Lifecycle event emitted by GeoSpec worker-style runners. Test events are
|
|
64
|
+
* emitted by in-process runners; a pool reports per file.
|
|
58
65
|
*
|
|
59
66
|
* @public
|
|
60
67
|
*/
|
|
@@ -64,6 +71,14 @@ type GeoSpecRunnerEvent = {
|
|
|
64
71
|
} | {
|
|
65
72
|
type: 'file-start';
|
|
66
73
|
file: string;
|
|
74
|
+
} | {
|
|
75
|
+
type: 'test-start';
|
|
76
|
+
file: string;
|
|
77
|
+
test: GeoSpecRunnerTestRef;
|
|
78
|
+
} | {
|
|
79
|
+
type: 'test-complete';
|
|
80
|
+
file: string;
|
|
81
|
+
test: GeoSpecTestCase;
|
|
67
82
|
} | {
|
|
68
83
|
type: 'file-complete';
|
|
69
84
|
file: string;
|
|
@@ -102,6 +117,12 @@ type GeoSpecRunnerRunOptions = {
|
|
|
102
117
|
testTimeout?: number;
|
|
103
118
|
/** Non-verdict matcher wall backstop. Milliseconds. */
|
|
104
119
|
matcherWallBackstop?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Engine work-unit budget for this run's claims, replacing the runner's
|
|
122
|
+
* `nativeAssertions.workUnitLimit`. A `loadModel` or `expectGeo` budget still
|
|
123
|
+
* wins for its own claims.
|
|
124
|
+
*/
|
|
125
|
+
workUnitLimit?: number;
|
|
105
126
|
/** Emit structured forensic measurements for this run. */
|
|
106
127
|
forensic?: boolean;
|
|
107
128
|
/**
|
|
@@ -143,4 +164,4 @@ type GeoSpecRunner = {
|
|
|
143
164
|
close(): Promise<void>;
|
|
144
165
|
};
|
|
145
166
|
//#endregion
|
|
146
|
-
export { GeoSpecForensicEvent, GeoSpecRunner, GeoSpecRunnerAccounting, GeoSpecRunnerEvent, GeoSpecRunnerFileResult, GeoSpecRunnerOptions, GeoSpecRunnerResult, GeoSpecRunnerRunOptions };
|
|
167
|
+
export { GeoSpecForensicEvent, GeoSpecRunner, GeoSpecRunnerAccounting, GeoSpecRunnerEvent, GeoSpecRunnerFileResult, GeoSpecRunnerOptions, GeoSpecRunnerResult, GeoSpecRunnerRunOptions, GeoSpecRunnerTestRef };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{runGeoSpecModule as e}from"../run-geospec-module.mjs";import{createNoMatchingGeoSpecTestsIssue as t}from"./no-matching-tests-issue.mjs";const n=()=>({code:`GEOSPEC_RUNNER_CLOSED`,message:`GeoSpec runner is closed.`,severity:`error`,type:`runtime`}),r=()=>({code:`GEOSPEC_RUNNER_ACTIVE`,message:`GeoSpec runner already has an active run.`,severity:`error`,type:`runtime`}),i=e=>({code:`GEOSPEC_RUNNER_ABORTED`,message:e?`GeoSpec run aborted: ${e}`:`GeoSpec run aborted.`,severity:`error`,type:`runtime`}),a=e=>({code:`GEOSPEC_RUNNER_BAILED`,message:`GeoSpec run stopped after first failure (--bail): ${e}. Remaining files were not executed.`,severity:`error`,type:`runtime`}),o=e=>{let t=0,n=0;for(let r of e)r.status!==`skipped`&&(r.status===`failed`?n+=1:r.status===`passed`&&(t+=1));return{passed:t,failed:n}},s=s=>{let c={closed:!1},l=new Set,u,d,f=new Map,p=e=>{for(let t of l)t(e)},m=()=>c.aborted,h=e=>({requestedFiles:[...e],completedFiles:[],notRunFiles:[...e],discoveryComplete:!1,discovered:0,selected:0,completed:0,passed:0,failed:0,unsupported:0,inconclusive:0,skipped:0,notRun:0,cancelled:!1,bailed:!1}),g=(e,t)=>({success:!1,passed:0,failed:1,selectedTests:0,files:[],issues:[e],accounting:h(t),lineageStatus:`unavailable`}),_=async n=>{let r=[...n.files],c=performance.now();p({type:`run-start`,files:r});let l=!1,u=async()=>{l||(l=!0,await s.nativeModelLoader?.releaseAll())},d=0,g=0,_=0,v=[],y=[],b=h(r),x=!0,S=`complete`,C=new Map;try{for(let t of r){let c=m();if(c!==void 0){let e=i(c);y.push(e),g+=1,p({type:`abort`,reason:c}),b.cancelled=!0,x=!1;break}p({type:`file-start`,file:t});let l=performance.now(),u=await e({filesystem:s.filesystem,entryPath:t,testNamePattern:n.testNamePattern,testTimeout:n.testTimeout,matcherWallBackstop:n.matcherWallBackstop,forensic:n.forensic,bundleCache:f,nativeAssertions:s.nativeAssertions,...s.nativeModelLoader?{nativeModelLoader:s.nativeModelLoader}:{},...s.builtinModules?{builtinModules:s.builtinModules}:{}}).catch(e=>({success:!1,issues:[{code:`GEOSPEC_MODULE_INTERRUPTED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}]})),h=performance.now()-l;p({type:`file-complete`,file:t,result:u,durationMs:h}),v.push({file:t,result:u,durationMs:h}),b.completedFiles=v.map(e=>e.file),b.notRunFiles=r.slice(v.length),x&&=u.success&&u.passed,u.lineage===void 0||u.lineage.status===`unavailable`?S!==`mixed`&&(S=`unavailable`):u.lineage.status===`mixed`&&(S=`mixed`);let w=u.lineage?.loads.flatMap(e=>{let{evidence:t}=e,n=t?.artifacts[0];return t?.exportOptions===void 0?[...(t?.artifacts??[]).flatMap(e=>e.sourcePath===void 0?[]:[{[e.sourcePath]:`sha256:${e.sha256}`}]),...t?.sourcePath===void 0||n===void 0?[]:[{[t.sourcePath]:`sha256:${n.sha256}`}]]:[]})??[];for(let e of[...u.lineage?.modules.map(e=>e.files)??[],...w,...u.lineage?.loads.map(e=>e.evidence?.sourceRevision?.files??{})??[]])for(let[t,n]of Object.entries(e))C.has(t)&&C.get(t)!==n&&(S=`mixed`),C.set(t,n);if(u.accounting!==void 0)for(let e of[`discovered`,`selected`,`completed`,`passed`,`failed`,`unsupported`,`inconclusive`,`skipped`,`notRun`])b[e]+=u.accounting[e];if(u.success){_+=u.tests.length;let e=o(u.tests);d+=e.passed,g+=e.failed}else g+=1;if(n.bail===!0&&(!x||g>0)){y.push(a(t)),b.bailed=!0;break}}_===0&&g===0&&(y.push(t()),g+=1);try{await u()}catch(e){y.push({code:`GEOSPEC_NATIVE_CLEANUP_FAILED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}),x=!1}b.discoveryComplete=b.notRunFiles.length===0&&v.every(e=>e.result.success&&e.result.accounting!==void 0);let l={success:x&&S===`complete`&&g===0&&y.length===0,passed:d,failed:g,selectedTests:_,files:v,...y.length>0?{issues:y}:{},durationMs:performance.now()-c,accounting:b,lineageStatus:S};return p({type:`run-complete`,result:l}),l}finally{await u()}};return{async run(e){if(new Set(e.files).size!==e.files.length)return g({code:`GEOSPEC_DUPLICATE_FILES`,message:`GeoSpec requested files must be unique.`,severity:`error`,type:`runtime`},e.files);if(c.closed)return g(n(),e.files);if(u!==void 0)return g(r(),e.files);delete c.aborted;let t=()=>void 0,i=new Promise(e=>{t=e});u=i;try{return await _(e)}finally{t(),u===i&&(u=void 0)}},on(e,t){let n=n=>{n.type===e&&t(n)};return l.add(n),()=>l.delete(n)},abort(e){c.aborted=e??`requested`},async close(){d===void 0&&(c.closed=!0,c.aborted??=`runner closed`,d=(async()=>{await u,f.clear(),p({type:`close`})})()),await d}}};export{o as countRunnerTests,s as createSerialGeoSpecRunner};
|
|
1
|
+
import{runGeoSpecModule as e}from"../run-geospec-module.mjs";import{createNoMatchingGeoSpecTestsIssue as t}from"./no-matching-tests-issue.mjs";const n=()=>({code:`GEOSPEC_RUNNER_CLOSED`,message:`GeoSpec runner is closed.`,severity:`error`,type:`runtime`}),r=()=>({code:`GEOSPEC_RUNNER_ACTIVE`,message:`GeoSpec runner already has an active run.`,severity:`error`,type:`runtime`}),i=e=>({code:`GEOSPEC_RUNNER_ABORTED`,message:e?`GeoSpec run aborted: ${e}`:`GeoSpec run aborted.`,severity:`error`,type:`runtime`}),a=e=>({code:`GEOSPEC_RUNNER_BAILED`,message:`GeoSpec run stopped after first failure (--bail): ${e}. Remaining files were not executed.`,severity:`error`,type:`runtime`}),o=e=>{let t=0,n=0;for(let r of e)r.status!==`skipped`&&(r.status===`failed`?n+=1:r.status===`passed`&&(t+=1));return{passed:t,failed:n}},s=s=>{let c={closed:!1},l=new Set,u,d,f=new Map,p=e=>{for(let t of l)t(e)},m=()=>c.aborted,h=e=>({requestedFiles:[...e],completedFiles:[],notRunFiles:[...e],discoveryComplete:!1,discovered:0,selected:0,completed:0,passed:0,failed:0,unsupported:0,inconclusive:0,skipped:0,notRun:0,cancelled:!1,bailed:!1}),g=(e,t)=>({success:!1,passed:0,failed:1,selectedTests:0,files:[],issues:[e],accounting:h(t),lineageStatus:`unavailable`}),_=async n=>{let r=[...n.files],c=performance.now();p({type:`run-start`,files:r});let l=!1,u=async()=>{l||(l=!0,await s.nativeModelLoader?.releaseAll())},d=0,g=0,_=0,v=[],y=[],b=h(r),x=!0,S=`complete`,C=new Map;try{for(let t of r){let c=m();if(c!==void 0){let e=i(c);y.push(e),g+=1,p({type:`abort`,reason:c}),b.cancelled=!0,x=!1;break}p({type:`file-start`,file:t});let l=performance.now(),u=await e({filesystem:s.filesystem,entryPath:t,testNamePattern:n.testNamePattern,testTimeout:n.testTimeout,matcherWallBackstop:n.matcherWallBackstop,forensic:n.forensic,onTestEvent:e=>{p(e.type===`test-start`?{type:`test-start`,file:t,test:{suite:[...e.test.suite],name:e.test.name,...e.test.ordinal===void 0?{}:{ordinal:e.test.ordinal}}}:{type:`test-complete`,file:t,test:e.test})},bundleCache:f,nativeAssertions:n.workUnitLimit===void 0?s.nativeAssertions:{...s.nativeAssertions,workUnitLimit:n.workUnitLimit},...s.nativeModelLoader?{nativeModelLoader:s.nativeModelLoader}:{},...s.builtinModules?{builtinModules:s.builtinModules}:{}}).catch(e=>({success:!1,issues:[{code:`GEOSPEC_MODULE_INTERRUPTED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}]})),h=performance.now()-l;p({type:`file-complete`,file:t,result:u,durationMs:h}),v.push({file:t,result:u,durationMs:h}),b.completedFiles=v.map(e=>e.file),b.notRunFiles=r.slice(v.length),x&&=u.success&&u.passed,u.lineage===void 0||u.lineage.status===`unavailable`?S!==`mixed`&&(S=`unavailable`):u.lineage.status===`mixed`&&(S=`mixed`);let w=u.lineage?.loads.flatMap(e=>{let{evidence:t}=e,n=t?.artifacts[0];return t?.exportOptions===void 0?[...(t?.artifacts??[]).flatMap(e=>e.sourcePath===void 0?[]:[{[e.sourcePath]:`sha256:${e.sha256}`}]),...t?.sourcePath===void 0||n===void 0?[]:[{[t.sourcePath]:`sha256:${n.sha256}`}]]:[]})??[];for(let e of[...u.lineage?.modules.map(e=>e.files)??[],...w,...u.lineage?.loads.map(e=>e.evidence?.sourceRevision?.files??{})??[]])for(let[t,n]of Object.entries(e))C.has(t)&&C.get(t)!==n&&(S=`mixed`),C.set(t,n);if(u.accounting!==void 0)for(let e of[`discovered`,`selected`,`completed`,`passed`,`failed`,`unsupported`,`inconclusive`,`skipped`,`notRun`])b[e]+=u.accounting[e];if(u.success){_+=u.tests.length;let e=o(u.tests);d+=e.passed,g+=e.failed}else g+=1;if(n.bail===!0&&(!x||g>0)){y.push(a(t)),b.bailed=!0;break}}_===0&&g===0&&(y.push(t()),g+=1);try{await u()}catch(e){y.push({code:`GEOSPEC_NATIVE_CLEANUP_FAILED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}),x=!1}b.discoveryComplete=b.notRunFiles.length===0&&v.every(e=>e.result.success&&e.result.accounting!==void 0);let l={success:x&&S===`complete`&&g===0&&y.length===0,passed:d,failed:g,selectedTests:_,files:v,...y.length>0?{issues:y}:{},durationMs:performance.now()-c,accounting:b,lineageStatus:S};return p({type:`run-complete`,result:l}),l}finally{await u()}};return{async run(e){if(new Set(e.files).size!==e.files.length)return g({code:`GEOSPEC_DUPLICATE_FILES`,message:`GeoSpec requested files must be unique.`,severity:`error`,type:`runtime`},e.files);if(c.closed)return g(n(),e.files);if(u!==void 0)return g(r(),e.files);delete c.aborted;let t=()=>void 0,i=new Promise(e=>{t=e});u=i;try{return await _(e)}finally{t(),u===i&&(u=void 0)}},on(e,t){let n=n=>{n.type===e&&t(n)};return l.add(n),()=>l.delete(n)},abort(e){c.aborted=e??`requested`},async close(){d===void 0&&(c.closed=!0,c.aborted??=`runner closed`,d=(async()=>{await u,f.clear(),p({type:`close`})})()),await d}}};export{o as countRunnerTests,s as createSerialGeoSpecRunner};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "geospec",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.3",
|
|
4
4
|
"description": "Geometry specification API for CAD models: DSL, selector language, diagnostics schema, and the native runner integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -96,9 +96,9 @@
|
|
|
96
96
|
"imports": {},
|
|
97
97
|
"dependencies": {
|
|
98
98
|
"zod": "4.4.3",
|
|
99
|
-
"@taucad/esbuild": "0.1.0-beta.
|
|
100
|
-
"@taucad/project-core": "0.1.0-beta.
|
|
101
|
-
"@taucad/runtime": "0.1.0-beta.
|
|
99
|
+
"@taucad/esbuild": "0.1.0-beta.3",
|
|
100
|
+
"@taucad/project-core": "0.1.0-beta.3",
|
|
101
|
+
"@taucad/runtime": "0.1.0-beta.3"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@gltf-transform/core": "^4.5.1"
|