functionalscript 0.45.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 (296) 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 +10 -0
  4. package/fjs/asn.1/proof.f.mjs +16 -0
  5. package/fjs/basen/base128/module.f.mjs +22 -5
  6. package/fjs/bnf/data/module.f.d.mts +32 -6
  7. package/fjs/bnf/data/module.f.mjs +112 -7
  8. package/fjs/bnf/data/proof.f.d.mts +2 -0
  9. package/fjs/bnf/data/proof.f.mjs +74 -3
  10. package/fjs/bnf/data/types.d.ts +20 -2
  11. package/fjs/bnf/descent/module.f.d.mts +28 -14
  12. package/fjs/bnf/descent/module.f.mjs +122 -77
  13. package/fjs/bnf/descent/proof.f.d.mts +2 -0
  14. package/fjs/bnf/descent/proof.f.mjs +117 -31
  15. package/fjs/bnf/descent/types.d.ts +12 -14
  16. package/fjs/bnf/ll1/module.f.d.mts +64 -22
  17. package/fjs/bnf/ll1/module.f.mjs +214 -154
  18. package/fjs/bnf/ll1/proof.f.d.mts +15 -2
  19. package/fjs/bnf/ll1/proof.f.mjs +323 -149
  20. package/fjs/bnf/ll1/types.d.ts +16 -24
  21. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  22. package/fjs/bnf/matcher/module.f.mjs +81 -0
  23. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  24. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  25. package/fjs/bnf/matcher/types.d.ts +54 -0
  26. package/fjs/bnf/testlib.f.d.mts +31 -0
  27. package/fjs/bnf/testlib.f.mjs +80 -0
  28. package/fjs/cas/cli/module.f.d.mts +1 -1
  29. package/fjs/cas/cli/module.f.mjs +14 -20
  30. package/fjs/cas/cli/proof.f.d.mts +1 -3
  31. package/fjs/cas/cli/proof.f.mjs +44 -33
  32. package/fjs/cas/evo/module.f.d.mts +64 -18
  33. package/fjs/cas/evo/module.f.mjs +148 -70
  34. package/fjs/cas/evo/proof.f.d.mts +10 -1
  35. package/fjs/cas/evo/proof.f.mjs +305 -223
  36. package/fjs/cas/evo/types.d.ts +45 -9
  37. package/fjs/cas/module.f.d.mts +18 -32
  38. package/fjs/cas/module.f.mjs +129 -128
  39. package/fjs/cas/proof.f.d.mts +11 -8
  40. package/fjs/cas/proof.f.mjs +259 -147
  41. package/fjs/cas/types.d.ts +24 -10
  42. package/fjs/ci/config/module.f.d.mts +2 -2
  43. package/fjs/ci/config/module.f.mjs +2 -2
  44. package/fjs/ci/module.f.d.mts +5 -5
  45. package/fjs/ci/module.f.mjs +8 -7
  46. package/fjs/ci/nix/module.f.d.mts +7 -5
  47. package/fjs/ci/nix/module.f.mjs +13 -12
  48. package/fjs/ci/nix/proof.f.mjs +2 -2
  49. package/fjs/ci/proof.f.mjs +9 -5
  50. package/fjs/cli/module.f.d.mts +4 -6
  51. package/fjs/cli/module.f.mjs +4 -8
  52. package/fjs/cli/proof.f.mjs +17 -16
  53. package/fjs/cli/types.d.ts +2 -3
  54. package/fjs/common/monoid/types.d.ts +1 -1
  55. package/fjs/crypto/hmac/module.f.mjs +2 -2
  56. package/fjs/crypto/sha2/module.f.mjs +3 -1
  57. package/fjs/crypto/sha2/proof.f.d.mts +1 -0
  58. package/fjs/crypto/sha2/proof.f.mjs +24 -0
  59. package/fjs/crypto/sha2/types.d.ts +11 -0
  60. package/fjs/crypto/sign/module.f.mjs +2 -2
  61. package/fjs/dev/module.f.d.mts +13 -4
  62. package/fjs/dev/module.f.mjs +56 -27
  63. package/fjs/dev/update/module.f.d.mts +9 -4
  64. package/fjs/dev/update/module.f.mjs +14 -10
  65. package/fjs/dev/update/proof.f.d.mts +1 -3
  66. package/fjs/dev/update/proof.f.mjs +10 -5
  67. package/fjs/djs/module.f.d.mts +13 -5
  68. package/fjs/djs/module.f.mjs +31 -16
  69. package/fjs/djs/parser/module.f.d.mts +13 -3
  70. package/fjs/djs/parser/module.f.mjs +117 -16
  71. package/fjs/djs/parser/proof.f.d.mts +5 -1
  72. package/fjs/djs/parser/proof.f.mjs +274 -12
  73. package/fjs/djs/parser/types.d.ts +7 -1
  74. package/fjs/djs/proof.f.d.mts +18 -2
  75. package/fjs/djs/proof.f.mjs +187 -12
  76. package/fjs/djs/serializer/module.f.d.mts +25 -8
  77. package/fjs/djs/serializer/module.f.mjs +61 -15
  78. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  79. package/fjs/djs/serializer/proof.f.mjs +23 -1
  80. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  81. package/fjs/djs/tokenizer/module.f.mjs +99 -60
  82. package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
  83. package/fjs/djs/tokenizer/proof.f.mjs +74 -67
  84. package/fjs/djs/transpiler/module.f.d.mts +12 -7
  85. package/fjs/djs/transpiler/module.f.mjs +82 -56
  86. package/fjs/djs/transpiler/types.d.ts +7 -3
  87. package/fjs/djs/types.d.ts +7 -1
  88. package/fjs/effects/list/module.f.d.mts +14 -11
  89. package/fjs/effects/list/module.f.mjs +13 -11
  90. package/fjs/effects/list/types.d.ts +27 -7
  91. package/fjs/effects/memory/module.f.d.mts +2 -1
  92. package/fjs/effects/memory/module.f.mjs +3 -4
  93. package/fjs/effects/memory/proof.f.mjs +13 -7
  94. package/fjs/effects/memory/types.d.ts +4 -3
  95. package/fjs/effects/mock/module.f.d.mts +20 -4
  96. package/fjs/effects/mock/module.f.mjs +37 -5
  97. package/fjs/effects/mock/types.d.ts +10 -1
  98. package/fjs/effects/module.d.mts +4 -2
  99. package/fjs/effects/module.f.d.mts +466 -280
  100. package/fjs/effects/module.f.mjs +537 -299
  101. package/fjs/effects/module.mjs +2 -1
  102. package/fjs/effects/node/memory/module.d.mts +4 -2
  103. package/fjs/effects/node/memory/module.mjs +6 -3
  104. package/fjs/effects/node/memory/proof.mjs +10 -4
  105. package/fjs/effects/node/module.d.mts +4 -3
  106. package/fjs/effects/node/module.f.d.mts +168 -33
  107. package/fjs/effects/node/module.f.mjs +256 -52
  108. package/fjs/effects/node/module.mjs +57 -34
  109. package/fjs/effects/node/proof.f.d.mts +28 -2
  110. package/fjs/effects/node/proof.f.mjs +161 -42
  111. package/fjs/effects/node/types.d.ts +106 -18
  112. package/fjs/effects/node/virtual/module.f.d.mts +18 -4
  113. package/fjs/effects/node/virtual/module.f.mjs +110 -68
  114. package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
  115. package/fjs/effects/node/virtual/proof.f.mjs +190 -9
  116. package/fjs/effects/proof.f.d.mts +69 -37
  117. package/fjs/effects/proof.f.mjs +410 -130
  118. package/fjs/effects/types.d.ts +161 -33
  119. package/fjs/emergent_testing/module.f.d.mts +19 -12
  120. package/fjs/emergent_testing/module.f.mjs +93 -33
  121. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  122. package/fjs/emergent_testing/proof.f.mjs +166 -32
  123. package/fjs/emergent_testing/types.d.ts +22 -4
  124. package/fjs/fsm/module.f.d.mts +14 -4
  125. package/fjs/fsm/module.f.mjs +54 -37
  126. package/fjs/fsm/proof.f.d.mts +2 -0
  127. package/fjs/fsm/proof.f.mjs +83 -114
  128. package/fjs/js/keywords/module.f.d.mts +52 -0
  129. package/fjs/js/keywords/module.f.mjs +72 -0
  130. package/fjs/js/keywords/proof.f.d.mts +3 -0
  131. package/fjs/js/keywords/proof.f.mjs +13 -0
  132. package/fjs/js/tokenizer/module.f.d.mts +26 -6
  133. package/fjs/js/tokenizer/module.f.mjs +145 -159
  134. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  135. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  136. package/fjs/js/tokenizer/types.d.ts +33 -24
  137. package/fjs/mcp/cas/module.f.d.mts +1 -6
  138. package/fjs/mcp/cas/module.f.mjs +55 -51
  139. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  140. package/fjs/mcp/cas/proof.f.mjs +174 -0
  141. package/fjs/mcp/evo/module.f.d.mts +19 -10
  142. package/fjs/mcp/evo/module.f.mjs +48 -27
  143. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  144. package/fjs/mcp/evo/proof.f.mjs +115 -31
  145. package/fjs/mcp/module.f.d.mts +4 -4
  146. package/fjs/mcp/module.f.mjs +6 -6
  147. package/fjs/mcp/proof.f.d.mts +5 -3
  148. package/fjs/mcp/proof.f.mjs +112 -46
  149. package/fjs/media/html/module.f.mjs +1 -1
  150. package/fjs/media/json/extended/module.f.d.mts +82 -0
  151. package/fjs/media/json/extended/module.f.mjs +153 -0
  152. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  153. package/fjs/media/json/extended/proof.f.mjs +127 -0
  154. package/fjs/media/json/extended/types.d.ts +23 -0
  155. package/fjs/media/json/module.f.d.mts +8 -2
  156. package/fjs/media/json/module.f.mjs +43 -41
  157. package/fjs/media/json/number/module.f.d.mts +59 -0
  158. package/fjs/media/json/number/module.f.mjs +136 -0
  159. package/fjs/media/json/number/proof.f.d.mts +24 -0
  160. package/fjs/media/json/number/proof.f.mjs +86 -0
  161. package/fjs/media/json/number/types.d.ts +28 -0
  162. package/fjs/media/json/parser/module.f.d.mts +25 -13
  163. package/fjs/media/json/parser/module.f.mjs +114 -70
  164. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  165. package/fjs/media/json/parser/proof.f.mjs +31 -1
  166. package/fjs/media/json/parser/types.d.ts +33 -14
  167. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  168. package/fjs/media/json/rtti/module.f.mjs +1 -1
  169. package/fjs/media/json/rtti/proof.f.mjs +9 -9
  170. package/fjs/media/json/schema/module.f.mjs +3 -13
  171. package/fjs/media/json/schema/proof.f.d.mts +0 -1
  172. package/fjs/media/json/schema/proof.f.mjs +1 -2
  173. package/fjs/media/json/serializer/module.f.d.mts +32 -1
  174. package/fjs/media/json/serializer/module.f.mjs +64 -2
  175. package/fjs/media/json/tokenizer/module.f.mjs +7 -3
  176. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  177. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  178. package/fjs/media/json/types.d.ts +36 -10
  179. package/fjs/media/lock/module.f.d.mts +100 -0
  180. package/fjs/media/lock/module.f.mjs +125 -0
  181. package/fjs/media/lock/proof.f.d.mts +33 -0
  182. package/fjs/media/lock/proof.f.mjs +196 -0
  183. package/fjs/media/lock/types.d.ts +15 -0
  184. package/fjs/media/module.f.d.mts +6 -5
  185. package/fjs/media/module.f.mjs +8 -7
  186. package/fjs/media/note/module.f.d.mts +121 -0
  187. package/fjs/media/note/module.f.mjs +131 -0
  188. package/fjs/media/note/proof.f.d.mts +29 -0
  189. package/fjs/media/note/proof.f.mjs +150 -0
  190. package/fjs/media/note/types.d.ts +10 -0
  191. package/fjs/media/proof.f.d.mts +4 -1
  192. package/fjs/media/proof.f.mjs +40 -21
  193. package/fjs/media/revision/module.f.d.mts +78 -7
  194. package/fjs/media/revision/module.f.mjs +119 -12
  195. package/fjs/media/revision/proof.f.d.mts +10 -0
  196. package/fjs/media/revision/proof.f.mjs +88 -0
  197. package/fjs/media/revision/types.d.ts +34 -5
  198. package/fjs/media/type/module.f.d.mts +33 -15
  199. package/fjs/media/type/module.f.mjs +35 -29
  200. package/fjs/media/type/proof.f.d.mts +2 -1
  201. package/fjs/media/type/proof.f.mjs +30 -10
  202. package/fjs/module.f.mjs +29 -8
  203. package/fjs/nanvm/proof.f.mjs +3 -3
  204. package/fjs/nanvm/rust/module.f.mjs +1 -1
  205. package/fjs/nanvm/update/module.f.d.mts +4 -4
  206. package/fjs/nanvm/update/module.f.mjs +8 -9
  207. package/fjs/nanvm/update/proof.f.mjs +4 -3
  208. package/fjs/proof.f.d.mts +3 -3
  209. package/fjs/proof.f.mjs +36 -10
  210. package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
  211. package/fjs/protocol/json_rpc/module.f.mjs +3 -3
  212. package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
  213. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  214. package/fjs/protocol/mcp/module.f.mjs +74 -58
  215. package/fjs/protocol/mcp/proof.f.d.mts +13 -4
  216. package/fjs/protocol/mcp/proof.f.mjs +193 -61
  217. package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
  218. package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
  219. package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
  220. package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
  221. package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
  222. package/fjs/protocol/mcp/types.d.ts +17 -6
  223. package/fjs/sul/id/module.f.d.mts +0 -1
  224. package/fjs/sul/id/module.f.mjs +2 -3
  225. package/fjs/sul/level/hash/module.f.mjs +2 -1
  226. package/fjs/sul/level/hash/proof.f.mjs +2 -2
  227. package/fjs/sul/module.f.mjs +18 -13
  228. package/fjs/text/code_point/module.f.d.mts +8 -0
  229. package/fjs/text/code_point/module.f.mjs +8 -1
  230. package/fjs/text/code_point/proof.f.d.mts +1 -0
  231. package/fjs/text/code_point/proof.f.mjs +11 -0
  232. package/fjs/text/sgr/module.f.d.mts +4 -6
  233. package/fjs/text/sgr/module.f.mjs +6 -7
  234. package/fjs/text/utf16/module.f.mjs +7 -2
  235. package/fjs/text/utf16/proof.f.mjs +3 -3
  236. package/fjs/text/utf8/module.f.mjs +4 -2
  237. package/fjs/types/array/module.f.mjs +14 -2
  238. package/fjs/types/bit_vec/module.f.d.mts +0 -2
  239. package/fjs/types/bit_vec/module.f.mjs +46 -32
  240. package/fjs/types/bit_vec/proof.f.mjs +2 -2
  241. package/fjs/types/btree/remove/module.f.mjs +1 -1
  242. package/fjs/types/btree/set/module.f.mjs +9 -11
  243. package/fjs/types/btree/set/proof.f.mjs +12 -0
  244. package/fjs/types/byte_set/module.f.d.mts +11 -4
  245. package/fjs/types/byte_set/module.f.mjs +14 -6
  246. package/fjs/types/byte_set/proof.f.mjs +7 -7
  247. package/fjs/types/function/compare/module.f.mjs +10 -3
  248. package/fjs/types/list/module.f.d.mts +1 -1
  249. package/fjs/types/list/module.f.mjs +1 -1
  250. package/fjs/types/nullable/module.f.d.mts +18 -4
  251. package/fjs/types/nullable/module.f.mjs +21 -4
  252. package/fjs/types/nullable/proof.f.d.mts +4 -0
  253. package/fjs/types/nullable/proof.f.mjs +15 -0
  254. package/fjs/types/object/module.f.d.mts +12 -2
  255. package/fjs/types/object/module.f.mjs +11 -1
  256. package/fjs/types/patricia_trie/module.f.mjs +26 -11
  257. package/fjs/types/result/module.f.d.mts +3 -3
  258. package/fjs/types/result/module.f.mjs +3 -3
  259. package/fjs/types/rtti/common/module.f.d.mts +25 -28
  260. package/fjs/types/rtti/common/module.f.mjs +36 -32
  261. package/fjs/types/rtti/common/proof.f.mjs +5 -5
  262. package/fjs/types/rtti/data/module.f.d.mts +14 -0
  263. package/fjs/types/rtti/data/module.f.mjs +25 -2
  264. package/fjs/types/rtti/data/proof.f.d.mts +1 -0
  265. package/fjs/types/rtti/data/proof.f.mjs +25 -2
  266. package/fjs/types/rtti/parse/module.f.d.mts +24 -14
  267. package/fjs/types/rtti/parse/module.f.mjs +37 -28
  268. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  269. package/fjs/types/rtti/parse/proof.f.mjs +33 -14
  270. package/fjs/types/rtti/proof.f.mjs +3 -1
  271. package/fjs/types/rtti/ts/module.f.mjs +13 -17
  272. package/fjs/types/rtti/ts/types.d.ts +14 -1
  273. package/fjs/types/sorted_set/module.f.d.mts +18 -0
  274. package/fjs/types/sorted_set/module.f.mjs +22 -0
  275. package/fjs/types/sorted_set/proof.f.d.mts +1 -0
  276. package/fjs/types/sorted_set/proof.f.mjs +16 -1
  277. package/fjs/types/uint8array/module.f.d.mts +1 -1
  278. package/fjs/types/uint8array/module.f.mjs +1 -1
  279. package/fjs/website/module.f.d.mts +3 -3
  280. package/fjs/website/module.f.mjs +4 -7
  281. package/fjs/website/proof.f.mjs +2 -1
  282. package/package.json +2 -2
  283. package/fjs/dev/package_json/module.f.d.mts +0 -39
  284. package/fjs/dev/package_json/module.f.mjs +0 -40
  285. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  286. package/fjs/dev/package_json/proof.f.mjs +0 -32
  287. package/fjs/effects/eff/module.f.d.mts +0 -20
  288. package/fjs/effects/eff/module.f.mjs +0 -70
  289. package/fjs/effects/eff/proof.f.d.mts +0 -15
  290. package/fjs/effects/eff/proof.f.mjs +0 -69
  291. package/fjs/effects/eff/types.d.ts +0 -71
  292. package/fjs/types/rtti/validate/module.f.d.mts +0 -41
  293. package/fjs/types/rtti/validate/module.f.mjs +0 -171
  294. package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
  295. package/fjs/types/rtti/validate/proof.f.mjs +0 -437
  296. package/fjs/types/rtti/validate/types.d.ts +0 -6
