geospec 0.0.0 → 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/LICENSE +201 -0
- package/README.md +244 -0
- package/agent/doctrine.md +55 -0
- package/agent/geospec-authoring/SKILL.md +495 -0
- package/agent/geospec-authoring/api-classes.md +13 -0
- package/agent/geospec-authoring/api-constants.md +16 -0
- package/agent/geospec-authoring/api-functions.md +57 -0
- package/agent/geospec-authoring/api-index.md +377 -0
- package/agent/geospec-authoring/api-types.md +1788 -0
- package/agent/geospec-authoring/public-api-classes.md +22 -0
- package/agent/geospec-authoring/public-api-constants.md +51 -0
- package/agent/geospec-authoring/public-api-functions.md +215 -0
- package/agent/geospec-authoring/public-api-index.md +893 -0
- package/agent/geospec-authoring/public-api-types-2.md +1560 -0
- package/agent/geospec-authoring/public-api-types-3.md +217 -0
- package/agent/geospec-authoring/public-api-types.md +1948 -0
- package/agent/resources.d.ts +19 -0
- package/agent/resources.js +27 -0
- package/agent/skills.d.cts +13 -0
- package/agent/skills.json +28 -0
- package/dist/assertion-client/client.d.mts +134 -0
- package/dist/assertion-client/client.mjs +2 -0
- package/dist/assertion-client/index.d.mts +5 -0
- package/dist/assertion-client/index.mjs +1 -0
- package/dist/config/index.d.mts +3 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/node/index.d.mts +3 -0
- package/dist/config/node/index.mjs +1 -0
- package/dist/config/node/load.d.mts +19 -0
- package/dist/config/node/load.mjs +1 -0
- package/dist/config/tau-project-artifact.d.mts +54 -0
- package/dist/config/tau-project-artifact.mjs +3 -0
- package/dist/config/types.d.mts +57 -0
- package/dist/config/validate.mjs +1 -0
- package/dist/create-geospec.d.mts +50 -0
- package/dist/create-geospec.mjs +1 -0
- package/dist/engine/client.d.mts +113 -0
- package/dist/engine/client.mjs +1 -0
- package/dist/engine/index.d.mts +3 -0
- package/dist/engine/index.mjs +1 -0
- package/dist/engine/matchers.d.mts +70 -0
- package/dist/engine/matchers.mjs +1 -0
- package/dist/engine/pmi.types.d.mts +78 -0
- package/dist/engine/protocol.d.mts +20 -0
- package/dist/engine/protocol.mjs +1 -0
- package/dist/geometry-unit.d.mts +12 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +1 -0
- package/dist/mesh/index.d.mts +4 -0
- package/dist/mesh/index.mjs +1 -0
- package/dist/mesh/types.d.mts +575 -0
- package/dist/model/errors.d.mts +20 -0
- package/dist/model/errors.mjs +2 -0
- package/dist/model/export-intent.d.mts +79 -0
- package/dist/model/export-intent.mjs +1 -0
- package/dist/model/index.d.mts +7 -0
- package/dist/model/index.mjs +1 -0
- package/dist/model/load-model.d.mts +25 -0
- package/dist/model/load-model.mjs +1 -0
- package/dist/model/native-model-loader.d.mts +142 -0
- package/dist/model/native-model-loader.mjs +1 -0
- package/dist/model/region-scope.d.mts +23 -0
- package/dist/model/region-scope.mjs +1 -0
- package/dist/model/subject-assertions.mjs +1 -0
- package/dist/model/subject.d.mts +11 -0
- package/dist/model/subject.mjs +1 -0
- package/dist/model/types.d.mts +254 -0
- package/dist/runner/collector.d.mts +64 -0
- package/dist/runner/collector.mjs +2 -0
- package/dist/runner/discovery.d.mts +93 -0
- package/dist/runner/discovery.mjs +1 -0
- package/dist/runner/filter.d.mts +50 -0
- package/dist/runner/filter.mjs +1 -0
- package/dist/runner/index.d.mts +7 -0
- package/dist/runner/index.mjs +1 -0
- package/dist/runner/native/index.d.mts +4 -0
- package/dist/runner/native/index.mjs +1 -0
- package/dist/runner/native/native-pool-grants.d.mts +21 -0
- package/dist/runner/native/native-pool-grants.mjs +1 -0
- package/dist/runner/native/native-serial-runner.d.mts +29 -0
- package/dist/runner/native/native-serial-runner.mjs +1 -0
- package/dist/runner/pool/pool-messages.d.mts +94 -0
- package/dist/runner/run-geospec-module.d.mts +13 -0
- package/dist/runner/run-geospec-module.mjs +47 -0
- package/dist/runner/timeout-codes.d.mts +45 -0
- package/dist/runner/timeout-codes.mjs +1 -0
- package/dist/runner/types.d.mts +776 -0
- package/dist/runner/worker/index.d.mts +4 -0
- package/dist/runner/worker/index.mjs +1 -0
- package/dist/runner/worker/no-matching-tests-issue.d.mts +12 -0
- package/dist/runner/worker/no-matching-tests-issue.mjs +1 -0
- package/dist/runner/worker/runner-types.d.mts +167 -0
- package/dist/runner/worker/serial-runner.mjs +1 -0
- package/dist/selector/types.d.mts +271 -0
- package/dist/step/types.d.mts +134 -0
- package/dist/vitest/adapter.d.mts +56 -0
- package/dist/vitest/adapter.mjs +3 -0
- package/dist/vitest/index.d.mts +4 -0
- package/dist/vitest/index.mjs +1 -0
- package/package.json +114 -5
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GeoSpecSubject } from "./subject.mjs";
|
|
2
|
+
import { CreateModelLoaderOptions, LoadModelOptions, ManagedGeoSpecModelLoader } from "./types.mjs";
|
|
3
|
+
//#region src/model/load-model.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Load a CAD model into GeoSpec evidence.
|
|
6
|
+
*
|
|
7
|
+
* This is the authoring declaration: a GeoSpec runner replaces it with the
|
|
8
|
+
* host's native model loader. Called outside a runner it always throws.
|
|
9
|
+
*
|
|
10
|
+
* @param _options - Source, code, or file model load options.
|
|
11
|
+
* @returns A GeoSpec geometry subject ready for `expectGeo`.
|
|
12
|
+
* @throws {@link GeoSpecModelLoadError} with `GEOSPEC_MODEL_LOADER_UNAVAILABLE` when no runner is active.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
declare function loadModel<Code extends Record<string, string> = Record<string, string>>(_options: LoadModelOptions<Code>): Promise<GeoSpecSubject>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a {@link loadModel} function over a host-supplied compiled engine.
|
|
18
|
+
*
|
|
19
|
+
* @param defaults - The compiled engine plus model loading defaults.
|
|
20
|
+
* @returns A configured model loader whose subjects are released by `dispose()`.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
declare const createModelLoader: (defaults: CreateModelLoaderOptions) => ManagedGeoSpecModelLoader;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { createModelLoader, loadModel };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{bindGeoSpecSubject as e,rawSubjectResidency as t}from"./subject.mjs";import{createGeoSpecAssertionClient as n}from"../assertion-client/client.mjs";import{GeoSpecModelLoadError as r}from"./errors.mjs";import{createGeoSpecNativeModelLoader as i}from"./native-model-loader.mjs";async function a(e){throw new r([{code:`GEOSPEC_MODEL_LOADER_UNAVAILABLE`,severity:`error`,message:`No GeoSpec model loader is active outside a GeoSpec runner.`,suggestion:`Run this test through the GeoSpec CLI or Tau test runner, or call createModelLoader({ engine }).`}])}const o=r=>{let{engine:a,readSource:o,format:s,...c}=r,l={...c,...s===void 0?{}:{format:s}},u=i({...c,engine:a,...o===void 0?{}:{readSource:o}}),d=n({engine:a}),f=0;return Object.assign(async n=>{let r=f,i=await u({...l,...n}),o=t(i);return e({client:d,engine:a,identity:{subjectHash:i.subjectHash},...i.load===void 0?{}:{load:i.load},isLive:()=>f===r,...o===void 0?{}:{ensureResident:o}})},{async dispose(){try{await u.releaseAll()}finally{f+=1}}})};export{o as createModelLoader,a as loadModel};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { GeoSpecLoadRegion, GeoSpecModelFormat, GeoSpecRuntimeClient, GeoSpecRuntimeClientFactory, GeoSpecRuntimeSourceAdapter, LoadModelOptions, LoadModelSourceOptions } from "./types.mjs";
|
|
2
|
+
import { GeoSpecNativeEngine, GeoSpecNativeSubject } from "../engine/client.mjs";
|
|
3
|
+
import "../assertion-client/index.mjs";
|
|
4
|
+
import { SourceRevision } from "@taucad/runtime/types";
|
|
5
|
+
//#region src/model/native-model-loader.d.ts
|
|
6
|
+
/** Native engine operations required for model admission and run-level cleanup. @public */
|
|
7
|
+
type GeoSpecNativeModelEngine = GeoSpecNativeEngine & {
|
|
8
|
+
ingestSubject(request: Uint8Array<ArrayBuffer>, primary: Uint8Array<ArrayBuffer>, resources: ReadonlyArray<Uint8Array<ArrayBuffer>>): Uint8Array<ArrayBuffer>;
|
|
9
|
+
subjectHandle(request: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
|
|
10
|
+
releaseSubject(request: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
|
|
11
|
+
};
|
|
12
|
+
/** One named external resource referenced by a direct glTF-family source. @public */
|
|
13
|
+
type GeoSpecNativeModelResource = {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly source: LoadModelSourceOptions['source'];
|
|
16
|
+
};
|
|
17
|
+
/** Native additions accepted by the injected `geospec/runner/native` loader. @public */
|
|
18
|
+
type GeoSpecNativeLoadModelOptions<Code extends Record<string, string> = Record<string, string>> = LoadModelOptions<Code> & {
|
|
19
|
+
/** Ordered external resource payloads declared to the native admission request. */
|
|
20
|
+
readonly resources?: readonly GeoSpecNativeModelResource[];
|
|
21
|
+
/** Format-specific native ingest options. */
|
|
22
|
+
readonly ingestOptions?: Readonly<Record<string, unknown>>;
|
|
23
|
+
};
|
|
24
|
+
/** Subject identity returned by native STEP/GLB admission. @public */
|
|
25
|
+
type GeoSpecNativeModelSubject = GeoSpecNativeSubject & {
|
|
26
|
+
readonly subjectHash: string;
|
|
27
|
+
/** Exact successful-load evidence retained by the admitting host, when available. */
|
|
28
|
+
readonly load?: GeoSpecModelLoadEvidence;
|
|
29
|
+
};
|
|
30
|
+
/** Immutable identity of the inputs and artifacts consumed by one model load. @public */
|
|
31
|
+
type GeoSpecModelLoadEvidence = {
|
|
32
|
+
readonly loadId: string;
|
|
33
|
+
readonly status: 'complete' | 'unavailable';
|
|
34
|
+
readonly format: string;
|
|
35
|
+
readonly parameters: Readonly<Record<string, unknown>>;
|
|
36
|
+
readonly exportOptions?: Readonly<Record<string, unknown>>;
|
|
37
|
+
readonly ingestOptions: Readonly<Record<string, unknown>>;
|
|
38
|
+
readonly sourceRevision?: SourceRevision;
|
|
39
|
+
/** Actual direct-source locator, when the load read one; absent for anonymous in-memory bytes. */
|
|
40
|
+
readonly sourcePath?: string;
|
|
41
|
+
/** Authored default work-unit budget for claims on this subject. */
|
|
42
|
+
readonly workUnitLimit?: number;
|
|
43
|
+
/**
|
|
44
|
+
* The crop box the kernel applied before export. Present only on a cropped load: its subject is
|
|
45
|
+
* the region, never the whole model.
|
|
46
|
+
*/
|
|
47
|
+
readonly region?: GeoSpecLoadRegion;
|
|
48
|
+
/**
|
|
49
|
+
* True when this load reused the run's earlier admission of identical inputs: the same file,
|
|
50
|
+
* code, parameters, format, tolerances, region and ingest options, with an unchanged source
|
|
51
|
+
* revision. No export or ingest ran for it; its artifacts and source revision are the earlier
|
|
52
|
+
* load's, and lineage still records it under its own load id.
|
|
53
|
+
*/
|
|
54
|
+
readonly reused?: true;
|
|
55
|
+
readonly artifacts: ReadonlyArray<{
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly sha256: string;
|
|
58
|
+
readonly byteLength: number;
|
|
59
|
+
/** Actual source locator consumed by a direct load; absent for bytes and Runtime exports. */
|
|
60
|
+
readonly sourcePath?: string;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a non-memory source into ordinary ArrayBuffer-backed bytes.
|
|
65
|
+
*
|
|
66
|
+
* The loader takes ownership of the returned bytes and admits them without a
|
|
67
|
+
* copy, so a reader must return bytes that nothing mutates afterwards (a fresh
|
|
68
|
+
* read, not a view of a shared or reused buffer).
|
|
69
|
+
*
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
type GeoSpecNativeSourceReader = (source: LoadModelSourceOptions['source']) => Promise<Uint8Array<ArrayBuffer>>;
|
|
73
|
+
/** Defaults and host dependencies for a managed native model loader. @public */
|
|
74
|
+
type CreateGeoSpecNativeModelLoaderOptions = {
|
|
75
|
+
readonly engine: GeoSpecNativeModelEngine;
|
|
76
|
+
readonly format?: Extract<GeoSpecModelFormat, 'glb' | 'step' | 'stp'>;
|
|
77
|
+
readonly projectPath?: string;
|
|
78
|
+
readonly readSource?: GeoSpecNativeSourceReader;
|
|
79
|
+
readonly runtime?: GeoSpecRuntimeClient | GeoSpecRuntimeClientFactory;
|
|
80
|
+
readonly sourceAdapters?: readonly GeoSpecRuntimeSourceAdapter[];
|
|
81
|
+
/**
|
|
82
|
+
* Subject handles carried between the release scopes of loaders that share one engine, keyed by
|
|
83
|
+
* subjectHash. With a carrier, `releaseAll` keeps this scope's subjects for the next scope and
|
|
84
|
+
* releases only the previous scope's subjects this scope did not load again, so reloading
|
|
85
|
+
* unchanged bytes in the next scope is digest-only. Share one carrier per engine and run its
|
|
86
|
+
* scopes one at a time: a scope's release touches only subjects whose scope has settled.
|
|
87
|
+
*/
|
|
88
|
+
readonly carried?: Map<string, unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* The largest `loadModel` `workUnitLimit` a spec may author. Host policy: omitted uses
|
|
91
|
+
* `geoSpecMaximumWorkUnitLimit`, and a host provisioned for larger claims raises it.
|
|
92
|
+
*/
|
|
93
|
+
readonly maximumWorkUnitLimit?: number;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Model loader injected into native VM runs.
|
|
97
|
+
*
|
|
98
|
+
* Direct `source` loads read their source again on every call and the engine
|
|
99
|
+
* digests those exact bytes; bytes equal to an admitted subject's reuse that
|
|
100
|
+
* subject by digest, length and descriptor, and edited bytes admit a new
|
|
101
|
+
* subject. Runtime loads are coalesced per release scope (one run): a load
|
|
102
|
+
* whose file, inline code, project path, parameters, format, tolerances,
|
|
103
|
+
* region and ingest options equal an earlier successful load's reuses that
|
|
104
|
+
* admission without exporting or ingesting again. A file load is reused only
|
|
105
|
+
* while a Runtime source snapshot still matches the earlier load's complete
|
|
106
|
+
* source revision; otherwise, or when every owner of the earlier admission has
|
|
107
|
+
* released it, the load exports afresh. Failures are never reused.
|
|
108
|
+
*
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
type GeoSpecNativeModelLoader = <Code extends Record<string, string> = Record<string, string>>(options: GeoSpecNativeLoadModelOptions<Code>) => Promise<GeoSpecNativeModelSubject>;
|
|
112
|
+
/**
|
|
113
|
+
* Reusable native model loader whose admitted subjects can be released as one run.
|
|
114
|
+
* The caller owns the engine and the boundaries between load scopes.
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
type ManagedGeoSpecNativeModelLoader = GeoSpecNativeModelLoader & {
|
|
118
|
+
/**
|
|
119
|
+
* Drain registered admissions, including additions while drainage awaits,
|
|
120
|
+
* then release this scope's subjects (with a carrier: the previous scope's
|
|
121
|
+
* subjects this scope did not load again) and owned Runtime clients.
|
|
122
|
+
*
|
|
123
|
+
* Await the intended complete load chain before final release, and await
|
|
124
|
+
* this method before closing the caller-owned engine. Calls after it returns
|
|
125
|
+
* start a new scope requiring another release; future detached loads are not
|
|
126
|
+
* part of the completed scope.
|
|
127
|
+
*
|
|
128
|
+
* @returns Completion of the current scope's admission drain and release.
|
|
129
|
+
*/
|
|
130
|
+
releaseAll(): Promise<void>;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Create a native model loader that admits actual STEP/GLB bytes and retains
|
|
134
|
+
* generation-checked handles until the owning runner finishes.
|
|
135
|
+
*
|
|
136
|
+
* @param defaults - Native engine, Runtime defaults, and optional source reader.
|
|
137
|
+
* @returns A loader plus run-level cleanup operation.
|
|
138
|
+
* @public
|
|
139
|
+
*/
|
|
140
|
+
declare const createGeoSpecNativeModelLoader: (defaults: CreateGeoSpecNativeModelLoaderOptions) => ManagedGeoSpecNativeModelLoader;
|
|
141
|
+
//#endregion
|
|
142
|
+
export { CreateGeoSpecNativeModelLoaderOptions, GeoSpecModelLoadEvidence, GeoSpecNativeLoadModelOptions, GeoSpecNativeModelEngine, GeoSpecNativeModelLoader, GeoSpecNativeModelResource, GeoSpecNativeModelSubject, GeoSpecNativeSourceReader, ManagedGeoSpecNativeModelLoader, createGeoSpecNativeModelLoader };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{geoSpecAuthoredWorkUnitLimitProblem as e,resolveGeoSpecMaximumWorkUnitLimit as t}from"../engine/client.mjs";import{bindRawSubjectResidency as n}from"./subject.mjs";import{GeoSpecModelLoadError as r}from"./errors.mjs";import{resolveRuntimeExportIntent as i}from"./export-intent.mjs";import{sha256Bytes as a}from"@taucad/runtime/kernel";const o={canonicalProfile:`geospec-jcs-v1`,protocolVersion:3,registryVersion:5},s=new TextEncoder,c=new TextDecoder(`utf-8`,{fatal:!0}),l=new Set([`glb`,`step`,`stp`]),u=new WeakMap,d=16777216,f=e=>e instanceof Error&&`code`in e&&e.code===`limit-exceeded`&&e.message===`Engine exceeds the configured retained subject count.`,p=e=>{let t=u.get(e);if(t!==void 0)return t;let n=y(e.processRequest(_({...o,method:`initialize`,requestId:`configuration`})),`initialize response`),r=v(n.result,`initialize result`);if(n.requestId!==`configuration`||r.protocolVersion!==3||r.registryVersion!==5||r.canonicalProfile!==`geospec-jcs-v1`)throw TypeError(`Native GeoSpec residency requires a compatible initialize profile.`);let i=v(r.configuration,`initialize configuration`),a=v(i.binaryAdmissionLimits,`binary admission limits`),s=[a.maxSubjectBytes,a.maxTotalBinaryBytes].map(e=>{if(typeof e!=`number`||!Number.isSafeInteger(e)||e<=0)throw TypeError(`Native GeoSpec residency requires safe positive binary admission limits.`);return e}),c={inputs:new Map,resident:new Map,binaryLimit:Math.max(...s),binaryBytes:0,descriptorBytes:0};return u.set(e,c),c},m=e=>new r(e),h=e=>({code:e.code,severity:`error`,message:e.message,suggestion:e.suggestion,...e.details===void 0?{}:{details:e.details}}),g=e=>({code:e.code,severity:e.severity,message:e.message,suggestion:`Fix the model source or its Runtime export route, then retry the native run.`}),_=e=>s.encode(JSON.stringify(e)),v=(e,t)=>{if(typeof e!=`object`||!e||Array.isArray(e))throw TypeError(`Native GeoSpec returned a non-object ${t}.`);return e},y=(e,t)=>v(JSON.parse(c.decode(e)),t),b=async(e,t)=>{if(e instanceof Uint8Array)return Uint8Array.from(e);if(e instanceof ArrayBuffer)return Uint8Array.from(new Uint8Array(e));if(typeof Blob<`u`&&e instanceof Blob)return new Uint8Array(await e.arrayBuffer());if(t!==void 0)try{return await t(e)}catch(t){throw m([h({code:`GEOSPEC_NATIVE_SOURCE_READ_FAILED`,message:`The host source reader could not read ${typeof e==`string`?e:`this source`}: ${t instanceof Error?t.message:String(t)}`,suggestion:`Check that the source exists at a project-rooted path and is readable, then retry the load.`,...typeof e==`string`?{details:{source:e}}:{}})])}throw m([h({code:`GEOSPEC_NATIVE_SOURCE_READER_UNAVAILABLE`,message:`The native model loader cannot read this source form without a host source reader.`,suggestion:`Pass in-memory bytes or configure readSource on createGeoSpecNativeModelLoader().`})])},x=e=>`code`in e?{files:e.code,entry:e.file}:{path:e.file},S=(e,t)=>{let n=e.format??t??`glb`;if(!l.has(n))throw m([h({code:`GEOSPEC_NATIVE_MODEL_FORMAT_UNSUPPORTED`,message:`The native model host does not admit '${n}' models.`,suggestion:`Use 'step', 'stp', or 'glb' for native model assertions.`,details:{format:n}})]);return n},C=(e,t)=>{let{routesFor:n,bestRouteFor:r}=e;if(typeof n==`function`)return n.call(e,t);let i=typeof r==`function`?r.call(e,t):void 0;return i===void 0?[]:[i]},w=async(e,t)=>{if(typeof e.describe==`function`)try{let{kernelId:n}=await e.describe({source:x(t)});return typeof n==`string`&&n.length>0?n:void 0}catch{return}},T=e=>{if(e===null||typeof e==`boolean`||typeof e==`string`)return JSON.stringify(e);if(typeof e==`number`)return Number.isFinite(e)?JSON.stringify(e):void 0;if(Array.isArray(e)){let t=e.map(e=>T(e));return t.includes(void 0)?void 0:`[${t.join(`,`)}]`}if(typeof e==`object`&&Object.getPrototypeOf(e)===Object.prototype){let t=Object.entries(e).filter(([,e])=>e!==void 0).sort(([e],[t])=>e<t?-1:1).map(([e,t])=>[e,T(t)]);return t.some(([,e])=>e===void 0)?void 0:`{${t.map(([e,t])=>`${JSON.stringify(e)}:${t}`).join(`,`)}}`}},E=e=>Array.isArray(e)&&e.length===3&&e.every(e=>typeof e==`number`&&Number.isFinite(e)),D=e=>{if(e===void 0)return;let t=typeof e==`object`&&e?e:{},{min:n,max:r}=t;return E(n)&&E(r)&&Object.keys(t).every(e=>e===`min`||e===`max`)&&n.every((e,t)=>e<r[t])?void 0:m([h({code:`GEOSPEC_MODEL_OPTION_INVALID`,message:`loadModel region must be { min: [x, y, z], max: [x, y, z] } in millimetres with every min axis below its max axis.`,suggestion:`Pass finite millimetre corners of the box to check, for example { min: [0, 0, 0], max: [40, 40, 60] }.`,details:{option:`region`,region:structuredClone(e)}})])},O=({min:e,max:t})=>({min:[e[0],e[1],e[2]],max:[t[0],t[1],t[2]]}),k=(e,t)=>{let n=t.sourceRevision?.files??Object.fromEntries(t.data.files.map(({path:e,sha256:t})=>[e,`sha256:${t}`]));return(t.sourceRevision?.entry??t.data.entryPath)===e.entry&&Object.entries(n).every(([t,n])=>n===`missing`||e.files[t]===n)&&Object.entries(e.files).every(([e,t])=>t===`missing`?n[e]===void 0||n[e]===`missing`:n[e]===t)},A=r=>{let s=0,c=t(r.maximumWorkUnitLimit),l=new Map,E=new Map,A=0,j=new Set,M=new Map,N=new Set,P=new Map,F=e=>(s+=1,`geospec-native-model:${e}:${s}`),I=e=>(e.sourceAdapters??r.sourceAdapters)?.find(t=>t.extensions.some(t=>e.file.endsWith(t))),L=async e=>{let t=e.runtime??r.runtime;if(typeof t==`function`){let e=P.get(t);e===void 0&&(e=t(),P.set(t,e));let n=await e;return N.add(n),n}if(t!==void 0)return t;let n=I(e);if(n!==void 0){let t=await n.createRuntime({file:e.file,...(e.projectPath??r.projectPath)===void 0?{}:{projectPath:e.projectPath??r.projectPath}});return N.add(t),t}throw m([h({code:`GEOSPEC_NATIVE_RUNTIME_UNAVAILABLE`,message:`No Tau Runtime is configured to export '${e.file}' for native GeoSpec.`,suggestion:`Pass a Runtime client/factory or a matching source adapter to the native runner.`,details:{file:e.file}})])},R=e=>{r.engine.releaseSubject(_({...o,method:`releaseSubject`,requestId:F(`release`),subjectHandle:e}))},z=(e,t)=>{let n=u.get(r.engine),i=n?.inputs.get(e);if(n!==void 0&&i!==void 0&&(i.cleanupPending?.(),delete i.cleanupPending,i.owners.has(t))){if(i.owners.size>1){i.owners.delete(t);return}i.handle!==void 0&&(R(i.handle),delete i.handle),i.owners.delete(t),n.resident.delete(e),n.inputs.delete(e),n.binaryBytes-=i.resources.reduce((e,t)=>e+t.byteLength,i.primary.byteLength),n.descriptorBytes-=i.request.byteLength}},B=e=>{for(let[t,n]of e.inputs)n.cleanupPending!==void 0&&(n.cleanupPending(),delete n.cleanupPending,delete n.handle,e.resident.delete(t))},V=()=>[...r.carried??[]].filter(([e])=>!l.has(e)),H=(e,t)=>{let n=e.format===`stp`?`step`:e.format,i=p(r.engine);B(i);let a=_({...o,method:`ingestSubject`,requestId:F(`ingest`),format:n,frame:{coordinateSystem:`z-up`,sourceUnit:n===`step`?`auto`:e.sourceUnit??`m`,outputUnit:`mm`},ingestOptions:e.ingestOptions??{},...e.diagnostics===void 0||e.diagnostics.length===0?{}:{diagnostics:e.diagnostics},primaryByteLength:e.primary.byteLength,resources:e.resources.map(({name:e,bytes:t})=>({name:e,byteLength:t.byteLength}))}),s=e.resources.reduce((e,{bytes:t})=>e+t.byteLength,e.primary.byteLength);if(!Number.isSafeInteger(s)||s>i.binaryLimit||a.byteLength>d)throw Object.assign(RangeError(`GeoSpec retained admission input exceeds its byte limit.`),{code:`limit-exceeded`});let c=(e,t)=>e.length===t.length&&e.every((e,n)=>e===t[n]),u={...y(a,`admission request`),requestId:``},m=[...i.inputs.values()].find(t=>{let n={...y(t.request,`retained request`),requestId:``};return JSON.stringify(n)===JSON.stringify(u)&&c(t.primary,e.primary)&&t.resources.length===e.resources.length&&t.resources.every((t,n)=>c(t,e.resources[n].bytes))});if(m===void 0&&(s>i.binaryLimit-i.binaryBytes||a.byteLength>d-i.descriptorBytes))throw Object.assign(RangeError(`GeoSpec live admission snapshots exceed their retained input byte limit.`),{code:`limit-exceeded`});let h=m??{request:Uint8Array.from(a),primary:Uint8Array.from(e.primary),resources:e.resources.map(({bytes:e})=>Uint8Array.from(e)),owners:new Set},g=()=>r.engine.ingestSubject(a,e.primary,e.resources.map(({bytes:e})=>e)),b;try{b=g()}catch(e){let t=V();if(!f(e))throw e;let n=!1;for(let[e,a]of t){let t=i.inputs.get(e);if(t===void 0)R(a),n=!0;else{let i=t.owners.size===1&&t.handle!==void 0;z(e,r.carried),n||=i}r.carried?.delete(e)}if(!n){let t=i.resident.entries().next().value;if(t===void 0)throw e;R(t[1].handle),delete t[1].handle,i.resident.delete(t[0])}b=g()}let x=y(b,`admission response`),S=v(x.result,`admission result`),{subjectHash:C}=v(S.subject,`admitted subject`);if(typeof C!=`string`||!/^[0-9a-f]{64}$/u.test(C))throw TypeError(`Native GeoSpec admission did not return a valid subjectHash.`);let w=y(r.engine.subjectHandle(_({...o,method:`subjectHandle`,requestId:F(`handle`),subjectHash:C})),`subject-handle response`),T=v(w.result,`subject-handle result`).subjectHandle;if(T===void 0)throw TypeError(`Native GeoSpec did not return a subject handle.`);let D=i.inputs.get(C),O=D??h;D===void 0&&(i.inputs.set(C,O),i.binaryBytes+=s,i.descriptorBytes+=O.request.byteLength);for(let e of t)O.owners.add(e),E.set(e,C);return O.handle=T,i.resident.delete(C),i.resident.set(C,O),l.set(C,O),{subjectHash:C}},U=e=>{let t=l.get(e);if(t===void 0)throw TypeError(`This subject is not admitted by the active GeoSpec host.`);let n=p(r.engine);if(B(n),t.handle===void 0){let i=()=>r.engine.ingestSubject(t.request,t.primary,t.resources),a;try{a=i()}catch(e){let t=n.resident.entries().next().value;if(!f(e)||t===void 0)throw e;R(t[1].handle),delete t[1].handle,n.resident.delete(t[0]),a=i()}let s=()=>{let t=v(y(r.engine.subjectHandle(_({...o,method:`subjectHandle`,requestId:F(`restore-handle`),subjectHash:e})),`restored handle`).result,`restored handle result`),n=v(t.subjectHandle,`restored subject handle`);if(n.subjectHash!==e)throw TypeError(`Native GeoSpec restored handle changed its subject identity.`);return n};try{if(v(v(y(a,`restored admission`).result,`restored result`).subject,`restored subject`).subjectHash!==e)throw TypeError(`Native GeoSpec restored admission changed its subject identity.`);t.handle=s()}catch(e){throw t.cleanupPending=()=>{try{R(s())}catch(t){throw AggregateError([e,t],`Native GeoSpec restored admission failed and cleanup remains pending.`,{cause:e})}},t.cleanupPending(),delete t.cleanupPending,e}}n.resident.delete(e),n.resident.set(e,t)},W=async(e,t)=>{let n=S(e,r.format),i=await b(e.source,r.readSource),o=await Promise.all((e.resources??[]).map(async({name:e,source:t})=>({name:e,bytes:await b(t,r.readSource),...typeof t==`string`?{sourcePath:t}:{}}))),s=await Promise.all([{name:e.path??e.name??`primary`,bytes:i,...typeof e.source==`string`?{sourcePath:e.source}:{}},...o].map(async({name:e,bytes:t,sourcePath:n})=>({name:e,sha256:await a(t),byteLength:t.byteLength,...n===void 0?{}:{sourcePath:n}})));return{...H({format:n,primary:i,resources:o,...e.ingestOptions===void 0?{}:{ingestOptions:e.ingestOptions},...e.sourceUnit===void 0?{}:{sourceUnit:e.sourceUnit}},t),load:{loadId:``,status:`complete`,format:n,parameters:e.parameters??{},ingestOptions:e.ingestOptions??{},...typeof e.source==`string`?{sourcePath:e.source}:{},...e.workUnitLimit===void 0?{}:{workUnitLimit:e.workUnitLimit},artifacts:s}}},G=async(e,t)=>{for(let t of[`sourceUnit`,`unit`,`scale`,`coordinateSystem`])if(t in e)throw m([h({code:`GEOSPEC_NATIVE_RUNTIME_FRAME_OVERRIDE`,message:`Native Runtime model loading rejects '${t}': the Runtime export intent owns the frame.`,suggestion:`Remove the frame override and let GeoSpec request canonical Z-up millimetre evidence.`,details:{key:t}})]);let n=S(e,r.format),o=n===`stp`?`step`:n,s=await L(e);await s.connect();let c=await w(s,e),l={runtime:s,format:o,...c===void 0?{}:{kernelId:c},...e.meshLinearTolerance===void 0?{}:{meshLinearTolerance:e.meshLinearTolerance},...e.meshAngularToleranceDegrees===void 0?{}:{meshAngularToleranceDegrees:e.meshAngularToleranceDegrees}},u=i(l);if(`success`in u)throw m(u.diagnostics);let d=e.region===void 0?void 0:O(e.region);if(d!==void 0){let t=C(s,o).filter(e=>c===void 0||e.kernelId===c);if(!t.some(e=>e.transcoderId===void 0&&`region`in(e.exportOptions?.schema.properties??{}))){let n=[...new Set(t.flatMap(e=>e.kernelId===void 0?[]:[e.kernelId]))];throw m([h({code:`GEOSPEC_MODEL_REGION_UNSUPPORTED`,message:`No direct ${o.toUpperCase()} export of this Runtime${n.length===0?``:` (${n.join(`, `)})`} declares a region option, so GeoSpec cannot crop '${e.file}' before admission.`,suggestion:`Load the whole model; if it exceeds a host limit, provision more resources and report the claim as not decided at this capacity. A region load needs a kernel whose GLB export crops, such as PicoVoxel, and only scopes a separate claim to that region.`,details:{file:e.file,format:o,region:d,kernelIds:n}})])}}let f={...structuredClone(u.options),...d===void 0?{}:{region:{min:[...d.min],max:[...d.max]}}},p=s.open({source:x(e),...e.parameters===void 0?{}:{parameters:e.parameters},watch:!1}),_=await(async()=>{try{return await p.export(o,{options:structuredClone(f)})}finally{p.close()}})();if(!_.success)throw m(_.issues.map(g));if(d!==void 0&&!_.issues.some(e=>{let{details:t}=e,n=typeof t==`object`&&t&&`region`in t?t.region:void 0;return typeof n==`object`&&!!n&&T(n)===T({min:[...d.min],max:[...d.max]})}))throw m([h({code:`GEOSPEC_MODEL_REGION_NOT_HONORED`,message:`The Runtime export of '${e.file}' did not confirm the requested region crop, so its bytes may be the whole model.`,suggestion:`Load the whole model, or update the kernel so its export reports the region it cropped.`,details:{file:e.file,format:o,region:d}})]);let v=[..._.files],[y,...b]=v;if(y===void 0)throw m([h({code:`GEOSPEC_NATIVE_MODEL_EXPORT_EMPTY`,message:`The Tau Runtime exported no ${o.toUpperCase()} artifact for '${e.file}'.`,suggestion:`Check that the selected source exports geometry in the requested format.`,details:{file:e.file,format:o}})]);let E=i(l);if(`success`in E)throw m(E.diagnostics);let D=await Promise.all(v.map(async({name:e,bytes:t})=>({name:e,sha256:await a(t),byteLength:t.byteLength}))),k=_.sourceRevision===void 0?void 0:structuredClone(_.sourceRevision),A=k!==void 0&&/^sha256:[0-9a-f]{64}$/u.test(k.files[k.entry]??``)&&Object.values(k.files).every(e=>e===`missing`||/^sha256:[0-9a-f]{64}$/u.test(e));return{...H({format:o,primary:y.bytes,resources:b,sourceUnit:E.sourceUnit,diagnostics:_.issues.map(g),...e.ingestOptions===void 0?{}:{ingestOptions:e.ingestOptions}},t),load:{loadId:``,status:A?`complete`:`unavailable`,format:o,parameters:e.parameters??{},exportOptions:f,ingestOptions:e.ingestOptions??{},...k===void 0?{}:{sourceRevision:k},...e.workUnitLimit===void 0?{}:{workUnitLimit:e.workUnitLimit},...d===void 0?{}:{region:d},artifacts:D}}},K=(e,t)=>{let n=u.get(r.engine)?.inputs.get(e);return n===void 0||n.owners.size===0?!1:(n.owners.add(t),E.set(t,e),l.set(e,n),!0)},q=async(e,t)=>{let n=t.status===`complete`?t.sourceRevision:void 0;if(n===void 0)return!1;let r=await L(e);if(r.snapshotSource===void 0)return!1;try{let t=await r.snapshotSource({source:{path:e.file}});return t.success&&k(n,t)}catch{return!1}},J=async(e,t)=>{let n=e.runtime??r.runtime,i=`code`in e,a=i&&Object.values(e.code).every(e=>typeof e==`string`)?e.code:void 0,o=n===void 0||i&&a===void 0||[`sourceUnit`,`unit`,`scale`,`coordinateSystem`].some(t=>t in e)?void 0:T({file:e.file,code:a,projectPath:e.projectPath??r.projectPath,format:e.format??r.format??`glb`,meshLinearTolerance:e.meshLinearTolerance,meshAngularToleranceDegrees:e.meshAngularToleranceDegrees,parameters:e.parameters,ingestOptions:e.ingestOptions,region:e.region});if(n===void 0||o===void 0)return G(e,new Set([t]));let s=M.get(n);s===void 0&&(s=new Map,M.set(n,s));let c=s.get(o);if(c!==void 0){c.owners?.add(t);let n=await c.pending;if((c.owners!==void 0||await q(e,n.load))&&K(n.subjectHash,t)){let{workUnitLimit:t,...r}=n.load;return{subjectHash:n.subjectHash,load:{...r,...e.workUnitLimit===void 0?{}:{workUnitLimit:e.workUnitLimit},reused:!0}}}}let l=new Set([t]),u=G(e,l),d={pending:u,...a===void 0?{}:{owners:l}};return s.set(o,d),u.then(void 0,()=>{s.delete(o)}),u};return Object.assign(t=>{let i={},a=F(`load`),o={...t,...`code`in t?{code:Object.fromEntries(Object.entries(t.code))}:{},...t.parameters===void 0?{}:{parameters:structuredClone(t.parameters)},...t.ingestOptions===void 0?{}:{ingestOptions:structuredClone(t.ingestOptions)},...`region`in t&&t.region!==void 0?{region:structuredClone(t.region)}:{}},s=t.format??r.format??`glb`,u=[`stepStreaming`,...t.mesh===!1&&(s===`step`||s===`stp`)?[]:[`mesh`],...`source`in t?[`meshLinearTolerance`,`meshAngularToleranceDegrees`,`region`,...s===`step`||s===`stp`?[`sourceUnit`]:[]]:[],...s===`step`||s===`stp`?[`region`]:[]].find(e=>e in t&&(e!==`region`||t[e]!==void 0));if(u!==void 0)return Promise.reject(m([h({code:`GEOSPEC_MODEL_OPTION_UNSUPPORTED`,message:`This GeoSpec host cannot honor model option '${u}'.`,suggestion:`Remove this option or configure a host that supports its declared behavior.`,details:{option:u}})]));let d=e(t.workUnitLimit,`loadModel workUnitLimit`,c);if(d!==void 0)return Promise.reject(m([h({code:`GEOSPEC_MODEL_OPTION_INVALID`,message:d,suggestion:`Pass a positive integer workUnitLimit within the stated bound, or omit it for the engine default.`,details:{option:`workUnitLimit`}})]));let f=`source`in t?void 0:D(t.region);if(f!==void 0)return Promise.reject(f);let p=`source`in t?W(o,new Set([i])):J(o,i),g=(async()=>{let e=await p,t={...e,...e.load===void 0?{}:{load:{...e.load,loadId:a}}},r=A,o=!1;return n(t,{ensureResident(){if(r!==A||!E.has(i))throw TypeError(`This subject is not admitted by the active GeoSpec host.`);U(e.subjectHash)},dispose(){if(!(o||!E.has(i))){o=!0;try{z(e.subjectHash,i),E.delete(i),[...E.values()].includes(e.subjectHash)||l.delete(e.subjectHash)}finally{o=!1}}}}),t})();return j.add(g),g},{async releaseAll(){do{let e=[...j];await Promise.allSettled(e);for(let t of e)j.delete(t)}while(j.size>0);let e=[],{carried:t}=r;if(A+=1,M.clear(),t!==void 0){for(let[n,i]of V())try{u.get(r.engine)?.inputs.has(n)?z(n,t):R(i),t.delete(n)}catch(t){e.push(t)}for(let[e,n]of l)n.handle===void 0?(n.owners.delete(t),t.delete(e)):(n.owners.add(t),t.set(e,n.handle))}for(let[t,n]of[...E].reverse())try{z(n,t),E.delete(t),[...E.values()].includes(n)||l.delete(n)}catch(t){e.push(t)}for(let t of N)try{t.shutdown?await t.shutdown():t.terminate()}catch(t){e.push(t)}if(N.clear(),P.clear(),e.length>0)throw AggregateError(e,`Native GeoSpec model cleanup failed.`)}})};export{A as createGeoSpecNativeModelLoader};
|
|
@@ -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};
|
|
@@ -0,0 +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";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};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "./native-model-loader.mjs";
|
|
2
|
+
import "../engine/client.mjs";
|
|
3
|
+
import "../assertion-client/client.mjs";
|
|
4
|
+
//#region src/model/subject.d.ts
|
|
5
|
+
declare const subjectBrand: unique symbol;
|
|
6
|
+
/** A model admitted by one live GeoSpec host scope. Load it through `geospec/model`. @public */
|
|
7
|
+
type GeoSpecSubject = {
|
|
8
|
+
readonly [subjectBrand]: true;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { GeoSpecSubject };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=new WeakMap,t=new WeakMap,n=(n,r)=>{e.set(n,r),t.set(r.ensureResident,r)},r=t=>e.get(t)?.ensureResident,i=new WeakMap,a=e=>{let n=Object.freeze({});return i.set(n,{client:e.client,engine:e.engine,identity:e.identity,isLive:e.isLive,...e.load===void 0?{}:{load:e.load},...e.ensureResident===void 0?{}:{ensureResident:e.ensureResident},...e.ensureResident===void 0||!t.has(e.ensureResident)?{}:{lease:t.get(e.ensureResident)}}),n},o=(e,t)=>{let n=typeof e==`object`&&e?i.get(e):void 0;if(n===void 0||!n.isLive()||t!==void 0&&n.engine!==t)throw Object.assign(TypeError(`This subject is not admitted by the active GeoSpec host. Reload it within its live scope.`),{code:`GEOSPEC_SUBJECT_INVALID`});return n.ensureResident?.(),n};export{a as bindGeoSpecSubject,n as bindRawSubjectResidency,r as rawSubjectResidency,o as resolveGeoSpecSubject};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { GeoSpecUnit } from "../geometry-unit.mjs";
|
|
2
|
+
import { StepSource, StepStreamingMode } from "../step/types.mjs";
|
|
3
|
+
import { MeshFileFormat } from "../mesh/types.mjs";
|
|
4
|
+
import { GeoSpecSubject } from "./subject.mjs";
|
|
5
|
+
import { GeoSpecNativeModelEngine, GeoSpecNativeSourceReader } from "./native-model-loader.mjs";
|
|
6
|
+
import { RuntimeClient } from "@taucad/runtime";
|
|
7
|
+
//#region src/model/types.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* In-memory triangle mesh source.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
type MeshBufferSource = {
|
|
14
|
+
format: 'mesh-buffer';
|
|
15
|
+
positions: Float32Array<ArrayBuffer> | number[];
|
|
16
|
+
indices?: Uint32Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | number[];
|
|
17
|
+
name?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Mesh source forms accepted by {@link import('./load-model.js').loadModel}.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
type MeshSource = Uint8Array<ArrayBuffer> | ArrayBuffer | Blob | File | URL | string | MeshBufferSource;
|
|
25
|
+
/**
|
|
26
|
+
* Geometry formats accepted by {@link import('./load-model.js').loadModel}.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
type GeoSpecModelFormat = MeshFileFormat | 'step' | 'stp';
|
|
31
|
+
/**
|
|
32
|
+
* Runtime client surface consumed by `geospec/model`.
|
|
33
|
+
*
|
|
34
|
+
* GeoSpec accepts concrete Tau runtime clients from multiple call sites but
|
|
35
|
+
* only needs connection lifecycle and request-scoped documents. Keep this shape
|
|
36
|
+
* small so typed runtime clients do not have to widen their full generic
|
|
37
|
+
* method surface to GeoSpec's testing DSL. A client with `shutdown` is awaited
|
|
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. A client with
|
|
40
|
+
* `snapshotSource` lets one run reuse an identical file load after confirming
|
|
41
|
+
* that the source closure it exported is unchanged.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
type GeoSpecRuntimeClient = Pick<RuntimeClient, 'connect' | 'terminate'> & Partial<Pick<RuntimeClient, 'shutdown' | 'snapshotSource' | 'describe'>> & {
|
|
46
|
+
open: (input: Pick<Parameters<RuntimeClient['open']>[0], 'source' | 'parameters' | 'stage' | 'watch' | 'signal'>) => Pick<ReturnType<RuntimeClient['open']>, 'export' | 'close'>;
|
|
47
|
+
on?(event: 'telemetry', handler: (batch: {
|
|
48
|
+
readonly entries: ReadonlyArray<{
|
|
49
|
+
name: string;
|
|
50
|
+
duration: number;
|
|
51
|
+
startTime: number;
|
|
52
|
+
workerTimeOrigin: number;
|
|
53
|
+
}>;
|
|
54
|
+
}) => void): () => void;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Lazy runtime factory consumed by `geospec/model`.
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
type GeoSpecRuntimeClientFactory = () => Promise<GeoSpecRuntimeClient>;
|
|
62
|
+
/**
|
|
63
|
+
* Explicit source adapter for formats whose runtime setup is not part of the
|
|
64
|
+
* generic Tau runtime preset.
|
|
65
|
+
*
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
type GeoSpecRuntimeSourceAdapter = {
|
|
69
|
+
id: string;
|
|
70
|
+
extensions: readonly string[];
|
|
71
|
+
createRuntime(options: {
|
|
72
|
+
projectPath?: string;
|
|
73
|
+
file?: string;
|
|
74
|
+
}): Promise<GeoSpecRuntimeClient>;
|
|
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
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Direct geometry-source model load options.
|
|
87
|
+
*
|
|
88
|
+
* @public
|
|
89
|
+
*/
|
|
90
|
+
type LoadModelSourceOptions = {
|
|
91
|
+
/** Geometry bytes, path, browser file/blob, or in-memory mesh buffer. */
|
|
92
|
+
source: MeshSource | StepSource;
|
|
93
|
+
/** Named external resources consumed alongside the direct geometry bytes. */
|
|
94
|
+
resources?: ReadonlyArray<{
|
|
95
|
+
readonly name: string;
|
|
96
|
+
readonly source: MeshSource | StepSource;
|
|
97
|
+
}>;
|
|
98
|
+
/** Source geometry format. Defaults to `glb`. */
|
|
99
|
+
format?: GeoSpecModelFormat;
|
|
100
|
+
/** Source path recorded in provenance. */
|
|
101
|
+
path?: string;
|
|
102
|
+
/** Human-readable source name recorded in provenance. */
|
|
103
|
+
name?: string;
|
|
104
|
+
/** Coordinate unit of raw GLB/glTF or mesh-buffer data before canonical millimetre normalization. */
|
|
105
|
+
sourceUnit?: GeoSpecUnit;
|
|
106
|
+
/** Explicit parameters recorded in provenance. */
|
|
107
|
+
parameters?: Record<string, unknown>;
|
|
108
|
+
/** STEP reader strategy used for STEP sources. */
|
|
109
|
+
stepStreaming?: StepStreamingMode;
|
|
110
|
+
/** Whether STEP loading should also produce mesh evidence. Defaults to true. */
|
|
111
|
+
mesh?: boolean;
|
|
112
|
+
/** Linear tolerance used while meshing exact BRep evidence. */
|
|
113
|
+
meshLinearTolerance?: number;
|
|
114
|
+
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
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;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Inline code-CAD model load options.
|
|
125
|
+
*
|
|
126
|
+
* @public
|
|
127
|
+
*/
|
|
128
|
+
type LoadModelCodeOptions<Code extends Record<string, string> = Record<string, string>> = {
|
|
129
|
+
/** Source files keyed by project-relative path. */
|
|
130
|
+
code: Code;
|
|
131
|
+
/** Entry path to render from {@link code}. */
|
|
132
|
+
file: keyof Code & string;
|
|
133
|
+
/** Geometry format to export. Defaults to `glb`. */
|
|
134
|
+
format?: GeoSpecModelFormat;
|
|
135
|
+
/** Explicit parameters passed to the runtime. */
|
|
136
|
+
parameters?: Record<string, unknown>;
|
|
137
|
+
/** Runtime client or lazy runtime factory. */
|
|
138
|
+
runtime?: GeoSpecRuntimeClient | GeoSpecRuntimeClientFactory;
|
|
139
|
+
/** Source-specific runtime adapters, e.g. host-provided GPL-isolated kernels. */
|
|
140
|
+
sourceAdapters?: readonly GeoSpecRuntimeSourceAdapter[];
|
|
141
|
+
/** Project root used by runtime integrations. */
|
|
142
|
+
projectPath?: string;
|
|
143
|
+
/** STEP reader strategy used for STEP exports. */
|
|
144
|
+
stepStreaming?: StepStreamingMode;
|
|
145
|
+
/** Whether STEP loading should also produce mesh evidence. Defaults to true. */
|
|
146
|
+
mesh?: boolean;
|
|
147
|
+
/** Linear tolerance used while meshing exact BRep evidence. */
|
|
148
|
+
meshLinearTolerance?: number;
|
|
149
|
+
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
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;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Filesystem-backed model load options.
|
|
169
|
+
*
|
|
170
|
+
* @public
|
|
171
|
+
*/
|
|
172
|
+
type LoadModelFileOptions = {
|
|
173
|
+
/** Project-relative model file to render. */
|
|
174
|
+
file: string;
|
|
175
|
+
/** Project root used by runtime integrations. */
|
|
176
|
+
projectPath?: string;
|
|
177
|
+
/** Geometry format to export. Defaults to `glb`. */
|
|
178
|
+
format?: GeoSpecModelFormat;
|
|
179
|
+
/** Explicit parameters passed to the runtime. */
|
|
180
|
+
parameters?: Record<string, unknown>;
|
|
181
|
+
/** Runtime client or lazy runtime factory. */
|
|
182
|
+
runtime?: GeoSpecRuntimeClient | GeoSpecRuntimeClientFactory;
|
|
183
|
+
/** Source-specific runtime adapters, e.g. host-provided GPL-isolated kernels. */
|
|
184
|
+
sourceAdapters?: readonly GeoSpecRuntimeSourceAdapter[];
|
|
185
|
+
/** STEP reader strategy used for STEP exports. */
|
|
186
|
+
stepStreaming?: StepStreamingMode;
|
|
187
|
+
/** Whether STEP loading should also produce mesh evidence. Defaults to true. */
|
|
188
|
+
mesh?: boolean;
|
|
189
|
+
/** Linear tolerance used while meshing exact BRep evidence. */
|
|
190
|
+
meshLinearTolerance?: number;
|
|
191
|
+
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
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;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Options accepted by {@link import('./load-model.js').loadModel}.
|
|
211
|
+
*
|
|
212
|
+
* @public
|
|
213
|
+
*/
|
|
214
|
+
type LoadModelOptions<Code extends Record<string, string> = Record<string, string>> = LoadModelSourceOptions | LoadModelCodeOptions<Code> | LoadModelFileOptions;
|
|
215
|
+
/**
|
|
216
|
+
* Function shape used by GeoSpec runners to provide model loading inside VM
|
|
217
|
+
* executed test files.
|
|
218
|
+
*
|
|
219
|
+
* @public
|
|
220
|
+
*/
|
|
221
|
+
type GeoSpecModelLoader = <Code extends Record<string, string> = Record<string, string>>(options: LoadModelOptions<Code>) => Promise<GeoSpecSubject>;
|
|
222
|
+
/** A configured loader whose shared runtime can be released with its owner. @public */
|
|
223
|
+
type ManagedGeoSpecModelLoader = GeoSpecModelLoader & {
|
|
224
|
+
dispose(): Promise<void>;
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Defaults accepted by {@link import('./load-model.js').createModelLoader}.
|
|
228
|
+
*
|
|
229
|
+
* @public
|
|
230
|
+
*/
|
|
231
|
+
type CreateModelLoaderOptions = {
|
|
232
|
+
/** Initialized compiled engine supplied by the host, never selected by an authored spec. */
|
|
233
|
+
engine: GeoSpecNativeModelEngine;
|
|
234
|
+
/** Rooted host reader for direct filesystem or URL sources. */
|
|
235
|
+
readSource?: GeoSpecNativeSourceReader;
|
|
236
|
+
/** Geometry format to export when an individual call does not specify one. */
|
|
237
|
+
format?: GeoSpecModelFormat;
|
|
238
|
+
/** Runtime client or lazy runtime factory. */
|
|
239
|
+
runtime?: GeoSpecRuntimeClient | GeoSpecRuntimeClientFactory;
|
|
240
|
+
/** Source-specific runtime adapters, e.g. host-provided GPL-isolated kernels. */
|
|
241
|
+
sourceAdapters?: readonly GeoSpecRuntimeSourceAdapter[];
|
|
242
|
+
/** Project root used by runtime integrations. */
|
|
243
|
+
projectPath?: string;
|
|
244
|
+
/** STEP reader strategy used for STEP sources or exports. */
|
|
245
|
+
stepStreaming?: StepStreamingMode;
|
|
246
|
+
/** Whether STEP loading should also produce mesh evidence. Defaults to true. */
|
|
247
|
+
mesh?: boolean;
|
|
248
|
+
/** Linear tolerance used while meshing exact BRep evidence. */
|
|
249
|
+
meshLinearTolerance?: number;
|
|
250
|
+
/** Angular tolerance in degrees used while meshing exact BRep evidence. */
|
|
251
|
+
meshAngularToleranceDegrees?: number;
|
|
252
|
+
};
|
|
253
|
+
//#endregion
|
|
254
|
+
export { CreateModelLoaderOptions, GeoSpecLoadRegion, GeoSpecModelFormat, GeoSpecModelLoader, GeoSpecRuntimeClient, GeoSpecRuntimeClientFactory, GeoSpecRuntimeSourceAdapter, LoadModelCodeOptions, LoadModelFileOptions, LoadModelOptions, LoadModelSourceOptions, ManagedGeoSpecModelLoader, MeshBufferSource, MeshSource };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GeometryDiagnostic } from "../mesh/types.mjs";
|
|
2
|
+
import { GeoSpecExpectOptions, GeoSpecMatcher, GeoSpecTestCase, GeoSpecTestEvent } from "./types.mjs";
|
|
3
|
+
import { GeoSpecAssertionClientOptions } from "../assertion-client/client.mjs";
|
|
4
|
+
import "../assertion-client/index.mjs";
|
|
5
|
+
import { GeoSpecTestNamePattern } from "./filter.mjs";
|
|
6
|
+
//#region src/runner/collector.d.ts
|
|
7
|
+
type GeoSpecTestFunction = () => unknown | PromiseLike<unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Collects suites, tests, assertions, and async completion state for one
|
|
10
|
+
* GeoSpec module execution.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
type GeoSpecCollector = {
|
|
15
|
+
tests: GeoSpecTestCase[];
|
|
16
|
+
describe(name: string, function_: GeoSpecTestFunction): void;
|
|
17
|
+
describeSkip(name: string, _function?: GeoSpecTestFunction): void;
|
|
18
|
+
it(name: string, function_: GeoSpecTestFunction): void;
|
|
19
|
+
itSkip(name: string, _function?: GeoSpecTestFunction): void;
|
|
20
|
+
expectGeo(subject: unknown, options?: GeoSpecExpectOptions): GeoSpecMatcher;
|
|
21
|
+
waitForCompletion(testTimeout?: number, testNamePattern?: GeoSpecTestNamePattern): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
/** Per-module collector configuration; native subject/engine lifetime stays with the host. @public */
|
|
24
|
+
type GeoSpecCollectorOptions = {
|
|
25
|
+
matcherWallBackstop?: number;
|
|
26
|
+
forensic?: boolean;
|
|
27
|
+
nativeAssertions: GeoSpecAssertionClientOptions;
|
|
28
|
+
/** Observes each selected test as it starts and settles, for host progress reporting. */
|
|
29
|
+
onTestEvent?: (event: GeoSpecTestEvent) => void;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Assertion error thrown by GeoSpec matchers when an expectation does not hold.
|
|
33
|
+
*
|
|
34
|
+
* Runner, CLI, and tool adapters unwrap this error to preserve structured
|
|
35
|
+
* diagnostics instead of collapsing them into a single string.
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
declare class GeoSpecAssertionError extends Error {
|
|
40
|
+
readonly diagnostics: readonly GeometryDiagnostic[];
|
|
41
|
+
constructor(diagnostics: readonly GeometryDiagnostic[]);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create the collector used by the embedded GeoSpec runner.
|
|
45
|
+
*
|
|
46
|
+
* @param options - The native assertion client configuration for this module.
|
|
47
|
+
* @returns A fresh collector whose matchers evaluate through the native engine.
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
declare function createCollector(options: GeoSpecCollectorOptions): GeoSpecCollector;
|
|
51
|
+
/**
|
|
52
|
+
* Clear runner globals after a module finishes.
|
|
53
|
+
*/
|
|
54
|
+
/** @public */
|
|
55
|
+
declare const clearCollectorGlobals: () => void;
|
|
56
|
+
/**
|
|
57
|
+
* Install a collector into the current JavaScript global scope.
|
|
58
|
+
*
|
|
59
|
+
* @param collector - Collector for the active run.
|
|
60
|
+
*/
|
|
61
|
+
/** @public */
|
|
62
|
+
declare const installCollector: (collector: GeoSpecCollector) => void;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { GeoSpecAssertionError, GeoSpecCollector, GeoSpecCollectorOptions, clearCollectorGlobals, createCollector, installCollector };
|
|
@@ -0,0 +1,2 @@
|
|
|
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};
|