functionalscript 0.46.0 → 0.47.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 (178) hide show
  1. package/fjs/basen/cbase32/module.f.mjs +18 -10
  2. package/fjs/basen/cbase32/proof.f.d.mts +3 -0
  3. package/fjs/basen/cbase32/proof.f.mjs +24 -2
  4. package/fjs/basen/proof.f.mjs +8 -16
  5. package/fjs/bnf/ll1/proof.f.d.mts +2 -0
  6. package/fjs/bnf/ll1/proof.f.mjs +33 -18
  7. package/fjs/bnf/module.f.d.mts +2 -2
  8. package/fjs/bnf/module.f.mjs +2 -2
  9. package/fjs/cas/proof.f.mjs +4 -26
  10. package/fjs/ci/common/module.f.mjs +6 -0
  11. package/fjs/ci/config/module.f.d.mts +7 -7
  12. package/fjs/ci/config/module.f.mjs +7 -7
  13. package/fjs/cli/module.f.mjs +14 -10
  14. package/fjs/crypto/vdf/module.f.d.mts +0 -1
  15. package/fjs/crypto/vdf/module.f.mjs +3 -14
  16. package/fjs/dev/module.f.mjs +10 -20
  17. package/fjs/djs/parser/module.f.d.mts +101 -53
  18. package/fjs/djs/parser/module.f.mjs +732 -525
  19. package/fjs/djs/parser/proof.f.d.mts +6 -0
  20. package/fjs/djs/parser/proof.f.mjs +315 -11
  21. package/fjs/djs/parser/types.d.ts +29 -2
  22. package/fjs/djs/tokenizer/module.f.mjs +122 -105
  23. package/fjs/djs/tokenizer/proof.f.mjs +17 -0
  24. package/fjs/djs/transpiler/module.f.mjs +4 -5
  25. package/fjs/djs/transpiler/proof.f.d.mts +2 -0
  26. package/fjs/djs/transpiler/proof.f.mjs +25 -0
  27. package/fjs/edag/amnesia/module.f.d.mts +20 -0
  28. package/fjs/edag/amnesia/module.f.mjs +303 -0
  29. package/fjs/edag/amnesia/proof.f.d.mts +79 -0
  30. package/fjs/edag/amnesia/proof.f.mjs +573 -0
  31. package/fjs/edag/amnesia/types.d.ts +15 -0
  32. package/fjs/edag/module.f.d.mts +410 -0
  33. package/fjs/edag/module.f.mjs +559 -0
  34. package/fjs/edag/proof.f.d.mts +116 -0
  35. package/fjs/edag/proof.f.mjs +686 -0
  36. package/fjs/edag/types.d.ts +55 -0
  37. package/fjs/effects/node/memory/module.d.mts +37 -3
  38. package/fjs/effects/node/memory/module.mjs +38 -4
  39. package/fjs/effects/node/memory/proof.d.mts +5 -2
  40. package/fjs/effects/node/memory/proof.mjs +36 -6
  41. package/fjs/effects/node/module.d.mts +9 -1
  42. package/fjs/effects/node/module.f.d.mts +39 -0
  43. package/fjs/effects/node/module.f.mjs +46 -0
  44. package/fjs/effects/node/module.mjs +234 -32
  45. package/fjs/effects/node/types.d.ts +28 -2
  46. package/fjs/effects/node/virtual/module.f.d.mts +19 -10
  47. package/fjs/effects/node/virtual/module.f.mjs +246 -32
  48. package/fjs/effects/node/virtual/proof.f.d.mts +17 -2
  49. package/fjs/effects/node/virtual/proof.f.mjs +232 -8
  50. package/fjs/effects/node/virtual/types.d.ts +57 -1
  51. package/fjs/emergent_testing/browser/proof.d.mts +55 -0
  52. package/fjs/emergent_testing/browser/proof.mjs +352 -0
  53. package/fjs/emergent_testing/browser/species.proof.d.mts +4 -0
  54. package/fjs/emergent_testing/browser/species.proof.mjs +45 -0
  55. package/fjs/emergent_testing/browser.d.mts +79 -0
  56. package/fjs/emergent_testing/browser.mjs +432 -0
  57. package/fjs/emergent_testing/proof.f.d.mts +1 -1
  58. package/fjs/emergent_testing/proof.f.mjs +2 -2
  59. package/fjs/js/string_escape/module.f.d.mts +47 -0
  60. package/fjs/js/string_escape/module.f.mjs +95 -0
  61. package/fjs/js/string_escape/proof.f.d.mts +8 -0
  62. package/fjs/js/string_escape/proof.f.mjs +68 -0
  63. package/fjs/js/tokenizer/module.f.mjs +14 -12
  64. package/fjs/mcp/cas/module.f.d.mts +1 -7
  65. package/fjs/mcp/cas/module.f.mjs +24 -15
  66. package/fjs/mcp/evo/module.f.mjs +9 -24
  67. package/fjs/mcp/module.f.d.mts +3 -1
  68. package/fjs/mcp/module.f.mjs +4 -2
  69. package/fjs/media/json/rtti/module.f.d.mts +2 -2
  70. package/fjs/media/json/rtti/module.f.mjs +1 -1
  71. package/fjs/media/json/schema/module.f.d.mts +15 -5
  72. package/fjs/media/json/schema/module.f.mjs +42 -15
  73. package/fjs/media/json/schema/proof.f.d.mts +10 -1
  74. package/fjs/media/json/schema/proof.f.mjs +88 -16
  75. package/fjs/media/json/serializer/module.f.mjs +14 -26
  76. package/fjs/media/json/types.d.ts +1 -1
  77. package/fjs/media/lock/module.f.d.mts +8 -3
  78. package/fjs/media/lock/module.f.mjs +9 -3
  79. package/fjs/media/lock/proof.f.d.mts +1 -1
  80. package/fjs/media/lock/proof.f.mjs +2 -2
  81. package/fjs/media/lock/types.d.ts +1 -3
  82. package/fjs/media/module.f.d.mts +20 -13
  83. package/fjs/media/module.f.mjs +29 -16
  84. package/fjs/media/note/module.f.d.mts +14 -7
  85. package/fjs/media/note/module.f.mjs +14 -7
  86. package/fjs/media/note/proof.f.mjs +1 -1
  87. package/fjs/media/proof.f.mjs +5 -5
  88. package/fjs/media/revision/module.f.d.mts +8 -2
  89. package/fjs/media/revision/module.f.mjs +9 -3
  90. package/fjs/media/revision/proof.f.mjs +1 -1
  91. package/fjs/media/revision/types.d.ts +1 -1
  92. package/fjs/media/type/module.f.d.mts +20 -0
  93. package/fjs/media/type/module.f.mjs +74 -0
  94. package/fjs/media/type/proof.f.d.mts +5 -0
  95. package/fjs/media/type/proof.f.mjs +24 -1
  96. package/fjs/module.f.mjs +6 -0
  97. package/fjs/path/module.f.d.mts +60 -3
  98. package/fjs/path/module.f.mjs +138 -14
  99. package/fjs/path/proof.f.d.mts +3 -0
  100. package/fjs/path/proof.f.mjs +298 -2
  101. package/fjs/protocol/json_rpc/module.f.d.mts +65 -28
  102. package/fjs/protocol/json_rpc/module.f.mjs +49 -13
  103. package/fjs/protocol/json_rpc/proof.f.d.mts +4 -0
  104. package/fjs/protocol/json_rpc/proof.f.mjs +29 -0
  105. package/fjs/protocol/json_rpc/types.d.ts +12 -2
  106. package/fjs/protocol/mcp/module.f.d.mts +89 -54
  107. package/fjs/protocol/mcp/module.f.mjs +110 -56
  108. package/fjs/protocol/mcp/proof.f.d.mts +13 -0
  109. package/fjs/protocol/mcp/proof.f.mjs +107 -7
  110. package/fjs/protocol/mcp/stdio/module.f.mjs +3 -4
  111. package/fjs/protocol/mcp/stdio/proof.f.mjs +2 -2
  112. package/fjs/protocol/mcp/types.d.ts +14 -2
  113. package/fjs/text/utf8/module.f.mjs +27 -1
  114. package/fjs/text/utf8/proof.f.mjs +37 -0
  115. package/fjs/types/array/module.f.mjs +18 -11
  116. package/fjs/types/array/proof.f.mjs +27 -1
  117. package/fjs/types/bigfloat/module.f.d.mts +48 -9
  118. package/fjs/types/bigfloat/module.f.mjs +147 -59
  119. package/fjs/types/bigfloat/proof.f.d.mts +2 -0
  120. package/fjs/types/bigfloat/proof.f.mjs +136 -4
  121. package/fjs/types/bigfloat/types.d.ts +17 -0
  122. package/fjs/types/function/module.f.d.mts +11 -2
  123. package/fjs/types/function/module.f.mjs +20 -2
  124. package/fjs/types/function/proof.f.mjs +5 -1
  125. package/fjs/types/phantom/types.d.ts +21 -0
  126. package/fjs/types/result/module.f.d.mts +4 -4
  127. package/fjs/types/result/module.f.mjs +2 -2
  128. package/fjs/types/result/proof.f.d.mts +6 -2
  129. package/fjs/types/result/proof.f.mjs +17 -1
  130. package/fjs/types/rtti/common/module.f.d.mts +78 -5
  131. package/fjs/types/rtti/common/module.f.mjs +168 -3
  132. package/fjs/types/rtti/common/proof.f.d.mts +14 -0
  133. package/fjs/types/rtti/common/proof.f.mjs +61 -2
  134. package/fjs/types/rtti/common/types.d.ts +23 -1
  135. package/fjs/types/rtti/data/module.f.d.mts +57 -1
  136. package/fjs/types/rtti/data/module.f.mjs +241 -47
  137. package/fjs/types/rtti/data/proof.f.d.mts +10 -0
  138. package/fjs/types/rtti/data/proof.f.mjs +272 -39
  139. package/fjs/types/rtti/data/types.d.ts +14 -7
  140. package/fjs/types/rtti/host.proof.d.mts +33 -0
  141. package/fjs/types/rtti/host.proof.mjs +170 -0
  142. package/fjs/types/rtti/module.f.d.mts +51 -6
  143. package/fjs/types/rtti/module.f.mjs +50 -3
  144. package/fjs/types/rtti/parse/module.f.d.mts +31 -24
  145. package/fjs/types/rtti/parse/module.f.mjs +197 -59
  146. package/fjs/types/rtti/parse/proof.f.d.mts +37 -2
  147. package/fjs/types/rtti/parse/proof.f.mjs +171 -47
  148. package/fjs/types/rtti/proof.f.d.mts +6 -0
  149. package/fjs/types/rtti/proof.f.mjs +42 -1
  150. package/fjs/types/rtti/ts/module.f.d.mts +9 -3
  151. package/fjs/types/rtti/ts/module.f.mjs +68 -15
  152. package/fjs/types/rtti/ts/proof.f.d.mts +42 -2
  153. package/fjs/types/rtti/ts/proof.f.mjs +139 -6
  154. package/fjs/types/rtti/ts/types.d.ts +164 -16
  155. package/fjs/types/rtti/types.d.ts +31 -3
  156. package/fjs/types/rtti/validate/module.f.d.mts +120 -0
  157. package/fjs/types/rtti/validate/module.f.mjs +351 -0
  158. package/fjs/types/rtti/validate/proof.f.d.mts +154 -0
  159. package/fjs/types/rtti/validate/proof.f.mjs +781 -0
  160. package/fjs/types/ts/types.d.ts +4 -0
  161. package/fjs/web/module.f.d.mts +115 -0
  162. package/fjs/web/module.f.mjs +581 -0
  163. package/fjs/web/proof.f.d.mts +39 -0
  164. package/fjs/web/proof.f.mjs +413 -0
  165. package/fjs/web/types.d.ts +39 -0
  166. package/fjs/website/browser-prepare.d.mts +5 -0
  167. package/fjs/website/browser-prepare.mjs +115 -0
  168. package/fjs/website/browser-source.d.mts +37 -0
  169. package/fjs/website/browser-source.mjs +202 -0
  170. package/fjs/website/browser-source.proof.d.mts +31 -0
  171. package/fjs/website/browser-source.proof.mjs +162 -0
  172. package/fjs/website/browser.d.mts +5 -0
  173. package/fjs/website/browser.mjs +8 -0
  174. package/fjs/website/module.f.d.mts +3 -3
  175. package/fjs/website/module.f.mjs +62 -9
  176. package/fjs/website/proof.f.d.mts +4 -0
  177. package/fjs/website/proof.f.mjs +18 -3
  178. package/package.json +2 -3