@@ -1,34 +1,33 @@
1
1
  /**
2
- * Shared kernel for RTTI consumers (`validate`, `parse`).
2
+ * Shared kernel for RTTI consumers.
3
3
  *
4
- * Both consumers traverse the same schema shape and produce the same
5
- * `Result<T, ValidationError>` outcome. Only the per-variant handling differs
6
- * `validate` keeps the original value, `parse` constructs a fresh one.
7
- *
8
- * This module hosts the parts that do not differ:
4
+ * `parse` (`../parse/module.f.mjs`) is the schema-form consumer; the data form
5
+ * (`../data/module.f.mjs`) is the other, walking a `Data` instead of a thunk
6
+ * graph. They produce the same `Result<T, ValidationError>` outcome and differ
7
+ * in how they dispatch, so this module hosts the parts that do not differ:
9
8
  *
10
9
  * - The error shape (`ValidationError`, `Path`) and path bookkeeping
11
10
  * (`verror`, `prependPath`).
12
11
  * - Primitive checks (`primitive0Validate`, `constPrimitiveValidate`).
13
- * - The `Validate<T>`/`Result<T>` signatures `parse` uses the same shape.
12
+ * - The `Validate<T>`/`Result<T>` signatures, which `parse` reuses
13
+ * (`Parse<T> = Validate<T>`).
14
14
  * - `visit`: a visitor over the `Type` ADT. Callers supply a `Visitor<R>`
15
15
  * with one handler per variant; `visit(v)(rtti)` recognizes `rtti` and
16
- * calls the matching handler. Both consumers compose their top-level
17
- * function from a visitor.
18
- * - `eachEntry`: the container entry loop (array/record/tuple/struct), shared
19
- * by both consumers' container builders. Callers choose what (if anything)
20
- * to accumulate, so `validate`'s pure pass/fail check pays no allocation.
16
+ * calls the matching handler. `parse` composes its top-level function from
17
+ * a visitor.
18
+ * - `eachEntry`: the container entry loop (array/record/tuple/struct). Callers
19
+ * choose what (if anything) to accumulate, so a caller that only needs
20
+ * pass/fail pays no allocation per entry.
21
21
  * - `orVisit`: the shared `or` handler — try each variant's recursive walker,
22
22
  * return the first match.
23
23
  *
24
- * Keeping the kernel here also removes `parse`'s incidental dependency on
25
- * `validate` and gives schema-driven consumers (e.g. the data form in
26
- * `../data/module.f.mjs`) a stable shared base.
24
+ * Keeping the kernel here gives schema-driven consumers a stable shared base
25
+ * that does not depend on any one of them.
27
26
  *
28
27
  * @module
29
28
  *
30
29
  * @import { Primitive, Unknown } from '../ts/types.ts'
31
- * @import { Const, Info0, Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts'
30
+ * @import { Const, Info0, Primitive0, Tag1, Tuple, Type } from '../types.ts'
32
31
  * @import { Error, Result as CommonResult } from '../../result/types.ts'
33
32
  * @import { StringMap } from '../../object/types.ts'
34
33
  * @import { Validate, Visitor, IsContainer, Container, ResultE, ValidateE, ValidationError } from './types.ts'
@@ -67,10 +66,10 @@ export declare const constPrimitiveValidate: <T extends Primitive>(
67
66
  * @returns {Validate<T>}
68
67
  */
