@panproto/core 0.6.0 → 0.8.0
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/README.md +40 -18
- package/dist/coverage.d.ts +58 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/data.d.ts +38 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/enrichment.d.ts +146 -0
- package/dist/enrichment.d.ts.map +1 -0
- package/dist/expr.d.ts +145 -0
- package/dist/expr.d.ts.map +1 -0
- package/dist/gat.d.ts +16 -0
- package/dist/gat.d.ts.map +1 -1
- package/dist/index.cjs +1030 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1031 -69
- package/dist/index.js.map +1 -1
- package/dist/lens.d.ts +171 -121
- package/dist/lens.d.ts.map +1 -1
- package/dist/panproto.d.ts +62 -2
- package/dist/panproto.d.ts.map +1 -1
- package/dist/protolens.d.ts +44 -0
- package/dist/protolens.d.ts.map +1 -0
- package/dist/types.d.ts +201 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/wasm.d.ts +23 -1
- package/dist/wasm.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -68,7 +68,21 @@ async function loadWasm(input) {
|
|
|
68
68
|
get_json: glue.get_json,
|
|
69
69
|
put_json: glue.put_json,
|
|
70
70
|
instance_element_count: glue.instance_element_count,
|
|
71
|
-
|
|
71
|
+
auto_generate_protolens: glue.auto_generate_protolens,
|
|
72
|
+
instantiate_protolens: glue.instantiate_protolens,
|
|
73
|
+
protolens_complement_spec: glue.protolens_complement_spec,
|
|
74
|
+
protolens_from_diff: glue.protolens_from_diff,
|
|
75
|
+
protolens_compose: glue.protolens_compose,
|
|
76
|
+
protolens_chain_to_json: glue.protolens_chain_to_json,
|
|
77
|
+
factorize_morphism: glue.factorize_morphism,
|
|
78
|
+
symmetric_lens_from_schemas: glue.symmetric_lens_from_schemas,
|
|
79
|
+
symmetric_lens_sync: glue.symmetric_lens_sync,
|
|
80
|
+
apply_protolens_step: glue.apply_protolens_step,
|
|
81
|
+
protolens_from_json: glue.protolens_from_json,
|
|
82
|
+
protolens_fuse: glue.protolens_fuse,
|
|
83
|
+
protolens_lift: glue.protolens_lift,
|
|
84
|
+
protolens_check_applicability: glue.protolens_check_applicability,
|
|
85
|
+
protolens_fleet: glue.protolens_fleet,
|
|
72
86
|
check_lens_laws: glue.check_lens_laws,
|
|
73
87
|
check_get_put: glue.check_get_put,
|
|
74
88
|
check_put_get: glue.check_put_get,
|
|
@@ -94,7 +108,16 @@ async function loadWasm(input) {
|
|
|
94
108
|
vcs_merge: glue.vcs_merge,
|
|
95
109
|
vcs_stash: glue.vcs_stash,
|
|
96
110
|
vcs_stash_pop: glue.vcs_stash_pop,
|
|
97
|
-
vcs_blame: glue.vcs_blame
|
|
111
|
+
vcs_blame: glue.vcs_blame,
|
|
112
|
+
// Phase 7: Data versioning
|
|
113
|
+
store_dataset: glue.store_dataset,
|
|
114
|
+
get_dataset: glue.get_dataset,
|
|
115
|
+
migrate_dataset_forward: glue.migrate_dataset_forward,
|
|
116
|
+
migrate_dataset_backward: glue.migrate_dataset_backward,
|
|
117
|
+
check_dataset_staleness: glue.check_dataset_staleness,
|
|
118
|
+
store_protocol_definition: glue.store_protocol_definition,
|
|
119
|
+
get_protocol_definition: glue.get_protocol_definition,
|
|
120
|
+
get_migration_complement: glue.get_migration_complement
|
|
98
121
|
};
|
|
99
122
|
const memory = initOutput.memory;
|
|
100
123
|
if (!memory) {
|
|
@@ -168,30 +191,212 @@ function packMigrationMapping(mapping) {
|
|
|
168
191
|
hyper_resolver: []
|
|
169
192
|
});
|
|
170
193
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
class ProtolensChainHandle {
|
|
195
|
+
#handle;
|
|
196
|
+
#wasm;
|
|
197
|
+
constructor(handle, wasm) {
|
|
198
|
+
this.#handle = handle;
|
|
199
|
+
this.#wasm = wasm;
|
|
200
|
+
}
|
|
201
|
+
/** The underlying WASM handle. Internal use only. */
|
|
202
|
+
get _handle() {
|
|
203
|
+
return this.#handle;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Auto-generate a protolens chain between two schemas.
|
|
207
|
+
*
|
|
208
|
+
* @param schema1 - The source schema
|
|
209
|
+
* @param schema2 - The target schema
|
|
210
|
+
* @param wasm - The WASM module
|
|
211
|
+
* @returns A ProtolensChainHandle wrapping the generated chain
|
|
212
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
213
|
+
*/
|
|
214
|
+
static autoGenerate(schema1, schema2, wasm) {
|
|
215
|
+
try {
|
|
216
|
+
const rawHandle = wasm.exports.auto_generate_protolens(schema1._handle.id, schema2._handle.id);
|
|
217
|
+
return new ProtolensChainHandle(createHandle(rawHandle, wasm), wasm);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
throw new WasmError(
|
|
220
|
+
`auto_generate_protolens failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
221
|
+
{ cause: error }
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Instantiate this protolens chain against a concrete schema.
|
|
227
|
+
*
|
|
228
|
+
* @param schema - The schema to instantiate against
|
|
229
|
+
* @returns A LensHandle for the instantiated lens
|
|
230
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
231
|
+
*/
|
|
232
|
+
instantiate(schema) {
|
|
233
|
+
try {
|
|
234
|
+
const rawHandle = this.#wasm.exports.instantiate_protolens(this.#handle.id, schema._handle.id);
|
|
235
|
+
return new LensHandle(createHandle(rawHandle, this.#wasm), this.#wasm);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
throw new WasmError(
|
|
238
|
+
`instantiate_protolens failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
239
|
+
{ cause: error }
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the complement specification for instantiation against a schema.
|
|
245
|
+
*
|
|
246
|
+
* @param schema - The schema to check requirements against
|
|
247
|
+
* @returns The complement spec describing defaults and captured data
|
|
248
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
249
|
+
*/
|
|
250
|
+
requirements(schema) {
|
|
251
|
+
try {
|
|
252
|
+
const bytes = this.#wasm.exports.protolens_complement_spec(this.#handle.id, schema._handle.id);
|
|
253
|
+
return unpackFromWasm(bytes);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new WasmError(
|
|
256
|
+
`protolens_complement_spec failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
257
|
+
{ cause: error }
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Compose this chain with another protolens chain.
|
|
263
|
+
*
|
|
264
|
+
* @param other - The chain to compose with (applied second)
|
|
265
|
+
* @returns A new ProtolensChainHandle for the composed chain
|
|
266
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
267
|
+
*/
|
|
268
|
+
compose(other) {
|
|
269
|
+
try {
|
|
270
|
+
const rawHandle = this.#wasm.exports.protolens_compose(this.#handle.id, other.#handle.id);
|
|
271
|
+
return new ProtolensChainHandle(createHandle(rawHandle, this.#wasm), this.#wasm);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
throw new WasmError(
|
|
274
|
+
`protolens_compose failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
275
|
+
{ cause: error }
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Serialize this chain to a JSON string.
|
|
281
|
+
*
|
|
282
|
+
* @returns A JSON representation of the chain
|
|
283
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
284
|
+
*/
|
|
285
|
+
toJson() {
|
|
286
|
+
try {
|
|
287
|
+
const bytes = this.#wasm.exports.protolens_chain_to_json(this.#handle.id);
|
|
288
|
+
return new TextDecoder().decode(bytes);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw new WasmError(
|
|
291
|
+
`protolens_chain_to_json failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
292
|
+
{ cause: error }
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Deserialize a protolens chain from JSON via WASM.
|
|
298
|
+
*
|
|
299
|
+
* @param json - JSON string representing a protolens chain
|
|
300
|
+
* @param wasm - The WASM module
|
|
301
|
+
* @returns A ProtolensChainHandle wrapping the deserialized chain
|
|
302
|
+
* @throws {@link WasmError} if the WASM call fails or JSON is invalid
|
|
303
|
+
*/
|
|
304
|
+
static fromJson(json, wasm) {
|
|
305
|
+
try {
|
|
306
|
+
const jsonBytes = new TextEncoder().encode(json);
|
|
307
|
+
const rawHandle = wasm.exports.protolens_from_json(jsonBytes);
|
|
308
|
+
return new ProtolensChainHandle(createHandle(rawHandle, wasm), wasm);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
throw new WasmError(
|
|
311
|
+
`protolens_from_json failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
312
|
+
{ cause: error }
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Fuse this chain into a single protolens step.
|
|
318
|
+
*
|
|
319
|
+
* Composes all steps into a single step with a composite complement,
|
|
320
|
+
* avoiding intermediate schema materialization.
|
|
321
|
+
*
|
|
322
|
+
* @returns A new ProtolensChainHandle containing the fused step
|
|
323
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
324
|
+
*/
|
|
325
|
+
fuse() {
|
|
326
|
+
try {
|
|
327
|
+
const rawHandle = this.#wasm.exports.protolens_fuse(this.#handle.id);
|
|
328
|
+
return new ProtolensChainHandle(createHandle(rawHandle, this.#wasm), this.#wasm);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
throw new WasmError(
|
|
331
|
+
`protolens_fuse failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
332
|
+
{ cause: error }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Check whether this chain can be instantiated at a given schema.
|
|
338
|
+
*
|
|
339
|
+
* @param schema - The schema to check against
|
|
340
|
+
* @returns An object with `applicable` boolean and `reasons` array
|
|
341
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
342
|
+
*/
|
|
343
|
+
checkApplicability(schema) {
|
|
344
|
+
try {
|
|
345
|
+
const bytes = this.#wasm.exports.protolens_check_applicability(this.#handle.id, schema._handle.id);
|
|
346
|
+
return unpackFromWasm(bytes);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
throw new WasmError(
|
|
349
|
+
`protolens_check_applicability failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
350
|
+
{ cause: error }
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Lift this chain along a theory morphism.
|
|
356
|
+
*
|
|
357
|
+
* Given a morphism between theories, produces a new chain that operates
|
|
358
|
+
* on schemas of the codomain theory instead of the domain theory.
|
|
359
|
+
*
|
|
360
|
+
* @param morphismBytes - MessagePack-encoded theory morphism
|
|
361
|
+
* @returns A new ProtolensChainHandle for the lifted chain
|
|
362
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
363
|
+
*/
|
|
364
|
+
lift(morphismBytes) {
|
|
365
|
+
try {
|
|
366
|
+
const rawHandle = this.#wasm.exports.protolens_lift(this.#handle.id, morphismBytes);
|
|
367
|
+
return new ProtolensChainHandle(createHandle(rawHandle, this.#wasm), this.#wasm);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
throw new WasmError(
|
|
370
|
+
`protolens_lift failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
371
|
+
{ cause: error }
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Apply this chain to a fleet of schemas.
|
|
377
|
+
*
|
|
378
|
+
* Checks applicability and instantiates the chain against each schema.
|
|
379
|
+
*
|
|
380
|
+
* @param schemas - Array of schema handles to apply the chain to
|
|
381
|
+
* @returns Fleet result with applied/skipped schema names and reasons
|
|
382
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
383
|
+
*/
|
|
384
|
+
applyToFleet(schemas) {
|
|
385
|
+
try {
|
|
386
|
+
const handles = new Uint32Array(schemas.map((s) => s._handle.id));
|
|
387
|
+
const bytes = this.#wasm.exports.protolens_fleet(this.#handle.id, handles);
|
|
388
|
+
return unpackFromWasm(bytes);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
throw new WasmError(
|
|
391
|
+
`protolens_fleet failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
392
|
+
{ cause: error }
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/** Release the underlying WASM resource. */
|
|
397
|
+
[Symbol.dispose]() {
|
|
398
|
+
this.#handle[Symbol.dispose]();
|
|
399
|
+
}
|
|
195
400
|
}
|
|
196
401
|
class LensHandle {
|
|
197
402
|
#handle;
|
|
@@ -204,6 +409,53 @@ class LensHandle {
|
|
|
204
409
|
get _handle() {
|
|
205
410
|
return this.#handle;
|
|
206
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Auto-generate a lens between two schemas.
|
|
414
|
+
*
|
|
415
|
+
* Generates a protolens chain and immediately instantiates it.
|
|
416
|
+
*
|
|
417
|
+
* @param schema1 - The source schema
|
|
418
|
+
* @param schema2 - The target schema
|
|
419
|
+
* @param wasm - The WASM module
|
|
420
|
+
* @returns A LensHandle wrapping the generated lens
|
|
421
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
422
|
+
*/
|
|
423
|
+
static autoGenerate(schema1, schema2, wasm) {
|
|
424
|
+
try {
|
|
425
|
+
const rawHandle = wasm.exports.auto_generate_protolens(schema1._handle.id, schema2._handle.id);
|
|
426
|
+
const chainHandle = createHandle(rawHandle, wasm);
|
|
427
|
+
const lensRaw = wasm.exports.instantiate_protolens(chainHandle.id, schema1._handle.id);
|
|
428
|
+
chainHandle[Symbol.dispose]();
|
|
429
|
+
const handle = createHandle(lensRaw, wasm);
|
|
430
|
+
return new LensHandle(handle, wasm);
|
|
431
|
+
} catch (error) {
|
|
432
|
+
throw new WasmError(
|
|
433
|
+
`autoGenerate failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
434
|
+
{ cause: error }
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Create a lens by instantiating a protolens chain against a schema.
|
|
440
|
+
*
|
|
441
|
+
* @param chain - The protolens chain to instantiate
|
|
442
|
+
* @param schema - The schema to instantiate against
|
|
443
|
+
* @param wasm - The WASM module
|
|
444
|
+
* @returns A LensHandle wrapping the instantiated lens
|
|
445
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
446
|
+
*/
|
|
447
|
+
static fromChain(chain, schema, wasm) {
|
|
448
|
+
try {
|
|
449
|
+
const rawHandle = wasm.exports.instantiate_protolens(chain._handle.id, schema._handle.id);
|
|
450
|
+
const handle = createHandle(rawHandle, wasm);
|
|
451
|
+
return new LensHandle(handle, wasm);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
throw new WasmError(
|
|
454
|
+
`fromChain failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
455
|
+
{ cause: error }
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
207
459
|
/**
|
|
208
460
|
* Forward projection: extract the view from a record.
|
|
209
461
|
*
|
|
@@ -321,40 +573,74 @@ class LensHandle {
|
|
|
321
573
|
this.#handle[Symbol.dispose]();
|
|
322
574
|
}
|
|
323
575
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
protocol._handle.id,
|
|
331
|
-
combBytes
|
|
332
|
-
);
|
|
333
|
-
const handle = createHandle(rawHandle, wasm);
|
|
334
|
-
return new LensHandle(handle, wasm);
|
|
335
|
-
} catch (error) {
|
|
336
|
-
throw new WasmError(
|
|
337
|
-
`lens_from_combinators failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
338
|
-
{ cause: error }
|
|
339
|
-
);
|
|
576
|
+
class SymmetricLensHandle {
|
|
577
|
+
#handle;
|
|
578
|
+
#wasm;
|
|
579
|
+
constructor(handle, wasm) {
|
|
580
|
+
this.#handle = handle;
|
|
581
|
+
this.#wasm = wasm;
|
|
340
582
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
583
|
+
/**
|
|
584
|
+
* Create a symmetric lens between two schemas.
|
|
585
|
+
*
|
|
586
|
+
* @param schema1 - The left schema
|
|
587
|
+
* @param schema2 - The right schema
|
|
588
|
+
* @param wasm - The WASM module
|
|
589
|
+
* @returns A SymmetricLensHandle for bidirectional sync
|
|
590
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
591
|
+
*/
|
|
592
|
+
static fromSchemas(schema1, schema2, wasm) {
|
|
593
|
+
try {
|
|
594
|
+
const rawHandle = wasm.exports.symmetric_lens_from_schemas(schema1._handle.id, schema2._handle.id);
|
|
595
|
+
return new SymmetricLensHandle(createHandle(rawHandle, wasm), wasm);
|
|
596
|
+
} catch (error) {
|
|
597
|
+
throw new WasmError(
|
|
598
|
+
`symmetric_lens_from_schemas failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
599
|
+
{ cause: error }
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Synchronize left view to right view.
|
|
605
|
+
*
|
|
606
|
+
* @param leftView - MessagePack-encoded left view data
|
|
607
|
+
* @param leftComplement - Opaque complement bytes from a prior sync
|
|
608
|
+
* @returns The synchronized right view and updated complement
|
|
609
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
610
|
+
*/
|
|
611
|
+
syncLeftToRight(leftView, leftComplement) {
|
|
612
|
+
try {
|
|
613
|
+
const bytes = this.#wasm.exports.symmetric_lens_sync(this.#handle.id, leftView, leftComplement, 0);
|
|
614
|
+
return unpackFromWasm(bytes);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
throw new WasmError(
|
|
617
|
+
`symmetric_lens_sync (left-to-right) failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
618
|
+
{ cause: error }
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Synchronize right view to left view.
|
|
624
|
+
*
|
|
625
|
+
* @param rightView - MessagePack-encoded right view data
|
|
626
|
+
* @param rightComplement - Opaque complement bytes from a prior sync
|
|
627
|
+
* @returns The synchronized left view and updated complement
|
|
628
|
+
* @throws {@link WasmError} if the WASM call fails
|
|
629
|
+
*/
|
|
630
|
+
syncRightToLeft(rightView, rightComplement) {
|
|
631
|
+
try {
|
|
632
|
+
const bytes = this.#wasm.exports.symmetric_lens_sync(this.#handle.id, rightView, rightComplement, 1);
|
|
633
|
+
return unpackFromWasm(bytes);
|
|
634
|
+
} catch (error) {
|
|
635
|
+
throw new WasmError(
|
|
636
|
+
`symmetric_lens_sync (right-to-left) failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
637
|
+
{ cause: error }
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/** Release the underlying WASM resource. */
|
|
642
|
+
[Symbol.dispose]() {
|
|
643
|
+
this.#handle[Symbol.dispose]();
|
|
358
644
|
}
|
|
359
645
|
}
|
|
360
646
|
class FullDiffReport {
|
|
@@ -1700,6 +1986,70 @@ class Repository {
|
|
|
1700
1986
|
this.#handle[Symbol.dispose]();
|
|
1701
1987
|
}
|
|
1702
1988
|
}
|
|
1989
|
+
class DataSetHandle {
|
|
1990
|
+
#handle;
|
|
1991
|
+
#wasm;
|
|
1992
|
+
constructor(handle, wasm) {
|
|
1993
|
+
this.#handle = handle;
|
|
1994
|
+
this.#wasm = wasm;
|
|
1995
|
+
}
|
|
1996
|
+
/** The WASM handle for this data set. Internal use only. */
|
|
1997
|
+
get _handle() {
|
|
1998
|
+
return this.#handle;
|
|
1999
|
+
}
|
|
2000
|
+
/** Store a data set from a JavaScript object, bound to a schema. */
|
|
2001
|
+
static fromData(data, schema, wasm) {
|
|
2002
|
+
const jsonBytes = new TextEncoder().encode(JSON.stringify(data));
|
|
2003
|
+
const rawHandle = wasm.exports.store_dataset(schema._handle.id, jsonBytes);
|
|
2004
|
+
return new DataSetHandle(createHandle(rawHandle, wasm), wasm);
|
|
2005
|
+
}
|
|
2006
|
+
/** Retrieve the data as MessagePack-encoded bytes. */
|
|
2007
|
+
getData() {
|
|
2008
|
+
const bytes = this.#wasm.exports.get_dataset(this.#handle.id);
|
|
2009
|
+
return unpackFromWasm(bytes);
|
|
2010
|
+
}
|
|
2011
|
+
/** Migrate this data set forward to a new schema. */
|
|
2012
|
+
migrateForward(srcSchema, tgtSchema) {
|
|
2013
|
+
const bytes = this.#wasm.exports.migrate_dataset_forward(
|
|
2014
|
+
this.#handle.id,
|
|
2015
|
+
srcSchema._handle.id,
|
|
2016
|
+
tgtSchema._handle.id
|
|
2017
|
+
);
|
|
2018
|
+
const result = unpackFromWasm(bytes);
|
|
2019
|
+
const complementBytes = this.#wasm.exports.get_dataset(result.complement_handle);
|
|
2020
|
+
this.#wasm.exports.free_handle(result.complement_handle);
|
|
2021
|
+
return {
|
|
2022
|
+
data: new DataSetHandle(createHandle(result.data_handle, this.#wasm), this.#wasm),
|
|
2023
|
+
complement: new Uint8Array(complementBytes)
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
/** Migrate this data set backward using a complement. */
|
|
2027
|
+
migrateBackward(complement, srcSchema, tgtSchema) {
|
|
2028
|
+
const rawHandle = this.#wasm.exports.migrate_dataset_backward(
|
|
2029
|
+
this.#handle.id,
|
|
2030
|
+
complement,
|
|
2031
|
+
srcSchema._handle.id,
|
|
2032
|
+
tgtSchema._handle.id
|
|
2033
|
+
);
|
|
2034
|
+
return new DataSetHandle(createHandle(rawHandle, this.#wasm), this.#wasm);
|
|
2035
|
+
}
|
|
2036
|
+
/** Check if this data set is stale relative to a schema. */
|
|
2037
|
+
isStale(schema) {
|
|
2038
|
+
const bytes = this.#wasm.exports.check_dataset_staleness(
|
|
2039
|
+
this.#handle.id,
|
|
2040
|
+
schema._handle.id
|
|
2041
|
+
);
|
|
2042
|
+
const raw = unpackFromWasm(bytes);
|
|
2043
|
+
return {
|
|
2044
|
+
stale: raw.stale,
|
|
2045
|
+
dataSchemaId: raw.data_schema_id,
|
|
2046
|
+
targetSchemaId: raw.target_schema_id
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
[Symbol.dispose]() {
|
|
2050
|
+
this.#handle[Symbol.dispose]();
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
1703
2053
|
class Panproto {
|
|
1704
2054
|
#wasm;
|
|
1705
2055
|
#protocols;
|
|
@@ -1707,6 +2057,10 @@ class Panproto {
|
|
|
1707
2057
|
this.#wasm = wasm;
|
|
1708
2058
|
this.#protocols = /* @__PURE__ */ new Map();
|
|
1709
2059
|
}
|
|
2060
|
+
/** The WASM module reference. Internal use only. */
|
|
2061
|
+
get _wasm() {
|
|
2062
|
+
return this.#wasm;
|
|
2063
|
+
}
|
|
1710
2064
|
/**
|
|
1711
2065
|
* Initialize the panproto SDK by loading the WASM module.
|
|
1712
2066
|
*
|
|
@@ -1929,6 +2283,76 @@ class Panproto {
|
|
|
1929
2283
|
initRepo(protocolName) {
|
|
1930
2284
|
return Repository.init(protocolName, this.#wasm);
|
|
1931
2285
|
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Convert data from one schema to another using an auto-generated lens.
|
|
2288
|
+
*
|
|
2289
|
+
* This is a convenience method that generates a protolens, applies the
|
|
2290
|
+
* forward projection, and disposes the lens automatically.
|
|
2291
|
+
*
|
|
2292
|
+
* @param data - The input data (Uint8Array of MessagePack, or a plain object)
|
|
2293
|
+
* @param opts - Conversion options specifying source and target schemas
|
|
2294
|
+
* @returns The converted data
|
|
2295
|
+
* @throws {@link WasmError} if lens generation or conversion fails
|
|
2296
|
+
*/
|
|
2297
|
+
async convert(data, opts) {
|
|
2298
|
+
const lens = LensHandle.autoGenerate(opts.from, opts.to, this.#wasm);
|
|
2299
|
+
try {
|
|
2300
|
+
const input = data instanceof Uint8Array ? data : packToWasm(data);
|
|
2301
|
+
const result = lens.get(input);
|
|
2302
|
+
return result.view;
|
|
2303
|
+
} finally {
|
|
2304
|
+
lens[Symbol.dispose]();
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Create an auto-generated lens between two schemas.
|
|
2309
|
+
*
|
|
2310
|
+
* @param from - The source schema
|
|
2311
|
+
* @param to - The target schema
|
|
2312
|
+
* @returns A LensHandle for the generated lens
|
|
2313
|
+
* @throws {@link WasmError} if lens generation fails
|
|
2314
|
+
*/
|
|
2315
|
+
lens(from, to) {
|
|
2316
|
+
return LensHandle.autoGenerate(from, to, this.#wasm);
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Create a protolens chain between two schemas.
|
|
2320
|
+
*
|
|
2321
|
+
* The returned chain is schema-independent and can be instantiated
|
|
2322
|
+
* against different concrete schemas.
|
|
2323
|
+
*
|
|
2324
|
+
* @param from - The source schema
|
|
2325
|
+
* @param to - The target schema
|
|
2326
|
+
* @returns A ProtolensChainHandle for the generated chain
|
|
2327
|
+
* @throws {@link WasmError} if chain generation fails
|
|
2328
|
+
*/
|
|
2329
|
+
protolensChain(from, to) {
|
|
2330
|
+
return ProtolensChainHandle.autoGenerate(from, to, this.#wasm);
|
|
2331
|
+
}
|
|
2332
|
+
/**
|
|
2333
|
+
* Store and track a data set against a schema.
|
|
2334
|
+
*
|
|
2335
|
+
* @param data - The data to store (array of records or a single object)
|
|
2336
|
+
* @param schema - The schema this data conforms to
|
|
2337
|
+
* @returns A disposable DataSetHandle
|
|
2338
|
+
*/
|
|
2339
|
+
dataSet(data, schema) {
|
|
2340
|
+
return DataSetHandle.fromData(data, schema, this.#wasm);
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Migrate data forward between two schemas.
|
|
2344
|
+
*
|
|
2345
|
+
* Auto-generates a lens and migrates each record, returning the
|
|
2346
|
+
* migrated data and a complement for backward migration.
|
|
2347
|
+
*
|
|
2348
|
+
* @param data - The data set to migrate
|
|
2349
|
+
* @param from - The source schema
|
|
2350
|
+
* @param to - The target schema
|
|
2351
|
+
* @returns The migration result with new data and complement
|
|
2352
|
+
*/
|
|
2353
|
+
migrateData(data, from, to) {
|
|
2354
|
+
return data.migrateForward(from, to);
|
|
2355
|
+
}
|
|
1932
2356
|
/**
|
|
1933
2357
|
* Release all WASM resources held by this instance.
|
|
1934
2358
|
*
|
|
@@ -1942,6 +2366,535 @@ class Panproto {
|
|
|
1942
2366
|
this.#protocols.clear();
|
|
1943
2367
|
}
|
|
1944
2368
|
}
|
|
2369
|
+
class SchemaEnrichment {
|
|
2370
|
+
#schema;
|
|
2371
|
+
#defaults;
|
|
2372
|
+
#coercions;
|
|
2373
|
+
#mergers;
|
|
2374
|
+
#policies;
|
|
2375
|
+
constructor(schema, defaults = [], coercions = [], mergers = [], policies = []) {
|
|
2376
|
+
this.#schema = schema;
|
|
2377
|
+
this.#defaults = defaults;
|
|
2378
|
+
this.#coercions = coercions;
|
|
2379
|
+
this.#mergers = mergers;
|
|
2380
|
+
this.#policies = policies;
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* Add a default expression for a vertex.
|
|
2384
|
+
*
|
|
2385
|
+
* The expression is evaluated when forward migration encounters a
|
|
2386
|
+
* missing value at the given vertex.
|
|
2387
|
+
*
|
|
2388
|
+
* @param vertex - The vertex identifier to attach the default to
|
|
2389
|
+
* @param expr - The default expression
|
|
2390
|
+
* @returns A new enrichment with the default added
|
|
2391
|
+
* @throws {@link PanprotoError} if the vertex is not in the schema
|
|
2392
|
+
*/
|
|
2393
|
+
addDefault(vertex, expr) {
|
|
2394
|
+
this.#assertVertex(vertex);
|
|
2395
|
+
if (this.#defaults.some((d) => d.vertex === vertex)) {
|
|
2396
|
+
throw new PanprotoError(
|
|
2397
|
+
`Default already exists for vertex "${vertex}". Remove it first with removeDefault().`
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
return new SchemaEnrichment(
|
|
2401
|
+
this.#schema,
|
|
2402
|
+
[...this.#defaults, { vertex, expr }],
|
|
2403
|
+
this.#coercions,
|
|
2404
|
+
this.#mergers,
|
|
2405
|
+
this.#policies
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Add a coercion function between two value kinds.
|
|
2410
|
+
*
|
|
2411
|
+
* The expression defines how to convert values from `fromKind` to
|
|
2412
|
+
* `toKind`. It receives a single argument (the source value) and
|
|
2413
|
+
* must produce a value of the target kind.
|
|
2414
|
+
*
|
|
2415
|
+
* @param fromKind - Source value kind (e.g., 'int')
|
|
2416
|
+
* @param toKind - Target value kind (e.g., 'float')
|
|
2417
|
+
* @param expr - The coercion expression
|
|
2418
|
+
* @returns A new enrichment with the coercion added
|
|
2419
|
+
* @throws {@link PanprotoError} if a coercion for this pair already exists
|
|
2420
|
+
*/
|
|
2421
|
+
addCoercion(fromKind, toKind, expr) {
|
|
2422
|
+
if (this.#coercions.some((c) => c.from === fromKind && c.to === toKind)) {
|
|
2423
|
+
throw new PanprotoError(
|
|
2424
|
+
`Coercion from "${fromKind}" to "${toKind}" already exists. Remove it first with removeCoercion().`
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
return new SchemaEnrichment(
|
|
2428
|
+
this.#schema,
|
|
2429
|
+
this.#defaults,
|
|
2430
|
+
[...this.#coercions, { from: fromKind, to: toKind, expr }],
|
|
2431
|
+
this.#mergers,
|
|
2432
|
+
this.#policies
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* Add a merger expression for a vertex.
|
|
2437
|
+
*
|
|
2438
|
+
* The expression defines how to merge two conflicting values at the
|
|
2439
|
+
* given vertex. It receives two arguments (left and right values)
|
|
2440
|
+
* and must produce a single merged value.
|
|
2441
|
+
*
|
|
2442
|
+
* @param vertex - The vertex identifier to attach the merger to
|
|
2443
|
+
* @param expr - The merger expression
|
|
2444
|
+
* @returns A new enrichment with the merger added
|
|
2445
|
+
* @throws {@link PanprotoError} if the vertex is not in the schema
|
|
2446
|
+
*/
|
|
2447
|
+
addMerger(vertex, expr) {
|
|
2448
|
+
this.#assertVertex(vertex);
|
|
2449
|
+
if (this.#mergers.some((m) => m.vertex === vertex)) {
|
|
2450
|
+
throw new PanprotoError(
|
|
2451
|
+
`Merger already exists for vertex "${vertex}". Remove it first.`
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
return new SchemaEnrichment(
|
|
2455
|
+
this.#schema,
|
|
2456
|
+
this.#defaults,
|
|
2457
|
+
this.#coercions,
|
|
2458
|
+
[...this.#mergers, { vertex, expr }],
|
|
2459
|
+
this.#policies
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Add a conflict resolution policy for a vertex.
|
|
2464
|
+
*
|
|
2465
|
+
* @param vertex - The vertex identifier
|
|
2466
|
+
* @param strategy - The conflict resolution strategy
|
|
2467
|
+
* @returns A new enrichment with the policy added
|
|
2468
|
+
* @throws {@link PanprotoError} if the vertex is not in the schema
|
|
2469
|
+
*/
|
|
2470
|
+
addPolicy(vertex, strategy) {
|
|
2471
|
+
this.#assertVertex(vertex);
|
|
2472
|
+
if (this.#policies.some((p) => p.vertex === vertex)) {
|
|
2473
|
+
throw new PanprotoError(
|
|
2474
|
+
`Policy already exists for vertex "${vertex}". Remove it first.`
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
return new SchemaEnrichment(
|
|
2478
|
+
this.#schema,
|
|
2479
|
+
this.#defaults,
|
|
2480
|
+
this.#coercions,
|
|
2481
|
+
this.#mergers,
|
|
2482
|
+
[...this.#policies, { vertex, strategy }]
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Remove the default expression for a vertex.
|
|
2487
|
+
*
|
|
2488
|
+
* @param vertex - The vertex identifier
|
|
2489
|
+
* @returns A new enrichment with the default removed
|
|
2490
|
+
* @throws {@link PanprotoError} if no default exists for the vertex
|
|
2491
|
+
*/
|
|
2492
|
+
removeDefault(vertex) {
|
|
2493
|
+
const filtered = this.#defaults.filter((d) => d.vertex !== vertex);
|
|
2494
|
+
if (filtered.length === this.#defaults.length) {
|
|
2495
|
+
throw new PanprotoError(
|
|
2496
|
+
`No default exists for vertex "${vertex}".`
|
|
2497
|
+
);
|
|
2498
|
+
}
|
|
2499
|
+
return new SchemaEnrichment(
|
|
2500
|
+
this.#schema,
|
|
2501
|
+
filtered,
|
|
2502
|
+
this.#coercions,
|
|
2503
|
+
this.#mergers,
|
|
2504
|
+
this.#policies
|
|
2505
|
+
);
|
|
2506
|
+
}
|
|
2507
|
+
/**
|
|
2508
|
+
* Remove the coercion function for a value kind pair.
|
|
2509
|
+
*
|
|
2510
|
+
* @param fromKind - Source value kind
|
|
2511
|
+
* @param toKind - Target value kind
|
|
2512
|
+
* @returns A new enrichment with the coercion removed
|
|
2513
|
+
* @throws {@link PanprotoError} if no coercion exists for the pair
|
|
2514
|
+
*/
|
|
2515
|
+
removeCoercion(fromKind, toKind) {
|
|
2516
|
+
const filtered = this.#coercions.filter(
|
|
2517
|
+
(c) => !(c.from === fromKind && c.to === toKind)
|
|
2518
|
+
);
|
|
2519
|
+
if (filtered.length === this.#coercions.length) {
|
|
2520
|
+
throw new PanprotoError(
|
|
2521
|
+
`No coercion exists from "${fromKind}" to "${toKind}".`
|
|
2522
|
+
);
|
|
2523
|
+
}
|
|
2524
|
+
return new SchemaEnrichment(
|
|
2525
|
+
this.#schema,
|
|
2526
|
+
this.#defaults,
|
|
2527
|
+
filtered,
|
|
2528
|
+
this.#mergers,
|
|
2529
|
+
this.#policies
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
/**
|
|
2533
|
+
* List all enrichments currently attached.
|
|
2534
|
+
*
|
|
2535
|
+
* @returns An enrichment summary with defaults, coercions, mergers, and policies
|
|
2536
|
+
*/
|
|
2537
|
+
listEnrichments() {
|
|
2538
|
+
return {
|
|
2539
|
+
defaults: this.#defaults.map((d) => ({ vertex: d.vertex, expr: d.expr })),
|
|
2540
|
+
coercions: this.#coercions.map((c) => ({ from: c.from, to: c.to, expr: c.expr })),
|
|
2541
|
+
mergers: this.#mergers.map((m) => ({ vertex: m.vertex, expr: m.expr })),
|
|
2542
|
+
policies: this.#policies.map((p) => ({ vertex: p.vertex, strategy: p.strategy }))
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Build the enriched schema.
|
|
2547
|
+
*
|
|
2548
|
+
* Returns a new `BuiltSchema` with the enrichments recorded in the
|
|
2549
|
+
* schema data. The underlying WASM handle is shared with the original
|
|
2550
|
+
* schema (enrichments are metadata that the SDK tracks client-side).
|
|
2551
|
+
*
|
|
2552
|
+
* @returns A new BuiltSchema with enrichment metadata
|
|
2553
|
+
*/
|
|
2554
|
+
build() {
|
|
2555
|
+
const originalData = this.#schema.data;
|
|
2556
|
+
const enrichedData = {
|
|
2557
|
+
...originalData,
|
|
2558
|
+
constraints: {
|
|
2559
|
+
...originalData.constraints
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
const enrichedConstraints = { ...enrichedData.constraints };
|
|
2563
|
+
for (const def of this.#defaults) {
|
|
2564
|
+
const existing = enrichedConstraints[def.vertex] ?? [];
|
|
2565
|
+
enrichedConstraints[def.vertex] = [
|
|
2566
|
+
...existing,
|
|
2567
|
+
{ sort: "__default", value: JSON.stringify(def.expr) }
|
|
2568
|
+
];
|
|
2569
|
+
}
|
|
2570
|
+
for (const coercion of this.#coercions) {
|
|
2571
|
+
const key = `__coercion:${coercion.from}:${coercion.to}`;
|
|
2572
|
+
const existing = enrichedConstraints[key] ?? [];
|
|
2573
|
+
enrichedConstraints[key] = [
|
|
2574
|
+
...existing,
|
|
2575
|
+
{ sort: "__coercion", value: JSON.stringify(coercion.expr) }
|
|
2576
|
+
];
|
|
2577
|
+
}
|
|
2578
|
+
for (const merger of this.#mergers) {
|
|
2579
|
+
const existing = enrichedConstraints[merger.vertex] ?? [];
|
|
2580
|
+
enrichedConstraints[merger.vertex] = [
|
|
2581
|
+
...existing,
|
|
2582
|
+
{ sort: "__merger", value: JSON.stringify(merger.expr) }
|
|
2583
|
+
];
|
|
2584
|
+
}
|
|
2585
|
+
for (const policy of this.#policies) {
|
|
2586
|
+
const existing = enrichedConstraints[policy.vertex] ?? [];
|
|
2587
|
+
enrichedConstraints[policy.vertex] = [
|
|
2588
|
+
...existing,
|
|
2589
|
+
{ sort: "__policy", value: JSON.stringify(policy.strategy) }
|
|
2590
|
+
];
|
|
2591
|
+
}
|
|
2592
|
+
const enrichedSchemaData = {
|
|
2593
|
+
...enrichedData,
|
|
2594
|
+
constraints: enrichedConstraints
|
|
2595
|
+
};
|
|
2596
|
+
return new BuiltSchema(
|
|
2597
|
+
this.#schema._handle,
|
|
2598
|
+
enrichedSchemaData,
|
|
2599
|
+
this.#schema._wasm
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
/**
|
|
2603
|
+
* Assert that a vertex exists in the schema.
|
|
2604
|
+
*
|
|
2605
|
+
* @param vertex - The vertex to check
|
|
2606
|
+
* @throws {@link PanprotoError} if the vertex is not found
|
|
2607
|
+
*/
|
|
2608
|
+
#assertVertex(vertex) {
|
|
2609
|
+
if (!(vertex in this.#schema.vertices)) {
|
|
2610
|
+
throw new PanprotoError(
|
|
2611
|
+
`Vertex "${vertex}" not found in schema. Available vertices: ${Object.keys(this.#schema.vertices).join(", ")}`
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
class ExprBuilder {
|
|
2617
|
+
/** This class is not instantiable; all methods are static. */
|
|
2618
|
+
constructor() {
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Create a variable reference expression.
|
|
2622
|
+
*
|
|
2623
|
+
* @param name - The variable name to reference
|
|
2624
|
+
* @returns A variable expression node
|
|
2625
|
+
*/
|
|
2626
|
+
static var_(name) {
|
|
2627
|
+
return { type: "var", name };
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Create a literal expression.
|
|
2631
|
+
*
|
|
2632
|
+
* @param value - The literal value
|
|
2633
|
+
* @returns A literal expression node
|
|
2634
|
+
*/
|
|
2635
|
+
static lit(value) {
|
|
2636
|
+
return { type: "lit", value };
|
|
2637
|
+
}
|
|
2638
|
+
/**
|
|
2639
|
+
* Create a lambda (anonymous function) expression.
|
|
2640
|
+
*
|
|
2641
|
+
* @param param - The parameter name
|
|
2642
|
+
* @param body - The function body expression
|
|
2643
|
+
* @returns A lambda expression node
|
|
2644
|
+
*/
|
|
2645
|
+
static lam(param, body) {
|
|
2646
|
+
return { type: "lam", param, body };
|
|
2647
|
+
}
|
|
2648
|
+
/**
|
|
2649
|
+
* Create a function application expression.
|
|
2650
|
+
*
|
|
2651
|
+
* When multiple arguments are provided, they are applied left-to-right
|
|
2652
|
+
* via currying: `app(f, a, b)` becomes `app(app(f, a), b)`.
|
|
2653
|
+
*
|
|
2654
|
+
* @param func - The function expression
|
|
2655
|
+
* @param args - One or more argument expressions
|
|
2656
|
+
* @returns An application expression node (possibly nested)
|
|
2657
|
+
*/
|
|
2658
|
+
static app(func, ...args) {
|
|
2659
|
+
let result = func;
|
|
2660
|
+
for (const arg of args) {
|
|
2661
|
+
result = { type: "app", func: result, arg };
|
|
2662
|
+
}
|
|
2663
|
+
return result;
|
|
2664
|
+
}
|
|
2665
|
+
/**
|
|
2666
|
+
* Create a let-binding expression.
|
|
2667
|
+
*
|
|
2668
|
+
* Binds `value` to `name` in the scope of `body`.
|
|
2669
|
+
*
|
|
2670
|
+
* @param name - The variable name to bind
|
|
2671
|
+
* @param value - The value expression to bind
|
|
2672
|
+
* @param body - The body expression where the binding is in scope
|
|
2673
|
+
* @returns A let expression node
|
|
2674
|
+
*/
|
|
2675
|
+
static let_(name, value, body) {
|
|
2676
|
+
return { type: "let", name, value, body };
|
|
2677
|
+
}
|
|
2678
|
+
/**
|
|
2679
|
+
* Create a field access expression.
|
|
2680
|
+
*
|
|
2681
|
+
* @param expr - The record expression to access
|
|
2682
|
+
* @param name - The field name
|
|
2683
|
+
* @returns A field access expression node
|
|
2684
|
+
*/
|
|
2685
|
+
static field(expr, name) {
|
|
2686
|
+
return { type: "field", expr, name };
|
|
2687
|
+
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Create a record literal expression.
|
|
2690
|
+
*
|
|
2691
|
+
* @param fields - A mapping of field names to expressions
|
|
2692
|
+
* @returns A record expression node
|
|
2693
|
+
*/
|
|
2694
|
+
static record(fields) {
|
|
2695
|
+
const entries = Object.entries(fields);
|
|
2696
|
+
return { type: "record", fields: entries };
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Create a list literal expression.
|
|
2700
|
+
*
|
|
2701
|
+
* @param items - The list element expressions
|
|
2702
|
+
* @returns A list expression node
|
|
2703
|
+
*/
|
|
2704
|
+
static list(...items) {
|
|
2705
|
+
return { type: "list", items };
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Create a pattern-match expression.
|
|
2709
|
+
*
|
|
2710
|
+
* @param scrutinee - The expression to match against
|
|
2711
|
+
* @param arms - Pattern-expression pairs tried in order
|
|
2712
|
+
* @returns A match expression node
|
|
2713
|
+
*/
|
|
2714
|
+
static match_(scrutinee, arms) {
|
|
2715
|
+
return { type: "match", scrutinee, arms };
|
|
2716
|
+
}
|
|
2717
|
+
/**
|
|
2718
|
+
* Create a builtin operation expression.
|
|
2719
|
+
*
|
|
2720
|
+
* @param op - The builtin operation name
|
|
2721
|
+
* @param args - Argument expressions for the operation
|
|
2722
|
+
* @returns A builtin expression node
|
|
2723
|
+
*/
|
|
2724
|
+
static builtin(op, ...args) {
|
|
2725
|
+
return { type: "builtin", op, args };
|
|
2726
|
+
}
|
|
2727
|
+
/**
|
|
2728
|
+
* Create an index expression for list or record access.
|
|
2729
|
+
*
|
|
2730
|
+
* @param expr - The collection expression
|
|
2731
|
+
* @param index - The index expression
|
|
2732
|
+
* @returns An index expression node
|
|
2733
|
+
*/
|
|
2734
|
+
static index(expr, index) {
|
|
2735
|
+
return { type: "index", expr, index };
|
|
2736
|
+
}
|
|
2737
|
+
// -----------------------------------------------------------------
|
|
2738
|
+
// Convenience arithmetic helpers
|
|
2739
|
+
// -----------------------------------------------------------------
|
|
2740
|
+
/**
|
|
2741
|
+
* Add two expressions.
|
|
2742
|
+
*
|
|
2743
|
+
* @param a - Left operand
|
|
2744
|
+
* @param b - Right operand
|
|
2745
|
+
* @returns A builtin 'Add' expression
|
|
2746
|
+
*/
|
|
2747
|
+
static add(a, b) {
|
|
2748
|
+
return ExprBuilder.builtin("Add", a, b);
|
|
2749
|
+
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Subtract two expressions.
|
|
2752
|
+
*
|
|
2753
|
+
* @param a - Left operand
|
|
2754
|
+
* @param b - Right operand
|
|
2755
|
+
* @returns A builtin 'Sub' expression
|
|
2756
|
+
*/
|
|
2757
|
+
static sub(a, b) {
|
|
2758
|
+
return ExprBuilder.builtin("Sub", a, b);
|
|
2759
|
+
}
|
|
2760
|
+
/**
|
|
2761
|
+
* Multiply two expressions.
|
|
2762
|
+
*
|
|
2763
|
+
* @param a - Left operand
|
|
2764
|
+
* @param b - Right operand
|
|
2765
|
+
* @returns A builtin 'Mul' expression
|
|
2766
|
+
*/
|
|
2767
|
+
static mul(a, b) {
|
|
2768
|
+
return ExprBuilder.builtin("Mul", a, b);
|
|
2769
|
+
}
|
|
2770
|
+
/**
|
|
2771
|
+
* Concatenate two expressions (strings or lists).
|
|
2772
|
+
*
|
|
2773
|
+
* @param a - Left operand
|
|
2774
|
+
* @param b - Right operand
|
|
2775
|
+
* @returns A builtin 'Concat' expression
|
|
2776
|
+
*/
|
|
2777
|
+
static concat(a, b) {
|
|
2778
|
+
return ExprBuilder.builtin("Concat", a, b);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
function classifyOpticKind(chain, schema, _wasm) {
|
|
2782
|
+
const spec = chain.requirements(schema);
|
|
2783
|
+
const hasDefaults = spec.forwardDefaults.length > 0;
|
|
2784
|
+
const hasCaptured = spec.capturedData.length > 0;
|
|
2785
|
+
if (!hasDefaults && !hasCaptured && spec.kind === "empty") {
|
|
2786
|
+
return "iso";
|
|
2787
|
+
}
|
|
2788
|
+
if (hasDefaults && hasCaptured) {
|
|
2789
|
+
return "affine";
|
|
2790
|
+
}
|
|
2791
|
+
if (hasCaptured) {
|
|
2792
|
+
return "lens";
|
|
2793
|
+
}
|
|
2794
|
+
if (hasDefaults) {
|
|
2795
|
+
return "prism";
|
|
2796
|
+
}
|
|
2797
|
+
return "traversal";
|
|
2798
|
+
}
|
|
2799
|
+
function runDryRun(compiled, instances, srcSchema, _tgtSchema, wasm) {
|
|
2800
|
+
const totalRecords = instances.length;
|
|
2801
|
+
const failed = [];
|
|
2802
|
+
let successful = 0;
|
|
2803
|
+
let recordIndex = 0;
|
|
2804
|
+
for (const record of instances) {
|
|
2805
|
+
try {
|
|
2806
|
+
const inputBytes = packToWasm(record);
|
|
2807
|
+
const instanceBytes = wasm.exports.json_to_instance(
|
|
2808
|
+
srcSchema._handle.id,
|
|
2809
|
+
inputBytes
|
|
2810
|
+
);
|
|
2811
|
+
wasm.exports.lift_record(compiled._handle.id, instanceBytes);
|
|
2812
|
+
successful++;
|
|
2813
|
+
} catch (error) {
|
|
2814
|
+
const reason = categorizeFailure(error);
|
|
2815
|
+
failed.push({ recordId: recordIndex, reason });
|
|
2816
|
+
}
|
|
2817
|
+
recordIndex++;
|
|
2818
|
+
}
|
|
2819
|
+
const coverageRatio = totalRecords > 0 ? successful / totalRecords : 1;
|
|
2820
|
+
return {
|
|
2821
|
+
totalRecords,
|
|
2822
|
+
successful,
|
|
2823
|
+
failed,
|
|
2824
|
+
coverageRatio
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
function categorizeFailure(error) {
|
|
2828
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2829
|
+
if (message.includes("constraint") || message.includes("Constraint")) {
|
|
2830
|
+
const constraintMatch = /constraint\s+"?([^"]+)"?\s+violated.*?value\s+"?([^"]*)"?/i.exec(message);
|
|
2831
|
+
return {
|
|
2832
|
+
type: "constraint_violation",
|
|
2833
|
+
constraint: constraintMatch?.[1] ?? "unknown",
|
|
2834
|
+
value: constraintMatch?.[2] ?? "unknown"
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
if (message.includes("required") || message.includes("missing")) {
|
|
2838
|
+
const fieldMatch = /(?:required|missing)\s+(?:field\s+)?"?([^"]+)"?/i.exec(message);
|
|
2839
|
+
return {
|
|
2840
|
+
type: "missing_required_field",
|
|
2841
|
+
field: fieldMatch?.[1] ?? "unknown"
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
if (message.includes("type") && message.includes("mismatch")) {
|
|
2845
|
+
const typeMatch = /expected\s+"?([^"]+)"?\s+got\s+"?([^"]+)"?/i.exec(message);
|
|
2846
|
+
return {
|
|
2847
|
+
type: "type_mismatch",
|
|
2848
|
+
expected: typeMatch?.[1] ?? "unknown",
|
|
2849
|
+
got: typeMatch?.[2] ?? "unknown"
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
return {
|
|
2853
|
+
type: "expr_eval_failed",
|
|
2854
|
+
exprName: "migration",
|
|
2855
|
+
error: message
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
class MigrationAnalysis {
|
|
2859
|
+
#wasm;
|
|
2860
|
+
/**
|
|
2861
|
+
* Create a new migration analysis instance.
|
|
2862
|
+
*
|
|
2863
|
+
* @param panproto - The Panproto instance providing WASM access
|
|
2864
|
+
*/
|
|
2865
|
+
constructor(panproto) {
|
|
2866
|
+
this.#wasm = panproto._wasm;
|
|
2867
|
+
}
|
|
2868
|
+
/**
|
|
2869
|
+
* Run a dry-run migration and return a coverage report.
|
|
2870
|
+
*
|
|
2871
|
+
* Tests each instance record against the compiled migration without
|
|
2872
|
+
* persisting results, producing detailed failure information for
|
|
2873
|
+
* records that cannot be migrated.
|
|
2874
|
+
*
|
|
2875
|
+
* @param compiled - The compiled migration to test
|
|
2876
|
+
* @param instances - Array of instance records (plain objects)
|
|
2877
|
+
* @param srcSchema - The source schema the instances conform to
|
|
2878
|
+
* @param tgtSchema - The target schema
|
|
2879
|
+
* @returns A coverage report with per-record success/failure data
|
|
2880
|
+
*/
|
|
2881
|
+
dryRun(compiled, instances, srcSchema, tgtSchema) {
|
|
2882
|
+
return runDryRun(compiled, instances, srcSchema, tgtSchema, this.#wasm);
|
|
2883
|
+
}
|
|
2884
|
+
/**
|
|
2885
|
+
* Classify the optic kind of a protolens chain.
|
|
2886
|
+
*
|
|
2887
|
+
* Determines whether the chain represents an isomorphism, lens, prism,
|
|
2888
|
+
* affine transformation, or traversal based on its complement structure.
|
|
2889
|
+
*
|
|
2890
|
+
* @param chain - The protolens chain to classify
|
|
2891
|
+
* @param schema - The schema to check the chain against
|
|
2892
|
+
* @returns The optic kind classification
|
|
2893
|
+
*/
|
|
2894
|
+
opticKind(chain, schema) {
|
|
2895
|
+
return classifyOpticKind(chain, schema, this.#wasm);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
1945
2898
|
class TheoryHandle {
|
|
1946
2899
|
#handle;
|
|
1947
2900
|
/** @internal Retained for future sort/op inspection methods. */
|
|
@@ -2062,19 +3015,33 @@ function migrateModel(sortInterp, morphism, wasm) {
|
|
|
2062
3015
|
const resultBytes = wasm.exports.migrate_model(modelBytes, morphBytes);
|
|
2063
3016
|
return unpackFromWasm(resultBytes);
|
|
2064
3017
|
}
|
|
3018
|
+
function factorizeMorphism(morphismBytes, domain, codomain, wasm) {
|
|
3019
|
+
try {
|
|
3020
|
+
const bytes = wasm.exports.factorize_morphism(morphismBytes, domain._handle.id, codomain._handle.id);
|
|
3021
|
+
return unpackFromWasm(bytes);
|
|
3022
|
+
} catch (error) {
|
|
3023
|
+
throw new WasmError(
|
|
3024
|
+
`factorize_morphism failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3025
|
+
{ cause: error }
|
|
3026
|
+
);
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
2065
3029
|
export {
|
|
2066
3030
|
ATPROTO_SPEC,
|
|
2067
3031
|
BUILTIN_PROTOCOLS,
|
|
2068
3032
|
BuiltSchema,
|
|
2069
3033
|
CompatReport,
|
|
2070
3034
|
CompiledMigration,
|
|
3035
|
+
DataSetHandle,
|
|
2071
3036
|
ExistenceCheckError,
|
|
3037
|
+
ExprBuilder,
|
|
2072
3038
|
FullDiffReport,
|
|
2073
3039
|
GRAPHQL_SPEC,
|
|
2074
3040
|
Instance,
|
|
2075
3041
|
IoRegistry,
|
|
2076
3042
|
JSON_SCHEMA_SPEC,
|
|
2077
3043
|
LensHandle,
|
|
3044
|
+
MigrationAnalysis,
|
|
2078
3045
|
MigrationBuilder,
|
|
2079
3046
|
MigrationError,
|
|
2080
3047
|
PROTOBUF_SPEC,
|
|
@@ -2082,28 +3049,23 @@ export {
|
|
|
2082
3049
|
Panproto,
|
|
2083
3050
|
PanprotoError,
|
|
2084
3051
|
Protocol,
|
|
3052
|
+
ProtolensChainHandle,
|
|
2085
3053
|
Repository,
|
|
2086
3054
|
SQL_SPEC,
|
|
2087
3055
|
SchemaBuilder,
|
|
3056
|
+
SchemaEnrichment,
|
|
2088
3057
|
SchemaValidationError,
|
|
3058
|
+
SymmetricLensHandle,
|
|
2089
3059
|
TheoryBuilder,
|
|
2090
3060
|
TheoryHandle,
|
|
2091
3061
|
ValidationResult,
|
|
2092
3062
|
WasmError,
|
|
2093
|
-
addField,
|
|
2094
3063
|
checkMorphism,
|
|
2095
|
-
coerceType,
|
|
2096
3064
|
colimit,
|
|
2097
|
-
compose,
|
|
2098
3065
|
createTheory,
|
|
2099
|
-
|
|
3066
|
+
factorizeMorphism,
|
|
2100
3067
|
getBuiltinProtocol,
|
|
2101
3068
|
getProtocolNames,
|
|
2102
|
-
|
|
2103
|
-
migrateModel,
|
|
2104
|
-
pipeline,
|
|
2105
|
-
removeField,
|
|
2106
|
-
renameField,
|
|
2107
|
-
wrapInObject
|
|
3069
|
+
migrateModel
|
|
2108
3070
|
};
|
|
2109
3071
|
//# sourceMappingURL=index.js.map
|