@calcit/procs 0.13.43 → 0.13.45

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.
Files changed (83) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/RFCs/04-15-match-syntax-rfc.md +14 -8
  3. package/RFCs/04-15-type-directed-optimization-catalog.md +20 -14
  4. package/RFCs/08-05-systematic-nil-reduction-rfc.md +16 -5
  5. package/editing-history/20260824-2119-validate-number-call-metadata.md +8 -0
  6. package/editing-history/20260824-2155-stable-js-struct-layout.md +11 -0
  7. package/editing-history/20260824-2224-struct-index-review-followups.md +7 -0
  8. package/editing-history/20260824-2233-indexed-struct-js-regressions.md +5 -0
  9. package/editing-history/20260824-2256-dynamic-method-analysis.md +9 -0
  10. package/editing-history/20260824-2329-dynamic-method-review-followups.md +7 -0
  11. package/editing-history/202608241731-contiguous-executable-calls.md +34 -0
  12. package/editing-history/202608241920-borrowed-syntax-arguments.md +34 -0
  13. package/editing-history/202608241924-unify-editing-history-directory.md +7 -0
  14. package/editing-history/202608242013-typed-native-number-ops.md +34 -0
  15. package/editing-history/20260825-0020-indexed-enum-match.md +34 -0
  16. package/editing-history/20260825-0100-indexed-enum-match-validation.md +7 -0
  17. package/editing-history/20260825-0120-indexed-enum-match-review.md +7 -0
  18. package/editing-history/20260825-1215-typed-literal-paths.md +56 -0
  19. package/editing-history/20260825-1344-typed-literal-path-review.md +17 -0
  20. package/editing-history/20260825-1505-typed-method-native-op.md +23 -0
  21. package/editing-history/20260825-1540-nil-unit-runtime-separation.md +15 -0
  22. package/editing-history/20260825-1725-typed-method-error-stack-review.md +10 -0
  23. package/editing-history/20260825-1733-nil-unit-doc-review.md +5 -0
  24. package/editing-history/20260825-1758-nil-unit-review-followup.md +6 -0
  25. package/editing-history/20260825-1845-release-01344.md +6 -0
  26. package/editing-history/20260825-2121-macro-parameter-diagnostics.md +10 -0
  27. package/editing-history/20260825-2138-keep-malformed-macro-params-hard.md +5 -0
  28. package/editing-history/20260825-2311-macro-capability-review-followup.md +10 -0
  29. package/editing-history/20260825-2312-macro-expansion-metrics.md +11 -0
  30. package/editing-history/20260825-2337-macro-query-and-capability-scope.md +11 -0
  31. package/editing-history/20260825-2338-core-structural-macro-contracts.md +10 -0
  32. package/editing-history/20260825-2356-delayed-macro-metrics-review.md +5 -0
  33. package/editing-history/202608252220-phase-aware-macro-signatures.md +35 -0
  34. package/editing-history/202608252249-macro-compile-time-capabilities.md +27 -0
  35. package/editing-history/20260826-0007-assertion-macro-contracts.md +8 -0
  36. package/editing-history/20260826-0023-assertion-macro-review.md +4 -0
  37. package/editing-history/20260826-0038-control-flow-macro-contracts.md +9 -0
  38. package/editing-history/20260826-0100-review-exact-control-flow-contracts.md +5 -0
  39. package/editing-history/20260826-0120-pattern-macro-contracts.md +8 -0
  40. package/editing-history/20260826-0133-collection-macro-contracts.md +9 -0
  41. package/editing-history/20260826-0152-definition-macro-contracts.md +25 -0
  42. package/editing-history/20260826-0203-transform-macro-contracts.md +28 -0
  43. package/editing-history/20260826-0214-binding-update-macro-contracts.md +14 -0
  44. package/editing-history/20260826-0629-type-observability-macros.md +8 -0
  45. package/editing-history/20260826-0642-type-remaining-match-macros.md +7 -0
  46. package/editing-history/20260826-0654-macro-log-capability.md +8 -0
  47. package/editing-history/20260826-0707-release-01345.md +6 -0
  48. package/examples/bench_enum_match.rs +41 -0
  49. package/lib/calcit-data.d.mts +4 -0
  50. package/lib/calcit-data.mjs +59 -9
  51. package/lib/calcit.procs.d.mts +16 -8
  52. package/lib/calcit.procs.mjs +68 -46
  53. package/lib/custom-formatter.mjs +12 -3
  54. package/lib/js-cirru.mjs +6 -5
  55. package/lib/js-impl.mjs +4 -3
  56. package/lib/js-primes.d.mts +1 -1
  57. package/lib/js-primes.mjs +22 -18
  58. package/lib/js-struct-def.mjs +4 -6
  59. package/lib/js-struct-value.d.mts +5 -1
  60. package/lib/js-struct-value.mjs +66 -38
  61. package/lib/package.json +8 -2
  62. package/package.json +8 -2
  63. package/ts-src/calcit-data.mts +54 -9
  64. package/ts-src/calcit.procs.mts +66 -49
  65. package/ts-src/custom-formatter.mts +12 -3
  66. package/ts-src/js-cirru.mts +6 -5
  67. package/ts-src/js-impl.mts +4 -3
  68. package/ts-src/js-primes.mts +5 -1
  69. package/ts-src/js-struct-def.mts +4 -6
  70. package/ts-src/js-struct-value.mts +78 -33
  71. /package/{history → editing-history}/202608191501-release-01326.md +0 -0
  72. /package/{history → editing-history}/202608191628-revert-transparent-union-types.md +0 -0
  73. /package/{history → editing-history}/202608191741-release-01327.md +0 -0
  74. /package/{history → editing-history}/202608212020-release-01328.md +0 -0
  75. /package/{2026082200-release-01330.md → editing-history/2026082200-release-01330.md} +0 -0
  76. /package/{2026082200-same-package-module-meta.md → editing-history/2026082200-same-package-module-meta.md} +0 -0
  77. /package/{2026082200-transitive-module-loading.md → editing-history/2026082200-transitive-module-loading.md} +0 -0
  78. /package/{2026082222-release-01331.md → editing-history/2026082222-release-01331.md} +0 -0
  79. /package/{history → editing-history}/2026082223-release-01332.md +0 -0
  80. /package/{history → editing-history}/2026082223-same-package-namespaces.md +0 -0
  81. /package/{history → editing-history}/2026082300-fix-cross-package-namespace-merge.md +0 -0
  82. /package/{history → editing-history}/2026082300-release-01333.md +0 -0
  83. /package/{history → editing-history}/2026082316-release-01334.md +0 -0