69
68
  rtti: T) => Validate<T>;
70
- /** `IsContainer` guard for arrays, shared by `validate` and `parse`. */
69
+ /** `IsContainer` guard for arrays. */
71
70
  /** @type {IsContainer<ReadonlyArray<Unknown>>} */
72
71
  export declare const isArray: IsContainer<ReadonlyArray<Unknown>>;
73
- /** `IsContainer` guard for records/structs, shared by `validate` and `parse`. */
72
+ /** `IsContainer` guard for records/structs. */
74
73
  /** @type {IsContainer<StringMap<Unknown>>} */
75
74
  export declare const isObject: IsContainer<StringMap<Unknown>>;
76
75
  /**
@@ -79,21 +78,19 @@ export declare const isObject: IsContainer<StringMap<Unknown>>;
79
78
  * result into `acc` (starting from `init`) with `accumulate` and returns the
80
79
  * final accumulator.
81
80
  *
82
- * Shared by `validate` and `parse`'s container builders (array/record/tuple/
83
- * struct), which differ only in what `item` does with the value and what
84
- * they accumulate: `validate` has nothing to collect its entire schema is
85
- * "did every entry succeed?" — so it passes `undefined`/`(acc) => acc` and
86
- * pays no allocation per entry; `parse` needs the rebuilt `[key, value]`
87
- * pairs, so it folds them into a `List` (see its call site) and converts to
88
- * an array once at the end.
81
+ * Used by `parse`'s container builders (array/record/tuple/struct), which
82
+ * need the rebuilt `[key, value]` pairs, so they fold them into a `List` (see
83
+ * the call site) and convert to an array once at the end. A caller whose
84
+ * whole question is "did every entry succeed?" passes `undefined`/`acc => acc`
85
+ * instead and pays no allocation per entry.
89
86
  */
