@elaraai/east 0.0.1-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/LICENSE.md +15 -666
  2. package/README.md +113 -88
  3. package/dist/src/analyze.d.ts +3 -0
  4. package/dist/src/analyze.d.ts.map +1 -1
  5. package/dist/src/analyze.js +223 -111
  6. package/dist/src/analyze.js.map +1 -1
  7. package/dist/src/analyze.spec.d.ts +2 -0
  8. package/dist/src/analyze.spec.d.ts.map +1 -0
  9. package/dist/src/analyze.spec.js +445 -0
  10. package/dist/src/analyze.spec.js.map +1 -0
  11. package/dist/src/ast.d.ts +54 -35
  12. package/dist/src/ast.d.ts.map +1 -1
  13. package/dist/src/ast_to_ir.coerce_to.spec.d.ts +15 -0
  14. package/dist/src/ast_to_ir.coerce_to.spec.d.ts.map +1 -0
  15. package/dist/src/ast_to_ir.coerce_to.spec.js +420 -0
  16. package/dist/src/ast_to_ir.coerce_to.spec.js.map +1 -0
  17. package/dist/src/ast_to_ir.d.ts +18 -4
  18. package/dist/src/ast_to_ir.d.ts.map +1 -1
  19. package/dist/src/ast_to_ir.js +233 -178
  20. package/dist/src/ast_to_ir.js.map +1 -1
  21. package/dist/src/builtins.d.ts +1 -1
  22. package/dist/src/builtins.d.ts.map +1 -1
  23. package/dist/src/builtins.js +194 -2
  24. package/dist/src/builtins.js.map +1 -1
  25. package/dist/src/comparison.d.ts +2 -2
  26. package/dist/src/comparison.d.ts.map +1 -1
  27. package/dist/src/comparison.js +115 -40
  28. package/dist/src/comparison.js.map +1 -1
  29. package/dist/src/comparison.spec.d.ts +2 -0
  30. package/dist/src/comparison.spec.d.ts.map +1 -0
  31. package/dist/src/comparison.spec.js +1200 -0
  32. package/dist/src/comparison.spec.js.map +1 -0
  33. package/dist/src/compile.d.ts +31 -9
  34. package/dist/src/compile.d.ts.map +1 -1
  35. package/dist/src/compile.js +1048 -548
  36. package/dist/src/compile.js.map +1 -1
  37. package/dist/src/containers/matrix.d.ts +15 -0
  38. package/dist/src/containers/matrix.d.ts.map +1 -0
  39. package/dist/src/containers/matrix.js +15 -0
  40. package/dist/src/containers/matrix.js.map +1 -0
  41. package/dist/src/containers/ref.d.ts.map +1 -1
  42. package/dist/src/containers/ref.js +1 -1
  43. package/dist/src/containers/ref.js.map +1 -1
  44. package/dist/src/containers/sortedmap.spec.d.ts +2 -0
  45. package/dist/src/containers/sortedmap.spec.d.ts.map +1 -0
  46. package/dist/src/containers/sortedmap.spec.js +180 -0
  47. package/dist/src/containers/sortedmap.spec.js.map +1 -0
  48. package/dist/src/containers/sortedset.spec.d.ts +2 -0
  49. package/dist/src/containers/sortedset.spec.d.ts.map +1 -0
  50. package/dist/src/containers/sortedset.spec.js +228 -0
  51. package/dist/src/containers/sortedset.spec.js.map +1 -0
  52. package/dist/src/containers/variant.d.ts.map +1 -1
  53. package/dist/src/containers/variant.js +1 -1
  54. package/dist/src/containers/variant.js.map +1 -1
  55. package/dist/src/containers/variant.spec.d.ts +2 -0
  56. package/dist/src/containers/variant.spec.d.ts.map +1 -0
  57. package/dist/src/containers/variant.spec.js +217 -0
  58. package/dist/src/containers/variant.spec.js.map +1 -0
  59. package/dist/src/datetime_format/parse.spec.d.ts +6 -0
  60. package/dist/src/datetime_format/parse.spec.d.ts.map +1 -0
  61. package/dist/src/datetime_format/parse.spec.js +379 -0
  62. package/dist/src/datetime_format/parse.spec.js.map +1 -0
  63. package/dist/src/datetime_format/print.spec.d.ts +6 -0
  64. package/dist/src/datetime_format/print.spec.d.ts.map +1 -0
  65. package/dist/src/datetime_format/print.spec.js +257 -0
  66. package/dist/src/datetime_format/print.spec.js.map +1 -0
  67. package/dist/src/datetime_format/tokenize.spec.d.ts +2 -0
  68. package/dist/src/datetime_format/tokenize.spec.d.ts.map +1 -0
  69. package/dist/src/datetime_format/tokenize.spec.js +508 -0
  70. package/dist/src/datetime_format/tokenize.spec.js.map +1 -0
  71. package/dist/src/datetime_format/types.d.ts +23 -23
  72. package/dist/src/default.d.ts.map +1 -1
  73. package/dist/src/default.js +33 -0
  74. package/dist/src/default.js.map +1 -1
  75. package/dist/src/default.spec.d.ts +2 -0
  76. package/dist/src/default.spec.d.ts.map +1 -0
  77. package/dist/src/default.spec.js +178 -0
  78. package/dist/src/default.spec.js.map +1 -0
  79. package/dist/src/eastir.d.ts +7 -0
  80. package/dist/src/eastir.d.ts.map +1 -1
  81. package/dist/src/eastir.js +55 -7
  82. package/dist/src/eastir.js.map +1 -1
  83. package/dist/src/error.d.ts +14 -4
  84. package/dist/src/error.d.ts.map +1 -1
  85. package/dist/src/error.js +28 -3
  86. package/dist/src/error.js.map +1 -1
  87. package/dist/src/example.d.ts +87 -0
  88. package/dist/src/example.d.ts.map +1 -0
  89. package/dist/src/example.js +18 -0
  90. package/dist/src/example.js.map +1 -0
  91. package/dist/src/expr/array.d.ts +43 -1
  92. package/dist/src/expr/array.d.ts.map +1 -1
  93. package/dist/src/expr/array.js +103 -53
  94. package/dist/src/expr/array.js.map +1 -1
  95. package/dist/src/expr/ast.d.ts +1 -1
  96. package/dist/src/expr/ast.d.ts.map +1 -1
  97. package/dist/src/expr/ast.js +112 -54
  98. package/dist/src/expr/ast.js.map +1 -1
  99. package/dist/src/expr/asyncfunction.d.ts.map +1 -1
  100. package/dist/src/expr/asyncfunction.js +6 -4
  101. package/dist/src/expr/asyncfunction.js.map +1 -1
  102. package/dist/src/expr/blob.d.ts +48 -0
  103. package/dist/src/expr/blob.d.ts.map +1 -1
  104. package/dist/src/expr/blob.js +63 -8
  105. package/dist/src/expr/blob.js.map +1 -1
  106. package/dist/src/expr/block.d.ts +213 -12
  107. package/dist/src/expr/block.d.ts.map +1 -1
  108. package/dist/src/expr/block.js +796 -293
  109. package/dist/src/expr/block.js.map +1 -1
  110. package/dist/src/expr/boolean.d.ts +44 -0
  111. package/dist/src/expr/boolean.d.ts.map +1 -1
  112. package/dist/src/expr/boolean.js +58 -6
  113. package/dist/src/expr/boolean.js.map +1 -1
  114. package/dist/src/expr/datetime.d.ts +135 -0
  115. package/dist/src/expr/datetime.d.ts.map +1 -1
  116. package/dist/src/expr/datetime.js +184 -34
  117. package/dist/src/expr/datetime.js.map +1 -1
  118. package/dist/src/expr/dict.d.ts +47 -2
  119. package/dist/src/expr/dict.d.ts.map +1 -1
  120. package/dist/src/expr/dict.js +122 -61
  121. package/dist/src/expr/dict.js.map +1 -1
  122. package/dist/src/expr/expr.d.ts +3 -1
  123. package/dist/src/expr/expr.d.ts.map +1 -1
  124. package/dist/src/expr/expr.js +4 -3
  125. package/dist/src/expr/expr.js.map +1 -1
  126. package/dist/src/expr/float.d.ts +153 -0
  127. package/dist/src/expr/float.d.ts.map +1 -1
  128. package/dist/src/expr/float.js +191 -17
  129. package/dist/src/expr/float.js.map +1 -1
  130. package/dist/src/expr/function.d.ts +7 -2
  131. package/dist/src/expr/function.d.ts.map +1 -1
  132. package/dist/src/expr/function.js +6 -4
  133. package/dist/src/expr/function.js.map +1 -1
  134. package/dist/src/expr/index.d.ts +186 -2
  135. package/dist/src/expr/index.d.ts.map +1 -1
  136. package/dist/src/expr/index.js +183 -2
  137. package/dist/src/expr/index.js.map +1 -1
  138. package/dist/src/expr/integer.d.ts +180 -0
  139. package/dist/src/expr/integer.d.ts.map +1 -1
  140. package/dist/src/expr/integer.js +189 -18
  141. package/dist/src/expr/integer.js.map +1 -1
  142. package/dist/src/expr/libs/array.js +3 -3
  143. package/dist/src/expr/libs/array.js.map +1 -1
  144. package/dist/src/expr/libs/blob.js +3 -3
  145. package/dist/src/expr/libs/blob.js.map +1 -1
  146. package/dist/src/expr/libs/dict.js +1 -1
  147. package/dist/src/expr/libs/dict.js.map +1 -1
  148. package/dist/src/expr/libs/matrix.d.ts +17 -0
  149. package/dist/src/expr/libs/matrix.d.ts.map +1 -0
  150. package/dist/src/expr/libs/matrix.js +60 -0
  151. package/dist/src/expr/libs/matrix.js.map +1 -0
  152. package/dist/src/expr/libs/set.js +1 -1
  153. package/dist/src/expr/libs/set.js.map +1 -1
  154. package/dist/src/expr/libs/string.d.ts.map +1 -1
  155. package/dist/src/expr/libs/string.js +2 -1
  156. package/dist/src/expr/libs/string.js.map +1 -1
  157. package/dist/src/expr/libs/vector.d.ts +16 -0
  158. package/dist/src/expr/libs/vector.d.ts.map +1 -0
  159. package/dist/src/expr/libs/vector.js +44 -0
  160. package/dist/src/expr/libs/vector.js.map +1 -0
  161. package/dist/src/expr/matrix.d.ts +109 -0
  162. package/dist/src/expr/matrix.d.ts.map +1 -0
  163. package/dist/src/expr/matrix.js +224 -0
  164. package/dist/src/expr/matrix.js.map +1 -0
  165. package/dist/src/expr/recursive.d.ts +83 -0
  166. package/dist/src/expr/recursive.d.ts.map +1 -0
  167. package/dist/src/expr/recursive.js +99 -0
  168. package/dist/src/expr/recursive.js.map +1 -0
  169. package/dist/src/expr/ref.js +5 -5
  170. package/dist/src/expr/ref.js.map +1 -1
  171. package/dist/src/expr/set.d.ts +44 -2
  172. package/dist/src/expr/set.d.ts.map +1 -1
  173. package/dist/src/expr/set.js +102 -52
  174. package/dist/src/expr/set.js.map +1 -1
  175. package/dist/src/expr/string.d.ts +134 -0
  176. package/dist/src/expr/string.d.ts.map +1 -1
  177. package/dist/src/expr/string.js +173 -23
  178. package/dist/src/expr/string.js.map +1 -1
  179. package/dist/src/expr/struct.d.ts +1 -1
  180. package/dist/src/expr/struct.d.ts.map +1 -1
  181. package/dist/src/expr/struct.js +2 -2
  182. package/dist/src/expr/struct.js.map +1 -1
  183. package/dist/src/expr/types.d.ts +12 -9
  184. package/dist/src/expr/types.d.ts.map +1 -1
  185. package/dist/src/expr/variant.d.ts +108 -11
  186. package/dist/src/expr/variant.d.ts.map +1 -1
  187. package/dist/src/expr/variant.js +76 -38
  188. package/dist/src/expr/variant.js.map +1 -1
  189. package/dist/src/expr/vector.d.ts +102 -0
  190. package/dist/src/expr/vector.d.ts.map +1 -0
  191. package/dist/src/expr/vector.js +202 -0
  192. package/dist/src/expr/vector.js.map +1 -0
  193. package/dist/src/fuzz.d.ts +36 -2
  194. package/dist/src/fuzz.d.ts.map +1 -1
  195. package/dist/src/fuzz.js +409 -77
  196. package/dist/src/fuzz.js.map +1 -1
  197. package/dist/src/index.d.ts +4 -0
  198. package/dist/src/index.d.ts.map +1 -1
  199. package/dist/src/index.js +4 -0
  200. package/dist/src/index.js.map +1 -1
  201. package/dist/src/internal.d.ts +12 -2
  202. package/dist/src/internal.d.ts.map +1 -1
  203. package/dist/src/internal.js +13 -2
  204. package/dist/src/internal.js.map +1 -1
  205. package/dist/src/ir.d.ts +1754 -1484
  206. package/dist/src/ir.d.ts.map +1 -1
  207. package/dist/src/ir.js +51 -34
  208. package/dist/src/ir.js.map +1 -1
  209. package/dist/src/ir.spec.d.ts +2 -0
  210. package/dist/src/ir.spec.d.ts.map +1 -0
  211. package/dist/src/ir.spec.js +35 -0
  212. package/dist/src/ir.spec.js.map +1 -0
  213. package/dist/src/location.d.ts +56 -17
  214. package/dist/src/location.d.ts.map +1 -1
  215. package/dist/src/location.js +226 -29
  216. package/dist/src/location.js.map +1 -1
  217. package/dist/src/location.spec.d.ts +2 -0
  218. package/dist/src/location.spec.d.ts.map +1 -0
  219. package/dist/src/location.spec.js +102 -0
  220. package/dist/src/location.spec.js.map +1 -0
  221. package/dist/src/patch/apply.d.ts +15 -0
  222. package/dist/src/patch/apply.d.ts.map +1 -0
  223. package/dist/src/patch/apply.js +352 -0
  224. package/dist/src/patch/apply.js.map +1 -0
  225. package/dist/src/patch/compose.d.ts +15 -0
  226. package/dist/src/patch/compose.d.ts.map +1 -0
  227. package/dist/src/patch/compose.js +448 -0
  228. package/dist/src/patch/compose.js.map +1 -0
  229. package/dist/src/patch/diff.d.ts +15 -0
  230. package/dist/src/patch/diff.d.ts.map +1 -0
  231. package/dist/src/patch/diff.js +347 -0
  232. package/dist/src/patch/diff.js.map +1 -0
  233. package/dist/src/patch/fuzz.d.ts +73 -0
  234. package/dist/src/patch/fuzz.d.ts.map +1 -0
  235. package/dist/src/patch/fuzz.js +159 -0
  236. package/dist/src/patch/fuzz.js.map +1 -0
  237. package/dist/src/patch/index.d.ts +32 -0
  238. package/dist/src/patch/index.d.ts.map +1 -0
  239. package/dist/src/patch/index.js +48 -0
  240. package/dist/src/patch/index.js.map +1 -0
  241. package/dist/src/patch/invert.d.ts +15 -0
  242. package/dist/src/patch/invert.d.ts.map +1 -0
  243. package/dist/src/patch/invert.js +284 -0
  244. package/dist/src/patch/invert.js.map +1 -0
  245. package/dist/src/patch/merge.d.ts +56 -0
  246. package/dist/src/patch/merge.d.ts.map +1 -0
  247. package/dist/src/patch/merge.js +586 -0
  248. package/dist/src/patch/merge.js.map +1 -0
  249. package/dist/src/patch/merge.spec.d.ts +2 -0
  250. package/dist/src/patch/merge.spec.d.ts.map +1 -0
  251. package/dist/src/patch/merge.spec.js +1139 -0
  252. package/dist/src/patch/merge.spec.js.map +1 -0
  253. package/dist/src/patch/patch.spec.d.ts +2 -0
  254. package/dist/src/patch/patch.spec.d.ts.map +1 -0
  255. package/dist/src/patch/patch.spec.js +452 -0
  256. package/dist/src/patch/patch.spec.js.map +1 -0
  257. package/dist/src/patch/path.d.ts +115 -0
  258. package/dist/src/patch/path.d.ts.map +1 -0
  259. package/dist/src/patch/path.js +192 -0
  260. package/dist/src/patch/path.js.map +1 -0
  261. package/dist/src/patch/path.spec.d.ts +6 -0
  262. package/dist/src/patch/path.spec.d.ts.map +1 -0
  263. package/dist/src/patch/path.spec.js +322 -0
  264. package/dist/src/patch/path.spec.js.map +1 -0
  265. package/dist/src/patch/prune.d.ts +77 -0
  266. package/dist/src/patch/prune.d.ts.map +1 -0
  267. package/dist/src/patch/prune.js +115 -0
  268. package/dist/src/patch/prune.js.map +1 -0
  269. package/dist/src/patch/prune.spec.d.ts +6 -0
  270. package/dist/src/patch/prune.spec.d.ts.map +1 -0
  271. package/dist/src/patch/prune.spec.js +473 -0
  272. package/dist/src/patch/prune.spec.js.map +1 -0
  273. package/dist/src/patch/type_of_patch.d.ts +25 -0
  274. package/dist/src/patch/type_of_patch.d.ts.map +1 -0
  275. package/dist/src/patch/type_of_patch.js +144 -0
  276. package/dist/src/patch/type_of_patch.js.map +1 -0
  277. package/dist/src/patch/types.d.ts +220 -0
  278. package/dist/src/patch/types.d.ts.map +1 -0
  279. package/dist/src/patch/types.js +62 -0
  280. package/dist/src/patch/types.js.map +1 -0
  281. package/dist/src/patch/validate.d.ts +44 -0
  282. package/dist/src/patch/validate.d.ts.map +1 -0
  283. package/dist/src/patch/validate.js +190 -0
  284. package/dist/src/patch/validate.js.map +1 -0
  285. package/dist/src/patch/validate.spec.d.ts +6 -0
  286. package/dist/src/patch/validate.spec.d.ts.map +1 -0
  287. package/dist/src/patch/validate.spec.js +225 -0
  288. package/dist/src/patch/validate.spec.js.map +1 -0
  289. package/dist/src/patch/walk.d.ts +121 -0
  290. package/dist/src/patch/walk.d.ts.map +1 -0
  291. package/dist/src/patch/walk.js +385 -0
  292. package/dist/src/patch/walk.js.map +1 -0
  293. package/dist/src/patch/walk.spec.d.ts +6 -0
  294. package/dist/src/patch/walk.spec.d.ts.map +1 -0
  295. package/dist/src/patch/walk.spec.js +621 -0
  296. package/dist/src/patch/walk.spec.js.map +1 -0
  297. package/dist/src/platform.d.ts +6 -0
  298. package/dist/src/platform.d.ts.map +1 -1
  299. package/dist/src/platform.spec.d.ts +2 -0
  300. package/dist/src/platform.spec.d.ts.map +1 -0
  301. package/dist/src/platform.spec.js +330 -0
  302. package/dist/src/platform.spec.js.map +1 -0
  303. package/dist/src/serialization/beast.d.ts.map +1 -1
  304. package/dist/src/serialization/beast.js +12 -0
  305. package/dist/src/serialization/beast.js.map +1 -1
  306. package/dist/src/serialization/beast.spec.d.ts +6 -0
  307. package/dist/src/serialization/beast.spec.d.ts.map +1 -0
  308. package/dist/src/serialization/beast.spec.js +406 -0
  309. package/dist/src/serialization/beast.spec.js.map +1 -0
  310. package/dist/src/serialization/beast2/index.d.ts +50 -0
  311. package/dist/src/serialization/beast2/index.d.ts.map +1 -0
  312. package/dist/src/serialization/beast2/index.js +756 -0
  313. package/dist/src/serialization/beast2/index.js.map +1 -0
  314. package/dist/src/serialization/beast2/index.spec.d.ts +6 -0
  315. package/dist/src/serialization/beast2/index.spec.d.ts.map +1 -0
  316. package/dist/src/serialization/beast2/index.spec.js +528 -0
  317. package/dist/src/serialization/beast2/index.spec.js.map +1 -0
  318. package/dist/src/serialization/beast2/sourcemap-table.d.ts +29 -0
  319. package/dist/src/serialization/beast2/sourcemap-table.d.ts.map +1 -0
  320. package/dist/src/serialization/beast2/sourcemap-table.js +82 -0
  321. package/dist/src/serialization/beast2/sourcemap-table.js.map +1 -0
  322. package/dist/src/serialization/beast2/string-table.d.ts +16 -0
  323. package/dist/src/serialization/beast2/string-table.d.ts.map +1 -0
  324. package/dist/src/serialization/beast2/string-table.js +38 -0
  325. package/dist/src/serialization/beast2/string-table.js.map +1 -0
  326. package/dist/src/serialization/beast2/type-table.d.ts +86 -0
  327. package/dist/src/serialization/beast2/type-table.d.ts.map +1 -0
  328. package/dist/src/serialization/beast2/type-table.js +618 -0
  329. package/dist/src/serialization/beast2/type-table.js.map +1 -0
  330. package/dist/src/serialization/beast2/value-table.d.ts +40 -0
  331. package/dist/src/serialization/beast2/value-table.d.ts.map +1 -0
  332. package/dist/src/serialization/beast2/value-table.js +157 -0
  333. package/dist/src/serialization/beast2/value-table.js.map +1 -0
  334. package/dist/src/serialization/binary-utils.d.ts +33 -0
  335. package/dist/src/serialization/binary-utils.d.ts.map +1 -1
  336. package/dist/src/serialization/binary-utils.js +157 -0
  337. package/dist/src/serialization/binary-utils.js.map +1 -1
  338. package/dist/src/serialization/csv.d.ts +17 -17
  339. package/dist/src/serialization/csv.d.ts.map +1 -1
  340. package/dist/src/serialization/csv.js +10 -8
  341. package/dist/src/serialization/csv.js.map +1 -1
  342. package/dist/src/serialization/csv.spec.d.ts +2 -0
  343. package/dist/src/serialization/csv.spec.d.ts.map +1 -0
  344. package/dist/src/serialization/csv.spec.js +556 -0
  345. package/dist/src/serialization/csv.spec.js.map +1 -0
  346. package/dist/src/serialization/east-inferred.spec.d.ts +2 -0
  347. package/dist/src/serialization/east-inferred.spec.d.ts.map +1 -0
  348. package/dist/src/serialization/east-inferred.spec.js +322 -0
  349. package/dist/src/serialization/east-inferred.spec.js.map +1 -0
  350. package/dist/src/serialization/east.d.ts +1 -1
  351. package/dist/src/serialization/east.d.ts.map +1 -1
  352. package/dist/src/serialization/east.js +178 -26
  353. package/dist/src/serialization/east.js.map +1 -1
  354. package/dist/src/serialization/east.spec.d.ts +2 -0
  355. package/dist/src/serialization/east.spec.d.ts.map +1 -0
  356. package/dist/src/serialization/east.spec.js +1548 -0
  357. package/dist/src/serialization/east.spec.js.map +1 -0
  358. package/dist/src/serialization/index.d.ts +1 -2
  359. package/dist/src/serialization/index.d.ts.map +1 -1
  360. package/dist/src/serialization/index.js +1 -2
  361. package/dist/src/serialization/index.js.map +1 -1
  362. package/dist/src/serialization/json.d.ts +1 -1
  363. package/dist/src/serialization/json.d.ts.map +1 -1
  364. package/dist/src/serialization/json.js +123 -24
  365. package/dist/src/serialization/json.js.map +1 -1
  366. package/dist/src/serialization/json.spec.d.ts +2 -0
  367. package/dist/src/serialization/json.spec.d.ts.map +1 -0
  368. package/dist/src/serialization/json.spec.js +1297 -0
  369. package/dist/src/serialization/json.spec.js.map +1 -0
  370. package/dist/src/type_of_type.d.ts +72 -35
  371. package/dist/src/type_of_type.d.ts.map +1 -1
  372. package/dist/src/type_of_type.is_data.spec.d.ts +6 -0
  373. package/dist/src/type_of_type.is_data.spec.d.ts.map +1 -0
  374. package/dist/src/type_of_type.is_data.spec.js +221 -0
  375. package/dist/src/type_of_type.is_data.spec.js.map +1 -0
  376. package/dist/src/type_of_type.js +355 -80
  377. package/dist/src/type_of_type.js.map +1 -1
  378. package/dist/src/type_of_type.to_etv.spec.d.ts +6 -0
  379. package/dist/src/type_of_type.to_etv.spec.d.ts.map +1 -0
  380. package/dist/src/type_of_type.to_etv.spec.js +263 -0
  381. package/dist/src/type_of_type.to_etv.spec.js.map +1 -0
  382. package/dist/src/types.d.ts +82 -12
  383. package/dist/src/types.d.ts.map +1 -1
  384. package/dist/src/types.error.spec.d.ts +2 -0
  385. package/dist/src/types.error.spec.d.ts.map +1 -0
  386. package/dist/src/types.error.spec.js +665 -0
  387. package/dist/src/types.error.spec.js.map +1 -0
  388. package/dist/src/types.js +663 -156
  389. package/dist/src/types.js.map +1 -1
  390. package/dist/src/types.spec.d.ts +2 -0
  391. package/dist/src/types.spec.d.ts.map +1 -0
  392. package/dist/src/types.spec.js +946 -0
  393. package/dist/src/types.spec.js.map +1 -0
  394. package/dist/src/walker.d.ts +65 -0
  395. package/dist/src/walker.d.ts.map +1 -0
  396. package/dist/src/walker.js +165 -0
  397. package/dist/src/walker.js.map +1 -0
  398. package/dist/src/walker.spec.d.ts +6 -0
  399. package/dist/src/walker.spec.d.ts.map +1 -0
  400. package/dist/src/walker.spec.js +109 -0
  401. package/dist/src/walker.spec.js.map +1 -0
  402. package/package.json +16 -38
  403. package/dist/src/serialization/beast2-stream.d.ts +0 -38
  404. package/dist/src/serialization/beast2-stream.d.ts.map +0 -1
  405. package/dist/src/serialization/beast2-stream.js +0 -670
  406. package/dist/src/serialization/beast2-stream.js.map +0 -1
  407. package/dist/src/serialization/beast2.d.ts +0 -41
  408. package/dist/src/serialization/beast2.d.ts.map +0 -1
  409. package/dist/src/serialization/beast2.js +0 -495
  410. package/dist/src/serialization/beast2.js.map +0 -1
