@calcit/procs 0.29.0-alpha.20 → 0.29.0-alpha.24

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.
@@ -155,7 +155,7 @@ export declare let _$n_list_$o_assoc_after: (xs: CalcitSliceList, k: number, v:
155
155
  export declare let _$n_list_$o_dissoc: (xs: CalcitValue | CalcitSliceList, k: CalcitValue) => CalcitList | CalcitSliceList;
156
156
  export declare let _$n_map_$o_dissoc: (xs: CalcitValue, ...args: CalcitValue[]) => CalcitMap | CalcitSliceMap;
157
157
  export declare let reset_$x_: (a: CalcitRef, v: CalcitValue) => CalcitValue;
158
- export declare let add_watch: (a: CalcitRef, k: CalcitTag, f: CalcitFn) => void;
158
+ export declare let add_watch_$x_: (a: CalcitRef, k: CalcitTag, f: CalcitFn) => void;
159
159
  export declare let remove_watch: (a: CalcitRef, k: CalcitTag) => void;
160
160
  export declare let range: (n: number, m?: number, step?: number) => CalcitSliceList;
161
161
  export declare function _$n_list_$o_empty_$q_(xs: CalcitValue): boolean;
@@ -243,7 +243,7 @@ export declare let turn_symbol: (x: CalcitValue) => CalcitSymbol;
243
243
  export declare let to_lispy_string: (...args: CalcitValue[]) => string;
244
244
  /** helper function for println, js only */
245
245
  export declare let printable: (...args: CalcitValue[]) => string;
246
- export declare let cpu_time: () => number;
246
+ export declare let monotonic_time_ms: () => number;
247
247
  export declare let quit_$x_: (code: number) => void;
248
248
  export declare let turn_string: (x: CalcitValue) => string;
249
249
  export declare let identical_$q_: (x: CalcitValue, y: CalcitValue) => boolean;
@@ -325,6 +325,8 @@ type DataShapeGraph = {
325
325
  fingerprint: string;
326
326
  nodes: DataShapeNode[];
327
327
  };
328
+ /** Validate existing data without the decoder's map conversion or Option lifting. */
329
+ export declare function validate_data_shape(input: CalcitValue, graph: DataShapeGraph): boolean;
328
330
  export declare let parse_cirru_edn_as: (code: string, graph: DataShapeGraph) => CalcitValue;
329
331
  export declare let decode_map_as: (value: CalcitValue, graph: DataShapeGraph) => CalcitValue;
330
332
  export declare let json_parse: (code: CalcitValue) => CalcitValue;
@@ -817,7 +817,7 @@ export let _$n_struct_$o_impl_traits = function (xs, ...traits) {
817
817
  throw new Error("&struct:impl-traits expected a struct value");
818
818
  const impls = traits.map((trait) => coerce_impl(trait, "&struct:impl-traits"));
819
819
  checkRequiredTraitImpls(xs.structRef.impls.concat(impls), "&struct:impl-traits");
820
- const nextStruct = new CalcitStructDef(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(impls), xs.structRef.definitionRef);
820
+ const nextStruct = new CalcitStructDef(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(impls), xs.structRef.definitionRef, xs.structRef.fieldValidators);
821
821
  return new CalcitStructValue(xs.name, xs.fields, xs.values, nextStruct);
822
822
  };
823
823
  export let _$n_struct_def_$o_impl_traits = function (xs, ...traits) {
@@ -828,7 +828,7 @@ export let _$n_struct_def_$o_impl_traits = function (xs, ...traits) {
828
828
  const addedImpls = traits.map((trait) => coerce_impl(trait, "&struct-def:impl-traits"));
829
829
  const baseImpls = xs.impls ?? [];
830
830
  checkRequiredTraitImpls(baseImpls.concat(addedImpls), "&struct-def:impl-traits");
831
- return new CalcitStructDef(xs.name, xs.fields, xs.fieldTypes, baseImpls.concat(addedImpls), xs.definitionRef);
831
+ return new CalcitStructDef(xs.name, xs.fields, xs.fieldTypes, baseImpls.concat(addedImpls), xs.definitionRef, xs.fieldValidators);
832
832
  };
833
833
  export let _$n_enum_def_$o_impl_traits = function (xs, ...traits) {
834
834
  if (traits.length < 1)
@@ -920,7 +920,7 @@ export let reset_$x_ = (a, v) => {
920
920
  });
921
921
  return v;
922
922
  };
923
- export let add_watch = (a, k, f) => {
923
+ export let add_watch_$x_ = (a, k, f) => {
924
924
  if (!(a instanceof CalcitRef)) {
925
925
  throw new Error("Expected ref for add-watch!");
926
926
  }
@@ -1661,8 +1661,8 @@ export let to_lispy_string = (...args) => {
1661
1661
  export let printable = (...args) => {
1662
1662
  return args.map((x) => toString(x, false)).join(" ");
1663
1663
  };
1664
- // time from app start
1665
- export let cpu_time = () => {
1664
+ // monotonic milliseconds since app start
1665
+ export let monotonic_time_ms = () => {
1666
1666
  if (inNodeJs) {
1667
1667
  // uptime returns in seconds
1668
1668
  return process.uptime() * 1000;
@@ -1947,6 +1947,64 @@ export let parse_cirru_edn = (code, options) => {
1947
1947
  throw new Error(`Expected EDN in a single node, got ${nodes.length}`);
1948
1948
  }
1949
1949
  };
1950
+ /** Validate existing data without the decoder's map conversion or Option lifting. */
1951
+ export function validate_data_shape(input, graph) {
1952
+ if (graph.version !== 3)
1953
+ throw new Error(`validate-data-shape expected ABI version 3, got ${graph.version}`);
1954
+ const sameNominal = (actual, expected) => actual === expected || (actual != null && expected != null && expected.definitionRef != null &&
1955
+ actual.definitionRef === expected.definitionRef && actual.name.value === expected.name.value &&
1956
+ actual.fields.length === expected.fields.length && actual.fields.every((field, idx) => field.value === expected.fields[idx].value && _$n__$e_(actual.fieldTypes[idx], expected.fieldTypes[idx])));
1957
+ const check = (value, nodeId, depth) => {
1958
+ if (depth > 1024)
1959
+ return false;
1960
+ const node = graph.nodes[nodeId];
1961
+ if (node == null)
1962
+ return false;
1963
+ switch (node.kind) {
1964
+ case "dynamic": return true;
1965
+ case "nil": return value === null;
1966
+ case "unit": return value === undefined;
1967
+ case "bool": return typeof value === "boolean";
1968
+ case "number": return typeof value === "number";
1969
+ case "numeric": return typeof value === "number" && _$n_number_$o_fits_$q_(value, newTag(node.target));
1970
+ case "string": return typeof value === "string";
1971
+ case "symbol": return value instanceof CalcitSymbol;
1972
+ case "tag": return value instanceof CalcitTag;
1973
+ case "buffer": return value instanceof Uint8Array;
1974
+ case "cirru-quote": return value instanceof CalcitCirruQuote;
1975
+ case "optional": return value === null || check(value, node.inner, depth + 1);
1976
+ case "list": {
1977
+ if (!(value instanceof CalcitList || value instanceof CalcitSliceList))
1978
+ return false;
1979
+ for (const item of value.items())
1980
+ if (!check(item, node.inner, depth + 1))
1981
+ return false;
1982
+ return true;
1983
+ }
1984
+ case "set": return value instanceof CalcitSet && value.values().every(item => check(item, node.inner, depth + 1));
1985
+ case "map": return (value instanceof CalcitMap || value instanceof CalcitSliceMap) && value.pairs().every(([key, item]) => check(key, node.key, depth + 1) && check(item, node.value, depth + 1));
1986
+ case "ref": return value instanceof CalcitRef && check(value.value, node.inner, depth + 1);
1987
+ case "struct": return value instanceof CalcitStructValue && sameNominal(value.structRef, node.nominal) &&
1988
+ value.values.length === node.fields.length && node.fields.every(([name, child], idx) => value.fields[idx]?.value === name && check(value.values[idx], child, depth + 1));
1989
+ case "map-option":
1990
+ case "enum": {
1991
+ if (!(value instanceof CalcitEnumValue) || value.enumPrototype == null ||
1992
+ !sameNominal(value.enumPrototype.prototype.structRef, node.nominal.prototype.structRef) ||
1993
+ !_$n__$e_(value.enumPrototype.prototype, node.nominal.prototype) || !(value.tag instanceof CalcitTag))
1994
+ return false;
1995
+ if (node.kind === "map-option") {
1996
+ return value.tag.value === "none" ? value.extra.length === 0 : value.tag.value === "some" &&
1997
+ value.extra.length === 1 && check(value.extra[0], node.inner, depth + 1);
1998
+ }
1999
+ const tag = value.tag.value;
2000
+ const variant = node.variants.find(candidate => candidate.tag === tag);
2001
+ return variant != null && value.extra.length === variant.payload.length &&
2002
+ variant.payload.every((child, idx) => check(value.extra[idx], child, depth + 1));
2003
+ }
2004
+ }
2005
+ };
2006
+ return check(input, graph.root, 0);
2007
+ }
1950
2008
  const typed_edn_kind = (value) => {
1951
2009
  if (value === null)
1952
2010
  return "nil";
@@ -1,6 +1,7 @@
1
1
  import { CalcitTag } from "./calcit-data.mjs";
2
2
  import { CalcitValue } from "./js-primes.mjs";
3
3
  import { CalcitImpl } from "./js-impl.mjs";
4
+ export type FieldValidator = ((value: CalcitValue, requireEvidence?: boolean) => boolean) | null;
4
5
  export declare class CalcitStructDef {
5
6
  name: CalcitTag;
6
7
  fields: CalcitTag[];
@@ -8,9 +9,10 @@ export declare class CalcitStructDef {
8
9
  impls: CalcitImpl[];
9
10
  cachedHash: number;
10
11
  readonly definitionRef: string | null;
11
- constructor(name: CalcitTag, fields: CalcitTag[], fieldTypes: CalcitValue[], impls?: CalcitImpl[], definitionRef?: string | null);
12
+ readonly fieldValidators: FieldValidator[] | null;
13
+ constructor(name: CalcitTag, fields: CalcitTag[], fieldTypes: CalcitValue[], impls?: CalcitImpl[], definitionRef?: string | null, fieldValidators?: FieldValidator[] | null);
12
14
  withImpls(impls: CalcitImpl | CalcitImpl[]): CalcitStructDef;
13
15
  toString(disableJsDataWarning?: boolean): string;
14
16
  }
15
17
  /** Bind nominal definitions like native, preserving an alias's existing identity. */
16
- export declare function bind_struct_definition(value: CalcitValue, definitionRef: string): CalcitValue;
18
+ export declare function bind_struct_definition(value: CalcitValue, definitionRef: string, fieldValidators?: FieldValidator[] | null): CalcitValue;
@@ -3,7 +3,7 @@ import { CalcitImpl } from "./js-impl.mjs";
3
3
  import { CalcitEnumDef } from "./js-enum-def.mjs";
4
4
  import { CalcitStructValue } from "./js-struct-value.mjs";
5
5
  export class CalcitStructDef {
6
- constructor(name, fields, fieldTypes, impls = [], definitionRef = null) {
6
+ constructor(name, fields, fieldTypes, impls = [], definitionRef = null, fieldValidators = null) {
7
7
  const [canonicalFields, canonicalTypes] = canonicalizeTagPairs(fields, fieldTypes, "CalcitStructDef");
8
8
  this.name = name;
9
9
  this.fields = canonicalFields;
@@ -11,13 +11,14 @@ export class CalcitStructDef {
11
11
  this.impls = impls ?? [];
12
12
  this.cachedHash = null;
13
13
  this.definitionRef = definitionRef;
14
+ this.fieldValidators = fieldValidators == null ? null : canonicalizeTagPairs(fields, fieldValidators, "CalcitStructDef validators")[1];
14
15
  }
15
16
  withImpls(impls) {
16
17
  if (impls instanceof CalcitImpl) {
17
- return new CalcitStructDef(this.name, this.fields, this.fieldTypes, [impls], this.definitionRef);
18
+ return new CalcitStructDef(this.name, this.fields, this.fieldTypes, [impls], this.definitionRef, this.fieldValidators);
18
19
  }
19
20
  else if (Array.isArray(impls)) {
20
- return new CalcitStructDef(this.name, this.fields, this.fieldTypes, impls, this.definitionRef);
21
+ return new CalcitStructDef(this.name, this.fields, this.fieldTypes, impls, this.definitionRef, this.fieldValidators);
21
22
  }
22
23
  throw new Error("Expected an impl as implementation");
23
24
  }
@@ -36,9 +37,9 @@ export class CalcitStructDef {
36
37
  }
37
38
  }
38
39
  /** Bind nominal definitions like native, preserving an alias's existing identity. */
39
- export function bind_struct_definition(value, definitionRef) {
40
+ export function bind_struct_definition(value, definitionRef, fieldValidators = null) {
40
41
  if (value instanceof CalcitStructDef && value.definitionRef == null) {
41
- return new CalcitStructDef(value.name, value.fields, value.fieldTypes, value.impls, definitionRef);
42
+ return new CalcitStructDef(value.name, value.fields, value.fieldTypes, value.impls, definitionRef, fieldValidators);
42
43
  }
43
44
  if (value instanceof CalcitEnumDef && value.prototype.structRef.definitionRef == null) {
44
45
  const prototype = value.prototype;
@@ -1,12 +1,14 @@
1
1
  import { CalcitImpl } from "./js-impl.mjs";
2
- import { newTag, castTag, toString, getStringName, findInFields, compareTagNames, canonicalizeTagPairs, } from "./calcit-data.mjs";
2
+ import { newTag, castTag, toString, CalcitTag, CalcitSymbol, getStringName, findInFields, compareTagNames, canonicalizeTagPairs, } from "./calcit-data.mjs";
3
3
  import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
4
4
  import { CalcitStructDef } from "./js-struct-def.mjs";
5
5
  import { valueMatchesTypeForm } from "./js-type-form.mjs";
6
6
  /// Field writes check the declared field type, like the native runtime.
7
- let assertFieldValue = (structRef, idx, value, operation) => {
7
+ let assertFieldValue = (structRef, idx, value, operation, requireEvidence = false) => {
8
8
  const fieldType = structRef?.fieldTypes?.[idx];
9
- if (fieldType != null && !valueMatchesTypeForm(value, fieldType)) {
9
+ const validator = structRef?.fieldValidators?.[idx];
10
+ if (validator != null ? !validator(value, requireEvidence)
11
+ : fieldType != null && !valueMatchesTypeForm(value, fieldType, requireEvidence)) {
10
12
  throw new Error(`${operation} field :${structRef.fields[idx].value} expects type ${toString(fieldType, true)}, but received ${toString(value, true)}`);
11
13
  }
12
14
  };
@@ -48,17 +50,14 @@ export class CalcitStructValue {
48
50
  }
49
51
  }
50
52
  assoc(k, v) {
51
- let values = new Array(this.fields.length);
52
- let k_id = castTag(k);
53
- for (let idx = 0; idx < this.fields.length; idx++) {
54
- if (this.fields[idx] === k_id) {
55
- assertFieldValue(this.structRef, idx, v, "&struct:assoc");
56
- values[idx] = v;
57
- }
58
- else {
59
- values[idx] = this.values[idx];
60
- }
53
+ const field = castTag(k);
54
+ const idx = findInFields(this.fields, field);
55
+ if (idx < 0) {
56
+ throw new Error(`&struct:assoc invalid field ${field.toString()} for struct '${this.name.value}'`);
61
57
  }
58
+ assertFieldValue(this.structRef, idx, v, "&struct:assoc", true);
59
+ const values = this.values.slice();
60
+ values[idx] = v;
62
61
  return new CalcitStructValue(this.name, this.fields, values, this.structRef);
63
62
  }
64
63
  nthAt(index, field) {
@@ -127,7 +126,7 @@ export class CalcitStructValue {
127
126
  else {
128
127
  throw new Error("Expected an impl or array of impls");
129
128
  }
130
- let nextStruct = new CalcitStructDef(this.name, this.fields, this.structRef.fieldTypes, this.structRef.impls.concat(nextImpls), this.structRef.definitionRef);
129
+ let nextStruct = new CalcitStructDef(this.name, this.fields, this.structRef.fieldTypes, this.structRef.impls.concat(nextImpls), this.structRef.definitionRef, this.structRef.fieldValidators);
131
130
  return new CalcitStructValue(this.name, this.fields, this.values, nextStruct);
132
131
  }
133
132
  }
@@ -192,45 +191,38 @@ export let fieldsEqual = (xs, ys) => {
192
191
  }
193
192
  return true;
194
193
  };
195
- export let _$n__PCT__$M_ = (proto, ...xs) => {
196
- let recordProto;
197
- if (proto instanceof CalcitStructValue) {
198
- recordProto = proto;
194
+ // Share complete construction without spreading map contents into call arguments.
195
+ const constructStruct = (proto, xs) => {
196
+ if (!(proto instanceof CalcitStructDef)) {
197
+ throw new Error("Expected prototype to be a StructDef");
199
198
  }
200
- else if (proto instanceof CalcitStructDef) {
201
- recordProto = new CalcitStructValue(proto.name, proto.fields, new Array(proto.fields.length).fill(null), proto);
199
+ if (xs.length % 2 !== 0) {
200
+ throw new Error("Expected even number of key/value");
202
201
  }
203
- else {
204
- throw new Error("Expected prototype to be a StructDef");
202
+ if (xs.length !== proto.fields.length * 2) {
203
+ throw new Error("fields size does not match");
205
204
  }
206
- {
207
- if (xs.length % 2 !== 0) {
208
- throw new Error("Expected even number of key/value");
205
+ const values = new Array(proto.fields.length);
206
+ const seen = new Set();
207
+ for (let i = 0; i < xs.length; i += 2) {
208
+ const key = xs[i];
209
+ if (!(key instanceof CalcitTag) && !(key instanceof CalcitSymbol) && typeof key !== "string") {
210
+ throw new Error("&%{} requires field in string/tag/symbol");
209
211
  }
210
- if (xs.length !== recordProto.fields.length * 2) {
211
- throw new Error("fields size does not match");
212
+ const idx = findInFields(proto.fields, castTag(key));
213
+ if (idx < 0) {
214
+ throw new Error("invalid field name for this struct");
212
215
  }
213
- let values = new Array(recordProto.fields.length);
214
- for (let i = 0; i < recordProto.fields.length; i++) {
215
- let idx = -1;
216
- let k = recordProto.fields[i];
217
- for (let j = 0; j < recordProto.fields.length; j++) {
218
- if (k === castTag(xs[j * 2])) {
219
- idx = j;
220
- break;
221
- }
222
- }
223
- if (idx < 0) {
224
- throw new Error("invalid field name for this struct");
225
- }
226
- if (values[i] != null) {
227
- throw new Error("struct field already has value, probably duplicated key");
228
- }
229
- values[i] = xs[idx * 2 + 1];
216
+ if (seen.has(idx)) {
217
+ throw new Error("struct field already has value, probably duplicated key");
230
218
  }
231
- return new CalcitStructValue(recordProto.name, recordProto.fields, values, recordProto.structRef);
219
+ seen.add(idx);
220
+ assertFieldValue(proto, idx, xs[i + 1], "&%{}");
221
+ values[idx] = xs[i + 1];
232
222
  }
223
+ return new CalcitStructValue(proto.name, proto.fields, values, proto);
233
224
  };
225
+ export let _$n__PCT__$M_ = (proto, ...xs) => constructStruct(proto, xs);
234
226
  /// update record with new values
235
227
  export let _$n_struct_$o_with = (proto, ...xs) => {
236
228
  if (proto instanceof CalcitStructValue) {
@@ -245,7 +237,7 @@ export let _$n_struct_$o_with = (proto, ...xs) => {
245
237
  if (idx < 0) {
246
238
  throw new Error(`Cannot find field ${k} among ${proto.fields}`);
247
239
  }
248
- assertFieldValue(proto.structRef, idx, v, "&struct:with");
240
+ assertFieldValue(proto.structRef, idx, v, "&struct:with", true);
249
241
  values[idx] = v;
250
242
  }
251
243
  return new CalcitStructValue(proto.name, proto.fields, values, proto.structRef);
@@ -273,57 +265,20 @@ export let _$n_struct_$o_definition = (x) => {
273
265
  }
274
266
  };
275
267
  export let _$n_struct_$o_from_map = (proto, data) => {
276
- let recordProto;
277
- if (proto instanceof CalcitStructDef) {
278
- recordProto = new CalcitStructValue(proto.name, proto.fields, new Array(proto.fields.length).fill(null), proto);
279
- }
280
- else {
268
+ if (!(proto instanceof CalcitStructDef)) {
281
269
  throw new Error("Expected prototype to be struct");
282
270
  }
283
- if (data instanceof CalcitStructValue) {
284
- if (fieldsEqual(recordProto.fields, data.fields)) {
285
- return new CalcitStructValue(recordProto.name, recordProto.fields, data.values, recordProto.structRef);
286
- }
287
- else {
288
- let values = [];
289
- for (let i = 0; i < recordProto.fields.length; i++) {
290
- let field = recordProto.fields[i];
291
- let idx = findInFields(data.fields, field);
292
- if (idx < 0) {
293
- throw new Error(`Cannot find field ${field} among ${data.fields}`);
294
- }
295
- values.push(data.values[idx]);
296
- }
297
- return new CalcitStructValue(recordProto.name, recordProto.fields, values, recordProto.structRef);
298
- }
271
+ if (!(data instanceof CalcitMap) && !(data instanceof CalcitSliceMap)) {
272
+ throw new Error("&struct:from-map requires a Map");
299
273
  }
300
- else if (data instanceof CalcitMap || data instanceof CalcitSliceMap) {
301
- let pairs_buffer = [];
302
- let pairs = data.pairs();
303
- for (let i = 0; i < pairs.length; i++) {
304
- let k = pairs[i][0];
305
- let v = pairs[i][1];
306
- pairs_buffer.push([castTag(k), v]);
307
- }
308
- // mutable sort
309
- pairs_buffer.sort((pair1, pair2) => pair1[0].cmp(pair2[0]));
310
- let values = [];
311
- outerLoop: for (let i = 0; i < recordProto.fields.length; i++) {
312
- let field = recordProto.fields[i];
313
- for (let idx = 0; idx < pairs_buffer.length; idx++) {
314
- let pair = pairs_buffer[idx];
315
- if (pair[0] === field) {
316
- values.push(pair[1]);
317
- continue outerLoop; // dirty code for performance
318
- }
319
- }
320
- throw new Error(`Cannot find field ${field} among ${pairs_buffer}`);
274
+ const fields = [];
275
+ for (const [key, value] of data.pairs()) {
276
+ if (!(key instanceof CalcitTag) && typeof key !== "string") {
277
+ throw new Error("&struct:from-map requires field in string/tag");
321
278
  }
322
- return new CalcitStructValue(recordProto.name, recordProto.fields, values, recordProto.structRef);
323
- }
324
- else {
325
- throw new Error("Expected a struct value or data for making a struct");
279
+ fields.push(key, value);
326
280
  }
281
+ return constructStruct(proto, fields);
327
282
  };
328
283
  export let _$n_struct_$o_to_map = (x) => {
329
284
  if (x instanceof CalcitStructValue) {
@@ -1,2 +1,2 @@
1
1
  import { CalcitValue } from "./js-primes.mjs";
2
- export declare let valueMatchesTypeForm: (value: CalcitValue, form: CalcitValue) => boolean;
2
+ export declare let valueMatchesTypeForm: (value: CalcitValue, form: CalcitValue, requireEvidence?: boolean) => boolean;
@@ -4,33 +4,42 @@ import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
4
4
  import { CalcitSet } from "./js-set.mjs";
5
5
  import { CalcitRef } from "./js-ref.mjs";
6
6
  import { CalcitEnumValue } from "./js-enum-value.mjs";
7
+ import { CalcitCirruQuote } from "./js-cirru.mjs";
7
8
  /// Shallow runtime check of a value against a struct field type form, matching
8
9
  /// the native `value_matches_type_annotation`: container kinds are checked,
9
10
  /// members are not. Names that cannot be resolved here (aliases, traits, type
10
- /// variables) stay permissive, as unresolved forms are on the native side.
11
- export let valueMatchesTypeForm = (value, form) => {
11
+ /// variables) stay permissive only for the legacy, statically checked path.
12
+ /// Dynamic writes require evidence: deep contracts use generated validators,
13
+ /// while this fallback accepts only completely checkable scalar/open forms.
14
+ export let valueMatchesTypeForm = (value, form, requireEvidence = false) => matchTypeForm(value, form, requireEvidence) === true;
15
+ // null means that the contract cannot be checked here, not a mismatched value.
16
+ // Nullable absence proves its own branch; present payloads still require
17
+ // evidence for the inner contract.
18
+ let matchTypeForm = (value, form, requireEvidence) => {
12
19
  if (form instanceof CalcitSliceList || form instanceof CalcitList) {
13
20
  const items = form.toArray();
14
21
  const head = items[0];
15
22
  if (head instanceof CalcitSymbol && head.value === "quote") {
16
- return valueMatchesTypeForm(value, items[1]);
23
+ return matchTypeForm(value, items[1], requireEvidence);
17
24
  }
18
25
  if (head instanceof CalcitSymbol && head.value === "::") {
19
26
  const name = typeFormName(items[1]);
20
27
  // Nil is `null` here; `undefined` is Unit. Only the JS host boundary
21
28
  // type also admits `undefined`.
22
29
  if (name === "Optional") {
23
- return value === null || valueMatchesTypeForm(value, items[2]);
30
+ return value === null ? true : matchTypeForm(value, items[2], requireEvidence);
24
31
  }
25
32
  if (name === "JsNullish") {
26
- return value == null || valueMatchesTypeForm(value, items[2]);
33
+ return value == null ? true : matchTypeForm(value, items[2], requireEvidence);
27
34
  }
28
- return name == null || valueMatchesTypeName(value, name);
35
+ if (name === "Fn" && requireEvidence)
36
+ return null;
37
+ return name == null ? (requireEvidence ? null : true) : valueMatchesTypeName(value, name, requireEvidence);
29
38
  }
30
- return true;
39
+ return requireEvidence ? null : true;
31
40
  }
32
41
  const name = typeFormName(form);
33
- return name == null || valueMatchesTypeName(value, name);
42
+ return name == null ? (requireEvidence ? null : true) : valueMatchesTypeName(value, name, requireEvidence);
34
43
  };
35
44
  let typeFormName = (form) => {
36
45
  if (form instanceof CalcitSymbol)
@@ -48,7 +57,7 @@ let typeFormName = (form) => {
48
57
  let isIntegerIn = (value, min, max) => typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
49
58
  let isList = (value) => value instanceof CalcitList || value instanceof CalcitSliceList;
50
59
  let isMap = (value) => value instanceof CalcitMap || value instanceof CalcitSliceMap;
51
- let valueMatchesTypeName = (value, rawName) => {
60
+ let valueMatchesTypeName = (value, rawName, requireEvidence) => {
52
61
  const name = rawName.startsWith("calcit.core/") ? rawName.slice("calcit.core/".length) : rawName;
53
62
  switch (name) {
54
63
  case "Dynamic":
@@ -106,30 +115,42 @@ let valueMatchesTypeName = (value, rawName) => {
106
115
  case "Unit":
107
116
  case "unit":
108
117
  return value === undefined;
118
+ case "Never":
119
+ return false;
120
+ case "Buffer":
121
+ case "buffer":
122
+ return value instanceof Uint8Array;
123
+ case "CirruQuote":
124
+ case "cirru-quote":
125
+ return value instanceof CalcitCirruQuote;
109
126
  case "List":
110
127
  case "list":
111
- return isList(value);
128
+ return requireEvidence ? null : isList(value);
112
129
  case "Map":
113
130
  case "map":
114
- return isMap(value);
131
+ return requireEvidence ? null : isMap(value);
115
132
  case "Set":
116
133
  case "set":
117
- return value instanceof CalcitSet;
134
+ return requireEvidence ? null : value instanceof CalcitSet;
118
135
  case "Ref":
119
136
  case "ref":
120
- return value instanceof CalcitRef;
137
+ return requireEvidence ? null : value instanceof CalcitRef;
121
138
  case "Fn":
122
139
  case "fn":
123
140
  return typeof value === "function";
124
141
  case "Struct":
125
142
  case "struct":
126
143
  case "record":
127
- return isStructValue(value);
144
+ return requireEvidence ? null : isStructValue(value);
128
145
  case "Enum":
129
146
  case "enum":
130
147
  case "tuple":
131
- return value instanceof CalcitEnumValue;
148
+ return requireEvidence ? null : value instanceof CalcitEnumValue;
132
149
  }
150
+ // Deep/nominal contracts must use the compiler's resolved validator. A
151
+ // short-name match or an erased generic cannot establish runtime evidence.
152
+ if (requireEvidence)
153
+ return null;
133
154
  // Core Struct and Enum definitions (bare names resolve to them through the
134
155
  // implicit core import) are known here, so a reference to one admits only
135
156
  // values of that definition, as the native matcher does.
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.29.0-alpha.20",
3
+ "version": "0.29.0-alpha.24",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "files": [
6
6
  "lib/",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.29.0-alpha.20",
3
+ "version": "0.29.0-alpha.24",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "files": [
6
6
  "lib/",