90
87
  export declare const eachEntry: <V, R, A>(entries: ReadonlyArray<readonly [string, V]>, item: (k: string, v: V) => CommonResult<R, ValidationError>, init: A, accumulate: (acc: A, k: string, value: R) => A) => CommonResult<A, ValidationError>;
91
88
  /**
92
89
  * First variant in `variants` that `recurse` accepts, else `verror('no match')`.
93
90
  *
94
- * Shared `or` handler for `validate` and `parse`: both try each variant
95
- * against the value and return the first `'ok'` verbatim, differing only in
96
- * which recursive function (`validate` or `parse`) walks each variant. `recurse`
91
+ * Shared `or` handler: try each variant against the value and return the
92
+ * first `'ok'` verbatim, parameterized by the recursive function that walks
93
+ * each variant. `recurse`
97
94
  * is typed over the erased `ValidateE` alias — annotating it as `(t: Type) =>
98
95
  * Validate<Type>` would itself instantiate `Validate<Type>` and hit TS2589 —
99
96
  * so each caller passes its recursive function through one boundary cast.
@@ -1,39 +1,39 @@
1
1
  /**
2
- * Shared kernel for RTTI consumers (`validate`, `parse`).
2
+ * Shared kernel for RTTI consumers.
3
3
  *
4
- * Both consumers traverse the same schema shape and produce the same
5
- * `Result<T, ValidationError>` outcome. Only the per-variant handling differs
6
- * `validate` keeps the original value, `parse` constructs a fresh one.
7
- *
8
- * This module hosts the parts that do not differ:
4
+ * `parse` (`../parse/module.f.mjs`) is the schema-form consumer; the data form
5
+ * (`../data/module.f.mjs`) is the other, walking a `Data` instead of a thunk
6
+ * graph. They produce the same `Result<T, ValidationError>` outcome and differ
7
+ * in how they dispatch, so this module hosts the parts that do not differ:
9
8
  *
10
9
  * - The error shape (`ValidationError`, `Path`) and path bookkeeping
11
10
  * (`verror`, `prependPath`).
12
11
  * - Primitive checks (`primitive0Validate`, `constPrimitiveValidate`).
13
- * - The `Validate<T>`/`Result<T>` signatures `parse` uses the same shape.
12
+ * - The `Validate<T>`/`Result<T>` signatures, which `parse` reuses
13
+ * (`Parse<T> = Validate<T>`).
14
14
  * - `visit`: a visitor over the `Type` ADT. Callers supply a `Visitor<R>`
15
15
  * with one handler per variant; `visit(v)(rtti)` recognizes `rtti` and
16
- * calls the matching handler. Both consumers compose their top-level
17
- * function from a visitor.
18
- * - `eachEntry`: the container entry loop (array/record/tuple/struct), shared
19
- * by both consumers' container builders. Callers choose what (if anything)
20
- * to accumulate, so `validate`'s pure pass/fail check pays no allocation.
16
+ * calls the matching handler. `parse` composes its top-level function from
17
+ * a visitor.
18
+ * - `eachEntry`: the container entry loop (array/record/tuple/struct). Callers
19
+ * choose what (if anything) to accumulate, so a caller that only needs
20
+ * pass/fail pays no allocation per entry.
21
21
  * - `orVisit`: the shared `or` handler — try each variant's recursive walker,
22
22
  * return the first match.
23
23
  *
24
- * Keeping the kernel here also removes `parse`'s incidental dependency on
25
- * `validate` and gives schema-driven consumers (e.g. the data form in
26
- * `../data/module.f.mjs`) a stable shared base.
24
+ * Keeping the kernel here gives schema-driven consumers a stable shared base
25
+ * that does not depend on any one of them.
27
26
  *
28
27
  * @module
29
28
  *
30
29
  * @import { Primitive, Unknown } from '../ts/types.ts'
31
- * @import { Const, Info0, Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts'
30
+ * @import { Const, Info0, Primitive0, Tag1, Tuple, Type } from '../types.ts'
32
31
  * @import { Error, Result as CommonResult } from '../../result/types.ts'
33
32
  * @import { StringMap } from '../../object/types.ts'
34
33
  * @import { Validate, Visitor, IsContainer, Container, ResultE, ValidateE, ValidationError } from './types.ts'
35
34
  */
