@calcit/procs 0.13.14 → 0.13.15
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/.yarn/install-state.gz +0 -0
- package/history/202608131607-runtime-map-decoder.md +13 -0
- package/history/202608131625-core-decode-map-as-metadata.md +12 -0
- package/history/202608131650-release-0.13.15.md +10 -0
- package/lib/calcit.procs.d.mts +6 -1
- package/lib/calcit.procs.mjs +133 -0
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/ts-src/calcit.procs.mts +132 -1
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Runtime map decoder for typed boundary data
|
|
2
|
+
|
|
3
|
+
## Change summary
|
|
4
|
+
|
|
5
|
+
- Added `decode-map-as value TypeExpr`, a compile-time-derived decoder for an already-evaluated Calcit Map.
|
|
6
|
+
- The decoder constructs nominal Struct values recursively, rejects unknown keys and missing required fields, and reports nested failure paths.
|
|
7
|
+
- Struct fields declared as `Option<T>` accept raw `T`, preserve an already-wrapped `%some`/`%none`, and become `%none` when the source field is absent.
|
|
8
|
+
- `Dynamic` is allowed only as an explicit runtime-boundary leaf for this decoder; the existing text-based `parse-cirru-edn-as` remains a closed-data decoder and continues to reject it.
|
|
9
|
+
- Native and JavaScript backends share the graph ABI and tests. WASM continues to reject both typed EDN decoder syntaxes explicitly.
|
|
10
|
+
|
|
11
|
+
## Knowledge point
|
|
12
|
+
|
|
13
|
+
Runtime Maps are not Cirru EDN: they do not carry nominal Struct identity and commonly represent optional data by omitted keys. A typed boundary decoder must therefore perform map-to-Struct construction, enforce required fields, and lift omitted or raw optional values into nominal `Option` variants. Reusing the closed EDN decoder without these rules silently permits invalid Structs or forces callers back to ad-hoc dynamic map readers.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Document `decode-map-as` in calcit-core
|
|
2
|
+
|
|
3
|
+
## Change summary
|
|
4
|
+
|
|
5
|
+
- Added the `decode-map-as` runtime syntax to the core snapshot metadata with builtin/internal/meta/syntax tags and a typed boundary schema.
|
|
6
|
+
- Added reusable `RuntimeMapMeta` and `RuntimeMapResponse` Struct fixtures for core examples and tests.
|
|
7
|
+
- Added a passing example plus definition-attached unit tests covering recursive Struct decoding through an Option field, omitted `Option` fields becoming `%none`, pre-wrapped `%some`, and explicit Dynamic payload preservation.
|
|
8
|
+
- Documented the native/JavaScript support boundary and kept WASM behavior explicit.
|
|
9
|
+
|
|
10
|
+
## Knowledge point
|
|
11
|
+
|
|
12
|
+
Compiler syntax and core snapshot metadata are separate surfaces. Adding a Rust/JS builtin is incomplete until `calcit-core.cirru` exposes its documentation, examples, schema, and tests; otherwise `cr docs`, `cr test`, and downstream agents cannot discover or verify the feature.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Release Calcit 0.13.15
|
|
2
|
+
|
|
3
|
+
## Change summary
|
|
4
|
+
|
|
5
|
+
- Released the merged `decode-map-as` runtime decoder and its core snapshot metadata, examples, and tests.
|
|
6
|
+
- Kept Cargo and npm package versions synchronized at `0.13.15` for the direct-main release workflow.
|
|
7
|
+
|
|
8
|
+
## Knowledge point
|
|
9
|
+
|
|
10
|
+
Version-only release changes are allowed directly on `main`; the functional implementation was merged and validated before this release commit. The release tag is created from the synchronized `main` commit so Cargo and npm publish the same version.
|
package/lib/calcit.procs.d.mts
CHANGED
|
@@ -247,7 +247,7 @@ export declare let parse_cirru: (code: string) => CalcitCirruQuote;
|
|
|
247
247
|
export declare let parse_cirru_list: (code: string) => CalcitList;
|
|
248
248
|
export declare let parse_cirru_edn: (code: string, options: CalcitValue) => CalcitValue;
|
|
249
249
|
type DataShapeNode = {
|
|
250
|
-
kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote";
|
|
250
|
+
kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic";
|
|
251
251
|
} | {
|
|
252
252
|
kind: "optional" | "list" | "set" | "ref";
|
|
253
253
|
inner: number;
|
|
@@ -255,6 +255,10 @@ type DataShapeNode = {
|
|
|
255
255
|
kind: "map";
|
|
256
256
|
key: number;
|
|
257
257
|
value: number;
|
|
258
|
+
} | {
|
|
259
|
+
kind: "map-option";
|
|
260
|
+
nominal: CalcitEnumDef;
|
|
261
|
+
inner: number;
|
|
258
262
|
} | {
|
|
259
263
|
kind: "struct";
|
|
260
264
|
nominal: CalcitStructDef;
|
|
@@ -274,6 +278,7 @@ type DataShapeGraph = {
|
|
|
274
278
|
nodes: DataShapeNode[];
|
|
275
279
|
};
|
|
276
280
|
export declare let parse_cirru_edn_as: (code: string, graph: DataShapeGraph) => CalcitValue;
|
|
281
|
+
export declare let decode_map_as: (value: CalcitValue, graph: DataShapeGraph) => CalcitValue;
|
|
277
282
|
export declare let json_parse: (code: CalcitValue) => CalcitValue;
|
|
278
283
|
export declare let json_stringify: (value: CalcitValue) => string;
|
|
279
284
|
export declare let json_pretty: (value: CalcitValue) => string;
|
package/lib/calcit.procs.mjs
CHANGED
|
@@ -1746,6 +1746,139 @@ export let parse_cirru_edn_as = (code, graph) => {
|
|
|
1746
1746
|
}
|
|
1747
1747
|
return decode_typed_edn_node(graph, graph.root, input, "$", 0);
|
|
1748
1748
|
};
|
|
1749
|
+
const map_decode_error = (path, message) => {
|
|
1750
|
+
throw new Error(`decode-map-as failed at ${path}: ${message}`);
|
|
1751
|
+
};
|
|
1752
|
+
const decode_runtime_map_node = (graph, nodeId, input, path, depth) => {
|
|
1753
|
+
if (depth > 1024)
|
|
1754
|
+
map_decode_error(path, "decode nesting exceeds 1024");
|
|
1755
|
+
const node = graph.nodes[nodeId];
|
|
1756
|
+
if (node == null)
|
|
1757
|
+
map_decode_error(path, `invalid data shape node #${nodeId}`);
|
|
1758
|
+
switch (node.kind) {
|
|
1759
|
+
case "dynamic":
|
|
1760
|
+
return input;
|
|
1761
|
+
case "map-option": {
|
|
1762
|
+
if (input instanceof CalcitEnumValue &&
|
|
1763
|
+
(input.enumPrototype === node.nominal || input.enumPrototype?.name() === node.nominal.name())) {
|
|
1764
|
+
const tag = input.tag;
|
|
1765
|
+
if (!(tag instanceof CalcitTag))
|
|
1766
|
+
map_decode_error(path, "Option variant is not a tag");
|
|
1767
|
+
const tag_name = tag.value;
|
|
1768
|
+
if (tag_name === "none" && input.extra.length === 0)
|
|
1769
|
+
return input;
|
|
1770
|
+
if (tag_name === "some" && input.extra.length === 1) {
|
|
1771
|
+
return new CalcitEnumValue(tag, [decode_runtime_map_node(graph, node.inner, input.extra[0], path, depth + 1)], node.nominal);
|
|
1772
|
+
}
|
|
1773
|
+
return map_decode_error(path, "invalid Option value");
|
|
1774
|
+
}
|
|
1775
|
+
return new CalcitEnumValue(newTag("some"), [decode_runtime_map_node(graph, node.inner, input, path, depth + 1)], node.nominal);
|
|
1776
|
+
}
|
|
1777
|
+
case "struct": {
|
|
1778
|
+
if (!(input instanceof CalcitMap || input instanceof CalcitSliceMap)) {
|
|
1779
|
+
return map_decode_error(path, `expected map for struct :${node.nominal.name.value}, got ${typed_edn_kind(input)}`);
|
|
1780
|
+
}
|
|
1781
|
+
const entries = new Map();
|
|
1782
|
+
input.pairs().forEach(([key, value]) => {
|
|
1783
|
+
const name = key instanceof CalcitTag ? key.value : typeof key === "string" ? key : null;
|
|
1784
|
+
if (name == null)
|
|
1785
|
+
map_decode_error(path, "struct map keys must be tags or strings");
|
|
1786
|
+
if (!node.fields.some(([field]) => field === name)) {
|
|
1787
|
+
map_decode_error(path, `struct :${node.nominal.name.value} has unknown field :${name}`);
|
|
1788
|
+
}
|
|
1789
|
+
if (entries.has(name))
|
|
1790
|
+
map_decode_error(path, `struct :${node.nominal.name.value} has duplicate field :${name}`);
|
|
1791
|
+
entries.set(name, value);
|
|
1792
|
+
});
|
|
1793
|
+
const decoded = new Map();
|
|
1794
|
+
node.fields.forEach(([field, child]) => {
|
|
1795
|
+
if (entries.has(field)) {
|
|
1796
|
+
decoded.set(field, decode_runtime_map_node(graph, child, entries.get(field), `${path}.${field}`, depth + 1));
|
|
1797
|
+
}
|
|
1798
|
+
else {
|
|
1799
|
+
const fieldNode = graph.nodes[child];
|
|
1800
|
+
if (fieldNode?.kind === "map-option") {
|
|
1801
|
+
decoded.set(field, new CalcitEnumValue(newTag("none"), [], fieldNode.nominal));
|
|
1802
|
+
}
|
|
1803
|
+
else {
|
|
1804
|
+
map_decode_error(path, `struct :${node.nominal.name.value} is missing required field :${field}`);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
});
|
|
1808
|
+
const values = node.nominal.fields.map((field) => decoded.get(field.value));
|
|
1809
|
+
return new CalcitStructValue(node.nominal.name, node.nominal.fields, values, node.nominal);
|
|
1810
|
+
}
|
|
1811
|
+
case "list": {
|
|
1812
|
+
if (!(input instanceof CalcitList || input instanceof CalcitSliceList)) {
|
|
1813
|
+
return map_decode_error(path, `expected list, got ${typed_edn_kind(input)}`);
|
|
1814
|
+
}
|
|
1815
|
+
return new CalcitSliceList(Array.from(input.items()).map((value, idx) => decode_runtime_map_node(graph, node.inner, value, `${path}[${idx}]`, depth + 1)));
|
|
1816
|
+
}
|
|
1817
|
+
case "set": {
|
|
1818
|
+
if (!(input instanceof CalcitSet || input instanceof TypedEdnSetView)) {
|
|
1819
|
+
return map_decode_error(path, `expected set, got ${typed_edn_kind(input)}`);
|
|
1820
|
+
}
|
|
1821
|
+
const values = [];
|
|
1822
|
+
const source = input instanceof TypedEdnSetView ? input.items : input.values();
|
|
1823
|
+
source.forEach((value) => {
|
|
1824
|
+
const decoded = decode_runtime_map_node(graph, node.inner, value, `${path}.item`, depth + 1);
|
|
1825
|
+
if (values.some((item) => _$n__$e_(item, decoded)))
|
|
1826
|
+
map_decode_error(path, "duplicate decoded set value");
|
|
1827
|
+
values.push(decoded);
|
|
1828
|
+
});
|
|
1829
|
+
return new CalcitSet(values);
|
|
1830
|
+
}
|
|
1831
|
+
case "map": {
|
|
1832
|
+
if (!(input instanceof CalcitMap || input instanceof CalcitSliceMap)) {
|
|
1833
|
+
return map_decode_error(path, `expected map, got ${typed_edn_kind(input)}`);
|
|
1834
|
+
}
|
|
1835
|
+
const entries = [];
|
|
1836
|
+
input.pairs().forEach(([key, value]) => {
|
|
1837
|
+
const decodedKey = decode_runtime_map_node(graph, node.key, key, `${path}.key`, depth + 1);
|
|
1838
|
+
if (entries.some(([existing]) => _$n__$e_(existing, decodedKey)))
|
|
1839
|
+
map_decode_error(path, "duplicate decoded map key");
|
|
1840
|
+
entries.push([decodedKey, decode_runtime_map_node(graph, node.value, value, `${path}.value`, depth + 1)]);
|
|
1841
|
+
});
|
|
1842
|
+
return new CalcitSliceMap(entries.flat());
|
|
1843
|
+
}
|
|
1844
|
+
case "optional":
|
|
1845
|
+
return input == null ? null : decode_runtime_map_node(graph, node.inner, input, path, depth + 1);
|
|
1846
|
+
case "ref":
|
|
1847
|
+
if (!(input instanceof CalcitRef))
|
|
1848
|
+
return map_decode_error(path, `expected atom, got ${typed_edn_kind(input)}`);
|
|
1849
|
+
return atom(decode_runtime_map_node(graph, node.inner, input.value, `${path}.value`, depth + 1));
|
|
1850
|
+
case "enum": {
|
|
1851
|
+
if (!(input instanceof CalcitEnumValue) || input.enumPrototype == null) {
|
|
1852
|
+
return map_decode_error(path, `expected enum :${node.nominal.name()}, got ${typed_edn_kind(input)}`);
|
|
1853
|
+
}
|
|
1854
|
+
const actualEnumName = enum_prototype_name(input.enumPrototype);
|
|
1855
|
+
if (actualEnumName !== node.nominal.name()) {
|
|
1856
|
+
return map_decode_error(path, `expected enum :${node.nominal.name()}, got enum :${actualEnumName}`);
|
|
1857
|
+
}
|
|
1858
|
+
if (!(input.tag instanceof CalcitTag))
|
|
1859
|
+
return map_decode_error(path, `enum :${node.nominal.name()} variant must be a tag`);
|
|
1860
|
+
const inputTag = input.tag;
|
|
1861
|
+
const variant = node.variants.find((candidate) => candidate.tag === inputTag.value);
|
|
1862
|
+
if (variant == null)
|
|
1863
|
+
return map_decode_error(path, `enum :${node.nominal.name()} has no variant :${inputTag.value}`);
|
|
1864
|
+
if (variant.payload.length !== input.extra.length) {
|
|
1865
|
+
return map_decode_error(path, `enum :${node.nominal.name()} variant :${variant.tag} expects ${variant.payload.length} payload(s), got ${input.extra.length}`);
|
|
1866
|
+
}
|
|
1867
|
+
const values = variant.payload.map((payloadNode, idx) => decode_runtime_map_node(graph, payloadNode, input.extra[idx], `${path}.payload[${idx}]`, depth + 1));
|
|
1868
|
+
return new CalcitEnumValue(newTag(variant.tag), values, node.nominal);
|
|
1869
|
+
}
|
|
1870
|
+
default:
|
|
1871
|
+
return decode_typed_edn_node(graph, nodeId, input, path, depth);
|
|
1872
|
+
}
|
|
1873
|
+
};
|
|
1874
|
+
export let decode_map_as = (value, graph) => {
|
|
1875
|
+
if (graph.version !== 1)
|
|
1876
|
+
throw new Error(`decode-map-as expected data shape ABI version 1, got ${graph.version}`);
|
|
1877
|
+
if (typeof graph.fingerprint !== "string" || graph.fingerprint.length === 0) {
|
|
1878
|
+
throw new Error("decode-map-as expected a non-empty data shape fingerprint");
|
|
1879
|
+
}
|
|
1880
|
+
return decode_runtime_map_node(graph, graph.root, value, "$", 0);
|
|
1881
|
+
};
|
|
1749
1882
|
const json_to_calcit = (value) => {
|
|
1750
1883
|
if (value == null)
|
|
1751
1884
|
return null;
|
package/lib/package.json
CHANGED
package/package.json
CHANGED
package/ts-src/calcit.procs.mts
CHANGED
|
@@ -1676,9 +1676,10 @@ export let parse_cirru_edn = (code: string, options: CalcitValue) => {
|
|
|
1676
1676
|
};
|
|
1677
1677
|
|
|
1678
1678
|
type DataShapeNode =
|
|
1679
|
-
| { kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" }
|
|
1679
|
+
| { kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic" }
|
|
1680
1680
|
| { kind: "optional" | "list" | "set" | "ref"; inner: number }
|
|
1681
1681
|
| { kind: "map"; key: number; value: number }
|
|
1682
|
+
| { kind: "map-option"; nominal: CalcitEnumDef; inner: number }
|
|
1682
1683
|
| { kind: "struct"; nominal: CalcitStructDef; fields: Array<[string, number]> }
|
|
1683
1684
|
| { kind: "enum"; nominal: CalcitEnumDef; variants: Array<{ tag: string; payload: number[] }> };
|
|
1684
1685
|
|
|
@@ -1883,6 +1884,136 @@ export let parse_cirru_edn_as = (code: string, graph: DataShapeGraph): CalcitVal
|
|
|
1883
1884
|
return decode_typed_edn_node(graph, graph.root, input, "$", 0) as CalcitValue;
|
|
1884
1885
|
};
|
|
1885
1886
|
|
|
1887
|
+
const map_decode_error = (path: string, message: string): never => {
|
|
1888
|
+
throw new Error(`decode-map-as failed at ${path}: ${message}`);
|
|
1889
|
+
};
|
|
1890
|
+
|
|
1891
|
+
const decode_runtime_map_node = (graph: DataShapeGraph, nodeId: number, input: any, path: string, depth: number): any => {
|
|
1892
|
+
if (depth > 1024) map_decode_error(path, "decode nesting exceeds 1024");
|
|
1893
|
+
const node = graph.nodes[nodeId];
|
|
1894
|
+
if (node == null) map_decode_error(path, `invalid data shape node #${nodeId}`);
|
|
1895
|
+
|
|
1896
|
+
switch (node.kind) {
|
|
1897
|
+
case "dynamic":
|
|
1898
|
+
return input;
|
|
1899
|
+
case "map-option": {
|
|
1900
|
+
if (
|
|
1901
|
+
input instanceof CalcitEnumValue &&
|
|
1902
|
+
(input.enumPrototype === node.nominal || input.enumPrototype?.name() === node.nominal.name())
|
|
1903
|
+
) {
|
|
1904
|
+
const tag: CalcitValue = input.tag;
|
|
1905
|
+
if (!(tag instanceof CalcitTag)) map_decode_error(path, "Option variant is not a tag");
|
|
1906
|
+
const tag_name = (tag as CalcitTag).value;
|
|
1907
|
+
if (tag_name === "none" && input.extra.length === 0) return input;
|
|
1908
|
+
if (tag_name === "some" && input.extra.length === 1) {
|
|
1909
|
+
return new CalcitEnumValue(tag as CalcitTag, [decode_runtime_map_node(graph, node.inner, input.extra[0], path, depth + 1)], node.nominal);
|
|
1910
|
+
}
|
|
1911
|
+
return map_decode_error(path, "invalid Option value");
|
|
1912
|
+
}
|
|
1913
|
+
return new CalcitEnumValue(newTag("some"), [decode_runtime_map_node(graph, node.inner, input, path, depth + 1)], node.nominal);
|
|
1914
|
+
}
|
|
1915
|
+
case "struct": {
|
|
1916
|
+
if (!(input instanceof CalcitMap || input instanceof CalcitSliceMap)) {
|
|
1917
|
+
return map_decode_error(path, `expected map for struct :${node.nominal.name.value}, got ${typed_edn_kind(input)}`);
|
|
1918
|
+
}
|
|
1919
|
+
const entries = new Map<string, any>();
|
|
1920
|
+
input.pairs().forEach(([key, value]) => {
|
|
1921
|
+
const name = key instanceof CalcitTag ? key.value : typeof key === "string" ? key : null;
|
|
1922
|
+
if (name == null) map_decode_error(path, "struct map keys must be tags or strings");
|
|
1923
|
+
if (!node.fields.some(([field]) => field === name)) {
|
|
1924
|
+
map_decode_error(path, `struct :${node.nominal.name.value} has unknown field :${name}`);
|
|
1925
|
+
}
|
|
1926
|
+
if (entries.has(name)) map_decode_error(path, `struct :${node.nominal.name.value} has duplicate field :${name}`);
|
|
1927
|
+
entries.set(name, value);
|
|
1928
|
+
});
|
|
1929
|
+
const decoded = new Map<string, any>();
|
|
1930
|
+
node.fields.forEach(([field, child]) => {
|
|
1931
|
+
if (entries.has(field)) {
|
|
1932
|
+
decoded.set(field, decode_runtime_map_node(graph, child, entries.get(field), `${path}.${field}`, depth + 1));
|
|
1933
|
+
} else {
|
|
1934
|
+
const fieldNode = graph.nodes[child];
|
|
1935
|
+
if (fieldNode?.kind === "map-option") {
|
|
1936
|
+
decoded.set(field, new CalcitEnumValue(newTag("none"), [], fieldNode.nominal));
|
|
1937
|
+
} else {
|
|
1938
|
+
map_decode_error(path, `struct :${node.nominal.name.value} is missing required field :${field}`);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
const values = node.nominal.fields.map((field) => decoded.get(field.value));
|
|
1943
|
+
return new CalcitStructValue(node.nominal.name, node.nominal.fields, values, node.nominal);
|
|
1944
|
+
}
|
|
1945
|
+
case "list": {
|
|
1946
|
+
if (!(input instanceof CalcitList || input instanceof CalcitSliceList)) {
|
|
1947
|
+
return map_decode_error(path, `expected list, got ${typed_edn_kind(input)}`);
|
|
1948
|
+
}
|
|
1949
|
+
return new CalcitSliceList(Array.from(input.items()).map((value, idx) => decode_runtime_map_node(graph, node.inner, value, `${path}[${idx}]`, depth + 1)));
|
|
1950
|
+
}
|
|
1951
|
+
case "set": {
|
|
1952
|
+
if (!(input instanceof CalcitSet || input instanceof TypedEdnSetView)) {
|
|
1953
|
+
return map_decode_error(path, `expected set, got ${typed_edn_kind(input)}`);
|
|
1954
|
+
}
|
|
1955
|
+
const values: any[] = [];
|
|
1956
|
+
const source = input instanceof TypedEdnSetView ? input.items : input.values();
|
|
1957
|
+
source.forEach((value) => {
|
|
1958
|
+
const decoded = decode_runtime_map_node(graph, node.inner, value, `${path}.item`, depth + 1);
|
|
1959
|
+
if (values.some((item) => _$n__$e_(item, decoded))) map_decode_error(path, "duplicate decoded set value");
|
|
1960
|
+
values.push(decoded);
|
|
1961
|
+
});
|
|
1962
|
+
return new CalcitSet(values);
|
|
1963
|
+
}
|
|
1964
|
+
case "map": {
|
|
1965
|
+
if (!(input instanceof CalcitMap || input instanceof CalcitSliceMap)) {
|
|
1966
|
+
return map_decode_error(path, `expected map, got ${typed_edn_kind(input)}`);
|
|
1967
|
+
}
|
|
1968
|
+
const entries: any[] = [];
|
|
1969
|
+
input.pairs().forEach(([key, value]) => {
|
|
1970
|
+
const decodedKey = decode_runtime_map_node(graph, node.key, key, `${path}.key`, depth + 1);
|
|
1971
|
+
if (entries.some(([existing]) => _$n__$e_(existing, decodedKey))) map_decode_error(path, "duplicate decoded map key");
|
|
1972
|
+
entries.push([decodedKey, decode_runtime_map_node(graph, node.value, value, `${path}.value`, depth + 1)]);
|
|
1973
|
+
});
|
|
1974
|
+
return new CalcitSliceMap(entries.flat());
|
|
1975
|
+
}
|
|
1976
|
+
case "optional":
|
|
1977
|
+
return input == null ? null : decode_runtime_map_node(graph, node.inner, input, path, depth + 1);
|
|
1978
|
+
case "ref":
|
|
1979
|
+
if (!(input instanceof CalcitRef)) return map_decode_error(path, `expected atom, got ${typed_edn_kind(input)}`);
|
|
1980
|
+
return atom(decode_runtime_map_node(graph, node.inner, input.value, `${path}.value`, depth + 1));
|
|
1981
|
+
case "enum": {
|
|
1982
|
+
if (!(input instanceof CalcitEnumValue) || input.enumPrototype == null) {
|
|
1983
|
+
return map_decode_error(path, `expected enum :${node.nominal.name()}, got ${typed_edn_kind(input)}`);
|
|
1984
|
+
}
|
|
1985
|
+
const actualEnumName = enum_prototype_name(input.enumPrototype);
|
|
1986
|
+
if (actualEnumName !== node.nominal.name()) {
|
|
1987
|
+
return map_decode_error(path, `expected enum :${node.nominal.name()}, got enum :${actualEnumName}`);
|
|
1988
|
+
}
|
|
1989
|
+
if (!(input.tag instanceof CalcitTag)) return map_decode_error(path, `enum :${node.nominal.name()} variant must be a tag`);
|
|
1990
|
+
const inputTag = input.tag as CalcitTag;
|
|
1991
|
+
const variant = node.variants.find((candidate) => candidate.tag === inputTag.value);
|
|
1992
|
+
if (variant == null) return map_decode_error(path, `enum :${node.nominal.name()} has no variant :${inputTag.value}`);
|
|
1993
|
+
if (variant.payload.length !== input.extra.length) {
|
|
1994
|
+
return map_decode_error(
|
|
1995
|
+
path,
|
|
1996
|
+
`enum :${node.nominal.name()} variant :${variant.tag} expects ${variant.payload.length} payload(s), got ${input.extra.length}`
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
const values = variant.payload.map((payloadNode, idx) =>
|
|
2000
|
+
decode_runtime_map_node(graph, payloadNode, input.extra[idx], `${path}.payload[${idx}]`, depth + 1)
|
|
2001
|
+
);
|
|
2002
|
+
return new CalcitEnumValue(newTag(variant.tag), values, node.nominal);
|
|
2003
|
+
}
|
|
2004
|
+
default:
|
|
2005
|
+
return decode_typed_edn_node(graph, nodeId, input, path, depth);
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
|
|
2009
|
+
export let decode_map_as = (value: CalcitValue, graph: DataShapeGraph): CalcitValue => {
|
|
2010
|
+
if (graph.version !== 1) throw new Error(`decode-map-as expected data shape ABI version 1, got ${graph.version}`);
|
|
2011
|
+
if (typeof graph.fingerprint !== "string" || graph.fingerprint.length === 0) {
|
|
2012
|
+
throw new Error("decode-map-as expected a non-empty data shape fingerprint");
|
|
2013
|
+
}
|
|
2014
|
+
return decode_runtime_map_node(graph, graph.root, value, "$", 0) as CalcitValue;
|
|
2015
|
+
};
|
|
2016
|
+
|
|
1886
2017
|
const json_to_calcit = (value: any): CalcitValue => {
|
|
1887
2018
|
if (value == null) return null;
|
|
1888
2019
|
if (typeof value === "string") return value;
|