@@ -0,0 +1,1297 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import { describe, test } from "node:test";
6
+ import assert from "node:assert/strict";
7
+ import { variant, some, none } from '../containers/variant.js';
8
+ import { fuzzerTest } from '../fuzz.js';
9
+ import { ArrayType, AsyncFunctionType, BlobType, BooleanType, DateTimeType, DictType, FloatType, FunctionType, IntegerType, NeverType, NullType, RecursiveType, SetType, StringType, StructType, VariantType, VectorType, MatrixType, } from '../types.js';
10
+ import { matrix } from '../containers/matrix.js';
11
+ import { decodeJSONFor, encodeJSONFor, fromJSONFor, toJSONFor } from "./json.js";
12
+ import { compareFor, equalFor } from "../comparison.js";
13
+ import { SortedSet } from "../containers/sortedset.js";
14
+ import { SortedMap } from "../containers/sortedmap.js";
15
+ describe('Json encoding/decoding of EAST values', () => {
16
+ function run(type, decoded, encoded, erroneous = []) {
17
+ assert.strictEqual(decoded.length, encoded.length);
18
+ const toJson = toJSONFor(type);
19
+ const fromJson = fromJSONFor(type);
20
+ const equal = equalFor(type);
21
+ for (let i = 0; i < decoded.length; i++) {
22
+ assert.deepEqual(toJson(decoded[i]), encoded[i]);
23
+ assert.ok(equal(fromJson(encoded[i]), decoded[i]), `Round-trip failed for ${JSON.stringify(encoded[i])}`);
24
+ }
25
+ for (const v of erroneous) {
26
+ assert.throws(() => fromJson(v));
27
+ }
28
+ }
29
+ test('should encode/decode null', () => {
30
+ const type = NullType;
31
+ const decoded = [
32
+ null,
33
+ ];
34
+ const encoded = [
35
+ null,
36
+ ];
37
+ const erroneous = [
38
+ undefined,
39
+ true,
40
+ 1,
41
+ "",
42
+ [],
43
+ {},
44
+ ];
45
+ run(type, decoded, encoded, erroneous);
46
+ });
47
+ test('should encode/decode boolean', () => {
48
+ const type = BooleanType;
49
+ const decoded = [
50
+ true,
51
+ false,
52
+ ];
53
+ const encoded = [
54
+ true,
55
+ false,
56
+ ];
57
+ const erroneous = [
58
+ undefined,
59
+ null,
60
+ 1,
61
+ "",
62
+ [],
63
+ {}
64
+ ];
65
+ run(type, decoded, encoded, erroneous);
66
+ });
67
+ test('should encode/decode integer', () => {
68
+ const type = IntegerType;
69
+ const decoded = [
70
+ 0n,
71
+ 42n,
72
+ -1n,
73
+ 90071992547409919n,
74
+ 9223372036854775807n,
75
+ -9223372036854775808n,
76
+ ];
77
+ const encoded = [
78
+ "0",
79
+ "42",
80
+ "-1",
81
+ "90071992547409919",
82
+ "9223372036854775807",
83
+ "-9223372036854775808",
84
+ ];
85
+ const erroneous = [
86
+ undefined,
87
+ null,
88
+ "",
89
+ [],
90
+ {},
91
+ "abc",
92
+ "9223372036854775808",
93
+ "-9223372036854775809",
94
+ ];
95
+ run(type, decoded, encoded, erroneous);
96
+ });
97
+ test('should encode/decode float', () => {
98
+ const type = FloatType;
99
+ const decoded = [
100
+ 0,
101
+ 3.14,
102
+ -1e6,
103
+ Infinity,
104
+ -Infinity,
105
+ NaN,
106
+ ];
107
+ const encoded = [
108
+ 0,
109
+ 3.14,
110
+ -1e6,
111
+ "Infinity",
112
+ "-Infinity",
113
+ "NaN",
114
+ ];
115
+ const erroneous = [
116
+ undefined,
117
+ null,
118
+ "",
119
+ "abc",
120
+ "Inf",
121
+ "-Inf",
122
+ [],
123
+ {}
124
+ ];
125
+ run(type, decoded, encoded, erroneous);
126
+ });
127
+ test('should encode/decode string', () => {
128
+ const type = StringType;
129
+ const decoded = [
130
+ "",
131
+ "abc",
132
+ "いろはにほへとちりぬるを",
133
+ ];
134
+ const encoded = [
135
+ "",
136
+ "abc",
137
+ "いろはにほへとちりぬるを",
138
+ ];
139
+ const erroneous = [
140
+ undefined,
141
+ null,
142
+ 1,
143
+ [],
144
+ {}
145
+ ];
146
+ run(type, decoded, encoded, erroneous);
147
+ });
148
+ test('should encode/decode date', () => {
149
+ const type = DateTimeType;
150
+ const decoded = [
151
+ new Date(0),
152
+ new Date("2022-06-29T13:43:00.123+00:00"),
153
+ new Date("2022-06-29T13:43:00.123Z"),
154
+ new Date("2022-06-29T13:43:00.123+05:00"),
155
+ ];
156
+ const encoded = [
157
+ "1970-01-01T00:00:00.000+00:00",
158
+ "2022-06-29T13:43:00.123+00:00",
159
+ "2022-06-29T13:43:00.123+00:00",
160
+ "2022-06-29T08:43:00.123+00:00",
161
+ ];
162
+ const erroneous = [
163
+ undefined,
164
+ null,
165
+ 1,
166
+ [],
167
+ {},
168
+ "1970-13-01T00:00:00.000+00:00", // Invalid month
169
+ "1970-01-01T00:00:00.000", // Missing timezone
170
+ "1970-01-01 00:00:00.000Z", // Space instead of T
171
+ "1970-01-01T00:00:00Z", // Missing milliseconds
172
+ "2022-06-29T13:43:00.123+5:00", // Invalid offset format (should be +05:00)
173
+ ];
174
+ run(type, decoded, encoded, erroneous);
175
+ });
176
+ test('should encode/decode array', () => {
177
+ const type = ArrayType(DateTimeType);
178
+ const decoded = [
179
+ [],
180
+ [
181
+ new Date(0),
182
+ new Date("2022-06-29T13:43:00.123+00:00"),
183
+ ],
184
+ ];
185
+ const encoded = [
186
+ [],
187
+ [
188
+ "1970-01-01T00:00:00.000+00:00",
189
+ "2022-06-29T13:43:00.123+00:00",
190
+ ],
191
+ ];
192
+ const erroneous = [
193
+ undefined,
194
+ null,
195
+ 1,
196
+ "",
197
+ {},
198
+ [undefined],
199
+ [null],
200
+ [1],
201
+ [[]],
202
+ [{}],
203
+ ["1970-01-01T00:00:00.000"], // Missing timezone
204
+ ];
205
+ run(type, decoded, encoded, erroneous);
206
+ });
207
+ test('should encode/decode set', () => {
208
+ const type = SetType(StringType);
209
+ const compare = compareFor(type.key);
210
+ const decoded = [
211
+ new SortedSet([], compare),
212
+ new SortedSet(["abc", "def"], compare),
213
+ ];
214
+ const encoded = [
215
+ [],
216
+ ["abc", "def"],
217
+ ];
218
+ const erroneous = [
219
+ undefined,
220
+ null,
221
+ 1,
222
+ "",
223
+ {},
224
+ [undefined],
225
+ [null],
226
+ [1],
227
+ [[]],
228
+ [{}],
229
+ ];
230
+ run(type, decoded, encoded, erroneous);
231
+ });
232
+ test('should encode/decode dict', () => {
233
+ const type = DictType(StringType, DateTimeType);
234
+ const compare = compareFor(StringType);
235
+ const decoded = [
236
+ new SortedMap([], compare),
237
+ new SortedMap([
238
+ ["abc", new Date(0)],
239
+ ["def", new Date("2022-06-29T13:43:00.123+00:00")],
240
+ ], compare),
241
+ ];
242
+ const encoded = [
243
+ [],
244
+ [
245
+ { key: "abc", value: "1970-01-01T00:00:00.000+00:00" },
246
+ { key: "def", value: "2022-06-29T13:43:00.123+00:00" },
247
+ ],
248
+ ];
249
+ const erroneous = [
250
+ undefined,
251
+ null,
252
+ 1,
253
+ "",
254
+ {},
255
+ [undefined],
256
+ [null],
257
+ [1],
258
+ ["abc"],
259
+ [[]],
260
+ [{}],
261
+ [{ key: "abc" }],
262
+ [{ value: "1970-01-01T00:00:00.000+00:00" }],
263
+ [{ key: 1, value: "1970-01-01T00:00:00.000+00:00" }],
264
+ [{ key: "abc", value: "1970-01-01T00:00:00.000" }], // Missing timezone
265
+ [{ key: "abc", value: "1970-01-01T00:00:00.000+00:00", extra: "naughty" }],
266
+ ];
267
+ run(type, decoded, encoded, erroneous);
268
+ });
269
+ test('should encode/decode struct', () => {
270
+ const type = StructType({
271
+ boolean: BooleanType,
272
+ string: StringType,
273
+ date: DateTimeType,
274
+ });
275
+ const decoded = [
276
+ { boolean: true, string: "good", date: new Date(0) },
277
+ { boolean: false, string: "bad", date: new Date("2022-06-29T13:43:00.123+00:00") },
278
+ ];
279
+ const encoded = [
280
+ { boolean: true, string: "good", date: "1970-01-01T00:00:00.000+00:00" },
281
+ { boolean: false, string: "bad", date: "2022-06-29T13:43:00.123+00:00" },
282
+ ];
283
+ const erroneous = [
284
+ undefined,
285
+ null,
286
+ 1,
287
+ "",
288
+ {},
289
+ { boolean: true, string: "good" },
290
+ { boolean: true, string: "good", date: "1970-01-01T00:00:00.000" }, // Missing timezone
291
+ { boolean: true, string: "good", date: "1970-01-01T00:00:00.000+00:00", extra: "naughty" },
292
+ ];
293
+ run(type, decoded, encoded, erroneous);
294
+ });
295
+ test('should encode/decode variant', () => {
296
+ const type = VariantType({
297
+ none: NullType,
298
+ some: DateTimeType,
299
+ });
300
+ const decoded = [
301
+ none,
302
+ some(new Date("2022-06-29T13:43:00.123+00:00")),
303
+ ];
304
+ const encoded = [
305
+ { type: "none", value: null },
306
+ { type: "some", value: "2022-06-29T13:43:00.123+00:00" },
307
+ ];
308
+ const erroneous = [
309
+ undefined,
310
+ null,
311
+ 1,
312
+ "",
313
+ {},
314
+ { type: "none" },
315
+ { value: null },
316
+ { type: "nothing", value: null },
317
+ { type: "none", value: 1 },
318
+ ];
319
+ run(type, decoded, encoded, erroneous);
320
+ });
321
+ test('should encode/decode simple linked list', () => {
322
+ // LinkedList = Variant<nil: Null, cons: Struct<head: Integer, tail: LinkedList>>
323
+ const LinkedListType = RecursiveType((self) => VariantType({
324
+ nil: NullType,
325
+ cons: StructType({
326
+ head: IntegerType,
327
+ tail: self,
328
+ }),
329
+ }));
330
+ const decoded = [
331
+ variant("nil", null),
332
+ variant("cons", { head: 1n, tail: variant("nil", null) }),
333
+ variant("cons", {
334
+ head: 1n,
335
+ tail: variant("cons", {
336
+ head: 2n,
337
+ tail: variant("cons", {
338
+ head: 3n,
339
+ tail: variant("nil", null),
340
+ }),
341
+ }),
342
+ }),
343
+ ];
344
+ const encoded = [
345
+ { type: "nil", value: null },
346
+ { type: "cons", value: { head: "1", tail: { type: "nil", value: null } } },
347
+ {
348
+ type: "cons",
349
+ value: {
350
+ head: "1",
351
+ tail: {
352
+ type: "cons",
353
+ value: {
354
+ head: "2",
355
+ tail: {
356
+ type: "cons",
357
+ value: { head: "3", tail: { type: "nil", value: null } },
358
+ },
359
+ },
360
+ },
361
+ },
362
+ },
363
+ ];
364
+ const erroneous = [
365
+ undefined,
366
+ null,
367
+ 1,
368
+ "",
369
+ {},
370
+ { type: "cons" },
371
+ { type: "cons", value: {} },
372
+ { type: "cons", value: { head: "1" } },
373
+ { type: "cons", value: { head: "not an int", tail: { type: "nil", value: null } } },
374
+ ];
375
+ run(LinkedListType, decoded, encoded, erroneous);
376
+ });
377
+ test('should encode/decode binary tree', () => {
378
+ // Tree = Variant<leaf: Integer, node: Struct<left: Tree, right: Tree>>
379
+ const TreeType = RecursiveType((self) => VariantType({
380
+ leaf: IntegerType,
381
+ node: StructType({
382
+ left: self,
383
+ right: self,
384
+ }),
385
+ }));
386
+ const decoded = [
387
+ variant("leaf", 42n),
388
+ variant("node", {
389
+ left: variant("leaf", 1n),
390
+ right: variant("leaf", 2n),
391
+ }),
392
+ variant("node", {
393
+ left: variant("node", {
394
+ left: variant("leaf", 1n),
395
+ right: variant("leaf", 2n),
396
+ }),
397
+ right: variant("leaf", 3n),
398
+ }),
399
+ ];
400
+ const encoded = [
401
+ { type: "leaf", value: "42" },
402
+ {
403
+ type: "node",
404
+ value: {
405
+ left: { type: "leaf", value: "1" },
406
+ right: { type: "leaf", value: "2" },
407
+ },
408
+ },
409
+ {
410
+ type: "node",
411
+ value: {
412
+ left: {
413
+ type: "node",
414
+ value: {
415
+ left: { type: "leaf", value: "1" },
416
+ right: { type: "leaf", value: "2" },
417
+ },
418
+ },
419
+ right: { type: "leaf", value: "3" },
420
+ },
421
+ },
422
+ ];
423
+ const erroneous = [
424
+ undefined,
425
+ null,
426
+ 1,
427
+ "",
428
+ {},
429
+ { type: "leaf" },
430
+ { type: "leaf", value: "not an int" },
431
+ { type: "node", value: {} },
432
+ { type: "node", value: { left: { type: "leaf", value: "1" } } },
433
+ ];
434
+ run(TreeType, decoded, encoded, erroneous);
435
+ });
436
+ test('should encode/decode tree with array children', () => {
437
+ // Node = Struct<value: Integer, children: Array<Node>>
438
+ const NodeType = RecursiveType((self) => StructType({
439
+ value: IntegerType,
440
+ children: ArrayType(self),
441
+ }));
442
+ const decoded = [
443
+ { value: 1n, children: [] },
444
+ {
445
+ value: 1n,
446
+ children: [
447
+ { value: 2n, children: [] },
448
+ { value: 3n, children: [] },
449
+ ],
450
+ },
451
+ {
452
+ value: 1n,
453
+ children: [
454
+ {
455
+ value: 2n,
456
+ children: [
457
+ { value: 4n, children: [] },
458
+ { value: 5n, children: [] },
459
+ ],
460
+ },
461
+ { value: 3n, children: [] },
462
+ ],
463
+ },
464
+ ];
465
+ const encoded = [
466
+ { value: "1", children: [] },
467
+ {
468
+ value: "1",
469
+ children: [
470
+ { value: "2", children: [] },
471
+ { value: "3", children: [] },
472
+ ],
473
+ },
474
+ {
475
+ value: "1",
476
+ children: [
477
+ {
478
+ value: "2",
479
+ children: [
480
+ { value: "4", children: [] },
481
+ { value: "5", children: [] },
482
+ ],
483
+ },
484
+ { value: "3", children: [] },
485
+ ],
486
+ },
487
+ ];
488
+ const erroneous = [
489
+ undefined,
490
+ null,
491
+ 1,
492
+ "",
493
+ {},
494
+ { value: "1" },
495
+ { children: [] },
496
+ { value: "not an int", children: [] },
497
+ { value: "1", children: [{}] },
498
+ ];
499
+ run(NodeType, decoded, encoded, erroneous);
500
+ });
501
+ test('should encode/decode graph with string labels', () => {
502
+ // GraphNode = Struct<label: String, edges: Array<GraphNode>>
503
+ const GraphNodeType = RecursiveType((self) => StructType({
504
+ label: StringType,
505
+ edges: ArrayType(self),
506
+ }));
507
+ const decoded = [
508
+ { label: "A", edges: [] },
509
+ {
510
+ label: "A",
511
+ edges: [
512
+ { label: "B", edges: [] },
513
+ { label: "C", edges: [] },
514
+ ],
515
+ },
516
+ ];
517
+ const encoded = [
518
+ { label: "A", edges: [] },
519
+ {
520
+ label: "A",
521
+ edges: [
522
+ { label: "B", edges: [] },
523
+ { label: "C", edges: [] },
524
+ ],
525
+ },
526
+ ];
527
+ const erroneous = [
528
+ undefined,
529
+ null,
530
+ 1,
531
+ "",
532
+ {},
533
+ { label: "A" },
534
+ { edges: [] },
535
+ { label: 123, edges: [] },
536
+ { label: "A", edges: [{ label: "B" }] },
537
+ ];
538
+ run(GraphNodeType, decoded, encoded, erroneous);
539
+ });
540
+ test('should encode/decode nested variant structures', () => {
541
+ // Expr = Variant<num: Integer, add: Struct<left: Expr, right: Expr>, mul: Struct<left: Expr, right: Expr>>
542
+ const ExprType = RecursiveType((self) => VariantType({
543
+ num: IntegerType,
544
+ add: StructType({
545
+ left: self,
546
+ right: self,
547
+ }),
548
+ mul: StructType({
549
+ left: self,
550
+ right: self,
551
+ }),
552
+ }));
553
+ const decoded = [
554
+ variant("num", 42n),
555
+ variant("add", {
556
+ left: variant("num", 1n),
557
+ right: variant("num", 2n),
558
+ }),
559
+ variant("mul", {
560
+ left: variant("add", {
561
+ left: variant("num", 2n),
562
+ right: variant("num", 3n),
563
+ }),
564
+ right: variant("num", 4n),
565
+ }),
566
+ ];
567
+ const encoded = [
568
+ { type: "num", value: "42" },
569
+ {
570
+ type: "add",
571
+ value: {
572
+ left: { type: "num", value: "1" },
573
+ right: { type: "num", value: "2" },
574
+ },
575
+ },
576
+ {
577
+ type: "mul",
578
+ value: {
579
+ left: {
580
+ type: "add",
581
+ value: {
582
+ left: { type: "num", value: "2" },
583
+ right: { type: "num", value: "3" },
584
+ },
585
+ },
586
+ right: { type: "num", value: "4" },
587
+ },
588
+ },
589
+ ];
590
+ const erroneous = [
591
+ undefined,
592
+ null,
593
+ 1,
594
+ "",
595
+ {},
596
+ { type: "num" },
597
+ { type: "add", value: {} },
598
+ { type: "add", value: { left: { type: "num", value: "1" } } },
599
+ { type: "unknown", value: "1" },
600
+ ];
601
+ run(ExprType, decoded, encoded, erroneous);
602
+ });
603
+ test('should encode/decode blob', () => {
604
+ const type = BlobType;
605
+ const decoded = [
606
+ new Uint8Array([1, 3, 3, 7]),
607
+ new Uint8Array([]),
608
+ ];
609
+ const encoded = [
610
+ '0x01030307',
611
+ '0x',
612
+ ];
613
+ const erroneous = [
614
+ undefined,
615
+ null,
616
+ 1,
617
+ true,
618
+ "",
619
+ {},
620
+ [256],
621
+ ["0"],
622
+ "abc",
623
+ "0xgg",
624
+ "0x123"
625
+ ];
626
+ run(type, decoded, encoded, erroneous);
627
+ });
628
+ test('should encode/decode float vector', () => {
629
+ const type = VectorType(FloatType);
630
+ const decoded = [
631
+ new Float64Array([]),
632
+ new Float64Array([1.0, 2.5, -3.14]),
633
+ new Float64Array([NaN, Infinity, -Infinity]),
634
+ ];
635
+ const encoded = [
636
+ [],
637
+ [1.0, 2.5, -3.14],
638
+ ["NaN", "Infinity", "-Infinity"],
639
+ ];
640
+ run(type, decoded, encoded);
641
+ });
642
+ test('should encode/decode integer vector', () => {
643
+ const type = VectorType(IntegerType);
644
+ const decoded = [
645
+ new BigInt64Array([]),
646
+ new BigInt64Array([1n, -2n, 300n]),
647
+ new BigInt64Array([9223372036854775807n]),
648
+ ];
649
+ const encoded = [
650
+ [],
651
+ ["1", "-2", "300"],
652
+ ["9223372036854775807"],
653
+ ];
654
+ run(type, decoded, encoded);
655
+ });
656
+ test('should encode/decode boolean vector', () => {
657
+ const type = VectorType(BooleanType);
658
+ const decoded = [
659
+ new Uint8ClampedArray([]),
660
+ new Uint8ClampedArray([1, 0, 1]),
661
+ ];
662
+ const encoded = [
663
+ [],
664
+ [true, false, true],
665
+ ];
666
+ run(type, decoded, encoded);
667
+ });
668
+ test('should encode/decode float matrix', () => {
669
+ const type = MatrixType(FloatType);
670
+ const decoded = [
671
+ matrix(new Float64Array([]), 0, 0),
672
+ matrix(new Float64Array([1.0, 2.0, 3.0, 4.0]), 2, 2),
673
+ ];
674
+ const encoded = [
675
+ [],
676
+ [[1.0, 2.0], [3.0, 4.0]],
677
+ ];
678
+ run(type, decoded, encoded);
679
+ });
680
+ test('should encode/decode integer matrix', () => {
681
+ const type = MatrixType(IntegerType);
682
+ const decoded = [
683
+ matrix(new BigInt64Array([]), 0, 0),
684
+ matrix(new BigInt64Array([1n, 2n, 3n, 4n, 5n, 6n]), 2, 3),
685
+ ];
686
+ const encoded = [
687
+ [],
688
+ [["1", "2", "3"], ["4", "5", "6"]],
689
+ ];
690
+ run(type, decoded, encoded);
691
+ });
692
+ test('should format error messages correctly', () => {
693
+ // Test error for wrong type
694
+ const booleanDecoder = fromJSONFor(BooleanType);
695
+ try {
696
+ booleanDecoder("not a boolean");
697
+ assert.fail('Should have thrown');
698
+ }
699
+ catch (e) {
700
+ assert.equal(e.message, 'Error occurred because expected boolean, got "not a boolean" (line 1, col 1) while parsing value of type ".Boolean"');
701
+ }
702
+ // Test error with path for nested array
703
+ const arrayDecoder = fromJSONFor(ArrayType(IntegerType));
704
+ try {
705
+ arrayDecoder(["42", "not an integer"]);
706
+ assert.fail('Should have thrown');
707
+ }
708
+ catch (e) {
709
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an integer" at [1] (line 1, col 1) while parsing value of type ".Array .Integer"');
710
+ }
711
+ // Test error with path for struct field
712
+ const structDecoder = fromJSONFor(StructType({ name: StringType, age: IntegerType }));
713
+ try {
714
+ structDecoder({ name: "Alice", age: 42 });
715
+ assert.fail('Should have thrown');
716
+ }
717
+ catch (e) {
718
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got 42 at .age (line 1, col 1) while parsing value of type ".Struct [(name="name", type=.String), (name="age", type=.Integer)]"');
719
+ }
720
+ // Test error for missing struct field
721
+ try {
722
+ structDecoder({ name: "Alice" });
723
+ assert.fail('Should have thrown');
724
+ }
725
+ catch (e) {
726
+ assert.equal(e.message, 'Error occurred because missing field "age" in Struct, got {"name":"Alice"} (line 1, col 1) while parsing value of type ".Struct [(name="name", type=.String), (name="age", type=.Integer)]"');
727
+ }
728
+ // Test error for unexpected struct field
729
+ const simpleStructDecoder = fromJSONFor(StructType({ name: StringType }));
730
+ try {
731
+ simpleStructDecoder({ name: "Alice", extra: "unexpected" });
732
+ assert.fail('Should have thrown');
733
+ }
734
+ catch (e) {
735
+ assert.equal(e.message, 'Error occurred because unexpected field "extra" in Struct, got {"name":"Alice","extra":"unexpected"} (line 1, col 1) while parsing value of type ".Struct [(name="name", type=.String)]"');
736
+ }
737
+ // Test error for dict entry value
738
+ const dictDecoder = fromJSONFor(DictType(StringType, IntegerType));
739
+ try {
740
+ dictDecoder([{ key: "a", value: "not an integer" }]);
741
+ assert.fail('Should have thrown');
742
+ }
743
+ catch (e) {
744
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an integer" at [0].value (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Integer)"');
745
+ }
746
+ // Test error for variant case value
747
+ const variantDecoder = fromJSONFor(VariantType({ none: NullType, some: IntegerType }));
748
+ try {
749
+ variantDecoder({ type: "some", value: "not an integer" });
750
+ assert.fail('Should have thrown');
751
+ }
752
+ catch (e) {
753
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an integer" at .some (line 1, col 1) while parsing value of type ".Variant [(name="none", type=.Null), (name="some", type=.Integer)]"');
754
+ }
755
+ // Test error for unknown variant type
756
+ try {
757
+ variantDecoder({ type: "unknown", value: null });
758
+ assert.fail('Should have thrown');
759
+ }
760
+ catch (e) {
761
+ assert.equal(e.message, 'Error occurred because unknown variant type "unknown", got {"type":"unknown","value":null} (line 1, col 1) while parsing value of type ".Variant [(name="none", type=.Null), (name="some", type=.Integer)]"');
762
+ }
763
+ // Test error for deeply nested structure - array of structs with error in second element
764
+ const nestedDecoder = fromJSONFor(ArrayType(StructType({ id: IntegerType, name: StringType })));
765
+ try {
766
+ nestedDecoder([
767
+ { id: "1", name: "Alice" },
768
+ { id: "not an int", name: "Bob" }
769
+ ]);
770
+ assert.fail('Should have thrown');
771
+ }
772
+ catch (e) {
773
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an int" at [1].id (line 1, col 1) while parsing value of type ".Array .Struct [(name="id", type=.Integer), (name="name", type=.String)]"');
774
+ }
775
+ // Test error for dict with array values - error in array element
776
+ const dictArrayDecoder = fromJSONFor(DictType(StringType, ArrayType(IntegerType)));
777
+ try {
778
+ dictArrayDecoder([
779
+ { key: "nums", value: ["1", "2", "not an int"] }
780
+ ]);
781
+ assert.fail('Should have thrown');
782
+ }
783
+ catch (e) {
784
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an int" at [0].value[2] (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Array .Integer)"');
785
+ }
786
+ // Test error for struct containing variant with error
787
+ const structVariantDecoder = fromJSONFor(StructType({
788
+ result: VariantType({ ok: IntegerType, error: StringType })
789
+ }));
790
+ try {
791
+ structVariantDecoder({ result: { type: "ok", value: "not an int" } });
792
+ assert.fail('Should have thrown');
793
+ }
794
+ catch (e) {
795
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an int" at .result.ok (line 1, col 1) while parsing value of type ".Struct [(name="result", type=.Variant [(name="error", type=.String), (name="ok", type=.Integer)])]"');
796
+ }
797
+ // Test error for set element
798
+ const setDecoder = fromJSONFor(SetType(IntegerType));
799
+ try {
800
+ setDecoder(["1", "2", "not an int"]);
801
+ assert.fail('Should have thrown');
802
+ }
803
+ catch (e) {
804
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an int" at [2] (line 1, col 1) while parsing value of type ".Set .Integer"');
805
+ }
806
+ // Test error for dict with missing key field
807
+ try {
808
+ dictDecoder([{ value: "123" }]);
809
+ assert.fail('Should have thrown');
810
+ }
811
+ catch (e) {
812
+ assert.equal(e.message, 'Error occurred because expected object with key and value for Dict entry, got {"value":"123"} at [0] (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Integer)"');
813
+ }
814
+ // Test error for dict with extra field
815
+ try {
816
+ dictDecoder([{ key: "a", value: "123", extra: "bad" }]);
817
+ assert.fail('Should have thrown');
818
+ }
819
+ catch (e) {
820
+ assert.equal(e.message, 'Error occurred because unexpected field "extra" in Dict entry, got {"key":"a","value":"123","extra":"bad"} at [0] (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Integer)"');
821
+ }
822
+ // Test error for extremely complex nested structure:
823
+ // Dict<String, Array<Struct{ results: Array<Variant<ok: Struct{items: Set<Integer>}, error: String>> }>>
824
+ const veryComplexType = DictType(StringType, ArrayType(StructType({
825
+ results: ArrayType(VariantType({
826
+ ok: StructType({
827
+ items: SetType(IntegerType)
828
+ }),
829
+ error: StringType
830
+ }))
831
+ })));
832
+ const veryComplexDecoder = fromJSONFor(veryComplexType);
833
+ try {
834
+ veryComplexDecoder([
835
+ {
836
+ key: "batch1",
837
+ value: [
838
+ {
839
+ results: [
840
+ { type: "ok", value: { items: ["1", "2", "not an int"] } }
841
+ ]
842
+ }
843
+ ]
844
+ }
845
+ ]);
846
+ assert.fail('Should have thrown');
847
+ }
848
+ catch (e) {
849
+ assert.equal(e.message, 'Error occurred because expected string representing integer, got "not an int" at [0].value[0].results[0].ok.items[2] (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Array .Struct [(name="results", type=.Array .Variant [(name="error", type=.String), (name="ok", type=.Struct [(name="items", type=.Set .Integer)])])])"');
850
+ }
851
+ // Another complex error - missing field deep in structure
852
+ try {
853
+ veryComplexDecoder([
854
+ {
855
+ key: "batch1",
856
+ value: [
857
+ {
858
+ results: [
859
+ { type: "ok", value: { wrong: ["1"] } } // missing 'items' field
860
+ ]
861
+ }
862
+ ]
863
+ }
864
+ ]);
865
+ assert.fail('Should have thrown');
866
+ }
867
+ catch (e) {
868
+ assert.equal(e.message, 'Error occurred because unexpected field "wrong" in Struct, got {"wrong":["1"]} at [0].value[0].results[0].ok (line 1, col 1) while parsing value of type ".Dict (key=.String, value=.Array .Struct [(name="results", type=.Array .Variant [(name="error", type=.String), (name="ok", type=.Struct [(name="items", type=.Set .Integer)])])])"');
869
+ }
870
+ });
871
+ test('should encode/decode using Uint8Array with encodeJSONFor/decodeJSONFor', () => {
872
+ const encode = encodeJSONFor(IntegerType);
873
+ const decode = decodeJSONFor(IntegerType);
874
+ const value = 42n;
875
+ const encoded = encode(value);
876
+ const decoded = decode(encoded);
877
+ assert.strictEqual(decoded, value);
878
+ assert.ok(encoded instanceof Uint8Array);
879
+ });
880
+ test('should encode/decode complex types with encodeJSONFor/decodeJSONFor', () => {
881
+ const type = StructType({ name: StringType, age: IntegerType });
882
+ const encode = encodeJSONFor(type);
883
+ const decode = decodeJSONFor(type);
884
+ const value = { name: "Alice", age: 30n };
885
+ const encoded = encode(value);
886
+ const decoded = decode(encoded);
887
+ assert.deepEqual(decoded, value);
888
+ });
889
+ test('should throw when encoding Never type', () => {
890
+ const toJson = toJSONFor(NeverType);
891
+ assert.throws(() => toJson(null), /Cannot encode Never type to JSON/);
892
+ });
893
+ test('should throw when decoding Never type with fromJSONFor', () => {
894
+ const fromJson = fromJSONFor(NeverType);
895
+ assert.throws(() => fromJson(null), /Cannot decode Never type from JSON/);
896
+ });
897
+ test('should throw when decoding Never type with decodeJSONFor', () => {
898
+ const textEncoder = new TextEncoder();
899
+ const decode = decodeJSONFor(NeverType);
900
+ const encoded = textEncoder.encode('null');
901
+ assert.throws(() => decode(encoded), /Cannot decode Never type from JSON/);
902
+ });
903
+ test('should throw when encoding Function type', () => {
904
+ const funcType = FunctionType([], IntegerType);
905
+ assert.throws(() => toJSONFor(funcType), /Cannot encode Function type to JSON/);
906
+ });
907
+ test('should throw when decoding Function type with fromJSONFor', () => {
908
+ const funcType = FunctionType([], IntegerType);
909
+ assert.throws(() => fromJSONFor(funcType), /Cannot decode Function type from JSON/);
910
+ });
911
+ test('should throw when creating decoder for Function type with decodeJSONFor', () => {
912
+ const funcType = FunctionType([], IntegerType);
913
+ assert.throws(() => decodeJSONFor(funcType), /Cannot decode Function type from JSON/);
914
+ });
915
+ test('should throw when encoding AsyncFunction type', () => {
916
+ const funcType = AsyncFunctionType([], IntegerType);
917
+ assert.throws(() => toJSONFor(funcType), /Cannot encode AsyncFunction type to JSON/);
918
+ });
919
+ test('should throw when decoding AsyncFunction type with fromJSONFor', () => {
920
+ const funcType = AsyncFunctionType([], IntegerType);
921
+ assert.throws(() => fromJSONFor(funcType), /Cannot decode AsyncFunction type from JSON/);
922
+ });
923
+ test('should throw when creating decoder for AsyncFunction type with decodeJSONFor', () => {
924
+ const funcType = AsyncFunctionType([], IntegerType);
925
+ assert.throws(() => decodeJSONFor(funcType), /Cannot decode AsyncFunction type from JSON/);
926
+ });
927
+ test('should freeze decoded Date when frozen=true', () => {
928
+ const fromJson = fromJSONFor(DateTimeType, true);
929
+ const date = fromJson("2022-06-29T13:43:00.123+00:00");
930
+ assert.ok(Object.isFrozen(date));
931
+ });
932
+ test('should not freeze decoded Date when frozen=false', () => {
933
+ const fromJson = fromJSONFor(DateTimeType, false);
934
+ const date = fromJson("2022-06-29T13:43:00.123+00:00");
935
+ assert.ok(!Object.isFrozen(date));
936
+ });
937
+ test('should attempt to freeze decoded Blob when frozen=true', () => {
938
+ // Note: Uint8Array cannot actually be frozen in JavaScript
939
+ // This test verifies that the frozen code path is executed
940
+ const fromJson = fromJSONFor(BlobType, true);
941
+ // This will execute the Object.freeze code path, which will throw
942
+ // because Uint8Array cannot be frozen
943
+ assert.throws(() => fromJson("0x01020304"), /Cannot freeze array buffer views/);
944
+ });
945
+ test('should not freeze decoded Blob when frozen=false', () => {
946
+ const fromJson = fromJSONFor(BlobType, false);
947
+ const blob = fromJson("0x01020304");
948
+ assert.ok(!Object.isFrozen(blob));
949
+ });
950
+ test('should freeze decoded Array when frozen=true', () => {
951
+ const fromJson = fromJSONFor(ArrayType(IntegerType), true);
952
+ const arr = fromJson(["1", "2"]);
953
+ assert.ok(Object.isFrozen(arr));
954
+ });
955
+ test('should not freeze decoded Array when frozen=false', () => {
956
+ const fromJson = fromJSONFor(ArrayType(IntegerType), false);
957
+ const arr = fromJson(["1", "2"]);
958
+ assert.ok(!Object.isFrozen(arr));
959
+ });
960
+ test('should freeze decoded Set when frozen=true', () => {
961
+ const fromJson = fromJSONFor(SetType(StringType), true);
962
+ const set = fromJson(["a", "b"]);
963
+ assert.ok(Object.isFrozen(set));
964
+ });
965
+ test('should not freeze decoded Set when frozen=false', () => {
966
+ const fromJson = fromJSONFor(SetType(StringType), false);
967
+ const set = fromJson(["a", "b"]);
968
+ assert.ok(!Object.isFrozen(set));
969
+ });
970
+ test('should freeze decoded Dict when frozen=true', () => {
971
+ const fromJson = fromJSONFor(DictType(StringType, IntegerType), true);
972
+ const dict = fromJson([{ key: "a", value: "1" }]);
973
+ assert.ok(Object.isFrozen(dict));
974
+ });
975
+ test('should not freeze decoded Dict when frozen=false', () => {
976
+ const fromJson = fromJSONFor(DictType(StringType, IntegerType), false);
977
+ const dict = fromJson([{ key: "a", value: "1" }]);
978
+ assert.ok(!Object.isFrozen(dict));
979
+ });
980
+ test('should freeze decoded Struct when frozen=true', () => {
981
+ const fromJson = fromJSONFor(StructType({ x: IntegerType }), true);
982
+ const struct = fromJson({ x: "42" });
983
+ assert.ok(Object.isFrozen(struct));
984
+ });
985
+ test('should not freeze decoded Struct when frozen=false', () => {
986
+ const fromJson = fromJSONFor(StructType({ x: IntegerType }), false);
987
+ const struct = fromJson({ x: "42" });
988
+ assert.ok(!Object.isFrozen(struct));
989
+ });
990
+ test('should freeze decoded Variant when frozen=true', () => {
991
+ const fromJson = fromJSONFor(VariantType({ some: IntegerType }), true);
992
+ const v = fromJson({ type: "some", value: "42" });
993
+ assert.ok(Object.isFrozen(v));
994
+ });
995
+ test('should not freeze decoded Variant when frozen=false', () => {
996
+ const fromJson = fromJSONFor(VariantType({ some: IntegerType }), false);
997
+ const v = fromJson({ type: "some", value: "42" });
998
+ assert.ok(!Object.isFrozen(v));
999
+ });
1000
+ test('should handle JSON.parse syntax errors in decodeJSONFor', () => {
1001
+ const textEncoder = new TextEncoder();
1002
+ const decode = decodeJSONFor(IntegerType);
1003
+ // Invalid JSON
1004
+ const invalidJson = textEncoder.encode('{"broken": }');
1005
+ assert.throws(() => decode(invalidJson), /Error occurred because.*line \d+, col \d+/);
1006
+ });
1007
+ test('should track line and column numbers in JSON parse errors', () => {
1008
+ const textEncoder = new TextEncoder();
1009
+ const decode = decodeJSONFor(IntegerType);
1010
+ // Multi-line invalid JSON
1011
+ const invalidJson = textEncoder.encode('{\n"foo": \n}');
1012
+ assert.throws(() => decode(invalidJson), /line \d+, col \d+/);
1013
+ });
1014
+ test('should handle JSON parse errors without position info', () => {
1015
+ const textEncoder = new TextEncoder();
1016
+ const decode = decodeJSONFor(IntegerType);
1017
+ // Another invalid JSON case
1018
+ const invalidJson = textEncoder.encode('[');
1019
+ assert.throws(() => decode(invalidJson), /Error occurred because/);
1020
+ });
1021
+ test('should use decodeJSONFor with frozen parameter', () => {
1022
+ const encode = encodeJSONFor(ArrayType(IntegerType));
1023
+ const decode = decodeJSONFor(ArrayType(IntegerType), true);
1024
+ const value = [1n, 2n, 3n];
1025
+ const encoded = encode(value);
1026
+ const decoded = decode(encoded);
1027
+ assert.ok(Object.isFrozen(decoded));
1028
+ assert.deepEqual(decoded, value);
1029
+ });
1030
+ test('should handle non-SyntaxError exceptions in decodeJSONFor', () => {
1031
+ const textEncoder = new TextEncoder();
1032
+ const decode = decodeJSONFor(IntegerType);
1033
+ // Create a malformed but parseable JSON that will fail type checking
1034
+ const validJson = textEncoder.encode('"not an integer"');
1035
+ assert.throws(() => decode(validJson), /Error occurred because/);
1036
+ });
1037
+ test('should round-trip random types and values', { timeout: 60_000 }, async () => {
1038
+ const result = await fuzzerTest((type) => {
1039
+ const toJson = toJSONFor(type);
1040
+ const fromJson = fromJSONFor(type);
1041
+ const equal = equalFor(type);
1042
+ return async (value) => {
1043
+ // Encode and decode
1044
+ const encoded = toJson(value);
1045
+ const decoded = fromJson(encoded);
1046
+ // Check value equality
1047
+ if (!equal(decoded, value)) {
1048
+ throw new Error(`Round-trip failed: values not equal`);
1049
+ }
1050
+ };
1051
+ }, 100, // 100 random types
1052
+ 10, // 10 samples per type
1053
+ { includeRecursive: false } // TODO: recursive value generation needs work
1054
+ );
1055
+ assert.strictEqual(result, true, "Fuzz test failed");
1056
+ });
1057
+ test('should round-trip with Uint8Array encoding for random types', { timeout: 60_000 }, async () => {
1058
+ const result = await fuzzerTest((type) => {
1059
+ const encode = encodeJSONFor(type);
1060
+ const decode = decodeJSONFor(type);
1061
+ const equal = equalFor(type);
1062
+ return async (value) => {
1063
+ // Encode and decode
1064
+ const encoded = encode(value);
1065
+ const decoded = decode(encoded);
1066
+ // Verify it's a Uint8Array
1067
+ if (!(encoded instanceof Uint8Array)) {
1068
+ throw new Error(`Encoded value is not a Uint8Array`);
1069
+ }
1070
+ // Check value equality
1071
+ if (!equal(decoded, value)) {
1072
+ throw new Error(`Round-trip failed: values not equal`);
1073
+ }
1074
+ };
1075
+ }, 100, // 100 random types
1076
+ 10, // 10 samples per type
1077
+ { includeRecursive: false } // TODO: recursive value generation needs work
1078
+ );
1079
+ assert.strictEqual(result, true, "Fuzz test failed");
1080
+ });
1081
+ test('should re-throw non-JSONDecodeError exceptions in Array decoding', () => {
1082
+ // This tests the throw e; path at line 260 in the Array decoder
1083
+ const type = ArrayType(IntegerType);
1084
+ const fromJson = fromJSONFor(type);
1085
+ // Create a scenario where a non-JSONDecodeError might be thrown
1086
+ // by passing malformed data that causes a different type of error
1087
+ try {
1088
+ // Using a symbol which should cause a different error type
1089
+ fromJson([Symbol('test')]);
1090
+ assert.fail('Should have thrown');
1091
+ }
1092
+ catch (e) {
1093
+ // Should re-throw the error
1094
+ assert.ok(e);
1095
+ }
1096
+ });
1097
+ test('should re-throw non-JSONDecodeError exceptions in Set decoding', () => {
1098
+ const type = SetType(IntegerType);
1099
+ const fromJson = fromJSONFor(type);
1100
+ try {
1101
+ fromJson([Symbol('test')]);
1102
+ assert.fail('Should have thrown');
1103
+ }
1104
+ catch (e) {
1105
+ assert.ok(e);
1106
+ }
1107
+ });
1108
+ test('should re-throw non-JSONDecodeError exceptions in Dict key decoding', () => {
1109
+ const type = DictType(IntegerType, StringType);
1110
+ const fromJson = fromJSONFor(type);
1111
+ try {
1112
+ fromJson([{ key: Symbol('test'), value: "test" }]);
1113
+ assert.fail('Should have thrown');
1114
+ }
1115
+ catch (e) {
1116
+ assert.ok(e);
1117
+ }
1118
+ });
1119
+ test('should re-throw non-JSONDecodeError exceptions in Dict value decoding', () => {
1120
+ const type = DictType(StringType, IntegerType);
1121
+ const fromJson = fromJSONFor(type);
1122
+ try {
1123
+ fromJson([{ key: "test", value: Symbol('test') }]);
1124
+ assert.fail('Should have thrown');
1125
+ }
1126
+ catch (e) {
1127
+ assert.ok(e);
1128
+ }
1129
+ });
1130
+ test('should re-throw non-JSONDecodeError exceptions in Struct decoding', () => {
1131
+ const type = StructType({ x: IntegerType });
1132
+ const fromJson = fromJSONFor(type);
1133
+ try {
1134
+ fromJson({ x: Symbol('test') });
1135
+ assert.fail('Should have thrown');
1136
+ }
1137
+ catch (e) {
1138
+ assert.ok(e);
1139
+ }
1140
+ });
1141
+ test('should re-throw non-JSONDecodeError exceptions in Variant decoding', () => {
1142
+ const type = VariantType({ some: IntegerType });
1143
+ const fromJson = fromJSONFor(type);
1144
+ try {
1145
+ fromJson({ type: "some", value: Symbol('test') });
1146
+ assert.fail('Should have thrown');
1147
+ }
1148
+ catch (e) {
1149
+ assert.ok(e);
1150
+ }
1151
+ });
1152
+ test('should encode shared array references within RecursiveType', () => {
1153
+ // Create a type that can hold shared arrays
1154
+ const NodeType = RecursiveType((self) => StructType({
1155
+ value: IntegerType,
1156
+ children: ArrayType(self),
1157
+ metadata: ArrayType(StringType),
1158
+ }));
1159
+ // Create a shared array that appears in multiple places
1160
+ const sharedMetadata = ["tag1", "tag2"];
1161
+ const value = {
1162
+ value: 1n,
1163
+ children: [
1164
+ {
1165
+ value: 2n,
1166
+ children: [],
1167
+ metadata: sharedMetadata, // First reference
1168
+ },
1169
+ {
1170
+ value: 3n,
1171
+ children: [],
1172
+ metadata: sharedMetadata, // Second reference (same instance)
1173
+ },
1174
+ ],
1175
+ metadata: sharedMetadata, // Third reference (same instance)
1176
+ };
1177
+ const toJson = toJSONFor(NodeType);
1178
+ const fromJson = fromJSONFor(NodeType);
1179
+ const encoded = toJson(value);
1180
+ // Check that references appear in the encoding (first occurrence is real data, rest are refs)
1181
+ assert.deepEqual(encoded.children[0].metadata, ["tag1", "tag2"]);
1182
+ assert.deepEqual(encoded.children[1].metadata, { "$ref": "2#0/metadata" });
1183
+ assert.deepEqual(encoded.metadata, { "$ref": "1#children/0/metadata" });
1184
+ // Check that decoding preserves shared references
1185
+ const decoded = fromJson(encoded);
1186
+ assert.ok(decoded.metadata === decoded.children[0].metadata, "metadata should be same instance as children[0].metadata");
1187
+ assert.ok(decoded.metadata === decoded.children[1].metadata, "metadata should be same instance as children[1].metadata");
1188
+ // Check round-trip equality
1189
+ const equal = equalFor(NodeType);
1190
+ assert.ok(equal(decoded, value), "decoded value should equal original");
1191
+ });
1192
+ test('should encode shared set references within RecursiveType', () => {
1193
+ const NodeType = RecursiveType((self) => StructType({
1194
+ value: IntegerType,
1195
+ children: ArrayType(self),
1196
+ tags: SetType(StringType),
1197
+ }));
1198
+ const compare = compareFor(StringType);
1199
+ const sharedTags = new SortedSet(["a", "b", "c"], compare);
1200
+ const value = {
1201
+ value: 1n,
1202
+ children: [
1203
+ {
1204
+ value: 2n,
1205
+ children: [],
1206
+ tags: sharedTags, // First reference
1207
+ },
1208
+ ],
1209
+ tags: sharedTags, // Second reference (same instance)
1210
+ };
1211
+ const toJson = toJSONFor(NodeType);
1212
+ const fromJson = fromJSONFor(NodeType);
1213
+ const encoded = toJson(value);
1214
+ // Check encoding (first occurrence is real data, rest are refs)
1215
+ assert.deepEqual(encoded.children[0].tags, ["a", "b", "c"]);
1216
+ assert.deepEqual(encoded.tags, { "$ref": "1#children/0/tags" });
1217
+ // Check decoding preserves shared references
1218
+ const decoded = fromJson(encoded);
1219
+ assert.ok(decoded.tags === decoded.children[0].tags, "tags should be same instance");
1220
+ // Check round-trip equality
1221
+ const equal = equalFor(NodeType);
1222
+ assert.ok(equal(decoded, value), "decoded value should equal original");
1223
+ });
1224
+ test('should encode shared dict references within RecursiveType', () => {
1225
+ const NodeType = RecursiveType((self) => StructType({
1226
+ value: IntegerType,
1227
+ children: ArrayType(self),
1228
+ properties: DictType(StringType, IntegerType),
1229
+ }));
1230
+ const compare = compareFor(StringType);
1231
+ const sharedProps = new SortedMap([["x", 10n], ["y", 20n]], compare);
1232
+ const value = {
1233
+ value: 1n,
1234
+ children: [
1235
+ {
1236
+ value: 2n,
1237
+ children: [],
1238
+ properties: sharedProps,
1239
+ },
1240
+ {
1241
+ value: 3n,
1242
+ children: [],
1243
+ properties: sharedProps,
1244
+ },
1245
+ ],
1246
+ properties: sharedProps,
1247
+ };
1248
+ const toJson = toJSONFor(NodeType);
1249
+ const fromJson = fromJSONFor(NodeType);
1250
+ const encoded = toJson(value);
1251
+ // Check that references appear in the encoding (first occurrence is real data, rest are refs)
1252
+ assert.deepEqual(encoded.children[0].properties, [
1253
+ { key: "x", value: "10" },
1254
+ { key: "y", value: "20" },
1255
+ ]);
1256
+ assert.deepEqual(encoded.children[1].properties, { "$ref": "2#0/properties" });
1257
+ assert.deepEqual(encoded.properties, { "$ref": "1#children/0/properties" });
1258
+ // Check that decoding preserves shared references
1259
+ const decoded = fromJson(encoded);
1260
+ assert.ok(decoded.properties === decoded.children[0].properties, "properties should be same instance as children[0].properties");
1261
+ assert.ok(decoded.properties === decoded.children[1].properties, "properties should be same instance as children[1].properties");
1262
+ // Check round-trip equality
1263
+ const equal = equalFor(NodeType);
1264
+ assert.ok(equal(decoded, value), "decoded value should equal original");
1265
+ });
1266
+ test('should handle JSON Pointer escaping in field names', () => {
1267
+ // Create a struct with field names that need escaping
1268
+ const NodeType = RecursiveType((self) => StructType({
1269
+ "field/with/slashes": IntegerType,
1270
+ "field~with~tildes": IntegerType,
1271
+ "normal": ArrayType(IntegerType),
1272
+ children: ArrayType(self),
1273
+ }));
1274
+ const sharedArray = [1n, 2n, 3n];
1275
+ const value = {
1276
+ "field/with/slashes": 42n,
1277
+ "field~with~tildes": 99n,
1278
+ "normal": sharedArray,
1279
+ children: [
1280
+ {
1281
+ "field/with/slashes": 1n,
1282
+ "field~with~tildes": 2n,
1283
+ "normal": sharedArray, // Reference to same array
1284
+ children: [],
1285
+ },
1286
+ ],
1287
+ };
1288
+ const toJson = toJSONFor(NodeType);
1289
+ const encoded = toJson(value);
1290
+ // First array should be actual data
1291
+ assert.deepEqual(encoded.normal, ["1", "2", "3"]);
1292
+ // Second occurrence should be a reference with properly escaped path
1293
+ // Path should be 3#normal (go up 3 levels from children[0].normal to root.normal)
1294
+ assert.deepEqual(encoded.children[0].normal, { "$ref": "3#normal" });
1295
+ });
1296
+ });
1297
+ //# sourceMappingURL=json.spec.js.map