36
35
 
36
+ import { assert } from '../../../asserts/module.f.mjs'
37
37
  import { error, ok } from '../../result/module.f.mjs'
38
38
  import { isArray as commonIsArray } from '../../array/module.f.mjs'
39
39
  import { isObject as commonIsObject } from '../../object/module.f.mjs'
@@ -80,15 +80,15 @@ export const constPrimitiveValidate =
80
80
  /** @type {<R>(v: Visitor<R>) => (c: Const) => R} */
81
81
  const visitConst = v => c =>
82
82
  typeof c === 'object' && c !== null
83
- ? (commonIsArray(c) ? v.tuple(c) : v.struct(/** @type {Struct} */ (c)))
84
- : v.constPrimitive(/** @type {Primitive} */ (c))
83
+ ? (commonIsArray(c) ? v.tuple(c) : v.struct(c))
84
+ : v.constPrimitive(c)
85
85
 
86
- /** `IsContainer` guard for arrays, shared by `validate` and `parse`. */
86
+ /** `IsContainer` guard for arrays. */
87
87
  /** @type {IsContainer<ReadonlyArray<Unknown>>} */
88
88
  export const isArray =
89
89
  value => commonIsArray(value)
90
90
 
91
- /** `IsContainer` guard for records/structs, shared by `validate` and `parse`. */
91
+ /** `IsContainer` guard for records/structs. */
92
92
  /** @type {IsContainer<StringMap<Unknown>>} */
93
93
  export const isObject =
94
94
  value => commonIsObject(value)
@@ -99,13 +99,11 @@ export const isObject =
99
99
  * result into `acc` (starting from `init`) with `accumulate` and returns the
100
100
  * final accumulator.
101
101
  *
102
- * Shared by `validate` and `parse`'s container builders (array/record/tuple/
103
- * struct), which differ only in what `item` does with the value and what
104
- * they accumulate: `validate` has nothing to collect its entire schema is
105
- * "did every entry succeed?" — so it passes `undefined`/`(acc) => acc` and
106
- * pays no allocation per entry; `parse` needs the rebuilt `[key, value]`
107
- * pairs, so it folds them into a `List` (see its call site) and converts to
108
- * an array once at the end.
102
+ * Used by `parse`'s container builders (array/record/tuple/struct), which
103
+ * need the rebuilt `[key, value]` pairs, so they fold them into a `List` (see
104
+ * the call site) and convert to an array once at the end. A caller whose
105
+ * whole question is "did every entry succeed?" passes `undefined`/`acc => acc`
106
+ * instead and pays no allocation per entry.
109
107
  */
110
108
  export const eachEntry =
111
109
  /**
@@ -133,9 +131,9 @@ export const eachEntry =
133
131
  /**
134
132
  * First variant in `variants` that `recurse` accepts, else `verror('no match')`.
135
133
  *
136
- * Shared `or` handler for `validate` and `parse`: both try each variant
137
- * against the value and return the first `'ok'` verbatim, differing only in
138
- * which recursive function (`validate` or `parse`) walks each variant. `recurse`
134
+ * Shared `or` handler: try each variant against the value and return the
135
+ * first `'ok'` verbatim, parameterized by the recursive function that walks
136
+ * each variant. `recurse`
139
137
  * is typed over the erased `ValidateE` alias — annotating it as `(t: Type) =>
140
138
  * Validate<Type>` would itself instantiate `Validate<Type>` and hit TS2589 —
141
139
  * so each caller passes its recursive function through one boundary cast.
@@ -173,13 +171,19 @@ export const visit =
173
171
  if (typeof rtti === 'function') {
174
172
  const [tag, ...value] = rtti()
175
173
  switch (tag) {
176
- case 'const': return visitConst(v)(/** @type {Const} */ (value[0]))
174
+ case 'const': {
175
+ const [c] = value
176
+ // `Type` is `Const | Thunk`, and a `Thunk` is a function, so
177
+ // this is exactly the check that defines `Const`.
178
+ assert(typeof c !== 'function', c)
179
+ return visitConst(v)(c)
180
+ }
177
181
  case 'array': return v.array(value[0])
178
182
  case 'record': return v.record(value[0])
179
183
  case 'unknown': return v.unknown()
180
184
  case 'or': return v.or(value)
181
185
  }
182
- return v.primitive0(/** @type {Primitive0} */ (tag))
186
+ return v.primitive0(tag)
183
187
  }
