functionalscript 0.44.0 → 0.46.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 (571) hide show
  1. package/README.md +5 -3
  2. package/fjs/asn.1/module.f.mjs +8 -1
  3. package/fjs/asn.1/proof.f.d.mts +15 -0
  4. package/fjs/asn.1/proof.f.mjs +31 -3
  5. package/fjs/asserts/module.f.d.mts +14 -0
  6. package/fjs/asserts/module.f.mjs +20 -0
  7. package/fjs/asserts/proof.f.d.mts +3 -0
  8. package/fjs/asserts/proof.f.mjs +15 -1
  9. package/fjs/basen/base128/module.f.mjs +22 -5
  10. package/fjs/basen/base128/proof.f.d.mts +3 -1
  11. package/fjs/basen/base128/proof.f.mjs +3 -1
  12. package/fjs/basen/base64/module.f.mjs +7 -3
  13. package/fjs/basen/base64/proof.f.d.mts +3 -1
  14. package/fjs/basen/base64/proof.f.mjs +7 -4
  15. package/fjs/basen/cbase32/proof.f.d.mts +3 -1
  16. package/fjs/basen/cbase32/proof.f.mjs +3 -1
  17. package/fjs/bnf/data/module.f.d.mts +32 -6
  18. package/fjs/bnf/data/module.f.mjs +112 -7
  19. package/fjs/bnf/data/proof.f.d.mts +2 -0
  20. package/fjs/bnf/data/proof.f.mjs +74 -4
  21. package/fjs/bnf/data/types.d.ts +20 -2
  22. package/fjs/bnf/descent/module.f.d.mts +34 -5
  23. package/fjs/bnf/descent/module.f.mjs +176 -54
  24. package/fjs/bnf/descent/proof.f.d.mts +3 -0
  25. package/fjs/bnf/descent/proof.f.mjs +189 -27
  26. package/fjs/bnf/descent/types.d.ts +24 -18
  27. package/fjs/bnf/ll1/module.f.d.mts +74 -6
  28. package/fjs/bnf/ll1/module.f.mjs +297 -95
  29. package/fjs/bnf/ll1/proof.f.d.mts +17 -2
  30. package/fjs/bnf/ll1/proof.f.mjs +372 -137
  31. package/fjs/bnf/ll1/types.d.ts +25 -27
  32. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  33. package/fjs/bnf/matcher/module.f.mjs +81 -0
  34. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  35. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  36. package/fjs/bnf/matcher/types.d.ts +54 -0
  37. package/fjs/bnf/module.f.d.mts +15 -6
  38. package/fjs/bnf/module.f.mjs +52 -11
  39. package/fjs/bnf/proof.f.d.mts +2 -0
  40. package/fjs/bnf/proof.f.mjs +79 -3
  41. package/fjs/bnf/testlib.f.d.mts +31 -0
  42. package/fjs/bnf/testlib.f.mjs +80 -0
  43. package/fjs/bnf/token_symbol/module.f.d.mts +4 -3
  44. package/fjs/bnf/token_symbol/module.f.mjs +7 -6
  45. package/fjs/bnf/token_symbol/proof.f.mjs +5 -2
  46. package/fjs/bnf/token_symbol/types.d.ts +2 -2
  47. package/fjs/bnf/types.d.ts +10 -3
  48. package/fjs/cas/cli/module.f.d.mts +1 -1
  49. package/fjs/cas/cli/module.f.mjs +14 -20
  50. package/fjs/cas/cli/proof.f.d.mts +4 -4
  51. package/fjs/cas/cli/proof.f.mjs +47 -34
  52. package/fjs/cas/evo/module.f.d.mts +71 -31
  53. package/fjs/cas/evo/module.f.mjs +223 -138
  54. package/fjs/cas/evo/proof.f.d.mts +10 -1
  55. package/fjs/cas/evo/proof.f.mjs +311 -226
  56. package/fjs/cas/evo/types.d.ts +45 -9
  57. package/fjs/cas/module.f.d.mts +18 -32
  58. package/fjs/cas/module.f.mjs +164 -176
  59. package/fjs/cas/proof.f.d.mts +11 -8
  60. package/fjs/cas/proof.f.mjs +259 -147
  61. package/fjs/cas/types.d.ts +24 -10
  62. package/fjs/ci/common/module.f.d.mts +1 -1
  63. package/fjs/ci/common/module.f.mjs +1 -0
  64. package/fjs/ci/config/module.f.d.mts +3 -3
  65. package/fjs/ci/config/module.f.mjs +3 -3
  66. package/fjs/ci/module.f.d.mts +5 -5
  67. package/fjs/ci/module.f.mjs +8 -7
  68. package/fjs/ci/nix/module.f.d.mts +7 -5
  69. package/fjs/ci/nix/module.f.mjs +13 -12
  70. package/fjs/ci/nix/proof.f.d.mts +2 -0
  71. package/fjs/ci/nix/proof.f.mjs +4 -4
  72. package/fjs/ci/proof.f.d.mts +4 -2
  73. package/fjs/ci/proof.f.mjs +13 -8
  74. package/fjs/cli/module.f.d.mts +4 -6
  75. package/fjs/cli/module.f.mjs +4 -8
  76. package/fjs/cli/proof.f.d.mts +4 -2
  77. package/fjs/cli/proof.f.mjs +21 -18
  78. package/fjs/cli/types.d.ts +2 -3
  79. package/fjs/common/monoid/module.f.d.mts +70 -12
  80. package/fjs/common/monoid/module.f.mjs +177 -14
  81. package/fjs/common/monoid/proof.f.d.mts +12 -1
  82. package/fjs/common/monoid/proof.f.mjs +88 -4
  83. package/fjs/common/monoid/types.d.ts +23 -0
  84. package/fjs/crypto/hmac/module.f.mjs +2 -2
  85. package/fjs/crypto/secp/proof.f.d.mts +3 -1
  86. package/fjs/crypto/secp/proof.f.mjs +3 -1
  87. package/fjs/crypto/sha2/module.f.mjs +3 -1
  88. package/fjs/crypto/sha2/proof.f.d.mts +4 -1
  89. package/fjs/crypto/sha2/proof.f.mjs +27 -1
  90. package/fjs/crypto/sha2/types.d.ts +11 -0
  91. package/fjs/crypto/sign/module.f.mjs +2 -2
  92. package/fjs/crypto/vdf/module.f.d.mts +23 -4
  93. package/fjs/crypto/vdf/module.f.mjs +6 -4
  94. package/fjs/dev/module.f.d.mts +17 -5
  95. package/fjs/dev/module.f.mjs +60 -30
  96. package/fjs/dev/update/module.f.d.mts +11 -3
  97. package/fjs/dev/update/module.f.mjs +16 -11
  98. package/fjs/dev/update/proof.f.d.mts +4 -3
  99. package/fjs/dev/update/proof.f.mjs +11 -7
  100. package/fjs/djs/module.f.d.mts +13 -5
  101. package/fjs/djs/module.f.mjs +31 -16
  102. package/fjs/djs/parser/module.f.d.mts +16 -3
  103. package/fjs/djs/parser/module.f.mjs +135 -16
  104. package/fjs/djs/parser/proof.f.d.mts +8 -1
  105. package/fjs/djs/parser/proof.f.mjs +287 -13
  106. package/fjs/djs/parser/types.d.ts +7 -1
  107. package/fjs/djs/proof.f.d.mts +20 -1
  108. package/fjs/djs/proof.f.mjs +190 -12
  109. package/fjs/djs/serializer/module.f.d.mts +25 -8
  110. package/fjs/djs/serializer/module.f.mjs +66 -19
  111. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  112. package/fjs/djs/serializer/proof.f.mjs +23 -1
  113. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  114. package/fjs/djs/tokenizer/module.f.mjs +120 -73
  115. package/fjs/djs/tokenizer/proof.f.d.mts +3 -0
  116. package/fjs/djs/tokenizer/proof.f.mjs +86 -67
  117. package/fjs/djs/transpiler/module.f.d.mts +13 -19
  118. package/fjs/djs/transpiler/module.f.mjs +79 -72
  119. package/fjs/djs/transpiler/types.d.ts +29 -0
  120. package/fjs/djs/types.d.ts +7 -1
  121. package/fjs/effects/list/module.f.d.mts +23 -12
  122. package/fjs/effects/list/module.f.mjs +16 -12
  123. package/fjs/effects/list/types.d.ts +27 -7
  124. package/fjs/effects/memory/module.f.d.mts +6 -3
  125. package/fjs/effects/memory/module.f.mjs +7 -7
  126. package/fjs/effects/memory/proof.f.d.mts +4 -0
  127. package/fjs/effects/memory/proof.f.mjs +18 -9
  128. package/fjs/effects/memory/types.d.ts +4 -3
  129. package/fjs/effects/mock/module.f.d.mts +28 -4
  130. package/fjs/effects/mock/module.f.mjs +39 -5
  131. package/fjs/effects/mock/types.d.ts +10 -1
  132. package/fjs/effects/module.d.mts +12 -2
  133. package/fjs/effects/module.f.d.mts +469 -281
  134. package/fjs/effects/module.f.mjs +538 -299
  135. package/fjs/effects/module.mjs +11 -2
  136. package/fjs/effects/node/memory/module.d.mts +7 -2
  137. package/fjs/effects/node/memory/module.mjs +9 -5
  138. package/fjs/effects/node/memory/proof.d.mts +2 -0
  139. package/fjs/effects/node/memory/proof.mjs +12 -5
  140. package/fjs/effects/node/module.d.mts +8 -2
  141. package/fjs/effects/node/module.f.d.mts +183 -43
  142. package/fjs/effects/node/module.f.mjs +260 -62
  143. package/fjs/effects/node/module.mjs +61 -50
  144. package/fjs/effects/node/proof.f.d.mts +28 -2
  145. package/fjs/effects/node/proof.f.mjs +161 -42
  146. package/fjs/effects/node/types.d.ts +106 -18
  147. package/fjs/effects/node/virtual/module.f.d.mts +21 -4
  148. package/fjs/effects/node/virtual/module.f.mjs +113 -70
  149. package/fjs/effects/node/virtual/proof.f.d.mts +31 -2
  150. package/fjs/effects/node/virtual/proof.f.mjs +201 -8
  151. package/fjs/effects/proof.f.d.mts +69 -34
  152. package/fjs/effects/proof.f.mjs +413 -130
  153. package/fjs/effects/types.d.ts +161 -33
  154. package/fjs/emergent_testing/all.test.d.mts +8 -0
  155. package/fjs/emergent_testing/all.test.mjs +14 -0
  156. package/fjs/emergent_testing/module.f.d.mts +22 -10
  157. package/fjs/emergent_testing/module.f.mjs +119 -85
  158. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  159. package/fjs/emergent_testing/proof.f.mjs +169 -35
  160. package/fjs/emergent_testing/types.d.ts +22 -4
  161. package/fjs/fsc/bnf.f.d.mts +3 -0
  162. package/fjs/fsc/bnf.f.mjs +4 -1
  163. package/fjs/fsc/json.f.d.mts +3 -0
  164. package/fjs/fsc/json.f.mjs +4 -1
  165. package/fjs/fsc/module.f.d.mts +9 -0
  166. package/fjs/fsc/module.f.mjs +5 -3
  167. package/fjs/fsm/module.f.d.mts +14 -4
  168. package/fjs/fsm/module.f.mjs +54 -37
  169. package/fjs/fsm/proof.f.d.mts +5 -0
  170. package/fjs/fsm/proof.f.mjs +87 -115
  171. package/fjs/js/keywords/module.f.d.mts +52 -0
  172. package/fjs/js/keywords/module.f.mjs +72 -0
  173. package/fjs/{emergent_testing/scenarios/return-value.pass.d.ts → js/keywords/proof.f.d.mts} +1 -1
  174. package/fjs/js/keywords/proof.f.mjs +13 -0
  175. package/fjs/js/tokenizer/module.f.d.mts +30 -3
  176. package/fjs/js/tokenizer/module.f.mjs +161 -211
  177. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  178. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  179. package/fjs/js/tokenizer/types.d.ts +33 -24
  180. package/fjs/mcp/cas/module.f.d.mts +1 -6
  181. package/fjs/mcp/cas/module.f.mjs +55 -51
  182. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  183. package/fjs/mcp/cas/proof.f.mjs +174 -0
  184. package/fjs/mcp/evo/module.f.d.mts +19 -10
  185. package/fjs/mcp/evo/module.f.mjs +48 -27
  186. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  187. package/fjs/mcp/evo/proof.f.mjs +115 -31
  188. package/fjs/mcp/module.f.d.mts +39 -4
  189. package/fjs/mcp/module.f.mjs +14 -12
  190. package/fjs/mcp/proof.f.d.mts +13 -1
  191. package/fjs/mcp/proof.f.mjs +120 -61
  192. package/fjs/media/html/module.f.d.mts +12 -0
  193. package/fjs/media/html/module.f.mjs +7 -5
  194. package/fjs/media/html/proof.f.d.mts +3 -0
  195. package/fjs/media/html/proof.f.mjs +4 -1
  196. package/fjs/media/json/extended/module.f.d.mts +82 -0
  197. package/fjs/media/json/extended/module.f.mjs +153 -0
  198. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  199. package/fjs/media/json/extended/proof.f.mjs +127 -0
  200. package/fjs/media/json/extended/types.d.ts +23 -0
  201. package/fjs/media/json/module.f.d.mts +8 -2
  202. package/fjs/media/json/module.f.mjs +43 -41
  203. package/fjs/media/json/number/module.f.d.mts +59 -0
  204. package/fjs/media/json/number/module.f.mjs +136 -0
  205. package/fjs/media/json/number/proof.f.d.mts +24 -0
  206. package/fjs/media/json/number/proof.f.mjs +86 -0
  207. package/fjs/media/json/number/types.d.ts +28 -0
  208. package/fjs/media/json/parser/module.f.d.mts +25 -13
  209. package/fjs/media/json/parser/module.f.mjs +133 -72
  210. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  211. package/fjs/media/json/parser/proof.f.mjs +31 -1
  212. package/fjs/media/json/parser/types.d.ts +38 -14
  213. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  214. package/fjs/media/json/rtti/module.f.mjs +1 -1
  215. package/fjs/media/json/rtti/proof.f.d.mts +3 -0
  216. package/fjs/media/json/rtti/proof.f.mjs +12 -12
  217. package/fjs/media/json/schema/module.f.d.mts +61 -27
  218. package/fjs/media/json/schema/module.f.mjs +218 -63
  219. package/fjs/media/json/schema/proof.f.d.mts +41 -1
  220. package/fjs/media/json/schema/proof.f.mjs +220 -9
  221. package/fjs/media/json/serializer/module.f.d.mts +44 -0
  222. package/fjs/media/json/serializer/module.f.mjs +71 -9
  223. package/fjs/media/json/tokenizer/module.f.d.mts +8 -0
  224. package/fjs/media/json/tokenizer/module.f.mjs +31 -8
  225. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  226. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  227. package/fjs/media/json/types.d.ts +36 -10
  228. package/fjs/media/lock/module.f.d.mts +100 -0
  229. package/fjs/media/lock/module.f.mjs +125 -0
  230. package/fjs/media/lock/proof.f.d.mts +33 -0
  231. package/fjs/media/lock/proof.f.mjs +196 -0
  232. package/fjs/media/lock/types.d.ts +15 -0
  233. package/fjs/media/module.f.d.mts +6 -5
  234. package/fjs/media/module.f.mjs +8 -7
  235. package/fjs/media/nix/module.f.d.mts +13 -0
  236. package/fjs/media/nix/module.f.mjs +4 -2
  237. package/fjs/media/nix/proof.f.d.mts +3 -0
  238. package/fjs/media/nix/proof.f.mjs +4 -1
  239. package/fjs/media/note/module.f.d.mts +121 -0
  240. package/fjs/media/note/module.f.mjs +131 -0
  241. package/fjs/media/note/proof.f.d.mts +29 -0
  242. package/fjs/media/note/proof.f.mjs +150 -0
  243. package/fjs/media/note/types.d.ts +10 -0
  244. package/fjs/media/proof.f.d.mts +4 -1
  245. package/fjs/media/proof.f.mjs +40 -21
  246. package/fjs/media/revision/module.f.d.mts +83 -7
  247. package/fjs/media/revision/module.f.mjs +127 -23
  248. package/fjs/media/revision/proof.f.d.mts +14 -0
  249. package/fjs/media/revision/proof.f.mjs +93 -2
  250. package/fjs/media/revision/types.d.ts +34 -5
  251. package/fjs/media/type/module.f.d.mts +53 -18
  252. package/fjs/media/type/module.f.mjs +87 -97
  253. package/fjs/media/type/proof.f.d.mts +17 -0
  254. package/fjs/media/type/proof.f.mjs +73 -13
  255. package/fjs/module.d.mts +5 -0
  256. package/fjs/module.f.d.mts +8 -0
  257. package/fjs/module.f.mjs +33 -10
  258. package/fjs/module.mjs +6 -0
  259. package/fjs/nanvm/proof.f.mjs +3 -3
  260. package/fjs/nanvm/rust/module.f.mjs +1 -1
  261. package/fjs/nanvm/update/module.f.d.mts +4 -4
  262. package/fjs/nanvm/update/module.f.mjs +8 -9
  263. package/fjs/nanvm/update/proof.f.mjs +4 -3
  264. package/fjs/path/module.f.d.mts +8 -0
  265. package/fjs/path/module.f.mjs +4 -2
  266. package/fjs/proof.f.d.mts +7 -3
  267. package/fjs/proof.f.mjs +41 -12
  268. package/fjs/protocol/json_rpc/module.f.d.mts +3 -3
  269. package/fjs/protocol/json_rpc/module.f.mjs +10 -7
  270. package/fjs/protocol/json_rpc/proof.f.d.mts +6 -0
  271. package/fjs/protocol/json_rpc/proof.f.mjs +26 -5
  272. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  273. package/fjs/protocol/mcp/module.f.mjs +74 -58
  274. package/fjs/protocol/mcp/proof.f.d.mts +16 -3
  275. package/fjs/protocol/mcp/proof.f.mjs +224 -69
  276. package/fjs/protocol/mcp/stdio/module.f.d.mts +17 -11
  277. package/fjs/protocol/mcp/stdio/module.f.mjs +39 -33
  278. package/fjs/protocol/mcp/stdio/proof.f.d.mts +5 -3
  279. package/fjs/protocol/mcp/stdio/proof.f.mjs +46 -13
  280. package/fjs/protocol/mcp/stdio/types.d.ts +14 -0
  281. package/fjs/protocol/mcp/types.d.ts +17 -6
  282. package/fjs/sul/id/module.f.d.mts +4 -0
  283. package/fjs/sul/id/module.f.mjs +6 -6
  284. package/fjs/sul/level/hash/module.f.d.mts +4 -1
  285. package/fjs/sul/level/hash/module.f.mjs +6 -4
  286. package/fjs/sul/level/hash/proof.f.d.mts +4 -0
  287. package/fjs/sul/level/hash/proof.f.mjs +7 -4
  288. package/fjs/sul/level/literal/module.f.d.mts +4 -1
  289. package/fjs/sul/level/literal/module.f.mjs +4 -3
  290. package/fjs/sul/level/literal/proof.f.d.mts +3 -0
  291. package/fjs/sul/level/literal/proof.f.mjs +4 -1
  292. package/fjs/sul/module.f.d.mts +5 -3
  293. package/fjs/sul/module.f.mjs +23 -17
  294. package/fjs/sul/proof.f.d.mts +4 -0
  295. package/fjs/sul/proof.f.mjs +5 -2
  296. package/fjs/text/ascii/module.f.d.mts +26 -0
  297. package/fjs/text/ascii/module.f.mjs +49 -1
  298. package/fjs/text/ascii/proof.f.d.mts +10 -0
  299. package/fjs/text/ascii/proof.f.mjs +33 -1
  300. package/fjs/text/code_point/module.f.d.mts +29 -3
  301. package/fjs/text/code_point/module.f.mjs +32 -9
  302. package/fjs/text/code_point/proof.f.d.mts +2 -0
  303. package/fjs/text/code_point/proof.f.mjs +39 -0
  304. package/fjs/text/module.f.d.mts +4 -2
  305. package/fjs/text/module.f.mjs +4 -3
  306. package/fjs/text/proof.f.d.mts +3 -0
  307. package/fjs/text/proof.f.mjs +4 -1
  308. package/fjs/text/sgr/module.f.d.mts +6 -5
  309. package/fjs/text/sgr/module.f.mjs +8 -8
  310. package/fjs/text/sgr/proof.f.d.mts +3 -0
  311. package/fjs/text/sgr/proof.f.mjs +4 -1
  312. package/fjs/text/utf16/module.f.d.mts +5 -1
  313. package/fjs/text/utf16/module.f.mjs +38 -35
  314. package/fjs/text/utf16/proof.f.d.mts +3 -1
  315. package/fjs/text/utf16/proof.f.mjs +19 -2
  316. package/fjs/text/utf8/module.f.d.mts +9 -5
  317. package/fjs/text/utf8/module.f.mjs +20 -20
  318. package/fjs/types/array/module.f.d.mts +2 -1
  319. package/fjs/types/array/module.f.mjs +16 -4
  320. package/fjs/types/bigfloat/module.f.d.mts +21 -1
  321. package/fjs/types/bigfloat/module.f.mjs +33 -7
  322. package/fjs/types/bigfloat/proof.f.d.mts +1 -0
  323. package/fjs/types/bigfloat/proof.f.mjs +46 -0
  324. package/fjs/types/bigint/module.f.d.mts +4 -0
  325. package/fjs/types/bigint/module.f.mjs +4 -3
  326. package/fjs/types/bit_vec/module.f.d.mts +10 -16
  327. package/fjs/types/bit_vec/module.f.mjs +99 -95
  328. package/fjs/types/bit_vec/proof.f.d.mts +6 -0
  329. package/fjs/types/bit_vec/proof.f.mjs +31 -5
  330. package/fjs/types/btree/find/module.f.d.mts +5 -1
  331. package/fjs/types/btree/find/module.f.mjs +5 -5
  332. package/fjs/types/btree/find/proof.f.d.mts +5 -1
  333. package/fjs/types/btree/find/proof.f.mjs +5 -3
  334. package/fjs/types/btree/module.f.d.mts +3 -0
  335. package/fjs/types/btree/module.f.mjs +3 -2
  336. package/fjs/types/btree/proof.f.d.mts +5 -1
  337. package/fjs/types/btree/proof.f.mjs +5 -3
  338. package/fjs/types/btree/remove/module.f.d.mts +11 -0
  339. package/fjs/types/btree/remove/module.f.mjs +10 -10
  340. package/fjs/types/btree/remove/proof.f.d.mts +3 -0
  341. package/fjs/types/btree/remove/proof.f.mjs +4 -1
  342. package/fjs/types/btree/set/module.f.d.mts +9 -0
  343. package/fjs/types/btree/set/module.f.mjs +14 -17
  344. package/fjs/types/btree/set/proof.f.d.mts +3 -0
  345. package/fjs/types/btree/set/proof.f.mjs +16 -1
  346. package/fjs/types/btree/types/module.f.d.mts +2 -1
  347. package/fjs/types/btree/types/module.f.mjs +2 -1
  348. package/fjs/types/byte_set/module.f.d.mts +20 -4
  349. package/fjs/types/byte_set/module.f.mjs +18 -8
  350. package/fjs/types/byte_set/proof.f.d.mts +3 -1
  351. package/fjs/types/byte_set/proof.f.mjs +10 -8
  352. package/fjs/types/function/compare/module.f.d.mts +3 -2
  353. package/fjs/types/function/compare/module.f.mjs +13 -5
  354. package/fjs/types/function/module.f.d.mts +8 -1
  355. package/fjs/types/function/module.f.mjs +8 -1
  356. package/fjs/types/function/operator/module.f.d.mts +2 -1
  357. package/fjs/types/function/operator/module.f.mjs +2 -2
  358. package/fjs/types/list/module.f.d.mts +10 -3
  359. package/fjs/types/list/module.f.mjs +6 -4
  360. package/fjs/types/list/proof.f.d.mts +4 -1
  361. package/fjs/types/list/proof.f.mjs +4 -2
  362. package/fjs/types/nibble_set/module.f.d.mts +2 -1
  363. package/fjs/types/nibble_set/module.f.mjs +2 -2
  364. package/fjs/types/nominal/module.f.d.mts +2 -1
  365. package/fjs/types/nominal/module.f.mjs +2 -1
  366. package/fjs/types/nullable/module.f.d.mts +26 -6
  367. package/fjs/types/nullable/module.f.mjs +25 -6
  368. package/fjs/types/nullable/proof.f.d.mts +4 -0
  369. package/fjs/types/nullable/proof.f.mjs +15 -0
  370. package/fjs/types/number/module.f.d.mts +4 -0
  371. package/fjs/types/number/module.f.mjs +4 -3
  372. package/fjs/types/object/module.f.d.mts +26 -4
  373. package/fjs/types/object/module.f.mjs +26 -7
  374. package/fjs/types/object/proof.f.d.mts +5 -2
  375. package/fjs/types/object/proof.f.mjs +6 -3
  376. package/fjs/types/object/structurally_same/module.f.d.mts +39 -0
  377. package/fjs/types/object/structurally_same/module.f.mjs +59 -0
  378. package/fjs/types/object/structurally_same/proof.f.d.mts +6 -0
  379. package/fjs/types/object/structurally_same/proof.f.mjs +73 -0
  380. package/fjs/types/ordered_map/module.f.d.mts +5 -0
  381. package/fjs/types/ordered_map/module.f.mjs +5 -4
  382. package/fjs/types/ordered_map/proof.f.d.mts +3 -0
  383. package/fjs/types/ordered_map/proof.f.mjs +4 -1
  384. package/fjs/types/patricia_trie/module.f.d.mts +2 -1
  385. package/fjs/types/patricia_trie/module.f.mjs +27 -12
  386. package/fjs/types/patricia_trie/proof.f.d.mts +3 -0
  387. package/fjs/types/patricia_trie/proof.f.mjs +4 -1
  388. package/fjs/types/prime_field/module.f.d.mts +3 -1
  389. package/fjs/types/prime_field/module.f.mjs +3 -2
  390. package/fjs/types/range/module.f.d.mts +2 -1
  391. package/fjs/types/range/module.f.mjs +2 -2
  392. package/fjs/types/range_map/module.f.d.mts +6 -0
  393. package/fjs/types/range_map/module.f.mjs +6 -9
  394. package/fjs/types/range_map/proof.f.d.mts +5 -1
  395. package/fjs/types/range_map/proof.f.mjs +5 -3
  396. package/fjs/types/range_set/module.f.d.mts +5 -0
  397. package/fjs/types/range_set/module.f.mjs +1 -0
  398. package/fjs/types/range_set/proof.f.d.mts +3 -0
  399. package/fjs/types/range_set/proof.f.mjs +4 -1
  400. package/fjs/types/result/module.d.mts +8 -0
  401. package/fjs/types/result/module.f.d.mts +37 -7
  402. package/fjs/types/result/module.f.mjs +38 -8
  403. package/fjs/types/result/module.mjs +9 -1
  404. package/fjs/types/result/proof.f.d.mts +5 -0
  405. package/fjs/types/result/proof.f.mjs +22 -2
  406. package/fjs/types/rtti/common/module.f.d.mts +44 -14
  407. package/fjs/types/rtti/common/module.f.mjs +42 -36
  408. package/fjs/types/rtti/common/proof.f.d.mts +4 -0
  409. package/fjs/types/rtti/common/proof.f.mjs +10 -7
  410. package/fjs/types/rtti/data/module.f.d.mts +134 -0
  411. package/fjs/types/rtti/data/module.f.mjs +1053 -0
  412. package/fjs/types/rtti/data/proof.f.d.mts +76 -0
  413. package/fjs/types/rtti/data/proof.f.mjs +589 -0
  414. package/fjs/types/rtti/data/types.d.ts +83 -0
  415. package/fjs/types/rtti/module.f.d.mts +12 -5
  416. package/fjs/types/rtti/module.f.mjs +7 -5
  417. package/fjs/types/rtti/parse/module.f.d.mts +48 -0
  418. package/fjs/types/rtti/parse/module.f.mjs +45 -34
  419. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  420. package/fjs/types/rtti/parse/proof.f.mjs +51 -52
  421. package/fjs/types/rtti/proof.f.d.mts +3 -1
  422. package/fjs/types/rtti/proof.f.mjs +6 -2
  423. package/fjs/types/rtti/ts/module.f.d.mts +68 -9
  424. package/fjs/types/rtti/ts/module.f.mjs +258 -30
  425. package/fjs/types/rtti/ts/proof.f.d.mts +44 -0
  426. package/fjs/types/rtti/ts/proof.f.mjs +152 -4
  427. package/fjs/types/rtti/ts/types.d.ts +25 -1
  428. package/fjs/types/rtti/types.d.ts +40 -0
  429. package/fjs/types/sorted_list/module.f.d.mts +4 -1
  430. package/fjs/types/sorted_list/module.f.mjs +21 -12
  431. package/fjs/types/sorted_list/proof.f.d.mts +3 -1
  432. package/fjs/types/sorted_list/proof.f.mjs +3 -1
  433. package/fjs/types/sorted_set/module.f.d.mts +49 -1
  434. package/fjs/types/sorted_set/module.f.mjs +26 -2
  435. package/fjs/types/sorted_set/proof.f.d.mts +4 -1
  436. package/fjs/types/sorted_set/proof.f.mjs +19 -2
  437. package/fjs/types/string/module.f.d.mts +4 -0
  438. package/fjs/types/string/module.f.mjs +4 -3
  439. package/fjs/types/string_set/module.f.d.mts +3 -1
  440. package/fjs/types/string_set/module.f.mjs +3 -2
  441. package/fjs/types/ts/module.f.d.mts +2 -0
  442. package/fjs/types/ts/module.f.mjs +3 -3
  443. package/fjs/types/ts/proof.f.d.mts +1 -0
  444. package/fjs/types/ts/proof.f.mjs +5 -0
  445. package/fjs/types/ts/types.d.ts +6 -1
  446. package/fjs/types/uint8array/module.f.d.mts +13 -2
  447. package/fjs/types/uint8array/module.f.mjs +20 -15
  448. package/fjs/website/module.f.d.mts +5 -2
  449. package/fjs/website/module.f.mjs +6 -8
  450. package/fjs/website/proof.f.mjs +2 -1
  451. package/package.json +3 -3
  452. package/fjs/asn.1/types.js +0 -6
  453. package/fjs/asserts/types.js +0 -6
  454. package/fjs/basen/types.js +0 -6
  455. package/fjs/bnf/data/types.js +0 -6
  456. package/fjs/bnf/descent/types.js +0 -6
  457. package/fjs/bnf/ll1/types.js +0 -6
  458. package/fjs/bnf/token_symbol/types.js +0 -6
  459. package/fjs/bnf/types.js +0 -6
  460. package/fjs/cas/evo/types.js +0 -7
  461. package/fjs/cas/types.js +0 -6
  462. package/fjs/ci/common/types.js +0 -1
  463. package/fjs/ci/nix/types.js +0 -6
  464. package/fjs/ci/types.js +0 -6
  465. package/fjs/cli/types.js +0 -6
  466. package/fjs/common/monoid/types.js +0 -6
  467. package/fjs/crypto/pow/types.js +0 -6
  468. package/fjs/crypto/secp/types.js +0 -6
  469. package/fjs/crypto/sha2/types.js +0 -6
  470. package/fjs/crypto/sign/types.js +0 -6
  471. package/fjs/crypto/vdf/types.js +0 -6
  472. package/fjs/dev/package_json/module.f.d.mts +0 -32
  473. package/fjs/dev/package_json/module.f.mjs +0 -37
  474. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  475. package/fjs/dev/package_json/proof.f.mjs +0 -32
  476. package/fjs/dev/types.js +0 -6
  477. package/fjs/djs/ast/types.js +0 -8
  478. package/fjs/djs/parser/types.js +0 -7
  479. package/fjs/djs/tokenizer/types.js +0 -7
  480. package/fjs/djs/types.js +0 -7
  481. package/fjs/effects/eff/module.f.d.mts +0 -10
  482. package/fjs/effects/eff/module.f.mjs +0 -68
  483. package/fjs/effects/eff/proof.f.d.mts +0 -12
  484. package/fjs/effects/eff/proof.f.mjs +0 -66
  485. package/fjs/effects/eff/types.d.ts +0 -71
  486. package/fjs/effects/eff/types.js +0 -6
  487. package/fjs/effects/list/types.js +0 -6
  488. package/fjs/effects/memory/types.js +0 -6
  489. package/fjs/effects/mock/types.js +0 -6
  490. package/fjs/effects/node/types.js +0 -6
  491. package/fjs/effects/node/virtual/types.js +0 -7
  492. package/fjs/effects/types.js +0 -6
  493. package/fjs/emergent_testing/all.test.d.ts +0 -1
  494. package/fjs/emergent_testing/all.test.js +0 -5
  495. package/fjs/emergent_testing/scenarios/all.d.ts +0 -1
  496. package/fjs/emergent_testing/scenarios/all.js +0 -1
  497. package/fjs/emergent_testing/scenarios/async-subtests.fail.d.ts +0 -6
  498. package/fjs/emergent_testing/scenarios/async-subtests.fail.js +0 -9
  499. package/fjs/emergent_testing/scenarios/async-subtests.pass.d.ts +0 -6
  500. package/fjs/emergent_testing/scenarios/async-subtests.pass.js +0 -9
  501. package/fjs/emergent_testing/scenarios/async.fail.d.ts +0 -3
  502. package/fjs/emergent_testing/scenarios/async.fail.js +0 -6
  503. package/fjs/emergent_testing/scenarios/async.pass.d.ts +0 -3
  504. package/fjs/emergent_testing/scenarios/async.pass.js +0 -5
  505. package/fjs/emergent_testing/scenarios/fail.fail.d.ts +0 -3
  506. package/fjs/emergent_testing/scenarios/fail.fail.js +0 -3
  507. package/fjs/emergent_testing/scenarios/return-value.pass.js +0 -4
  508. package/fjs/emergent_testing/scenarios/thenable.pass.d.ts +0 -5
  509. package/fjs/emergent_testing/scenarios/thenable.pass.js +0 -11
  510. package/fjs/emergent_testing/scenarios/thenable2.pass.d.ts +0 -5
  511. package/fjs/emergent_testing/scenarios/thenable2.pass.js +0 -3
  512. package/fjs/emergent_testing/scenarios/throw.pass.d.ts +0 -5
  513. package/fjs/emergent_testing/scenarios/throw.pass.js +0 -3
  514. package/fjs/emergent_testing/types.js +0 -6
  515. package/fjs/js/tokenizer/types.js +0 -6
  516. package/fjs/media/html/types.js +0 -6
  517. package/fjs/media/json/parser/types.js +0 -6
  518. package/fjs/media/json/tokenizer/types.js +0 -6
  519. package/fjs/media/json/types.js +0 -13
  520. package/fjs/media/nix/types.js +0 -6
  521. package/fjs/media/revision/types.js +0 -8
  522. package/fjs/media/type/types.js +0 -6
  523. package/fjs/media/types.js +0 -7
  524. package/fjs/nanvm/types.js +0 -11
  525. package/fjs/protocol/json_rpc/types.js +0 -8
  526. package/fjs/protocol/mcp/types.js +0 -8
  527. package/fjs/sul/id/types.js +0 -6
  528. package/fjs/sul/level/hash/types.js +0 -6
  529. package/fjs/sul/level/literal/types.js +0 -6
  530. package/fjs/sul/types.js +0 -6
  531. package/fjs/text/sgr/types.js +0 -6
  532. package/fjs/text/types.js +0 -6
  533. package/fjs/text/utf16/types.js +0 -6
  534. package/fjs/text/utf8/types.js +0 -6
  535. package/fjs/types/array/types.js +0 -6
  536. package/fjs/types/bigfloat/types.js +0 -6
  537. package/fjs/types/bigint/types.js +0 -6
  538. package/fjs/types/bit_vec/types.js +0 -6
  539. package/fjs/types/btree/find/types.js +0 -6
  540. package/fjs/types/btree/types/types.js +0 -6
  541. package/fjs/types/byte_set/types.js +0 -6
  542. package/fjs/types/function/compare/types.js +0 -6
  543. package/fjs/types/function/operator/types.js +0 -6
  544. package/fjs/types/function/types.js +0 -6
  545. package/fjs/types/list/types.js +0 -6
  546. package/fjs/types/nibble_set/types.js +0 -6
  547. package/fjs/types/nominal/types.js +0 -6
  548. package/fjs/types/nullable/types.js +0 -6
  549. package/fjs/types/object/types.js +0 -8
  550. package/fjs/types/option/types.js +0 -6
  551. package/fjs/types/ordered_map/types.js +0 -6
  552. package/fjs/types/patricia_trie/types.js +0 -6
  553. package/fjs/types/phantom/types.js +0 -11
  554. package/fjs/types/prime_field/types.js +0 -6
  555. package/fjs/types/range/types.js +0 -6
  556. package/fjs/types/range_map/types.js +0 -6
  557. package/fjs/types/result/types.js +0 -6
  558. package/fjs/types/rtti/common/types.js +0 -1
  559. package/fjs/types/rtti/parse/types.js +0 -1
  560. package/fjs/types/rtti/ts/types.js +0 -1
  561. package/fjs/types/rtti/types.js +0 -1
  562. package/fjs/types/rtti/validate/module.f.d.mts +0 -6
  563. package/fjs/types/rtti/validate/module.f.mjs +0 -169
  564. package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
  565. package/fjs/types/rtti/validate/proof.f.mjs +0 -437
  566. package/fjs/types/rtti/validate/types.d.ts +0 -6
  567. package/fjs/types/rtti/validate/types.js +0 -1
  568. package/fjs/types/sorted_list/types.js +0 -6
  569. package/fjs/types/sorted_set/types.js +0 -6
  570. package/fjs/types/string_set/types.js +0 -6
  571. package/fjs/types/ts/types.js +0 -8