@@ -17,6 +17,7 @@ import {
17
17
  refsRegistry,
18
18
  toString,
19
19
  getStringName,
20
+ compareTagNames,
20
21
  _$n__$e_,
21
22
  hashFunction,
22
23
  } from "./calcit-data.mjs";
@@ -71,9 +72,10 @@ export let type_of = (x: any): CalcitTag => {
71
72
  if (x instanceof CalcitMap || x instanceof CalcitSliceMap) {
72
73
  return newTag("map");
73
74
  }
74
- if (x == null) {
75
+ if (x === null) {
75
76
  return newTag("nil");
76
77
  }
78
+ if (x === undefined) return newTag("unit");
77
79
  if (x instanceof CalcitRef) {
78
80
  return newTag("ref");
79
81
  }
@@ -252,7 +254,7 @@ export let defstruct = (name: CalcitValue, ...entries: CalcitValue[]): CalcitStr
252
254
  fields.push({ tag: fieldTag, type: fieldType });
253
255
  }
254
256
 
255
- fields.sort((a, b) => a.tag.idx - b.tag.idx);
257
+ fields.sort((a, b) => compareTagNames(a.tag, b.tag));
256
258
  for (let i = 1; i < fields.length; i++) {
257
259
  if (fields[i - 1].tag.value === fields[i].tag.value) {
258
260
  throw new Error(`defstruct duplicated field: ${fields[i].tag.toString()}`);
@@ -279,7 +281,7 @@ export let defenum = (name: CalcitValue, ...variants: CalcitValue[]): CalcitEnum
279
281
  entries.push({ tag, payload });
280
282
  }
281
283
 
282
- entries.sort((a, b) => a.tag.idx - b.tag.idx);
284
+ entries.sort((a, b) => compareTagNames(a.tag, b.tag));
283
285
  for (let i = 1; i < entries.length; i++) {
284
286
  if (entries[i - 1].tag.value === entries[i].tag.value) {
285
287
  throw new Error(`defenum duplicated variant: ${entries[i].tag.toString()}`);
@@ -324,7 +326,7 @@ export let _$n_impl_$o__$o_new = (name: CalcitValue, ...pairs: CalcitValue[]): C
324
326
  }
325
327
  entries.push({ tag: fieldTag, value });
326
328
  }
327
- entries.sort((a, b) => a.tag.idx - b.tag.idx);
329
+ entries.sort((a, b) => compareTagNames(a.tag, b.tag));
328
330
  for (let i = 1; i < entries.length; i++) {
329
331
  if (entries[i - 1].tag.value === entries[i].tag.value) {
330
332
  throw new Error(`&impl::new duplicated field: ${entries[i].tag.toString()}`);
@@ -391,13 +393,24 @@ export function _$n_struct_$o_field_tag(x: CalcitValue, idx: CalcitValue): Calci
391
393
  return x.fields[i];
392
394
  }
393
395
 
394
- export function _$n_struct_$o_nth(x: CalcitValue, idx: CalcitValue): CalcitValue {
396
+ export function _$n_struct_$o_nth(x: CalcitValue, idx: CalcitValue, field?: CalcitValue): CalcitValue {
395
397
  if (!(x instanceof CalcitStructValue)) throw new Error(`&struct:nth expected a struct value, got ${x}`);
398
+ if (field !== undefined) return x.nthAt(idx, field);
396
399
  const i = idx as number;
397
400
  if (i < 0 || i >= x.values.length) throw new Error(`&struct:nth index ${i} out of range for struct with ${x.values.length} fields`);
398
401
  return x.values[i];
399
402
  }
400
403
 
404
+ export function _$n_struct_$o_assoc_at(x: CalcitValue, idx: CalcitValue, field: CalcitValue, value: CalcitValue): CalcitValue {
405
+ if (!(x instanceof CalcitStructValue)) throw new Error(`&struct:assoc-at expected a struct value, got ${x}`);
406
+ return x.assocAt(idx, field, value);
407
+ }
408
+
409
+ export function _$n_struct_$o_with_at(x: CalcitValue, ...triples: CalcitValue[]): CalcitValue {
410
+ if (!(x instanceof CalcitStructValue)) throw new Error(`&struct:with-at expected a struct value, got ${x}`);
411
+ return x.withAt(...triples);
412
+ }
413
+
401
414
 
402
415
  export function _$n_set_$o_count(x: CalcitValue): number {
403
416
  if (x instanceof CalcitSet) return x.len();
@@ -449,7 +462,7 @@ export let _$n__$s_ = (x: number, y: number): number => {
449
462
  };
450
463
 
451
464
  export let _$n_str = (x: CalcitValue): string => {
452
- if (x == null) {
465
+ if (x === null) {
453
466
  return "";
454
467
  }
455
468
  if (typeof x === "string") {
@@ -675,11 +688,11 @@ export let _$n_enum_def_$o_variant_arity = function (enumPrototype: CalcitValue,
675
688
  throw new Error("Expected variant to be a list");
676
689
  };
677
690
 
678
- export let _$n_enum_$o_validate = function (enumValue: CalcitValue, tag: CalcitValue): CalcitValue {
691
+ export let _$n_enum_$o_validate = function (enumValue: CalcitValue, tag: CalcitValue): void {
679
692
  if (arguments.length !== 2) throw new Error("&enum:validate takes 2 arguments");
680
693
  if (!(enumValue instanceof CalcitEnumValue)) throw new Error("&enum:validate expects an enum value as first argument");
681
694
  if (enumValue.enumPrototype == null) {
682
- return null;
695
+ return;
683
696
  }
684
697
 
685
698
  const proto = assert_enum_tag_args("&enum:validate", enumValue.enumPrototype as CalcitValue, tag as CalcitTag);
@@ -696,7 +709,7 @@ export let _$n_enum_$o_validate = function (enumValue: CalcitValue, tag: CalcitV
696
709
  if (expected !== actual) {
697
710
  throw new Error(`enum variant expects ${expected} payload(s), got ${actual} for ${enumValue}`);
698
711
  }
699
- return null;
712
+ return;
700
713
  }
701
714
 
702
715
  throw new Error("Expected variant to be a list");
@@ -858,7 +871,7 @@ export let _$n_map_$o_dissoc = function (xs: CalcitValue, ...args: CalcitValue[]
858
871
  throw new Error("`dissoc` expected a map");
859
872
  };
860
873
 
861
- export let reset_$x_ = (a: CalcitRef, v: CalcitValue): null => {
874
+ export let reset_$x_ = (a: CalcitRef, v: CalcitValue): CalcitValue => {
862
875
  if (!(a instanceof CalcitRef)) {
863
876
  throw new Error("Expected ref for reset!");
864
877
  }
@@ -867,10 +880,10 @@ export let reset_$x_ = (a: CalcitRef, v: CalcitValue): null => {
867
880
  a.listeners.forEach((f) => {
868
881
  f(v, prev);
869
882
  });
870
- return null;
883
+ return v;
871
884
  };
872
885
 
873
- export let add_watch = (a: CalcitRef, k: CalcitTag, f: CalcitFn): null => {
886
+ export let add_watch = (a: CalcitRef, k: CalcitTag, f: CalcitFn): void => {
874
887
  if (!(a instanceof CalcitRef)) {
875
888
  throw new Error("Expected ref for add-watch!");
876
889
  }
@@ -881,12 +894,10 @@ export let add_watch = (a: CalcitRef, k: CalcitTag, f: CalcitFn): null => {
881
894
  throw new Error("Expected watcher function");
882
895
  }
883
896
  a.listeners.set(k, f);
884
- return null;
885
897
  };
886
898
 
887
- export let remove_watch = (a: CalcitRef, k: CalcitTag): null => {
899
+ export let remove_watch = (a: CalcitRef, k: CalcitTag): void => {
888
900
  a.listeners.delete(k);
889
- return null;
890
901
  };
891
902
 
892
903
  const MAX_RANGE_LENGTH = 0xffff_ffff;
@@ -1006,7 +1017,7 @@ export let _$n_set_$o_destruct = (xs: CalcitValue): CalcitValue => {
1006
1017
  throw new Error("Expect a set");
1007
1018
  };
1008
1019
 
1009
- export let timeout_call = (duration: number, f: CalcitFn): null => {
1020
+ export let timeout_call = (duration: number, f: CalcitFn): void => {
1010
1021
  if (typeof duration !== "number") {
1011
1022
  throw new Error("Expected duration in number");
1012
1023
  }
@@ -1014,7 +1025,6 @@ export let timeout_call = (duration: number, f: CalcitFn): null => {
1014
1025
  throw new Error("Expected callback in fn");
1015
1026
  }
1016
1027
  setTimeout(f, duration);
1017
- return null;
1018
1028
  };
1019
1029
 
1020
1030
  export let _$n_list_$o_rest = (xs: CalcitValue): CalcitList | CalcitSliceList => {
@@ -1111,13 +1121,12 @@ export let generate_id_$x_ = (): string => {
1111
1121
  return `gen_id_${idCounter}_${time}`;
1112
1122
  };
1113
1123
 
1114
- export let _$n_display_stack = (): null => {
1124
+ export let _$n_display_stack = (): void => {
1115
1125
  console.trace();
1116
- return null;
1117
1126
  };
1118
1127
 
1119
1128
  export let _$n_list_$o_slice = (xs: CalcitList, from: number, to: number): CalcitSliceList | CalcitList => {
1120
- if (xs == null) {
1129
+ if (xs === null) {
1121
1130
  return null;
1122
1131
  }
1123
1132
  let size = xs.len();
@@ -1135,7 +1144,7 @@ export let _$n_list_$o_concat = (...lists: (CalcitList | CalcitSliceList)[]): Ca
1135
1144
  let result: CalcitSliceList | CalcitList = new CalcitSliceList([]);
1136
1145
  for (let idx = 0; idx < lists.length; idx++) {
1137
1146
  let item = lists[idx];
1138
- if (item == null) {
1147
+ if (item === null) {
1139
1148
  continue;
1140
1149
  }
1141
1150
  if (item instanceof CalcitList || item instanceof CalcitSliceList) {
@@ -1152,7 +1161,7 @@ export let _$n_list_$o_concat = (...lists: (CalcitList | CalcitSliceList)[]): Ca
1152
1161
  };
1153
1162
 
1154
1163
  export let _$n_list_$o_reverse = (xs: CalcitList): CalcitList => {
1155
- if (xs == null) {
1164
+ if (xs === null) {
1156
1165
  return null;
1157
1166
  }
1158
1167
  return xs.reverse();
@@ -1183,12 +1192,12 @@ export let round_$q_ = (a: number) => {
1183
1192
  };
1184
1193
  export let _$n_str_$o_concat = (a: string, b: string) => {
1185
1194
  // Optimize string concatenation by avoiding unnecessary toString calls
1186
- const aStr = a != null ? toString(a, false) : "";
1187
- const bStr = b != null ? toString(b, false) : "";
1195
+ const aStr = a !== null ? toString(a, false) : "";
1196
+ const bStr = b !== null ? toString(b, false) : "";
1188
1197
  return aStr + bStr;
1189
1198
  };
1190
1199
  export let sort = (xs: CalcitList | CalcitSliceList, f: CalcitFn): CalcitSliceList => {
1191
- if (xs == null) {
1200
+ if (xs === null) {
1192
1201
  return null;
1193
1202
  }
1194
1203
  if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
@@ -1203,10 +1212,10 @@ export let floor = (n: number): number => {
1203
1212
  };
1204
1213
 
1205
1214
  export let _$n_merge = (a: CalcitValue, b: CalcitMap | CalcitSliceMap): CalcitValue => {
1206
- if (a == null) {
1215
+ if (a === null) {
1207
1216
  return b;
1208
1217
  }
1209
- if (b == null) {
1218
+ if (b === null) {
1210
1219
  return a;
1211
1220
  }
1212
1221
  if (a instanceof CalcitMap || a instanceof CalcitSliceMap) {
@@ -1246,10 +1255,10 @@ export let _$n_merge = (a: CalcitValue, b: CalcitMap | CalcitSliceMap): CalcitVa
1246
1255
  };
1247
1256
 
1248
1257
  export let _$n_merge_non_nil = (a: CalcitMap | CalcitSliceMap, b: CalcitMap | CalcitSliceMap): CalcitMap | CalcitSliceMap => {
1249
- if (a == null) {
1258
+ if (a === null) {
1250
1259
  return b;
1251
1260
  }
1252
- if (b == null) {
1261
+ if (b === null) {
1253
1262
  return a;
1254
1263
  }
1255
1264
  if (!(a instanceof CalcitMap || a instanceof CalcitSliceMap)) {
@@ -1311,7 +1320,7 @@ export let _$n_include = (xs: CalcitSet, y: CalcitValue): CalcitSet => {
1311
1320
  if (!(xs instanceof CalcitSet)) {
1312
1321
  throw new Error("Expected a set");
1313
1322
  }
1314
- if (y == null) {
1323
+ if (y === null) {
1315
1324
  return xs;
1316
1325
  }
1317
1326
  return xs.include(y);
@@ -1321,7 +1330,7 @@ export let _$n_exclude = (xs: CalcitSet, y: CalcitValue): CalcitSet => {
1321
1330
  if (!(xs instanceof CalcitSet)) {
1322
1331
  throw new Error("Expected a set");
1323
1332
  }
1324
- if (y == null) {
1333
+ if (y === null) {
1325
1334
  return xs;
1326
1335
  }
1327
1336
  return xs.exclude(y);
@@ -1452,7 +1461,7 @@ export let aget = (x: any, name: string): any => {
1452
1461
  export let aset = (x: any, name: string, v: any): any => {
1453
1462
  return (x[name] = v);
1454
1463
  };
1455
- export let js_get = aget;
1464
+ export let js_get = (x: any, name: string): any => x[name] ?? null;
1456
1465
  export let js_set = aset;
1457
1466
  /** generates `delete a.b` */
1458
1467
  export let js_delete = (obj: any, name: string): any => {
@@ -1537,7 +1546,7 @@ export let quit_$x_ = (): void => {
1537
1546
  };
1538
1547
 
1539
1548
  export let turn_string = (x: CalcitValue): string => {
1540
- if (x == null) {
1549
+ if (x === null) {
1541
1550
  return "";
1542
1551
  }
1543
1552
  if (typeof x === "string") {
@@ -1580,7 +1589,7 @@ export let ends_with_$q_ = (xs: string, y: string): boolean => {
1580
1589
  };
1581
1590
 
1582
1591
  export let blank_$q_ = (x: string): boolean => {
1583
- if (x == null) {
1592
+ if (x === null) {
1584
1593
  return true;
1585
1594
  }
1586
1595
  if (typeof x === "string") {
@@ -1605,7 +1614,7 @@ export let arrayToList = (xs: Array<CalcitValue>): CalcitSliceList => {
1605
1614
  };
1606
1615
 
1607
1616
  export let listToArray = (xs: CalcitList | CalcitSliceList): Array<CalcitValue> => {
1608
- if (xs == null) {
1617
+ if (xs === null) {
1609
1618
  return null;
1610
1619
  }
1611
1620
  if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
@@ -1625,7 +1634,7 @@ export let bool_$q_ = (x: CalcitValue): boolean => {
1625
1634
  return typeof x === "boolean";
1626
1635
  };
1627
1636
  export let nil_$q_ = (x: CalcitValue): boolean => {
1628
- return x == null;
1637
+ return x === null;
1629
1638
  };
1630
1639
  export let tag_$q_ = (x: CalcitValue): boolean => {
1631
1640
  return x instanceof CalcitTag;
@@ -1705,7 +1714,7 @@ export let parse_cirru_edn = (code: string, options: CalcitValue) => {
1705
1714
  };
1706
1715
 
1707
1716
  type DataShapeNode =
1708
- | { kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic" }
1717
+ | { kind: "nil" | "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic" }
1709
1718
  | { kind: "optional" | "list" | "set" | "ref"; inner: number }
1710
1719
  | { kind: "map"; key: number; value: number }
1711
1720
  | { kind: "map-option"; nominal: CalcitEnumDef; inner: number }
@@ -1720,7 +1729,8 @@ type DataShapeGraph = {
1720
1729
  };
1721
1730
 
1722
1731
  const typed_edn_kind = (value: any): string => {
1723
- if (value == null) return "nil";
1732
+ if (value === null) return "nil";
1733
+ if (value === undefined) return "unit";
1724
1734
  if (typeof value === "boolean") return "bool";
1725
1735
  if (typeof value === "number") return "number";
1726
1736
  if (typeof value === "string") return "string";
@@ -1751,9 +1761,12 @@ const decode_typed_edn_node = (graph: DataShapeGraph, nodeId: number, input: any
1751
1761
  if (node == null) typed_edn_error(path, `invalid data shape node #${nodeId}`);
1752
1762
 
1753
1763
  switch (node.kind) {
1764
+ case "nil":
1765
+ if (input === null) return null;
1766
+ return typed_edn_error(path, `expected Nil, got ${typed_edn_kind(input)}`);
1754
1767
  case "unit":
1755
- if (input == null) return null;
1756
- return typed_edn_error(path, `expected nil, got ${typed_edn_kind(input)}`);
1768
+ if (input === undefined) return input;
1769
+ return typed_edn_error(path, `expected Unit, got ${typed_edn_kind(input)}`);
1757
1770
  case "bool":
1758
1771
  if (typeof input === "boolean") return input;
1759
1772
  return typed_edn_error(path, `expected bool, got ${typed_edn_kind(input)}`);
@@ -1776,7 +1789,7 @@ const decode_typed_edn_node = (graph: DataShapeGraph, nodeId: number, input: any
1776
1789
  if (input instanceof CalcitCirruQuote) return input;
1777
1790
  return typed_edn_error(path, `expected cirru-quote, got ${typed_edn_kind(input)}`);
1778
1791
  case "optional":
1779
- return input == null ? null : decode_typed_edn_node(graph, node.inner, input, path, depth + 1);
1792
+ return input === null ? null : decode_typed_edn_node(graph, node.inner, input, path, depth + 1);
1780
1793
  case "list": {
1781
1794
  if (!(input instanceof CalcitList || input instanceof CalcitSliceList)) {
1782
1795
  return typed_edn_error(path, `expected list, got ${typed_edn_kind(input)}`);
@@ -1845,8 +1858,8 @@ const decode_typed_edn_node = (graph: DataShapeGraph, nodeId: number, input: any
1845
1858
  const idx = actualNames.indexOf(name);
1846
1859
  decodedFields.set(name, decode_typed_edn_node(graph, fieldNode, input.values[idx], `${path}.${name}`, depth + 1));
1847
1860
  });
1848
- // Native declarations use lexical field order while the JS runtime keeps
1849
- // its interned-tag order. Re-align values to the nominal JS declaration.
1861
+ // Re-align by name so values produced by older runtimes or external data
1862
+ // still adopt the current nominal declaration's canonical field layout.
1850
1863
  if (decodedFields.size !== node.nominal.fields.length) {
1851
1864
  return typed_edn_error(path, `struct :${node.nominal.name.value} decoder fields do not match its nominal declaration`);
1852
1865
  }
@@ -1892,7 +1905,7 @@ const decode_typed_edn_node = (graph: DataShapeGraph, nodeId: number, input: any
1892
1905
 
1893
1906
  export let parse_cirru_edn_as = (code: string, graph: DataShapeGraph): CalcitValue => {
1894
1907
  if (typeof code !== "string") throw new Error(`parse-cirru-edn-as expected a string, got ${typed_edn_kind(code)}`);
1895
- if (graph.version !== 1) throw new Error(`parse-cirru-edn-as expected data shape ABI version 1, got ${graph.version}`);
1908
+ if (graph.version !== 2) throw new Error(`parse-cirru-edn-as expected data shape ABI version 2, got ${graph.version}`);
1896
1909
  if (typeof graph.fingerprint !== "string" || graph.fingerprint.length === 0) {
1897
1910
  throw new Error("parse-cirru-edn-as expected a non-empty data shape fingerprint");
1898
1911
  }
@@ -2003,7 +2016,7 @@ const decode_runtime_map_node = (graph: DataShapeGraph, nodeId: number, input: a
2003
2016
  return new CalcitSliceMap(entries.flat());
2004
2017
  }
2005
2018
  case "optional":
2006
- return input == null ? null : decode_runtime_map_node(graph, node.inner, input, path, depth + 1);
2019
+ return input === null ? null : decode_runtime_map_node(graph, node.inner, input, path, depth + 1);
2007
2020
  case "ref":
2008
2021
  if (!(input instanceof CalcitRef)) return map_decode_error(path, `expected atom, got ${typed_edn_kind(input)}`);
2009
2022
  return atom(decode_runtime_map_node(graph, node.inner, input.value, `${path}.value`, depth + 1));
@@ -2036,7 +2049,7 @@ const decode_runtime_map_node = (graph: DataShapeGraph, nodeId: number, input: a
2036
2049
  };
2037
2050
 
2038
2051
  export let decode_map_as = (value: CalcitValue, graph: DataShapeGraph): CalcitValue => {
2039
- if (graph.version !== 1) throw new Error(`decode-map-as expected data shape ABI version 1, got ${graph.version}`);
2052
+ if (graph.version !== 2) throw new Error(`decode-map-as expected data shape ABI version 2, got ${graph.version}`);
2040
2053
  if (typeof graph.fingerprint !== "string" || graph.fingerprint.length === 0) {
2041
2054
  throw new Error("decode-map-as expected a non-empty data shape fingerprint");
2042
2055
  }
@@ -2074,7 +2087,7 @@ const cirru_quote_to_json = (value: ICirruNode): any => {
2074
2087
  };
2075
2088
 
2076
2089
  const calcit_to_json = (value: CalcitValue): any => {
2077
- if (value == null) return null;
2090
+ if (value === null) return null;
2078
2091
  if (typeof value === "string") return value;
2079
2092
  if (typeof value === "number") {
2080
2093
  if (Number.isFinite(value)) return value;
@@ -2131,8 +2144,10 @@ export let json_pretty = function (value: CalcitValue): string {
2131
2144
  };
2132
2145
 
2133
2146
  export let format_to_lisp = (x: CalcitValue): string => {
2134
- if (x == null) {
2147
+ if (x === null) {
2135
2148
  return "nil";
2149
+ } else if (x === undefined) {
2150
+ return "&unit";
2136
2151
  } else if (x instanceof CalcitSymbol) {
2137
2152
  return x.value;
2138
2153
  } else if (x instanceof CalcitList || x instanceof CalcitSliceList) {
@@ -2159,8 +2174,10 @@ export let format_to_cirru = (x: CalcitValue): string => {
2159
2174
  };
2160
2175
 
2161
2176
  export let transform_code_to_cirru = (x: CalcitValue): ICirruNode => {
2162
- if (x == null) {
2177
+ if (x === null) {
2163
2178
  return "nil";
2179
+ } else if (x === undefined) {
2180
+ return "&unit";
2164
2181
  } else if (x instanceof CalcitSymbol) {
2165
2182
  return x.value;
2166
2183
  } else if (x instanceof CalcitList || x instanceof CalcitSliceList) {
@@ -21,9 +21,12 @@ declare global {
21
21
  }
22
22
 
23
23
  let embedObject = (x: CalcitValue) => {
24
- if (x == null) {
24
+ if (x === null) {
25
25
  return null;
26
26
  }
27
+ if (x === undefined) {
28
+ return span({ whiteSpace: "pre", color: hsl(240, 70, 50) }, "&unit");
29
+ }
27
30
  if (typeof x === "string") {
28
31
  return span({ whiteSpace: "pre", color: hsl(120, 70, 50), maxWidth: "100vw" }, `|${x}`);
29
32
  }
@@ -77,16 +80,22 @@ let td = (style: any, ...children: any[]) => {
77
80
 
78
81
  /** handle null value in nested data */
79
82
  let saveString = (v: CalcitValue) => {
83
+ if (v === null) {
84
+ return "nil";
85
+ }
86
+ if (v === undefined) {
87
+ return "&unit";
88
+ }
80
89
  if (typeof v === "string") {
81
90
  if (v.match(/[\s\"\n\t\,]/)) {
82
91
  return `"|${v}"`;
83
92
  } else {
84
93
  return `|${v}`;
85
94
  }
86
- } else if (v != null && v.toString) {
95
+ } else if (v.toString) {
87
96
  return v.toString();
88
97
  } else {
89
- return "nil";
98
+ return String(v);
90
99
  }
91
100
  };
92
101
 
@@ -6,7 +6,7 @@ import { CalcitList, CalcitSliceList } from "./js-list.mjs";
6
6
  import { CalcitStructValue } from "./js-struct-value.mjs";
7
7
  import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
8
8
  import { CalcitSet } from "./js-set.mjs";
9
- import { CalcitTag, CalcitSymbol, CalcitRecur, newTag } from "./calcit-data.mjs";
9
+ import { CalcitTag, CalcitSymbol, CalcitRecur, newTag, compareTagNames } from "./calcit-data.mjs";
10
10
  import { CalcitEnumValue } from "./js-enum-value.mjs";
11
11
  import { CalcitEnumDef } from "./js-enum-def.mjs";
12
12
  import { CalcitImpl } from "./js-impl.mjs";
@@ -87,9 +87,12 @@ export let format_cirru_one_liner = (data: CalcitCirruQuote | CalcitList): strin
87
87
 
88
88
  /** better use string version of Cirru EDN in future */
89
89
  export let to_cirru_edn = (x: CalcitValue): CirruEdnFormat => {
90
- if (x == null) {
90
+ if (x === null) {
91
91
  return "nil";
92
92
  }
93
+ if (x === undefined) {
94
+ throw new Error("Cirru EDN cannot encode &unit");
95
+ }
93
96
  if (typeof x === "string") {
94
97
  return `|${x}`;
95
98
  }
@@ -352,9 +355,7 @@ const extract_cirru_edn_inner = (x: CirruEdnFormat, options: CalcitValue, preser
352
355
  throw new Error(`Expected field pairs for struct, got: ${pair}`);
353
356
  }
354
357
  });
355
- entries.sort((a, b) => {
356
- return a[0].cmp(b[0]);
357
- });
358
+ entries.sort((a, b) => compareTagNames(a[0], b[0]));
358
359
  let fields: Array<CalcitTag> = [];
359
360
  let values: Array<CalcitValue> = [];
360
361
 
@@ -1,6 +1,6 @@
1
1
  import { Hash } from "@calcit/ternary-tree";
2
2
  import { CalcitValue } from "./js-primes.mjs";
3
- import { CalcitTag, castTag, findInFields, toString } from "./calcit-data.mjs";
3
+ import { CalcitTag, canonicalizeTagPairs, castTag, findInFields, toString } from "./calcit-data.mjs";
4
4
  import type { CalcitTrait } from "./js-trait.mjs";
5
5
 
6
6
  const CALCIT_IMPL_BRAND = Symbol.for("@calcit/procs/CalcitImpl");
@@ -44,10 +44,11 @@ export class CalcitImpl {
44
44
  // optimized dependencies. A global, non-enumerable brand keeps impl values
45
45
  // recognizable across those otherwise distinct module instances.
46
46
  Object.defineProperty(this, CALCIT_IMPL_BRAND, { value: true });
47
+ const [canonicalFields, canonicalValues] = canonicalizeTagPairs(fields, values, "CalcitImpl");
47
48
  this.name = name;
48
49
  this.origin = origin;
49
- this.fields = fields;
50
- this.values = values;
50
+ this.fields = canonicalFields;
51
+ this.values = canonicalValues;
51
52
  this.cachedHash = null;
52
53
  }
53
54
 
@@ -32,6 +32,7 @@ export type CalcitValue =
32
32
  | CalcitStructDef
33
33
  | CalcitEnumDef
34
34
  | CalcitCirruQuote
35
+ | undefined
35
36
  | null;
36
37
 
37
38
  export let isLiteral = (x: CalcitValue): boolean => {
@@ -46,6 +47,7 @@ export let isLiteral = (x: CalcitValue): boolean => {
46
47
 
47
48
  enum PseudoTypeIndex {
48
49
  nil,
50
+ unit,
49
51
  bool,
50
52
  number,
51
53
  symbol,
@@ -67,7 +69,8 @@ enum PseudoTypeIndex {
67
69
 
68
70
  let typeAsInt = (x: CalcitValue): number => {
69
71
  // based on order used in Ord trait
70
- if (x == null) return PseudoTypeIndex.nil;
72
+ if (x === null) return PseudoTypeIndex.nil;
73
+ if (x === undefined) return PseudoTypeIndex.unit;
71
74
  let t = typeof x;
72
75
  if (t === "boolean") return PseudoTypeIndex.bool;
73
76
  if (t === "number") return PseudoTypeIndex.number;
@@ -107,6 +110,7 @@ export let _$n_compare = (a: CalcitValue, b: CalcitValue): number => {
107
110
  if (ta === tb) {
108
111
  switch (ta) {
109
112
  case PseudoTypeIndex.nil:
113
+ case PseudoTypeIndex.unit:
110
114
  return 0;
111
115
  case PseudoTypeIndex.bool:
112
116
  return rawCompare(a, b);
@@ -1,4 +1,4 @@
1
- import { CalcitTag, toString } from "./calcit-data.mjs";
1
+ import { CalcitTag, canonicalizeTagPairs, toString } from "./calcit-data.mjs";
2
2
  import { CalcitValue } from "./js-primes.mjs";
3
3
  import { CalcitImpl } from "./js-impl.mjs";
4
4
 
@@ -10,12 +10,10 @@ export class CalcitStructDef {
10
10
  cachedHash: number;
11
11
 
12
12
  constructor(name: CalcitTag, fields: CalcitTag[], fieldTypes: CalcitValue[], impls: CalcitImpl[] = []) {
13
- if (fields.length !== fieldTypes.length) {
14
- throw new Error("CalcitStructDef: fields and fieldTypes length mismatch");
15
- }
13
+ const [canonicalFields, canonicalTypes] = canonicalizeTagPairs(fields, fieldTypes, "CalcitStructDef");
16
14
  this.name = name;
17
- this.fields = fields;
18
- this.fieldTypes = fieldTypes;
15
+ this.fields = canonicalFields;
16
+ this.fieldTypes = canonicalTypes;
19
17
  this.impls = impls;
20
18
  this.cachedHash = null;
21
19
  }