@calcit/procs 0.29.0-alpha.17 → 0.29.0-alpha.19
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/lib/calcit.procs.d.mts +1 -1
- package/lib/calcit.procs.mjs +1 -1
- package/lib/js-ref.d.mts +3 -0
- package/lib/js-ref.mjs +4 -1
- package/lib/js-struct-def.d.mts +1 -1
- package/lib/js-struct-def.mjs +8 -1
- package/lib/js-struct-value.mjs +12 -0
- package/lib/js-type-form.d.mts +2 -0
- package/lib/js-type-form.mjs +167 -0
- package/lib/package.json +1 -1
- package/package.json +1 -1
package/lib/calcit.procs.d.mts
CHANGED
|
@@ -112,7 +112,7 @@ export declare let _$L_: (...xs: CalcitValue[]) => CalcitSliceList;
|
|
|
112
112
|
export declare let _SQUO_: (...xs: CalcitValue[]) => CalcitSliceList;
|
|
113
113
|
export declare let _$n__$M_: (...xs: CalcitValue[]) => CalcitSliceMap;
|
|
114
114
|
export declare let defatom: (path: string, x: CalcitValue) => CalcitValue;
|
|
115
|
-
export { atom } from "./js-ref.mjs";
|
|
115
|
+
export { atom, ref } from "./js-ref.mjs";
|
|
116
116
|
export declare let peekDefatom: (path: string) => CalcitRef;
|
|
117
117
|
export declare let _$n_atom_$o_deref: (x: CalcitRef) => CalcitValue;
|
|
118
118
|
export declare let _$n__ADD_: (x: number, y: number) => number;
|
package/lib/calcit.procs.mjs
CHANGED
|
@@ -508,7 +508,7 @@ export let defatom = (path, x) => {
|
|
|
508
508
|
refsRegistry.set(path, v);
|
|
509
509
|
return v;
|
|
510
510
|
};
|
|
511
|
-
export { atom } from "./js-ref.mjs";
|
|
511
|
+
export { atom, ref } from "./js-ref.mjs";
|
|
512
512
|
export let peekDefatom = (path) => {
|
|
513
513
|
return refsRegistry.get(path);
|
|
514
514
|
};
|
package/lib/js-ref.d.mts
CHANGED
|
@@ -9,4 +9,7 @@ export declare class CalcitRef {
|
|
|
9
9
|
constructor(x: CalcitValue, path: string);
|
|
10
10
|
toString(): string;
|
|
11
11
|
}
|
|
12
|
+
/** Creates a local `Ref<T>`; generated code calls this for both `ref` and the compatibility spelling `atom`. */
|
|
13
|
+
export declare let ref: (x: CalcitValue) => CalcitValue;
|
|
14
|
+
/** Compatibility export for JavaScript callers written before `ref`; it is the same function. */
|
|
12
15
|
export declare let atom: (x: CalcitValue) => CalcitValue;
|
package/lib/js-ref.mjs
CHANGED
|
@@ -10,8 +10,11 @@ export class CalcitRef {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
var atomCounter = 0;
|
|
13
|
-
|
|
13
|
+
/** Creates a local `Ref<T>`; generated code calls this for both `ref` and the compatibility spelling `atom`. */
|
|
14
|
+
export let ref = (x) => {
|
|
14
15
|
atomCounter = atomCounter + 1;
|
|
15
16
|
let v = new CalcitRef(x, `atom-${atomCounter}`);
|
|
16
17
|
return v;
|
|
17
18
|
};
|
|
19
|
+
/** Compatibility export for JavaScript callers written before `ref`; it is the same function. */
|
|
20
|
+
export let atom = ref;
|
package/lib/js-struct-def.d.mts
CHANGED
|
@@ -12,5 +12,5 @@ export declare class CalcitStructDef {
|
|
|
12
12
|
withImpls(impls: CalcitImpl | CalcitImpl[]): CalcitStructDef;
|
|
13
13
|
toString(disableJsDataWarning?: boolean): string;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/** Bind nominal definitions like native, preserving an alias's existing identity. */
|
|
16
16
|
export declare function bind_struct_definition(value: CalcitValue, definitionRef: string): CalcitValue;
|
package/lib/js-struct-def.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { canonicalizeTagPairs, toString } from "./calcit-data.mjs";
|
|
2
2
|
import { CalcitImpl } from "./js-impl.mjs";
|
|
3
|
+
import { CalcitEnumDef } from "./js-enum-def.mjs";
|
|
4
|
+
import { CalcitStructValue } from "./js-struct-value.mjs";
|
|
3
5
|
export class CalcitStructDef {
|
|
4
6
|
constructor(name, fields, fieldTypes, impls = [], definitionRef = null) {
|
|
5
7
|
const [canonicalFields, canonicalTypes] = canonicalizeTagPairs(fields, fieldTypes, "CalcitStructDef");
|
|
@@ -33,10 +35,15 @@ export class CalcitStructDef {
|
|
|
33
35
|
return parts.join("");
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
|
-
/**
|
|
38
|
+
/** Bind nominal definitions like native, preserving an alias's existing identity. */
|
|
37
39
|
export function bind_struct_definition(value, definitionRef) {
|
|
38
40
|
if (value instanceof CalcitStructDef && value.definitionRef == null) {
|
|
39
41
|
return new CalcitStructDef(value.name, value.fields, value.fieldTypes, value.impls, definitionRef);
|
|
40
42
|
}
|
|
43
|
+
if (value instanceof CalcitEnumDef && value.prototype.structRef.definitionRef == null) {
|
|
44
|
+
const prototype = value.prototype;
|
|
45
|
+
const structRef = bind_struct_definition(prototype.structRef, definitionRef);
|
|
46
|
+
return new CalcitEnumDef(new CalcitStructValue(prototype.name, prototype.fields, prototype.values, structRef));
|
|
47
|
+
}
|
|
41
48
|
return value;
|
|
42
49
|
}
|
package/lib/js-struct-value.mjs
CHANGED
|
@@ -2,6 +2,14 @@ import { CalcitImpl } from "./js-impl.mjs";
|
|
|
2
2
|
import { newTag, castTag, toString, 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
|
+
import { valueMatchesTypeForm } from "./js-type-form.mjs";
|
|
6
|
+
/// Field writes check the declared field type, like the native runtime.
|
|
7
|
+
let assertFieldValue = (structRef, idx, value, operation) => {
|
|
8
|
+
const fieldType = structRef?.fieldTypes?.[idx];
|
|
9
|
+
if (fieldType != null && !valueMatchesTypeForm(value, fieldType)) {
|
|
10
|
+
throw new Error(`${operation} field :${structRef.fields[idx].value} expects type ${toString(fieldType, true)}, but received ${toString(value, true)}`);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
5
13
|
export class CalcitStructValue {
|
|
6
14
|
constructor(name, fields, values, structRef) {
|
|
7
15
|
this.name = name;
|
|
@@ -44,6 +52,7 @@ export class CalcitStructValue {
|
|
|
44
52
|
let k_id = castTag(k);
|
|
45
53
|
for (let idx = 0; idx < this.fields.length; idx++) {
|
|
46
54
|
if (this.fields[idx] === k_id) {
|
|
55
|
+
assertFieldValue(this.structRef, idx, v, "&struct:assoc");
|
|
47
56
|
values[idx] = v;
|
|
48
57
|
}
|
|
49
58
|
else {
|
|
@@ -60,6 +69,7 @@ export class CalcitStructValue {
|
|
|
60
69
|
assocAt(index, field, value) {
|
|
61
70
|
const idx = checkedStructIndex(index, "&struct:assoc-at");
|
|
62
71
|
this.assertFieldAt(idx, field, "&struct:assoc-at");
|
|
72
|
+
assertFieldValue(this.structRef, idx, value, "&struct:assoc-at");
|
|
63
73
|
const values = this.values.slice();
|
|
64
74
|
values[idx] = value;
|
|
65
75
|
return new CalcitStructValue(this.name, this.fields, values, this.structRef);
|
|
@@ -72,6 +82,7 @@ export class CalcitStructValue {
|
|
|
72
82
|
for (let base = 0; base < triples.length; base += 3) {
|
|
73
83
|
const idx = checkedStructIndex(triples[base], "&struct:with-at");
|
|
74
84
|
this.assertFieldAt(idx, triples[base + 1], "&struct:with-at");
|
|
85
|
+
assertFieldValue(this.structRef, idx, triples[base + 2], "&struct:with-at");
|
|
75
86
|
values[idx] = triples[base + 2];
|
|
76
87
|
}
|
|
77
88
|
return new CalcitStructValue(this.name, this.fields, values, this.structRef);
|
|
@@ -234,6 +245,7 @@ export let _$n_struct_$o_with = (proto, ...xs) => {
|
|
|
234
245
|
if (idx < 0) {
|
|
235
246
|
throw new Error(`Cannot find field ${k} among ${proto.fields}`);
|
|
236
247
|
}
|
|
248
|
+
assertFieldValue(proto.structRef, idx, v, "&struct:with");
|
|
237
249
|
values[idx] = v;
|
|
238
250
|
}
|
|
239
251
|
return new CalcitStructValue(proto.name, proto.fields, values, proto.structRef);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { CalcitSymbol, CalcitTag } from "./calcit-data.mjs";
|
|
2
|
+
import { CalcitList, CalcitSliceList } from "./js-list.mjs";
|
|
3
|
+
import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
|
|
4
|
+
import { CalcitSet } from "./js-set.mjs";
|
|
5
|
+
import { CalcitRef } from "./js-ref.mjs";
|
|
6
|
+
import { CalcitEnumValue } from "./js-enum-value.mjs";
|
|
7
|
+
/// Shallow runtime check of a value against a struct field type form, matching
|
|
8
|
+
/// the native `value_matches_type_annotation`: container kinds are checked,
|
|
9
|
+
/// 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) => {
|
|
12
|
+
if (form instanceof CalcitSliceList || form instanceof CalcitList) {
|
|
13
|
+
const items = form.toArray();
|
|
14
|
+
const head = items[0];
|
|
15
|
+
if (head instanceof CalcitSymbol && head.value === "quote") {
|
|
16
|
+
return valueMatchesTypeForm(value, items[1]);
|
|
17
|
+
}
|
|
18
|
+
if (head instanceof CalcitSymbol && head.value === "::") {
|
|
19
|
+
const name = typeFormName(items[1]);
|
|
20
|
+
// Nil is `null` here; `undefined` is Unit. Only the JS host boundary
|
|
21
|
+
// type also admits `undefined`.
|
|
22
|
+
if (name === "Optional") {
|
|
23
|
+
return value === null || valueMatchesTypeForm(value, items[2]);
|
|
24
|
+
}
|
|
25
|
+
if (name === "JsNullish") {
|
|
26
|
+
return value == null || valueMatchesTypeForm(value, items[2]);
|
|
27
|
+
}
|
|
28
|
+
return name == null || valueMatchesTypeName(value, name);
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
const name = typeFormName(form);
|
|
33
|
+
return name == null || valueMatchesTypeName(value, name);
|
|
34
|
+
};
|
|
35
|
+
let typeFormName = (form) => {
|
|
36
|
+
if (form instanceof CalcitSymbol)
|
|
37
|
+
return form.value;
|
|
38
|
+
if (form instanceof CalcitTag)
|
|
39
|
+
return form.value;
|
|
40
|
+
if (form instanceof CalcitSliceList || form instanceof CalcitList) {
|
|
41
|
+
const items = form.toArray();
|
|
42
|
+
if (items[0] instanceof CalcitSymbol && items[0].value === "quote")
|
|
43
|
+
return typeFormName(items[1]);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
};
|
|
47
|
+
/// Numeric refinements check range and integrality like the native `CalcitNumericRefinement::accepts`.
|
|
48
|
+
let isIntegerIn = (value, min, max) => typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
|
|
49
|
+
let isList = (value) => value instanceof CalcitList || value instanceof CalcitSliceList;
|
|
50
|
+
let isMap = (value) => value instanceof CalcitMap || value instanceof CalcitSliceMap;
|
|
51
|
+
let valueMatchesTypeName = (value, rawName) => {
|
|
52
|
+
const name = rawName.startsWith("calcit.core/") ? rawName.slice("calcit.core/".length) : rawName;
|
|
53
|
+
switch (name) {
|
|
54
|
+
case "Dynamic":
|
|
55
|
+
case "dynamic":
|
|
56
|
+
case "any":
|
|
57
|
+
case "JsObject":
|
|
58
|
+
return true;
|
|
59
|
+
case "Number":
|
|
60
|
+
case "number":
|
|
61
|
+
case "Float64":
|
|
62
|
+
case "float64":
|
|
63
|
+
return typeof value === "number";
|
|
64
|
+
case "Float32":
|
|
65
|
+
case "float32":
|
|
66
|
+
return typeof value === "number" && Math.fround(value) === value;
|
|
67
|
+
case "Int8":
|
|
68
|
+
case "int8":
|
|
69
|
+
return isIntegerIn(value, -128, 127);
|
|
70
|
+
case "UInt8":
|
|
71
|
+
case "uint8":
|
|
72
|
+
return isIntegerIn(value, 0, 255);
|
|
73
|
+
case "Int16":
|
|
74
|
+
case "int16":
|
|
75
|
+
return isIntegerIn(value, -32768, 32767);
|
|
76
|
+
case "UInt16":
|
|
77
|
+
case "uint16":
|
|
78
|
+
return isIntegerIn(value, 0, 65535);
|
|
79
|
+
case "Int32":
|
|
80
|
+
case "int32":
|
|
81
|
+
return isIntegerIn(value, -2147483648, 2147483647);
|
|
82
|
+
case "UInt32":
|
|
83
|
+
case "uint32":
|
|
84
|
+
return isIntegerIn(value, 0, 4294967295);
|
|
85
|
+
case "Int64":
|
|
86
|
+
case "int64":
|
|
87
|
+
return isIntegerIn(value, -Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
|
|
88
|
+
case "UInt64":
|
|
89
|
+
case "uint64":
|
|
90
|
+
return isIntegerIn(value, 0, Number.MAX_SAFE_INTEGER);
|
|
91
|
+
case "String":
|
|
92
|
+
case "string":
|
|
93
|
+
return typeof value === "string";
|
|
94
|
+
case "Bool":
|
|
95
|
+
case "bool":
|
|
96
|
+
return typeof value === "boolean";
|
|
97
|
+
case "Tag":
|
|
98
|
+
case "tag":
|
|
99
|
+
return value instanceof CalcitTag;
|
|
100
|
+
case "Symbol":
|
|
101
|
+
case "symbol":
|
|
102
|
+
return value instanceof CalcitSymbol;
|
|
103
|
+
case "Nil":
|
|
104
|
+
case "nil":
|
|
105
|
+
return value === null;
|
|
106
|
+
case "Unit":
|
|
107
|
+
case "unit":
|
|
108
|
+
return value === undefined;
|
|
109
|
+
case "List":
|
|
110
|
+
case "list":
|
|
111
|
+
return isList(value);
|
|
112
|
+
case "Map":
|
|
113
|
+
case "map":
|
|
114
|
+
return isMap(value);
|
|
115
|
+
case "Set":
|
|
116
|
+
case "set":
|
|
117
|
+
return value instanceof CalcitSet;
|
|
118
|
+
case "Ref":
|
|
119
|
+
case "ref":
|
|
120
|
+
return value instanceof CalcitRef;
|
|
121
|
+
case "Fn":
|
|
122
|
+
case "fn":
|
|
123
|
+
return typeof value === "function";
|
|
124
|
+
case "Struct":
|
|
125
|
+
case "struct":
|
|
126
|
+
case "record":
|
|
127
|
+
return isStructValue(value);
|
|
128
|
+
case "Enum":
|
|
129
|
+
case "enum":
|
|
130
|
+
case "tuple":
|
|
131
|
+
return value instanceof CalcitEnumValue;
|
|
132
|
+
}
|
|
133
|
+
// Core Struct and Enum definitions (bare names resolve to them through the
|
|
134
|
+
// implicit core import) are known here, so a reference to one admits only
|
|
135
|
+
// values of that definition, as the native matcher does.
|
|
136
|
+
if (CORE_NOMINAL_DEFS.has(name)) {
|
|
137
|
+
if (isStructValue(value))
|
|
138
|
+
return value.structRef.definitionRef === `calcit.core/${name}`;
|
|
139
|
+
return value instanceof CalcitEnumValue && value.enumPrototype?.prototype.structRef.definitionRef === `calcit.core/${name}`;
|
|
140
|
+
}
|
|
141
|
+
// Other names may be type variables, aliases or traits that cannot be
|
|
142
|
+
// resolved here. A qualified reference is checked against the value's own
|
|
143
|
+
// Struct or Enum name; other values are left to the static checker like
|
|
144
|
+
// unresolved forms.
|
|
145
|
+
const shortName = name.includes("/") ? name.slice(name.lastIndexOf("/") + 1) : name;
|
|
146
|
+
if (isStructValue(value))
|
|
147
|
+
return value.name.value === shortName || !name.includes("/");
|
|
148
|
+
if (value instanceof CalcitEnumValue && value.enumPrototype != null) {
|
|
149
|
+
return value.enumPrototype.name() === shortName || !name.includes("/");
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
/// Struct and Enum definitions of `calcit.core` usable as field types.
|
|
154
|
+
const CORE_NOMINAL_DEFS = new Set([
|
|
155
|
+
"Option",
|
|
156
|
+
"Result",
|
|
157
|
+
"Data",
|
|
158
|
+
"ListDestruct",
|
|
159
|
+
"MapDestruct",
|
|
160
|
+
"SetDestruct",
|
|
161
|
+
"StringDestruct",
|
|
162
|
+
"MapEntry",
|
|
163
|
+
"RuntimeMapMeta",
|
|
164
|
+
"RuntimeMapResponse",
|
|
165
|
+
]);
|
|
166
|
+
// Duck-typed to avoid a module cycle with js-struct-value.
|
|
167
|
+
let isStructValue = (value) => value != null && typeof value === "object" && "structRef" in value && "fields" in value;
|
package/lib/package.json
CHANGED