@@ -0,0 +1,351 @@
1
+ /**
2
+ * Runtime validation of unknown values against RTTI schemas — the verbatim
3
+ * reader.
4
+ *
5
+ * The main entry point is `validate(rtti)`, which takes a schema `Type` and
6
+ * returns a `Validate<T>` function. When called with an unknown value, it
7
+ * returns a `Result` that is either `['ok', value]` — **the value it was
8
+ * given** — or `['error', { path, message }]`.
9
+ *
10
+ * ## What distinguishes it from `parse`
11
+ *
12
+ * `../parse/module.f.mjs` answers "read this value as `T`" and builds a fresh
13
+ * value holding exactly what the schema declares. `validate` answers "is this
14
+ * value a `T`?" about the value itself, so on success the caller keeps the
15
+ * object it passed in — same reference, same members, same serialization:
16
+ *
17
+ * ```js
18
+ * const schema = { a: number, b: option(string) }
19
+ * parse(schema)({ a: 1, extra: 'x' }) // ['ok', { a: 1, b: undefined }]
20
+ * validate(schema)({ a: 1, extra: 'x' }) // ['ok', { a: 1, extra: 'x' }]
21
+ * ```
22
+ *
23
+ * The two agree on **acceptance**: every value one accepts the other accepts,
24
+ * with the same error `path` and `message`. They differ only in what a success
25
+ * carries. `./proof.f.mjs` pins that agreement as a table rather than leaving
26
+ * it to convention. Which reader a caller wants, and why both exist, is in
27
+ * "The two schema-form readers" in `../README.md`.
28
+ *
29
+ * ## Structs and tuples are closed
30
+ *
31
+ * Closedness is the shared rule, not a `parse` detail — see "Structs and
32
+ * tuples are closed" in `../README.md`. A bare `Struct` or `Tuple` admits the
33
+ * members it declares and no others, so an undeclared key or an index past the
34
+ * prefix rejects the value. A tuple answers by **length** as well as by
35
+ * member, because a hole past the prefix is no member and would slip through
36
+ * the member check alone.
37
+ *
38
+ * Closedness is about *undeclared* members and leaves the required/optional
39
+ * rule alone: an absent member reads as `undefined`, so a member is required
40
+ * exactly when its set excludes `undefined`, and a schema whose trailing
41
+ * position admits it still accepts a shorter array. A tuple schema declares by
42
+ * length, so a hole in the *schema* is a position whose schema is `undefined`
43
+ * — see "A hole is a declared position" in `../README.md`.
44
+ *
45
+ * The length check is the model rather than an inference from `Ts<>`. #1622
46
+ * added one by reading `Ts<readonly[42]>`'s exact tuple as the value model
47
+ * while the model said open, and it was reverted for that reason; what has
48
+ * changed since is the model, not the reading.
49
+ *
50
+ * ## Stated rests
51
+ *
52
+ * `rest(c, r)` admits the declared members plus any number of members
53
+ * belonging to `r`, and `open(c)` — `rest(c, unknown)` — admits anything else
54
+ * besides. This widens what is accepted and changes nothing else: a success
55
+ * still carries the very value it was given, undeclared members included.
56
+ *
57
+ * ## Dispatch strategy
58
+ *
59
+ * Schema recognition is delegated to `visit` in `../common/module.f.mjs`,
60
+ * which routes each `Type` variant to a handler in the `Visitor` record
61
+ * defined below; nothing here walks the `Type` ADT itself. The container
62
+ * handlers drive `eachEntry` in its no-accumulator mode — the mode its JSDoc
63
+ * describes for "a caller whose whole question is 'did every entry
64
+ * succeed?'" — so a validation allocates nothing per entry. The data form's
65
+ * `validate` (`../data/module.f.mjs`) is the same shape over `Data`.
66
+ *
67
+ * ## Recursion safety
68
+ *
69
+ * The inner validator of an `array`, a `record` or a `rest` is instantiated
70
+ * lazily — only after confirming there is a member for it to read. This
71
+ * prevents infinite recursion when validating recursive schemas like
72
+ * `const list = () => ['array', list]`.
73
+ *
74
+ * See `./types.ts` for the `Path`/`Result`/`Validate`/`ValidationError`
75
+ * type-level API.
76
+ *
77
+ * @module
78
+ *
79
+ * @import { Unknown } from '../ts/types.ts'
80
+ * @import { ConstObject, Info1, Tag1, Type } from '../types.ts'
81
+ * @import { Container, Fits, IsContainer, SchemaEntries, Validate, ValidateE, Visitor } from '../common/types.ts'
82
+ * @import { StringMap } from '../../object/types.ts'
83
+ */
84
+
85
+ import { ok } from '../../result/module.f.mjs'
86
+ import {
87
+ constPrimitiveValidate,
88
+ eachEntry,
89
+ isArray,
90
+ isObject,
91
+ orVisit,
92
+ primitive0Validate,
93
+ structSchemaEntries,
94
+ tupleSchemaEntries,
95
+ undeclaredMembers,
96
+ verror,
97
+ visit,
98
+ } from '../common/module.f.mjs'
99
+ import { emptyRest } from '../data/module.f.mjs'
100
+
101
+ /** `validate` has nothing to collect from a successful entry — only pass/fail matters. */
102
+ const noAccumulate = () => undefined
103
+
104
+ /** A uniform container declares no member by name, so every one is undeclared. */
105
+ /** @type {readonly string[]} */
106
+ const noDeclared = []
107
+
108
+ /**
109
+ * Builds a validator for `array` or `record` schemas.
110
+ * The inner item validator is instantiated lazily (only when the container is
111
+ * non-empty) to avoid infinite recursion with recursive schemas.
112
+ *
113
+ * The members are `undeclaredMembers`', not `Object.entries`': `array(t)` is
114
+ * `rest([], t)`, so the two have to walk a value the same way — an own-entry
115
+ * walk here skipped an index the prototype supplies while the data form's
116
+ * reader found it, which broke the acceptance agreement the three readers are
117
+ * pinned on.
118
+ *
119
+ * `fits` bounds the array kind's length when its element set admits nothing,
120
+ * which is what the data form says by normalizing such a `rest` away: an
121
+ * `array(or())` is the *empty* array and not "any number of holes". It is
122
+ * consulted only where it can change the answer — no member present, and the
123
+ * value reaching further than that — so an ordinary array never asks.
124
+ */
125
+ const containerValidate =
126
+ /**
127
+ * @template {Tag1} K
128
+ * @param {IsContainer<Container<K>>} isContainer
129
+ * @param {(item: Type) => Fits<Container<K>>} restFits
130
+ * @returns {<I extends Type>(item: I) => Validate<Info1<K, I>>}
131
+ */
132
+ (isContainer, restFits) =>
133
+ item => {
134
+ // Depends on the schema alone, so it is built once per schema rather
135
+ // than once per validated value.
136
+ const fits = restFits(item)
137
+ return value => {
138
+ if (!isContainer(value)) {
139
+ return verror('unexpected value')
140
+ }
141
+ const e = undeclaredMembers(noDeclared, value)
142
+ if (e.length === 0) {
143
+ return fits(value, 0)
144
+ ? /** @type {any} */ (ok(value))
145
+ : verror('unexpected value')
146
+ }
147
+ // Note: we shouldn't instantiate `itemValidate` until we make sure `entries` is not empty.
148
+ // Otherwise, we can get infinite recursion on empty arrays and objects
149
+ const itemValidate = validate(item)
150
+ const r = eachEntry(e, (_k, v) => itemValidate(v), undefined, noAccumulate)
151
+ // `value` is Container<K>, but Ts<Info1<K,I>> = readonly Ts<I>[] | Record<string,Ts<I>>.
152
+ // TypeScript can't narrow the container's element types through the validation loop.
153
+ return r[0] === 'error' ? r : /** @type {any} */ (ok(value))
154
+ }
155
+ }
156
+
157
+ const arrayValidate = containerValidate(
158
+ isArray,
159
+ // The cast is the price of one factory over two kinds: `Container<K>` is
160
+ // the union until `K` is bound, and only the array arm has a `length`.
161
+ item => (value, declared) =>
162
+ /** @type {ReadonlyArray<Unknown>} */ (value).length <= declared || !emptyRest([], item),
163
+ )
164
+
165
+ const recordValidate = containerValidate(isObject, () => () => true)
166
+
167
+ /**
168
+ * Builds a validator for `Tuple` or `Struct` const schemas — **closed**: the
169
+ * members the schema declares and no others. It reads each declared member,
170
+ * then answers for every member of the value the schema does not name.
171
+ *
172
+ * `fits` is the one thing the two kinds do not share. An undeclared member is
173
+ * a member on both, but an array is also *as long as it is*: a hole past the
174
+ * prefix is no member and would slip through the member check alone, so the
175
+ * array kind answers with its length as well.
176
+ */
177
+ const constContainerValidate =
178
+ /**
179
+ * @template {ReadonlyArray<Unknown> | StringMap<Unknown>} C
180
+ * @template {ConstObject} S
181
+ * @param {IsContainer<C>} isContainer
182
+ * @param {SchemaEntries<S>} schemaEntries
183
+ * @param {(value: C, k: string) => Unknown} getItem
184
+ * @param {Fits<C>} fits
185
+ * @returns {<T extends S>(rtti: T) => Validate<T>}
186
+ */
187
+ (isContainer, schemaEntries, getItem, fits) =>
188
+ rtti => {
189
+ // Depend on `rtti` alone, so they are computed once per schema rather
190
+ // than once per validated value.
191
+ const rttiEntries = schemaEntries(rtti)
192
+ const declared = rttiEntries.map(([k]) => k)
193
+ return value => {
194
+ if (!isContainer(value)) {
195
+ return verror('unexpected value')
196
+ }
197
+ const r = eachEntry(
198
+ rttiEntries,
199
+ (k, v) => /** @type {any} */ (validate(v))(getItem(value, k)),
200
+ undefined,
201
+ noAccumulate,
202
+ )
203
+ if (r[0] === 'error') { return r }
204
+ // `value` is C (Unknown container), but Ts<T> for T extends Tuple|Struct is not
205
+ // structurally equivalent to C — TypeScript can't narrow element types through the loop.
206
+ return undeclaredMembers(declared, value).length === 0 && fits(value, declared.length)
207
+ ? /** @type {any} */ (ok(value))
208
+ : verror('unexpected value')
209
+ }
210
+ }
211
+
212
+ const tupleValidate = constContainerValidate(
213
+ isArray,
214
+ tupleSchemaEntries,
215
+ (value, k) => value[Number(k)],
216
+ (value, declared) => value.length <= declared,
217
+ )
218
+
219
+ const structValidate = constContainerValidate(
220
+ isObject,
221
+ structSchemaEntries,
222
+ (value, k) => value[k],
223
+ () => true,
224
+ )
225
+
226
+ /**
227
+ * Builds a validator for a container with a stated `rest`. The declared
228
+ * members are read exactly as the bare form reads them, and every member the
229
+ * schema does not name is held to `rest`.
230
+ *
231
+ * `restFits` carries the array kind's length bound, which a `rest` removes
232
+ * only while it admits something. An empty one says what the bare form says,
233
+ * so `rest(c, or())` and `c` stay one set — the criterion for "empty" is
234
+ * `emptyRest`'s, and it is consulted only when nothing is present past the
235
+ * prefix, since a member that got there and passed is itself the proof that
236
+ * the rest admits something.
237
+ */
238
+ const restContainerValidate =
239
+ /**
240
+ * @template {ReadonlyArray<Unknown> | StringMap<Unknown>} C
241
+ * @template {ConstObject} S
242
+ * @param {IsContainer<C>} isContainer
243
+ * @param {SchemaEntries<S>} schemaEntries
244
+ * @param {(value: C, k: string) => Unknown} getItem
245
+ * @param {(rtti: S, r: Type) => Fits<C>} restFits
246
+ * @returns {(rtti: S, r: Type) => ValidateE}
247
+ */
248
+ (isContainer, schemaEntries, getItem, restFits) =>
249
+ (rtti, r) => {
250
+ // Depend on the schema alone, so they are computed once per schema.
251
+ const rttiEntries = schemaEntries(rtti)
252
+ const declared = rttiEntries.map(([k]) => k)
253
+ const fits = restFits(rtti, r)
254
+ return value => {
255
+ if (!isContainer(value)) {
256
+ return verror('unexpected value')
257
+ }
258
+ const d = eachEntry(
259
+ rttiEntries,
260
+ (k, v) => /** @type {any} */ (validate(v))(getItem(value, k)),
261
+ undefined,
262
+ noAccumulate,
263
+ )
264
+ if (d[0] === 'error') { return d }
265
+ const extra = undeclaredMembers(declared, value)
266
+ if (extra.length === 0) {
267
+ return fits(value, declared.length) ? ok(value) : verror('unexpected value')
268
+ }
269
+ const restValidate = /** @type {any} */ (validate(r))
270
+ const e = eachEntry(extra, (_k, v) => restValidate(v), undefined, noAccumulate)
271
+ return e[0] === 'error' ? e : ok(value)
272
+ }
273
+ }
274
+
275
+ const restTupleValidate = restContainerValidate(
276
+ isArray,
277
+ tupleSchemaEntries,
278
+ (value, k) => value[Number(k)],
279
+ (rtti, r) => (value, declared) => value.length <= declared || !emptyRest(rtti, r),
280
+ )
281
+
282
+ const restStructValidate = restContainerValidate(
283
+ isObject,
284
+ structSchemaEntries,
285
+ (value, k) => value[k],
286
+ () => () => true,
287
+ )
288
+
289
+ /** @type {(rtti: ConstObject, r: Type) => ValidateE} */
290
+ const restValidate = (rtti, r) =>
291
+ rtti instanceof Array
292
+ ? restTupleValidate(rtti, r)
293
+ : restStructValidate(rtti, r)
294
+
295
+ const orValidate =
296
+ /**
297
+ * @template {readonly Type[]} T
298
+ * @param {T} rtti
299
+ * @returns {Validate<() => readonly ['or', ...T]>}
300
+ */
301
+ rtti =>
302
+ /** @type {any} */ (orVisit(/** @type {any} */ (validate))(rtti))
303
+
304
+ const validateVisitor = /** @type {any} */ ({
305
+ tuple: tupleValidate,
306
+ struct: structValidate,
307
+ rest: restValidate,
308
+ array: arrayValidate,
309
+ record: recordValidate,
310
+ or: orValidate,
311
+ constPrimitive: constPrimitiveValidate,
312
+ primitive0: primitive0Validate,
313
+ unknown: () => ok,
314
+ })
315
+
316
+ /**
317
+ * Creates a validator function for the given RTTI schema: a `Thunk` for
318
+ * tag-based schemas, or a `Const` (primitive literal, tuple, or struct) for
319
+ * exact-value schemas.
320
+ *
321
+ * The returned function takes an unknown value and returns either
322
+ * `['ok', value]` — the very value it was given, not a reconstruction — or
323
+ * `['error', { path, message }]` describing the failure location.
324
+ *
325
+ * Use it when the question is "is this value of this shape?" and the value has
326
+ * to survive the question intact. Use `../parse/module.f.mjs` when the answer
327
+ * wanted is a value built to the schema.
328
+ *
329
+ * @example
330
+ * ```js
331
+ * const v = validate(array(number))
332
+ * const input = [1, 2, 3]
333
+ * v(input) // ['ok', input] — the same array, not a copy
334
+ * v([1, 'two']) // ['error', { path: ['1'], message: 'unexpected value' }]
335
+ *
336
+ * // closed, so a member the schema does not name rejects the value
337
+ * validate([number, number])([1, 2, 3]) // ['error', …]
338
+ * validate({ a: number })({ a: 1, b: 2 }) // ['error', …]
339
+ *
340
+ * // an absent optional member stays absent
341
+ * validate({ a: number, b: option(string) })({ a: 1 }) // ['ok', { a: 1 }]
342
+ *
343
+ * // a stated rest says what the undeclared members may be; `open` says anything
344
+ * validate(rest({ a: number }, number))({ a: 1, b: 2 }) // ['ok', { a: 1, b: 2 }]
345
+ * validate(open({ a: number }))({ a: 1, b: 'x' }) // ['ok', { a: 1, b: 'x' }]
346
+ * ```
347
+ *
348
+ * @type {<const T extends Type>(rtti: T) => Validate<T>}
349
+ */
350
+ export const validate = rtti =>
351
+ (visit(validateVisitor)(rtti))
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @import { ValidationError, ValidateE, Validate } from '../common/types.ts'
3
+ * @import { Type } from '../types.ts'
4
+ * @import { Equal } from '../../ts/types.ts'
5
+ * @import { Ts, Unknown } from '../ts/types.ts'
6
+ * @import { Unknown as DjsUnknown } from '../../../djs/types.ts'
7
+ * @import { Assert } from '../../../asserts/types.ts'
8
+ */
9
+ import { never } from '../module.f.mjs';
10
+ export type _RecursiveRest = () => readonly ['rest', readonly [_RecursiveRest], typeof never];
11
+ export type _OrCycleA = () => readonly ['or', _OrCycleB];
12
+ export type _OrCycleB = () => readonly ['or', _OrCycleA];
13
+ export type _SelfList = () => readonly ['or', undefined, () => readonly ['array', _SelfList]];
14
+ export declare const proof: {
15
+ verbatim: {
16
+ absentOptionalStaysAbsent: () => void;
17
+ undeclaredMemberSurvives: () => void;
18
+ referenceIdentity: () => void;
19
+ };
20
+ sameAcceptanceAsParse: () => void;
21
+ sameAcceptanceInTheDataForm: () => void;
22
+ optionalPositions: () => void;
23
+ interiorOptionBeforeRequired: () => void;
24
+ sparseTuple: {
25
+ holeIsDeclaredUndefined: () => void;
26
+ arityIsTheSchemaLength: () => void;
27
+ nonIndexPropertyIsNotDeclared: () => void;
28
+ };
29
+ boolean: {
30
+ ok: () => void;
31
+ error: () => void;
32
+ };
33
+ number: {
34
+ ok: () => void;
35
+ error: () => void;
36
+ };
37
+ string: {
38
+ ok: () => void;
39
+ error: () => void;
40
+ };
41
+ bigint: {
42
+ ok: () => void;
43
+ error: () => void;
44
+ };
45
+ unknown: {
46
+ ok: () => void;
47
+ };
48
+ const: {
49
+ null: {
50
+ ok: () => void;
51
+ error: () => void;
52
+ };
53
+ undefined: {
54
+ ok: () => void;
55
+ error: () => void;
56
+ };
57
+ number: {
58
+ ok: () => void;
59
+ error: () => void;
60
+ };
61
+ nan: {
62
+ ok: () => void;
63
+ error: () => void;
64
+ };
65
+ infinity: {
66
+ ok: () => void;
67
+ error: () => void;
68
+ };
69
+ signedZero: {
70
+ distinct: () => void;
71
+ self: () => void;
72
+ };
73
+ string: {
74
+ ok: () => void;
75
+ error: () => void;
76
+ };
77
+ bigint: {
78
+ ok: () => void;
79
+ error: () => void;
80
+ };
81
+ boolean: {
82
+ ok: () => void;
83
+ error: () => void;
84
+ };
85
+ tuple: {
86
+ ok: () => void;
87
+ extraItemsRejected: () => void;
88
+ shortArrayKeepsItsLength: () => void;
89
+ empty: () => void;
90
+ error: () => void;
91
+ };
92
+ struct: {
93
+ ok: () => void;
94
+ error: () => void;
95
+ };
96
+ };
97
+ array: {
98
+ empty: () => void;
99
+ ok: () => void;
100
+ error: () => void;
101
+ nested: () => void;
102
+ };
103
+ record: {
104
+ empty: () => void;
105
+ ok: () => void;
106
+ error: () => void;
107
+ };
108
+ constThunk: {
109
+ primitive: () => void;
110
+ };
111
+ or: {
112
+ consts: {
113
+ ok: () => void;
114
+ error: () => void;
115
+ };
116
+ thunks: {
117
+ ok: () => void;
118
+ error: () => void;
119
+ };
120
+ firstMatchWins: () => void;
121
+ };
122
+ option: {
123
+ ok: () => void;
124
+ error: () => void;
125
+ };
126
+ path: {
127
+ rootMismatch: () => void;
128
+ arrayIndex: () => void;
129
+ recordKey: () => void;
130
+ nestedArray: () => void;
131
+ tupleIndex: () => void;
132
+ structKey: () => void;
133
+ deepStruct: () => void;
134
+ recursiveSchema: () => void;
135
+ orRoot: () => void;
136
+ };
137
+ recursive: {
138
+ arrayOfArrays: () => void;
139
+ recordOfRecords: () => void;
140
+ };
141
+ rest: {
142
+ verbatim: () => void;
143
+ absentOptionalStaysAbsent: () => void;
144
+ path: () => void;
145
+ notAContainer: () => void;
146
+ };
147
+ emptyRests: {
148
+ dropped: () => void;
149
+ kept: () => void;
150
+ };
151
+ beyondAClosedPrefix: () => void;
152
+ lengthDoesNotBoundTheWalk: () => void;
153
+ arrayOptional: () => void;
154
+ };