184
188
  return visitConst(v)(rtti)
185
189
  }
@@ -19,12 +19,12 @@ const collect = (acc, k, v) => [...acc, [k, v]]
19
19
 
20
20
  export const proof = {
21
21
  empty: () => {
22
- const r = eachEntry(/** @type {_Entries} */ ([]), item, /** @type {_Entries} */ ([]), collect)
22
+ const r = eachEntry([], item, [], collect)
23
23
  assert(r[0] === 'ok')
24
24
  assertEq(r[1].length, 0)
25
25
  },
26
26
  allOk: () => {
27
- const r = eachEntry([['a', 1], ['b', 2]], item, /** @type {_Entries} */ ([]), collect)
27
+ const r = eachEntry([['a', 1], ['b', 2]], item, [], collect)
28
28
  assert(r[0] === 'ok')
29
29
  assertEq(r[1].length, 2)
30
30
  assertEq(r[1][0][0], 'a')
@@ -39,7 +39,7 @@ export const proof = {
39
39
  assertEq(r[1], undefined)
40
40
  },
41
41
  firstErrorWins: () => {
42
- const r = eachEntry([['a', -1], ['b', -2]], item, /** @type {_Entries} */ ([]), collect)
42
+ const r = eachEntry([['a', -1], ['b', -2]], item, [], collect)
43
43
  assert(r[0] === 'error')
44
44
  assertEq(r[1].message, 'negative at a')
45
45
  },
@@ -50,7 +50,7 @@ export const proof = {
50
50
  calls++
51
51
  return item(k, v)
52
52
  }
53
- const r = eachEntry([['a', -1], ['b', -2], ['c', -3]], counting, /** @type {_Entries} */ ([]), collect)
53
+ const r = eachEntry([['a', -1], ['b', -2], ['c', -3]], counting, [], collect)
54
54
  assert(r[0] === 'error')
55
55
  assertEq(calls, 1)
56
56
  },
@@ -58,7 +58,7 @@ export const proof = {
58
58
  /** @type {(k: string, v: number) => Result<number, ValidationError>} */
59
59
  const nested = (k, v) =>
60
60
  v < 0 ? error({ path: ['inner'], message: 'bad' }) : ok(v)
61
- const r = eachEntry([['outer', -1]], nested, /** @type {_Entries} */ ([]), collect)
61
+ const r = eachEntry([['outer', -1]], nested, [], collect)
62
62
  assert(r[0] === 'error')
63
63
  assertEq(r[1].path.length, 2)
64
64
  assertEq(r[1].path[0], 'outer')
@@ -49,6 +49,20 @@ export declare const never: UnionSet;
49
49
  * @type {UnionSet}
50
50
  */
51
51
  export declare const unknown: UnionSet;
52
+ /**
53
+ * The union with the given unit bits removed — set subtraction restricted to
54
+ * the unit kind. Dropping `undefined` from an optional property's value set is
55
+ * the motivating case.
56
+ *
57
+ * The other five kinds are carried through untouched rather than copied field
58
+ * by field. That is not only shorter: a caller that enumerates `UnionSet`'s
59
+ * members to rebuild the node silently **drops** any kind added to the type
60
+ * later, whereas spreading cannot. Removing every unit bit removes the `unit`
61
+ * key entirely, since an empty kind is an absent property here, never a zero.
62
+ *
63
+ * @type {(bits: number) => (n: UnionSet) => UnionSet}
64
+ */
65
+ export declare const withoutUnits: (bits: number) => (n: UnionSet) => UnionSet;
52
66
  /**
53
67
  * Total order over the data form: negative, zero or positive, with zero
54
68
  * exactly on structural identity. {@link toData} output is canonical, so two
@@ -22,7 +22,7 @@
22
22
  * @import { ArraySet, Data, KindSet, Node, ObjectSet, RuleSet, UnionSet } from './types.ts'
23
23
  */
24
24
 
25
- import { assertNotNullish } from '../../../asserts/module.f.mjs'
25
+ import { assert, assertNotNullish } from '../../../asserts/module.f.mjs'
26
26
  import { at, definedEntries, definedValues } from '../../object/module.f.mjs'
27
27
  import { ok } from '../../result/module.f.mjs'
28
28
  import { eachEntry, isArray, verror } from '../common/module.f.mjs'
@@ -68,6 +68,25 @@ export const unknown = {
68
68
  object: true,
69
69
  }
70
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
+
71
90
  // ── canonical order ──────────────────────────────────────────────────────────
72
91
 
73
92
  /** @type {(a: string, b: string) => number} */
@@ -747,7 +766,11 @@ const orUnion = (state, t, operands) => {
747
766
  const thunkUnion = (state, t) => {
748
767
  const [tag, ...rest] = t()
749
768
  switch (tag) {
750
- case 'const': { return constUnion(state, /** @type {Const} */ (rest[0])) }
769
+ case 'const': {
770
+ const [c] = rest
771
+ assert(typeof c !== 'function', c)
772
+ return constUnion(state, c)
773
+ }
751
774
  case 'boolean': { return [state, { unit: booleanUnits }] }
752
775
  case 'number': { return [state, { number: true }] }
753
776
  case 'string': { return [state, { string: true }] }
@@ -31,6 +31,7 @@ export type _Odd = () => readonly ['const', {
31
31
  }];
32
32
  export type _Rec = () => readonly ['array', _Rec];
33
33
  export declare const proof: {
34
+ withoutUnits: (() => void)[];
34
35
  unitBits: () => void;
35
36
  toData: {
36
37
  primitives: () => void;
@@ -3,7 +3,7 @@
3
3
  * @import { Data } from './types.ts'
4
4
  */
5
5
 
6
- import { assert, assertEq } from '../../../asserts/module.f.mjs'
6
+ import { assert, assertEq, assertStructurallySame } from '../../../asserts/module.f.mjs'
7
7
  import {
8
8
  array,
9
9
  bigint,
@@ -16,7 +16,7 @@ import {
16
16
  string,
17
17
  unknown as unknownRtti,
18
18
  } from '../module.f.mjs'
19
- import { cmp, equal, never, subset, toData, unitBit, unitList, unknown, validate } from './module.f.mjs'
19
+ import { cmp, equal, never, subset, toData, unitBit, unitList, unknown, validate, withoutUnits } from './module.f.mjs'
20
20
 
21
21
  /** @type {(actual: Data) => (expected: Data) => void} */
22
22
  const assertData = actual => expected =>
@@ -119,6 +119,29 @@ const tupleString = /** @type {const} */ ([string])
119
119
  const emptyTuple = /** @type {const} */ ([])
120
120
 
121
121
  export const proof = {
122
+ withoutUnits: [
123
+ // Removing the last unit bit removes the key: an empty kind is an
124
+ // absent property here, never a zero.
125
+ () => assertStructurallySame(
126
+ withoutUnits(unitBit(undefined))({ unit: unitBit(undefined) }),
127
+ never),
128
+ () => assertStructurallySame(
129
+ withoutUnits(unitBit(undefined))({ unit: unitBit(undefined) | unitBit(null) }),
130
+ { unit: unitBit(null) }),
131
+ // Bits that are not set are a no-op.
132
+ () => assertStructurallySame(
133
+ withoutUnits(unitBit(undefined))({ unit: unitBit(null) }),
134
+ { unit: unitBit(null) }),
135
+ () => assertStructurallySame(withoutUnits(unitBit(undefined))(never), never),
136
+ // The other five kinds are carried through untouched — this is what
137
+ // enumerating `UnionSet`'s members by hand would silently drop.
138
+ () => assertStructurallySame(
139
+ withoutUnits(unitBit(undefined))(unknown),
140
+ { ...unknown, unit: unitBit(null) | unitBit(false) | unitBit(true) }),
141
+ () => assertStructurallySame(
142
+ withoutUnits(unitBit(undefined))({ unit: unitBit(undefined), string: true }),
143
+ { string: true }),
144
+ ],
122
145
  unitBits: () => {
123
146
  // the literal bits are the encoding under test
124
147
  assertEq(unitList.join(), 'null,undefined,false,true')
@@ -5,24 +5,34 @@
5
5
  * a `Parse<T>` function. When called with an unknown value, it returns a `Result`
6
6
  * that is either `['ok', newValue]` or `['error', { path, message }]`.
7
7
  *
8
- * Unlike `validate`, which checks an existing value in-place and returns it
9
- * unchanged on success, `parse` always returns a freshly constructed value that
10
- * contains only the fields/elements declared by the schema. This makes both
11
- * structs and tuples effectively closed at runtime, matching the TypeScript
12
- * type produced by `Ts<T>`:
13
- *
14
- * - Tuples: the result has exactly the schema's length; extra elements are dropped.
15
- * - Structs: the result contains only the schema's keys; extra properties are dropped.
8
+ * **Structs and tuples are open.** A value carrying more than the schema
9
+ * declares is accepted; `parse` then returns a freshly constructed value that
10
+ * contains only the declared fields/elements, so the extras are accepted on
11
+ * the way in and absent on the way out:
12
+ *
13
+ * - Tuples: a longer array is accepted; the result has the schema's length.
14
+ * - Structs: undeclared properties are accepted; the result has only the
15
+ * schema's keys.
16
16
  * - Arrays/records: every element/value is itself parsed, so a fresh container is
17
17
  * always returned even if the inner type is a primitive.
18
18
  *
19
- * This also provides forward compatibility with extended serialization formats:
20
- * a schema-based parser keeps working when newer versions of the format add
21
- * extra fields or tuple elements.
19
+ * A member is required exactly when its set excludes `undefined` — an absent
20
+ * member reads as `undefined`, on both kinds so a shorter array whose
21
+ * trailing position admits `undefined` is accepted and the gap is filled.
22
+ *
23
+ * Openness is what makes this forward-compatible with extended serialization
24
+ * formats: a schema-based parser keeps working when newer versions of the
25
+ * format add extra fields or tuple elements.
26
+ *
27
+ * **Do not read "the result has the schema's length" as "tuples are closed"
28
+ * and add a length check here.** The set a tuple schema describes includes
29
+ * longer arrays; `Ts<T>` renders the closed approximation only because
30
+ * TypeScript cannot express the open one (see `../ts/types.ts` `TupleTs`), and
31
+ * taking that rendering for the model is what produced #1622. A schema that
32
+ * wants exact members says so — see `../todo/close-type.md`.
22
33
  *
23
34
  * The error shape, path bookkeeping, primitive checks, and schema
24
- * recognition (`visit`) are shared with `validate` through
25
- * `../common/module.f.mjs`; only container construction differs.
35
+ * recognition (`visit`) come from `../common/module.f.mjs`.
26
36
  *
27
37
  * See `./types.ts` for the `Result`/`Parse` type-level API.
28
38
  *
@@ -32,7 +42,7 @@
32
42
  * @import { Result as CommonResult } from '../../result/types.ts'
33
43
  * @import { StringMap } from '../../object/types.ts'
34
44
  * @import { List } from '../../list/types.ts'
35
- * @import { Container, IsContainer, ValidateE, ValidationError, Visitor } from '../common/types.ts'
45
+ * @import { Container, IsContainer, ValidationError, Visitor } from '../common/types.ts'
36
46
  * @import { Unknown } from '../ts/types.ts'
37
47
  * @import { Parse } from './types.ts'
38
48
  */
@@ -5,24 +5,34 @@
5
5
  * a `Parse<T>` function. When called with an unknown value, it returns a `Result`
6
6
  * that is either `['ok', newValue]` or `['error', { path, message }]`.
7
7
  *
8
- * Unlike `validate`, which checks an existing value in-place and returns it
9
- * unchanged on success, `parse` always returns a freshly constructed value that
10
- * contains only the fields/elements declared by the schema. This makes both
11
- * structs and tuples effectively closed at runtime, matching the TypeScript
12
- * type produced by `Ts<T>`:
8
+ * **Structs and tuples are open.** A value carrying more than the schema
9
+ * declares is accepted; `parse` then returns a freshly constructed value that
10
+ * contains only the declared fields/elements, so the extras are accepted on
11
+ * the way in and absent on the way out:
13
12
  *
14
- * - Tuples: the result has exactly the schema's length; extra elements are dropped.
15
- * - Structs: the result contains only the schema's keys; extra properties are dropped.
13
+ * - Tuples: a longer array is accepted; the result has the schema's length.
14
+ * - Structs: undeclared properties are accepted; the result has only the
15
+ * schema's keys.
16
16
  * - Arrays/records: every element/value is itself parsed, so a fresh container is
17
17
  * always returned even if the inner type is a primitive.
18
18
  *
19
- * This also provides forward compatibility with extended serialization formats:
20
- * a schema-based parser keeps working when newer versions of the format add
21
- * extra fields or tuple elements.
19
+ * A member is required exactly when its set excludes `undefined` — an absent
20
+ * member reads as `undefined`, on both kinds so a shorter array whose
21
+ * trailing position admits `undefined` is accepted and the gap is filled.
22
+ *
23
+ * Openness is what makes this forward-compatible with extended serialization
24
+ * formats: a schema-based parser keeps working when newer versions of the
25
+ * format add extra fields or tuple elements.
26
+ *
27
+ * **Do not read "the result has the schema's length" as "tuples are closed"
28
+ * and add a length check here.** The set a tuple schema describes includes
29
+ * longer arrays; `Ts<T>` renders the closed approximation only because
30
+ * TypeScript cannot express the open one (see `../ts/types.ts` `TupleTs`), and
31
+ * taking that rendering for the model is what produced #1622. A schema that
32
+ * wants exact members says so — see `../todo/close-type.md`.
22
33
  *
23
34
  * The error shape, path bookkeeping, primitive checks, and schema
24
- * recognition (`visit`) are shared with `validate` through
25
- * `../common/module.f.mjs`; only container construction differs.
35
+ * recognition (`visit`) come from `../common/module.f.mjs`.
26
36
  *
27
37
  * See `./types.ts` for the `Result`/`Parse` type-level API.
28
38
  *
@@ -32,7 +42,7 @@
32
42
  * @import { Result as CommonResult } from '../../result/types.ts'
33
43
  * @import { StringMap } from '../../object/types.ts'
34
44
  * @import { List } from '../../list/types.ts'
35
- * @import { Container, IsContainer, ValidateE, ValidationError, Visitor } from '../common/types.ts'
45
+ * @import { Container, IsContainer, ValidationError, Visitor } from '../common/types.ts'
36
46
  * @import { Unknown } from '../ts/types.ts'
37
47
  * @import { Parse } from './types.ts'
38
48
  */
@@ -78,11 +88,10 @@ const orderedEntries = list =>
78
88
  toArray(reverse(list))
79
89
 
80
90
  /**
81
- * Builds a parser for `array` or `record` schemas. Mirrors `validate`'s
82
- * `containerValidate`, but rebuilds a fresh container from each item's parsed
83
- * result instead of returning the value unchanged. The inner item parser is
84
- * instantiated lazily (only when the container is non-empty) so recursive
85
- * schemas don't recurse forever on empty containers.
91
+ * Builds a parser for `array` or `record` schemas: rebuilds a fresh container
92
+ * from each item's parsed result. The inner item parser is instantiated lazily
93
+ * (only when the container is non-empty) so recursive schemas don't recurse
94
+ * forever on empty containers.
86
95
  */
87
96
  const containerParse =
88
97
  /**
@@ -100,7 +109,7 @@ const containerParse =
100
109
  if (e.length === 0) {
101
110
  return /** @type {any} */ (ok(rebuild([])))
102
111
  }
103
- const itemParse = /** @type {(v: Unknown) => _ItemResult} */ (/** @type {any} */ (parse(item)))
112
+ const itemParse = /** @type {any} */ (parse(item))
104
113
  const r = eachEntry(e, (_k, v) => itemParse(v), emptyEntries, consEntry)
105
114
  return r[0] === 'error' ? r : /** @type {any} */ (ok(rebuild(orderedEntries(r[1]))))
106
115
  }
@@ -110,10 +119,10 @@ const arrayParse = containerParse(isArray, arrayRebuild)
110
119
  const recordParse = containerParse(isObject, recordRebuild)
111
120
 
112
121
  /**
113
- * Builds a parser for `Tuple` or `Struct` const schemas. Mirrors `validate`'s
114
- * `constContainerValidate`: it iterates the schema's entries (so extra tuple
115
- * elements and undeclared struct keys are dropped) and rebuilds the result
116
- * from each parsed item.
122
+ * Builds a parser for `Tuple` or `Struct` const schemas. It iterates the
123
+ * *schema's* entries, which is what makes both kinds open: a longer array or
124
+ * an undeclared key is never visited, so it is accepted and left out of the
125
+ * rebuilt result.
117
126
  */
118
127
  const constContainerParse =
119
128
  /**
@@ -130,7 +139,7 @@ const constContainerParse =
130
139
  }
131
140
  const r = eachEntry(
132
141
  entries(rtti),
133
- (k, t) => /** @type {_ItemResult} */ (/** @type {any} */ (parse(t))(getItem(value, k))),
142
+ (k, t) => (/** @type {any} */ (parse(t))(getItem(value, k))),
134
143
  emptyEntries,
135
144
  consEntry,
136
145
  )
@@ -156,7 +165,7 @@ const orParse =
156
165
  * @returns {Parse<() => readonly ['or', ...T]>}
157
166
  */
158
167
  rtti =>
159
- /** @type {any} */ (orVisit(/** @type {(t: Type) => ValidateE} */ (/** @type {any} */ (parse)))(rtti))
168
+ /** @type {any} */ (orVisit(/** @type {any} */ (parse))(rtti))
160
169
 
161
170
  /**
162
171
  * Creates a parser function for the given RTTI schema.
@@ -175,10 +184,10 @@ const orParse =
175
184
  * p([1, 2, 3]) // ['ok', [1, 2, 3]] (a new array)
176
185
  * p([1, 'two']) // ['error', { path: ['1'], message: 'unexpected value' }]
177
186
  *
178
- * // tuples are closed: extra elements are dropped
187
+ * // open: a longer array is accepted, and the extra is not carried over
179
188
  * parse([number, number])([1, 2, 3]) // ['ok', [1, 2]]
180
189
  *
181
- * // structs drop undeclared keys
190
+ * // open: an undeclared key is accepted, and not carried over
182
191
  * parse({ a: number })({ a: 1, b: 2 }) // ['ok', { a: 1 }]
183
192
  * ```
184
193
  */
@@ -195,4 +204,4 @@ const parseVisitor = /** @type {any} */ ({
195
204
 
196
205
  /** @type {<T extends Type>(rtti: T) => Parse<T>} */
197
206
  export const parse = rtti =>
198
- /** @type {any} */ (visit(parseVisitor)(rtti))
207
+ (visit(parseVisitor)(rtti))
@@ -64,12 +64,13 @@ export declare const proof: {
64
64
  };
65
65
  tuple: {
66
66
  ok: () => void;
67
- extraItemsDropped: () => void;
67
+ extraItemsAcceptedAndDropped: () => void;
68
+ shortArrayFillsAnOptionalPosition: () => void;
68
69
  error: () => void;
69
70
  };
70
71
  struct: {
71
72
  ok: () => void;
72
- extraKeysDropped: () => void;
73
+ extraKeysAcceptedAndDropped: () => void;
73
74
  error: () => void;
74
75
  };
75
76
  };