@@ -0,0 +1,1053 @@
1
+ /**
2
+ * The serializable RTTI data form and the {@link toData} conversion from the
3
+ * thunk form.
4
+ *
5
+ * A schema denotes a set of values. The data form partitions that set into
6
+ * six disjoint kinds — unit values (`null`, `undefined`, `false`, `true`),
7
+ * numbers, strings, bigints, arrays and objects — so that all schema algebra
8
+ * (union normalization, coverage collapse, {@link equal}, {@link subset},
9
+ * canonical ordering via {@link cmp}) reduces to kind-wise set operations.
10
+ * {@link toData} is the single bridge from the thunk form; {@link validate}
11
+ * is the data-driven counterpart of `../validate`. The form serializes as
12
+ * DJS — plain JSON when no `bigint` literals are involved. See `./README.md`
13
+ * for the design rationale and serialization notes, and `./types.ts` for the
14
+ * type-level API.
15
+ *
16
+ * @module
17
+ *
18
+ * @import { Const, ConstObject, Type } from '../types.ts'
19
+ * @import { Primitive, Unknown } from '../ts/types.ts'
20
+ * @import { ResultE } from '../common/types.ts'
21
+ * @import { StringMap } from '../../object/types.ts'
22
+ * @import { ArraySet, Data, KindSet, Node, ObjectSet, RuleSet, UnionSet } from './types.ts'
23
+ */
24
+
25
+ import { assert, assertNotNullish } from '../../../asserts/module.f.mjs'
26
+ import { at, definedEntries, definedValues } from '../../object/module.f.mjs'
27
+ import { ok } from '../../result/module.f.mjs'
28
+ import { eachEntry, isArray, verror } from '../common/module.f.mjs'
29
+
30
+ /**
31
+ * The unit kind's enumeration: bit `1 << i` of a {@link UnionSet}'s `unit`
32
+ * bitset stands for `unitList[i]`.
33
+ */
34
+ export const unitList = /** @type {const} */ (['null', 'undefined', 'false', 'true'])
35
+
36
+ /**
37
+ * The `unit` bit of one unit value.
38
+ *
39
+ * @type {(v: null | undefined | boolean) => number}
40
+ */
41
+ export const unitBit = v =>
42
+ v === null ? 1 :
43
+ v === undefined ? 2 :
44
+ v ? 8 : 4
45
+
46
+ const allUnits = unitBit(null) | unitBit(undefined) | unitBit(false) | unitBit(true)
47
+
48
+ const booleanUnits = unitBit(false) | unitBit(true)
49
+
50
+ /**
51
+ * The data form of the empty set — rtti `never`.
52
+ *
53
+ * @type {UnionSet}
54
+ */
55
+ export const never = {}
56
+
57
+ /**
58
+ * The data form of the set of all values — rtti `unknown`.
59
+ *
60
+ * @type {UnionSet}
61
+ */
62
+ export const unknown = {
63
+ unit: allUnits,
64
+ number: true,
65
+ string: true,
66
+ bigint: true,
67
+ array: true,
68
+ object: true,
69
+ }
70
+
71
+ /**
72
+ * The union with the given unit bits removed — set subtraction restricted to
73
+ * the unit kind. Dropping `undefined` from an optional property's value set is
74
+ * the motivating case.
75
+ *
76
+ * The other five kinds are carried through untouched rather than copied field
77
+ * by field. That is not only shorter: a caller that enumerates `UnionSet`'s
78
+ * members to rebuild the node silently **drops** any kind added to the type
79
+ * later, whereas spreading cannot. Removing every unit bit removes the `unit`
80
+ * key entirely, since an empty kind is an absent property here, never a zero.
81
+ *
82
+ * @type {(bits: number) => (n: UnionSet) => UnionSet}
83
+ */
84
+ export const withoutUnits = bits => n => {
85
+ const unit = (n.unit ?? 0) & ~bits
86
+ const { unit: _, ...rest } = n
87
+ return unit === 0 ? rest : { unit, ...rest }
88
+ }
89
+
90
+ // ── canonical order ──────────────────────────────────────────────────────────
91
+
92
+ /** @type {(a: string, b: string) => number} */
93
+ const cmpString = (a, b) => a < b ? -1 : a > b ? 1 : 0
94
+
95
+ /**
96
+ * Total order on number literals matching the SameValue equality the
97
+ * validators use: ascending, `-0` before `0`, `NaN` last.
98
+ *
99
+ * @type {(a: number, b: number) => number}
100
+ */
101
+ const cmpNumber = (a, b) => {
102
+ if (Object.is(a, b)) { return 0 }
103
+ if (Number.isNaN(a)) { return 1 }
104
+ if (Number.isNaN(b)) { return -1 }
105
+ if (a < b) { return -1 }
106
+ if (a > b) { return 1 }
107
+ // `a` and `b` are `+0` and `-0`, in one of the two orders
108
+ return Object.is(a, -0) ? -1 : 1
109
+ }
110
+
111
+ /** @type {(a: bigint, b: bigint) => number} */
112
+ const cmpBigint = (a, b) => a < b ? -1 : a > b ? 1 : 0
113
+
114
+ /**
115
+ * Lexicographic order, shorter lists first.
116
+ *
117
+ * @template T
118
+ * @param {(a: T, b: T) => number} cmpItem
119
+ * @returns {(a: readonly T[], b: readonly T[]) => number}
120
+ */
121
+ const cmpList = cmpItem => (a, b) => {
122
+ const d = a.length - b.length
123
+ if (d !== 0) { return d }
124
+ for (let i = 0; i < a.length; ++i) {
125
+ const c = cmpItem(a[i], b[i])
126
+ if (c !== 0) { return c }
127
+ }
128
+ return 0
129
+ }
130
+
131
+ /**
132
+ * Order on one kind component: absent, then member lists, then `true`.
133
+ *
134
+ * @template T
135
+ * @param {(a: T, b: T) => number} cmpItem
136
+ * @returns {(a: KindSet<T> | undefined, b: KindSet<T> | undefined) => number}
137
+ */
138
+ const cmpKind = cmpItem => (a, b) => {
139
+ if (a === undefined) { return b === undefined ? 0 : -1 }
140
+ if (b === undefined) { return 1 }
141
+ if (a === true) { return b === true ? 0 : 1 }
142
+ if (b === true) { return -1 }
143
+ return cmpList(cmpItem)(a, b)
144
+ }
145
+
146
+ /**
147
+ * @template T
148
+ * @param {(a: T, b: T) => number} cmpValue
149
+ * @returns {(a: readonly [string, T], b: readonly [string, T]) => number}
150
+ */
151
+ const cmpEntry = cmpValue => ([ak, av], [bk, bv]) => {
152
+ const c = cmpString(ak, bk)
153
+ return c !== 0 ? c : cmpValue(av, bv)
154
+ }
155
+
156
+ /** @type {(a: Node | undefined, b: Node | undefined) => number} */
157
+ const cmpRest = (a, b) => {
158
+ if (a === undefined) { return b === undefined ? 0 : -1 }
159
+ if (b === undefined) { return 1 }
160
+ return cmpNode(a, b)
161
+ }
162
+
163
+ /** @type {(a: ArraySet, b: ArraySet) => number} */
164
+ const cmpArraySet = (a, b) => {
165
+ const c = cmpList(cmpNode)(a.prefix, b.prefix)
166
+ return c !== 0 ? c : cmpRest(a.rest, b.rest)
167
+ }
168
+
169
+ /** @type {(a: ObjectSet, b: ObjectSet) => number} */
170
+ const cmpObjectSet = (a, b) => {
171
+ const c = cmpList(cmpEntry(cmpNode))(definedEntries(a.props), definedEntries(b.props))
172
+ return c !== 0 ? c : cmpRest(a.rest, b.rest)
173
+ }
174
+
175
+ /** @type {(a: UnionSet, b: UnionSet) => number} */
176
+ const cmpUnion = (a, b) => {
177
+ const c0 = (a.unit ?? 0) - (b.unit ?? 0)
178
+ if (c0 !== 0) { return c0 }
179
+ const c1 = cmpKind(cmpNumber)(a.number, b.number)
180
+ if (c1 !== 0) { return c1 }
181
+ const c2 = cmpKind(cmpString)(a.string, b.string)
182
+ if (c2 !== 0) { return c2 }
183
+ const c3 = cmpKind(cmpBigint)(a.bigint, b.bigint)
184
+ if (c3 !== 0) { return c3 }
185
+ const c4 = cmpKind(cmpArraySet)(a.array, b.array)
186
+ return c4 !== 0 ? c4 : cmpKind(cmpObjectSet)(a.object, b.object)
187
+ }
188
+
189
+ /**
190
+ * Inline unions sort before references; references sort by rule name.
191
+ *
192
+ * @type {(a: Node, b: Node) => number}
193
+ */
194
+ const cmpNode = (a, b) => {
195
+ if (typeof a === 'string') {
196
+ return typeof b === 'string' ? cmpString(a, b) : 1
197
+ }
198
+ return typeof b === 'string' ? -1 : cmpUnion(a, b)
199
+ }
200
+
201
+ /**
202
+ * Total order over the data form: negative, zero or positive, with zero
203
+ * exactly on structural identity. {@link toData} output is canonical, so two
204
+ * conversions of equivalent thunk schemas compare equal — this is what makes
205
+ * the data form comparable and sortable.
206
+ *
207
+ * @type {(a: Data) => (b: Data) => number}
208
+ */
209
+ export const cmp = ([aRules, aNode]) => ([bRules, bNode]) => {
210
+ const c = cmpNode(aNode, bNode)
211
+ return c !== 0
212
+ ? c
213
+ : cmpList(cmpEntry(cmpUnion))(definedEntries(aRules), definedEntries(bRules))
214
+ }
215
+
216
+ /**
217
+ * Structural equality of canonical forms: `equal(toData(a))(toData(b))`
218
+ * holds exactly when `a` and `b` normalize to the same data — e.g.
219
+ * `or(a, b)` and `or(b, a)` are equal. Recursive definitions compare by
220
+ * their rule names, which are derived from the defining functions' names.
221
+ *
222
+ * @type {(a: Data) => (b: Data) => boolean}
223
+ */
224
+ export const equal = a => b => cmp(a)(b) === 0
225
+
226
+ // ── kind-wise union ──────────────────────────────────────────────────────────
227
+
228
+ /**
229
+ * Merges two sorted, deduplicated lists into one.
230
+ *
231
+ * @template T
232
+ * @param {(a: T, b: T) => number} cmpItem
233
+ * @returns {(a: readonly T[], b: readonly T[]) => readonly T[]}
234
+ */
235
+ const mergeSorted = cmpItem => (a, b) => {
236
+ if (a.length === 0) { return b }
237
+ if (b.length === 0) { return a }
238
+ const c = cmpItem(a[0], b[0])
239
+ if (c < 0) { return [a[0], ...mergeSorted(cmpItem)(a.slice(1), b)] }
240
+ if (c > 0) { return [b[0], ...mergeSorted(cmpItem)(a, b.slice(1))] }
241
+ return [a[0], ...mergeSorted(cmpItem)(a.slice(1), b.slice(1))]
242
+ }
243
+
244
+ /**
245
+ * Union of one kind component: absent = empty, `true` = the whole kind, so
246
+ * `or(42, number)` collapses to all numbers here with no special-case rule.
247
+ *
248
+ * @template T
249
+ * @param {(a: T, b: T) => number} cmpItem
250
+ * @returns {(a: KindSet<T> | undefined, b: KindSet<T> | undefined) => KindSet<T> | undefined}
251
+ */
252
+ const mergeKind = cmpItem => (a, b) => {
253
+ if (a === undefined) { return b }
254
+ if (b === undefined) { return a }
255
+ if (a === true || b === true) { return true }
256
+ return mergeSorted(cmpItem)(a, b)
257
+ }
258
+
259
+ /**
260
+ * Kind-wise union of two union sets.
261
+ *
262
+ * @type {(a: UnionSet, b: UnionSet) => UnionSet}
263
+ */
264
+ const merge = (a, b) => {
265
+ const unit = (a.unit ?? 0) | (b.unit ?? 0)
266
+ const number = mergeKind(cmpNumber)(a.number, b.number)
267
+ const string = mergeKind(cmpString)(a.string, b.string)
268
+ const bigint = mergeKind(cmpBigint)(a.bigint, b.bigint)
269
+ const array = mergeKind(cmpArraySet)(a.array, b.array)
270
+ const object = mergeKind(cmpObjectSet)(a.object, b.object)
271
+ return {
272
+ ...(unit === 0 ? {} : { unit }),
273
+ ...(number === undefined ? {} : { number }),
274
+ ...(string === undefined ? {} : { string }),
275
+ ...(bigint === undefined ? {} : { bigint }),
276
+ ...(array === undefined ? {} : { array }),
277
+ ...(object === undefined ? {} : { object }),
278
+ }
279
+ }
280
+
281
+ // ── canonical constructors ───────────────────────────────────────────────────
282
+
283
+ /** @type {(n: Node) => boolean} */
284
+ const isNever = n => typeof n !== 'string' && cmpUnion(n, never) === 0
285
+
286
+ /** @type {(n: Node) => boolean} */
287
+ const isTop = n => typeof n !== 'string' && cmpUnion(n, unknown) === 0
288
+
289
+ /**
290
+ * Canonical array-kind singleton. A syntactically empty position makes the
291
+ * whole pattern empty; an empty `rest` is the same set as no `rest`; an
292
+ * unconstrained `rest` with no prefix is every array.
293
+ *
294
+ * @type {(prefix: readonly Node[], rest: Node | undefined) => UnionSet}
295
+ */
296
+ const arraySet = (prefix, rest) => {
297
+ if (prefix.some(isNever)) { return never }
298
+ const r = rest !== undefined && isNever(rest) ? undefined : rest
299
+ return prefix.length === 0 && r !== undefined && isTop(r)
300
+ ? { array: true }
301
+ : { array: [r === undefined ? { prefix } : { prefix, rest: r }] }
302
+ }
303
+
304
+ /**
305
+ * Canonical object-kind singleton. An unconstrained key is dropped (reading
306
+ * it yields some value regardless); a syntactically empty key set makes the
307
+ * whole pattern empty; an unconstrained `rest` is the same set as no `rest`;
308
+ * with nothing left, the pattern is every object.
309
+ *
310
+ * @type {(props: readonly (readonly [string, Node])[], rest: Node | undefined) => UnionSet}
311
+ */
312
+ const objectSet = (props, rest) => {
313
+ const constrained = props.filter(([, v]) => !isTop(v))
314
+ if (constrained.some(([, v]) => isNever(v))) { return never }
315
+ const r = rest !== undefined && isTop(rest) ? undefined : rest
316
+ if (constrained.length === 0 && r === undefined) { return { object: true } }
317
+ /** @type {StringMap<Node>} */
318
+ const sorted = Object.fromEntries(constrained.toSorted(([ak], [bk]) => cmpString(ak, bk)))
319
+ return { object: [r === undefined ? { props: sorted } : { props: sorted, rest: r }] }
320
+ }
321
+
322
+ // ── subset ───────────────────────────────────────────────────────────────────
323
+
324
+ /** The rule sets of the two compared schemas: `[left, right]`. */
325
+ /** @typedef {readonly [RuleSet, RuleSet]} _Ctx */
326
+
327
+ /**
328
+ * Node pairs assumed included while they are being checked — the standard
329
+ * coinductive treatment of reference cycles, keyed by {@link _Keyed} node
330
+ * identities.
331
+ */
332
+ /** @typedef {StringMap<StringMap<true>>} _Assumed */
333
+
334
+ /**
335
+ * A node with a canonical identity for the coinductive memo: `r:<name>` a
336
+ * rule reference, `u:<name>` a rule's object read-set (its rest plus
337
+ * `undefined`), `t` the top set. A node synthesized from inline data has no
338
+ * identity (`undefined`) — recursion through it descends its finite tree,
339
+ * so every cycle still crosses identified pairs and the memo closes it.
340
+ */
341
+ /** @typedef {readonly [Node, string | undefined]} _Keyed */
342
+
343
+ /**
344
+ * Own-property lookups only: a `RuleSet`/`props` map is a plain object, so
345
+ * reading through the prototype chain would return `Object.prototype`
346
+ * members (`toString`, `constructor`, …) for names that are not defined.
347
+ *
348
+ * @type {(rules: RuleSet) => (n: Node) => UnionSet}
349
+ */
350
+ const resolve = rules => n => typeof n === 'string' ? assertNotNullish(at(n)(rules)) : n
351
+
352
+ /** @type {<T>(a: T, b: T) => boolean} */
353
+ const strictEqual = (a, b) => a === b
354
+
355
+ /**
356
+ * Inclusion of one kind component: every member of `a` below some member of
357
+ * `b`; absent = empty, `true` = the whole kind.
358
+ *
359
+ * @template T
360
+ * @param {(a: T, b: T) => boolean} le
361
+ * @returns {(a: KindSet<T> | undefined, b: KindSet<T> | undefined) => boolean}
362
+ */
363
+ const kindSubset = le => (a, b) => {
364
+ if (a === undefined) { return true }
365
+ if (b === true) { return true }
366
+ if (a === true || b === undefined) { return false }
367
+ return a.every(x => b.some(y => le(x, y)))
368
+ }
369
+
370
+ /** @type {(ctx: _Ctx) => (assumed: _Assumed) => (p: ArraySet, q: ArraySet) => boolean} */
371
+ const arraySetSubset = ctx => assumed => (p, q) => {
372
+ const le = nodeSubset(ctx)(assumed)
373
+ const pn = p.prefix.length
374
+ const qn = q.prefix.length
375
+ // `p` admits lengths `{pn}` or `[pn, ∞)`; they must fit `q`'s admitted lengths
376
+ const lengthOk = q.rest !== undefined
377
+ ? qn <= pn
378
+ : p.rest === undefined && qn === pn
379
+ if (!lengthOk) { return false }
380
+ /** @type {(i: number) => Node} */
381
+ const qAt = i => i < qn ? q.prefix[i] : assertNotNullish(q.rest)
382
+ return p.prefix.every((el, i) => le(el, qAt(i)))
383
+ && (p.rest === undefined || le(p.rest, assertNotNullish(q.rest)))
384
+ }
385
+
386
+ /** @type {(n: Node) => _Keyed} */
387
+ const keyed = n => [n, typeof n === 'string' ? `r:${n}` : undefined]
388
+
389
+ /**
390
+ * The set of values *read* at key `k` from objects of the pattern: the
391
+ * declared set, else — since the key may also be absent, reading
392
+ * `undefined` — the `rest` set plus `undefined`, else anything. A read-set
393
+ * synthesized from a referenced rest keeps that rule's identity (`u:`), so
394
+ * the coinductive memo closes cycles through it.
395
+ *
396
+ * @type {(rules: RuleSet) => (pattern: ObjectSet) => (k: string) => _Keyed}
397
+ */
398
+ const objectReadSet = rules => pattern => k => {
399
+ const n = at(k)(pattern.props)
400
+ if (n !== null) { return keyed(n) }
401
+ const { rest } = pattern
402
+ return rest === undefined
403
+ ? [unknown, 't']
404
+ : [
405
+ merge(resolve(rules)(rest), { unit: unitBit(undefined) }),
406
+ typeof rest === 'string' ? `u:${rest}` : undefined,
407
+ ]
408
+ }
409
+
410
+ /** @type {(list: readonly string[]) => readonly string[]} */
411
+ const dedup = list => list.filter((n, i) => list.indexOf(n) === i)
412
+
413
+ /** @type {(ctx: _Ctx) => (assumed: _Assumed) => (p: ObjectSet, q: ObjectSet) => boolean} */
414
+ const objectSetSubset = ctx => assumed => (p, q) => {
415
+ const le = keyedSubset(ctx)(assumed)
416
+ const keys = dedup([
417
+ ...definedEntries(p.props).map(([k]) => k),
418
+ ...definedEntries(q.props).map(([k]) => k),
419
+ ])
420
+ return keys.every(k => le(objectReadSet(ctx[0])(p)(k), objectReadSet(ctx[1])(q)(k)))
421
+ // values at the keys declared by neither side
422
+ && (q.rest === undefined || nodeSubset(ctx)(assumed)(p.rest ?? unknown, q.rest))
423
+ }
424
+
425
+ /** @type {(ctx: _Ctx) => (assumed: _Assumed) => (a: UnionSet, b: UnionSet) => boolean} */
426
+ const unionSubset = ctx => assumed => (a, b) =>
427
+ ((a.unit ?? 0) & ~(b.unit ?? 0)) === 0
428
+ && kindSubset(Object.is)(a.number, b.number)
429
+ && kindSubset(strictEqual)(a.string, b.string)
430
+ && kindSubset(strictEqual)(a.bigint, b.bigint)
431
+ && kindSubset(arraySetSubset(ctx)(assumed))(a.array, b.array)
432
+ && kindSubset(objectSetSubset(ctx)(assumed))(a.object, b.object)
433
+
434
+ /** @type {(ctx: _Ctx) => (assumed: _Assumed) => (a: _Keyed, b: _Keyed) => boolean} */
435
+ const keyedSubset = ctx => assumed => ([a, aKey], [b, bKey]) => {
436
+ let assumed1 = assumed
437
+ if (aKey !== undefined && bKey !== undefined) {
438
+ const inner = assumed[aKey]
439
+ if (inner !== undefined && inner[bKey] === true) { return true }
440
+ assumed1 = { ...assumed, [aKey]: inner === undefined ? { [bKey]: true } : { ...inner, [bKey]: true } }
441
+ }
442
+ return unionSubset(ctx)(assumed1)(resolve(ctx[0])(a), resolve(ctx[1])(b))
443
+ }
444
+
445
+ /** @type {(ctx: _Ctx) => (assumed: _Assumed) => (a: Node, b: Node) => boolean} */
446
+ const nodeSubset = ctx => assumed => (a, b) =>
447
+ keyedSubset(ctx)(assumed)(keyed(a), keyed(b))
448
+
449
+ /**
450
+ * Sound subset test: `true` means every value of `a` is a value of `b`.
451
+ * Kind-wise on unions, pattern-wise on arrays/objects, coinductive on
452
+ * reference cycles. Incomplete in the known-hard corners of semantic
453
+ * subtyping (see `./README.md`): it may answer `false` for an inclusion
454
+ * that only holds by distributing a union across positions, or one whose
455
+ * left side is a non-syntactic empty set — never `true` for a non-inclusion.
456
+ *
457
+ * @type {(a: Data) => (b: Data) => boolean}
458
+ */
459
+ export const subset = ([aRules, aNode]) => ([bRules, bNode]) =>
460
+ nodeSubset([aRules, bRules])({})(aNode, bNode)
461
+
462
+ // ── coverage collapse ────────────────────────────────────────────────────────
463
+
464
+ /**
465
+ * Drops every pattern subsumed by another pattern of the same list.
466
+ *
467
+ * Two *distinct* patterns can subsume each other: references to
468
+ * α-equivalent rules under different names spell the same value set two
469
+ * ways (e.g. `list` and a differently-named `X = readonly X[]`). A
470
+ * mutually-subsumed pattern is therefore dropped only in favor of an
471
+ * earlier one, keeping exactly the first member of each such group —
472
+ * dropping on subsumption alone would drop the whole group.
473
+ *
474
+ * @template T
475
+ * @param {(p: T, q: T) => boolean} le
476
+ * @returns {(list: readonly T[]) => readonly T[]}
477
+ */
478
+ const dropSubsumed = le => list =>
479
+ list.filter((p, i) => !list.some((q, j) => j !== i && le(p, q) && (j < i || !le(q, p))))
480
+
481
+ /**
482
+ * @template T
483
+ * @param {(a: T, b: T) => number} cmpItem
484
+ * @returns {(list: readonly T[]) => readonly T[]}
485
+ */
486
+ const sortedDedup = cmpItem => list => {
487
+ const sorted = list.toSorted(cmpItem)
488
+ return sorted.filter((x, i) => i === 0 || cmpItem(sorted[i - 1], x) !== 0)
489
+ }
490
+
491
+ /** @typedef {(n: Node) => Node} _NodeMap */
492
+
493
+ /** @type {(f: _NodeMap) => (p: ArraySet) => ArraySet} */
494
+ const mapArraySet = f => p => ({
495
+ prefix: p.prefix.map(f),
496
+ ...(p.rest === undefined ? {} : { rest: f(p.rest) }),
497
+ })
498
+
499
+ /** @type {(f: _NodeMap) => (p: ObjectSet) => ObjectSet} */
500
+ const mapObjectSet = f => p => ({
501
+ props: Object.fromEntries(definedEntries(p.props).map(
502
+ ([k, v]) => /** @type {const} */ ([k, f(v)]))),
503
+ ...(p.rest === undefined ? {} : { rest: f(p.rest) }),
504
+ })
505
+
506
+ /**
507
+ * Rewrites a union's nested nodes with `f`, keeping each pattern list
508
+ * sorted and deduplicated.
509
+ *
510
+ * @type {(f: _NodeMap) => (u: UnionSet) => UnionSet}
511
+ */
512
+ const mapChildren = f => u => ({
513
+ ...u,
514
+ ...(u.array === undefined || u.array === true ? {} : {
515
+ array: sortedDedup(cmpArraySet)(u.array.map(mapArraySet(f))),
516
+ }),
517
+ ...(u.object === undefined || u.object === true ? {} : {
518
+ object: sortedDedup(cmpObjectSet)(u.object.map(mapObjectSet(f))),
519
+ }),
520
+ })
521
+
522
+ /**
523
+ * Bottom-up node rewrite: children first, then `post` on every node.
524
+ *
525
+ * @type {(post: _NodeMap) => _NodeMap}
526
+ */
527
+ const rewriteNodes = post => {
528
+ /** @type {_NodeMap} */
529
+ const go = n => post(typeof n === 'string' ? n : mapChildren(go)(n))
530
+ return go
531
+ }
532
+
533
+ /**
534
+ * Drops every subsumed array/object pattern of one union.
535
+ *
536
+ * @type {(ctx: _Ctx) => (u: UnionSet) => UnionSet}
537
+ */
538
+ const dropSubsumedUnion = ctx => u => ({
539
+ ...u,
540
+ ...(u.array === undefined || u.array === true ? {} : {
541
+ array: dropSubsumed(arraySetSubset(ctx)({}))(u.array),
542
+ }),
543
+ ...(u.object === undefined || u.object === true ? {} : {
544
+ object: dropSubsumed(objectSetSubset(ctx)({}))(u.object),
545
+ }),
546
+ })
547
+
548
+ /** @type {(ctx: _Ctx) => _NodeMap} */
549
+ const collapsePost = ctx => n => typeof n === 'string' ? n : dropSubsumedUnion(ctx)(n)
550
+
551
+ /**
552
+ * The coverage collapse: every subsumed array/object pattern dropped,
553
+ * recursively through inline nodes.
554
+ *
555
+ * @type {(ctx: _Ctx) => _NodeMap}
556
+ */
557
+ const collapseNode = ctx => rewriteNodes(collapsePost(ctx))
558
+
559
+ /** @type {(ctx: _Ctx) => (u: UnionSet) => UnionSet} */
560
+ const collapseUnion = ctx => u => dropSubsumedUnion(ctx)(mapChildren(collapseNode(ctx))(u))
561
+
562
+ /**
563
+ * Replaces a union structurally equal to a rule's body with a reference to
564
+ * that rule (the alphabetically first one on a tie). This is what keeps
565
+ * `or` idempotent over recursive schemas — the union of a rule with itself
566
+ * is the rule's body, which reads back as the rule — and it also collapses
567
+ * re-stated fixpoints such as `array(list)` for `list = readonly list[]`.
568
+ *
569
+ * @type {(rules: RuleSet) => _NodeMap}
570
+ */
571
+ const internPost = rules => n => {
572
+ if (typeof n === 'string') { return n }
573
+ for (const [name, body] of definedEntries(rules)) {
574
+ if (cmpUnion(n, body) === 0) { return name }
575
+ }
576
+ return n
577
+ }
578
+
579
+ /** @type {(rules: RuleSet) => _NodeMap} */
580
+ const internNode = rules => rewriteNodes(internPost(rules))
581
+
582
+ /** @type {(rules: RuleSet) => (u: UnionSet) => UnionSet} */
583
+ const internUnion = rules => mapChildren(internNode(rules))
584
+
585
+ /**
586
+ * The final canonical step: interns rule-body copies in the entry and in
587
+ * every rule body's nested positions. `rules` must already be sorted so a
588
+ * tie between equal rule bodies resolves deterministically.
589
+ *
590
+ * @type {(rules: RuleSet, entry: Node) => Data}
591
+ */
592
+ const internData = (rules, entry) => [
593
+ Object.fromEntries(definedEntries(rules).map(
594
+ ([n, u]) => /** @type {const} */ ([n, internUnion(rules)(u)]))),
595
+ internNode(rules)(entry),
596
+ ]
597
+
598
+ // ── toData ───────────────────────────────────────────────────────────────────
599
+
600
+ /** A thunk — the only schema form that can close a reference cycle. */
601
+ /** @typedef {Exclude<Type, Const>} _Thunk */
602
+
603
+ /** A schema tracked by identity: a thunk or a const container. */
604
+ /** @typedef {Exclude<Type, Primitive>} _Key */
605
+
606
+ /**
607
+ * The conversion state, threaded functionally:
608
+ *
609
+ * - `converting` — thunks whose union is being computed (the recursion stack).
610
+ * - `names` — rule names, assigned to a thunk the moment something needs to
611
+ * reference it (a cycle, or a deferred merge).
612
+ * - `done` — computed unions, memoized by identity.
613
+ * - `deferred` — union merges `target ∪= source` that could not run eagerly
614
+ * because `source`'s union was not final; resolved by {@link fixpoint}.
615
+ *
616
+ * @typedef {{
617
+ * readonly converting: readonly _Thunk[]
618
+ * readonly names: readonly (readonly [_Thunk, string])[]
619
+ * readonly done: readonly (readonly [_Key, UnionSet])[]
620
+ * readonly deferred: readonly (readonly [_Thunk, _Thunk])[]
621
+ * }} _State
622
+ */
623
+
624
+ /**
625
+ * The first value associated with `key` by identity.
626
+ *
627
+ * @template K
628
+ * @template T
629
+ * @param {readonly (readonly [K, T])[]} list
630
+ * @param {unknown} key
631
+ * @returns {T | undefined}
632
+ */
633
+ const assoc = (list, key) => {
634
+ for (const [k, v] of list) {
635
+ if (k === key) { return v }
636
+ }
637
+ return undefined
638
+ }
639
+
640
+ /**
641
+ * The rule name of `t`, assigning a fresh one on first request — the
642
+ * defining function's name, disambiguated with a counter on collision.
643
+ *
644
+ * @type {(state: _State, t: _Thunk) => readonly [_State, string]}
645
+ */
646
+ const ensureName = (state, t) => {
647
+ const existing = assoc(state.names, t)
648
+ if (existing !== undefined) { return [state, existing] }
649
+ const used = state.names.map(([, n]) => n)
650
+ let name = t.name
651
+ let i = 0
652
+ while (used.some(n => n === name)) {
653
+ name = t.name + i
654
+ ++i
655
+ }
656
+ return [{ ...state, names: [...state.names, [t, name]] }, name]
657
+ }
658
+
659
+ /**
660
+ * Records the pending merge `t ∪= op` and names `t`, so every embedding of
661
+ * `t` stays a reference that late-binds to the final, merged union.
662
+ *
663
+ * @type {(state: _State, t: _Thunk, op: _Thunk) => _State}
664
+ */
665
+ const defer = (state, t, op) => {
666
+ const [state1] = ensureName(state, t)
667
+ return { ...state1, deferred: [...state1.deferred, [t, op]] }
668
+ }
669
+
670
+ /** @type {(p: Primitive) => UnionSet} */
671
+ const primitiveUnion = p => {
672
+ switch (typeof p) {
673
+ case 'number': { return { number: [p] } }
674
+ case 'string': { return { string: [p] } }
675
+ case 'bigint': { return { bigint: [p] } }
676
+ default: { return { unit: unitBit(p) } }
677
+ }
678
+ }
679
+
680
+ /**
681
+ * The union of a const container, memoized by identity.
682
+ *
683
+ * @type {(state: _State, c: ConstObject) => readonly [_State, UnionSet]}
684
+ */
685
+ const containerMemo = (state, c) => {
686
+ const done = assoc(state.done, c)
687
+ if (done !== undefined) { return [state, done] }
688
+ const [state1, u] = containerUnion(state, c)
689
+ return [{ ...state1, done: [...state1.done, [c, u]] }, u]
690
+ }
691
+
692
+ /** @type {(state: _State, c: ConstObject) => readonly [_State, UnionSet]} */
693
+ const containerUnion = (state, c) => {
694
+ let s = state
695
+ if (c instanceof Array) {
696
+ /** @type {readonly Node[]} */
697
+ let prefix = []
698
+ for (const item of c) {
699
+ const [s1, n] = nodeOf(s)(item)
700
+ s = s1
701
+ prefix = [...prefix, n]
702
+ }
703
+ return [s, arraySet(prefix, undefined)]
704
+ }
705
+ /** @type {readonly (readonly [string, Node])[]} */
706
+ let props = []
707
+ for (const [k, v] of Object.entries(c)) {
708
+ const [s1, n] = nodeOf(s)(v)
709
+ s = s1
710
+ props = [...props, [k, n]]
711
+ }
712
+ return [s, objectSet(props, undefined)]
713
+ }
714
+
715
+ /** @type {(state: _State, c: Const) => readonly [_State, UnionSet]} */
716
+ const constUnion = (state, c) =>
717
+ c !== null && typeof c === 'object'
718
+ ? containerMemo(state, c)
719
+ : [state, primitiveUnion(c)]
720
+
721
+ /**
722
+ * The union of the `or` operands of `t`.
723
+ *
724
+ * A direct self-operand is skipped: `X = A ∪ X` collapses to `X = A`. An
725
+ * operand whose union is not final — one still being converted (an ancestor
726
+ * on the recursion stack), or a named rule with its own merges pending — is
727
+ * {@link defer}red instead of merged eagerly.
728
+ *
729
+ * @type {(state: _State, t: _Thunk, operands: readonly Type[]) => readonly [_State, UnionSet]}
730
+ */
731
+ const orUnion = (state, t, operands) => {
732
+ let s = state
733
+ let result = never
734
+ for (const op of operands) {
735
+ if (op === t) { continue }
736
+ if (op === null || (typeof op !== 'object' && typeof op !== 'function')) {
737
+ result = merge(result, primitiveUnion(op))
738
+ continue
739
+ }
740
+ if (typeof op !== 'function') {
741
+ const [s1, u] = containerMemo(s, op)
742
+ s = s1
743
+ result = merge(result, u)
744
+ continue
745
+ }
746
+ if (s.converting.some(k => k === op)) {
747
+ s = defer(s, t, op)
748
+ continue
749
+ }
750
+ let u = assoc(s.done, op)
751
+ if (u === undefined) {
752
+ const [s1, u1] = convertThunk(s, op)
753
+ s = s1
754
+ u = u1
755
+ }
756
+ if (s.deferred.some(([target]) => target === op)) {
757
+ s = defer(s, t, op)
758
+ } else {
759
+ result = merge(result, u)
760
+ }
761
+ }
762
+ return [s, result]
763
+ }
764
+
765
+ /** @type {(state: _State, t: _Thunk) => readonly [_State, UnionSet]} */
766
+ const thunkUnion = (state, t) => {
767
+ const [tag, ...rest] = t()
768
+ switch (tag) {
769
+ case 'const': {
770
+ const [c] = rest
771
+ assert(typeof c !== 'function', c)
772
+ return constUnion(state, c)
773
+ }
774
+ case 'boolean': { return [state, { unit: booleanUnits }] }
775
+ case 'number': { return [state, { number: true }] }
776
+ case 'string': { return [state, { string: true }] }
777
+ case 'bigint': { return [state, { bigint: true }] }
778
+ case 'unknown': { return [state, unknown] }
779
+ case 'array': {
780
+ const [state1, item] = nodeOf(state)(rest[0])
781
+ return [state1, arraySet([], item)]
782
+ }
783
+ case 'record': {
784
+ const [state1, value] = nodeOf(state)(rest[0])
785
+ return [state1, objectSet([], value)]
786
+ }
787
+ default: { return orUnion(state, t, rest) }
788
+ }
789
+ }
790
+
791
+ /**
792
+ * Computes and memoizes the union of a thunk.
793
+ *
794
+ * @type {(state: _State, t: _Thunk) => readonly [_State, UnionSet]}
795
+ */
796
+ const convertThunk = (state, t) => {
797
+ const [state1, u] = thunkUnion({ ...state, converting: [...state.converting, t] }, t)
798
+ return [{
799
+ ...state1,
800
+ converting: state1.converting.filter(k => k !== t),
801
+ done: [...state1.done, [t, u]],
802
+ }, u]
803
+ }
804
+
805
+ /**
806
+ * Converts a schema into a {@link Node} for a nested position: a reference
807
+ * for named (recursive) thunks, an inline union for everything else.
808
+ *
809
+ * @type {(state: _State) => (t: Type) => readonly [_State, Node]}
810
+ */
811
+ const nodeOf = state => t => {
812
+ if (t === null || (typeof t !== 'object' && typeof t !== 'function')) {
813
+ return [state, primitiveUnion(t)]
814
+ }
815
+ if (typeof t !== 'function') {
816
+ return containerMemo(state, t)
817
+ }
818
+ const name = assoc(state.names, t)
819
+ if (name !== undefined) { return [state, name] }
820
+ const done = assoc(state.done, t)
821
+ if (done !== undefined) { return [state, done] }
822
+ if (state.converting.some(k => k === t)) {
823
+ // a cycle: from here on, `t` is a named rule
824
+ const [state1, name1] = ensureName(state, t)
825
+ return [state1, name1]
826
+ }
827
+ const [state1] = convertThunk(state, t)
828
+ return nodeOf(state1)(t)
829
+ }
830
+
831
+ /**
832
+ * Applies the deferred merges until nothing changes. Every round only grows
833
+ * unions with patterns drawn from the finite already-computed content, so
834
+ * the loop terminates.
835
+ *
836
+ * @type {(state: _State) => readonly (readonly [_Key, UnionSet])[]}
837
+ */
838
+ const fixpoint = state => {
839
+ let done = state.done
840
+ let changed = true
841
+ while (changed) {
842
+ changed = false
843
+ for (const [target, source] of state.deferred) {
844
+ const targetUnion = assertNotNullish(assoc(done, target))
845
+ const merged = merge(targetUnion, assertNotNullish(assoc(done, source)))
846
+ if (cmpUnion(merged, targetUnion) !== 0) {
847
+ changed = true
848
+ done = done.map(e => e[0] === target ? /** @type {const} */ ([target, merged]) : e)
849
+ }
850
+ }
851
+ }
852
+ return done
853
+ }
854
+
855
+ /** @type {(n: Node) => readonly string[]} */
856
+ const nodeRefs = n => typeof n === 'string' ? [n] : unionRefs(n)
857
+
858
+ /** @type {(rest: Node | undefined) => readonly string[]} */
859
+ const restRefs = rest => rest === undefined ? [] : nodeRefs(rest)
860
+
861
+ /** @type {(p: ArraySet) => readonly string[]} */
862
+ const arraySetRefs = p => [...p.prefix.flatMap(nodeRefs), ...restRefs(p.rest)]
863
+
864
+ /** @type {(p: ObjectSet) => readonly string[]} */
865
+ const objectSetRefs = p => [
866
+ ...definedEntries(p.props).flatMap(([, v]) => nodeRefs(v)),
867
+ ...restRefs(p.rest),
868
+ ]
869
+
870
+ /**
871
+ * @template T
872
+ * @param {(p: T) => readonly string[]} f
873
+ * @returns {(k: KindSet<T> | undefined) => readonly string[]}
874
+ */
875
+ const kindRefs = f => k => k === undefined || k === true ? [] : k.flatMap(f)
876
+
877
+ /** @type {(u: UnionSet) => readonly string[]} */
878
+ const unionRefs = u => [...kindRefs(arraySetRefs)(u.array), ...kindRefs(objectSetRefs)(u.object)]
879
+
880
+ /**
881
+ * All rule names reachable from `init` through rule bodies.
882
+ *
883
+ * @type {(rules: RuleSet, init: readonly string[]) => readonly string[]}
884
+ */
885
+ const reachableFrom = (rules, init) => {
886
+ let result = dedup(init)
887
+ let frontier = result
888
+ while (frontier.length !== 0) {
889
+ const next = dedup(frontier
890
+ .flatMap(n => unionRefs(assertNotNullish(rules[n])))
891
+ .filter(n => !result.some(r => r === n)))
892
+ result = [...result, ...next]
893
+ frontier = next
894
+ }
895
+ return result
896
+ }
897
+
898
+ /** @type {(rules: RuleSet) => RuleSet} */
899
+ const sortRules = rules =>
900
+ Object.fromEntries(definedEntries(rules).toSorted(([an], [bn]) => cmpString(an, bn)))
901
+
902
+ /**
903
+ * Converts a thunk-form schema into its canonical data form.
904
+ *
905
+ * Runs once per consumer need; schemas that are built but never consumed pay
906
+ * nothing. The output is normalized — unions are flattened and merged
907
+ * kind-wise, literals are sorted and deduplicated, subsumed array/object
908
+ * patterns are dropped, rules are pruned to the reachable set and sorted,
909
+ * and a union equal to a rule's body reads back as a reference — so schema
910
+ * identity is a property of this form: `toData(or(a, b))` and
911
+ * `toData(or(b, a))` are structurally identical even though the two thunks
912
+ * are distinct, and `or` is idempotent on recursive schemas.
913
+ *
914
+ * Only recursive definitions become named rules (named after their defining
915
+ * functions), everything else is inlined; a schema with no reference cycles
916
+ * converts to `[{}, unionSet]`.
917
+ *
918
+ * @type {(t: Type) => Data}
919
+ */
920
+ export const toData = t => {
921
+ /** @type {_State} */
922
+ const empty = { converting: [], names: [], done: [], deferred: [] }
923
+ const [state, node] = nodeOf(empty)(t)
924
+ const done = fixpoint(state)
925
+ const ruleEntries = done.flatMap(
926
+ /** @returns {readonly (readonly [string, UnionSet])[]} */
927
+ ([key, u]) => {
928
+ const name = assoc(state.names, key)
929
+ return name === undefined ? [] : [[name, u]]
930
+ })
931
+ /** @type {RuleSet} */
932
+ const rules = Object.fromEntries(ruleEntries)
933
+ /** @type {_Ctx} */
934
+ const ctx = [rules, rules]
935
+ /** @type {RuleSet} */
936
+ const collapsed = Object.fromEntries(definedEntries(rules).map(
937
+ ([n, u]) => /** @type {const} */ ([n, collapseUnion(ctx)(u)])))
938
+ const entry = collapseNode(ctx)(node)
939
+ const keep = reachableFrom(collapsed, nodeRefs(entry))
940
+ /** @type {RuleSet} */
941
+ const kept = Object.fromEntries(definedEntries(collapsed).filter(([n]) => keep.some(k => k === n)))
942
+ if (typeof entry === 'string'
943
+ && !definedValues(kept).some(u => unionRefs(u).some(r => r === entry))) {
944
+ // the entry rule is not referenced by any rule body — inline it
945
+ const entryUnion = assertNotNullish(kept[entry])
946
+ /** @type {RuleSet} */
947
+ const rest = Object.fromEntries(definedEntries(kept).filter(([n]) => n !== entry))
948
+ return internData(sortRules(rest), entryUnion)
949
+ }
950
+ return internData(sortRules(kept), entry)
951
+ }
952
+
953
+ // ── data-driven validation ───────────────────────────────────────────────────
954
+
955
+ /** @type {(cond: boolean, value: Unknown) => ResultE} */
956
+ const checkValue = (cond, value) => cond ? ok(value) : verror('unexpected value')
957
+
958
+ /**
959
+ * @template T
960
+ * @param {(a: T, b: T) => boolean} eq
961
+ * @returns {(k: KindSet<T> | undefined, v: T) => boolean}
962
+ */
963
+ const kindHas = eq => (k, v) => k !== undefined && (k === true || k.some(x => eq(x, v)))
964
+
965
+ /** `validate` has nothing to collect from a successful entry — only pass/fail matters. */
966
+ const noAccumulate = () => undefined
967
+
968
+ /**
969
+ * The first matching pattern wins; a single pattern's error is kept intact
970
+ * (paths included), several candidates report `no match` like `or` does.
971
+ *
972
+ * @template T
973
+ * @template {Unknown} V
974
+ * @param {KindSet<T> | undefined} k
975
+ * @param {(p: T) => (value: V) => ResultE} item
976
+ * @param {V} value
977
+ * @returns {ResultE}
978
+ */
979
+ const patternsValidate = (k, item, value) => {
980
+ if (k === undefined) { return verror('unexpected value') }
981
+ if (k === true) { return ok(value) }
982
+ if (k.length === 1) { return item(k[0])(value) }
983
+ for (const p of k) {
984
+ const r = item(p)(value)
985
+ if (r[0] === 'ok') { return r }
986
+ }
987
+ return verror('no match')
988
+ }
989
+
990
+ /** @type {(p: ArraySet, i: number) => Node} */
991
+ const atIndex = (p, i) => i < p.prefix.length ? p.prefix[i] : assertNotNullish(p.rest)
992
+
993
+ /** @type {(rules: RuleSet) => (p: ArraySet) => (value: readonly Unknown[]) => ResultE} */
994
+ const arraySetValidate = rules => p => value => {
995
+ const pn = p.prefix.length
996
+ if (p.rest === undefined ? value.length !== pn : value.length < pn) {
997
+ return verror('unexpected value')
998
+ }
999
+ const r = eachEntry(
1000
+ Object.entries(value),
1001
+ (k, v) => nodeValidate(rules)(atIndex(p, Number(k)))(v),
1002
+ undefined,
1003
+ noAccumulate,
1004
+ )
1005
+ return r[0] === 'error' ? r : ok(value)
1006
+ }
1007
+
1008
+ /** @type {(rules: RuleSet) => (p: ObjectSet) => (value: StringMap<Unknown>) => ResultE} */
1009
+ const objectSetValidate = rules => p => value => {
1010
+ const declared = eachEntry(
1011
+ definedEntries(p.props),
1012
+ (k, n) => nodeValidate(rules)(n)(value[k]),
1013
+ undefined,
1014
+ noAccumulate,
1015
+ )
1016
+ if (declared[0] === 'error') { return declared }
1017
+ const { rest } = p
1018
+ if (rest === undefined) { return ok(value) }
1019
+ const extra = eachEntry(
1020
+ Object.entries(value).filter(([k]) => at(k)(p.props) === null),
1021
+ (_k, v) => nodeValidate(rules)(rest)(v),
1022
+ undefined,
1023
+ noAccumulate,
1024
+ )
1025
+ return extra[0] === 'error' ? extra : ok(value)
1026
+ }
1027
+
1028
+ /** @type {(rules: RuleSet) => (u: UnionSet) => (value: Unknown) => ResultE} */
1029
+ const unionValidate = rules => u => value => {
1030
+ if (typeof value === 'number') { return checkValue(kindHas(Object.is)(u.number, value), value) }
1031
+ if (typeof value === 'string') { return checkValue(kindHas(strictEqual)(u.string, value), value) }
1032
+ if (typeof value === 'bigint') { return checkValue(kindHas(strictEqual)(u.bigint, value), value) }
1033
+ if (value === null || value === undefined || typeof value === 'boolean') {
1034
+ return checkValue(((u.unit ?? 0) & unitBit(value)) !== 0, value)
1035
+ }
1036
+ if (isArray(value)) {
1037
+ return patternsValidate(u.array, arraySetValidate(rules), value)
1038
+ }
1039
+ return patternsValidate(u.object, objectSetValidate(rules), value)
1040
+ }
1041
+
1042
+ /** @type {(rules: RuleSet) => (n: Node) => (value: Unknown) => ResultE} */
1043
+ const nodeValidate = rules => n => unionValidate(rules)(resolve(rules)(n))
1044
+
1045
+ /**
1046
+ * Data-driven validation — the counterpart of `../validate` that consumes a
1047
+ * {@link Data} produced by {@link toData} instead of walking the thunk
1048
+ * graph. Returns the original value on success, or the first
1049
+ * `{ path, message }` error.
1050
+ *
1051
+ * @type {(data: Data) => (value: Unknown) => ResultE}
1052
+ */
1053
+ export const validate = ([rules, node]) => nodeValidate(rules)(node)