functionalscript 0.45.0 → 0.46.1
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.
- package/README.md +5 -3
- package/fjs/asn.1/module.f.mjs +8 -1
- package/fjs/asn.1/proof.f.d.mts +10 -0
- package/fjs/asn.1/proof.f.mjs +16 -0
- package/fjs/basen/base128/module.f.mjs +22 -5
- package/fjs/bnf/data/module.f.d.mts +32 -6
- package/fjs/bnf/data/module.f.mjs +112 -7
- package/fjs/bnf/data/proof.f.d.mts +2 -0
- package/fjs/bnf/data/proof.f.mjs +74 -3
- package/fjs/bnf/data/types.d.ts +20 -2
- package/fjs/bnf/descent/module.f.d.mts +28 -14
- package/fjs/bnf/descent/module.f.mjs +122 -77
- package/fjs/bnf/descent/proof.f.d.mts +2 -0
- package/fjs/bnf/descent/proof.f.mjs +117 -31
- package/fjs/bnf/descent/types.d.ts +12 -14
- package/fjs/bnf/ll1/module.f.d.mts +64 -22
- package/fjs/bnf/ll1/module.f.mjs +214 -154
- package/fjs/bnf/ll1/proof.f.d.mts +15 -2
- package/fjs/bnf/ll1/proof.f.mjs +323 -149
- package/fjs/bnf/ll1/types.d.ts +16 -24
- package/fjs/bnf/matcher/module.f.d.mts +66 -0
- package/fjs/bnf/matcher/module.f.mjs +81 -0
- package/fjs/bnf/matcher/proof.f.d.mts +10 -0
- package/fjs/bnf/matcher/proof.f.mjs +79 -0
- package/fjs/bnf/matcher/types.d.ts +54 -0
- package/fjs/bnf/testlib.f.d.mts +31 -0
- package/fjs/bnf/testlib.f.mjs +80 -0
- package/fjs/cas/cli/module.f.d.mts +1 -1
- package/fjs/cas/cli/module.f.mjs +14 -20
- package/fjs/cas/cli/proof.f.d.mts +1 -3
- package/fjs/cas/cli/proof.f.mjs +44 -33
- package/fjs/cas/evo/module.f.d.mts +64 -18
- package/fjs/cas/evo/module.f.mjs +148 -70
- package/fjs/cas/evo/proof.f.d.mts +10 -1
- package/fjs/cas/evo/proof.f.mjs +305 -223
- package/fjs/cas/evo/types.d.ts +45 -9
- package/fjs/cas/module.f.d.mts +18 -32
- package/fjs/cas/module.f.mjs +129 -128
- package/fjs/cas/proof.f.d.mts +11 -8
- package/fjs/cas/proof.f.mjs +259 -147
- package/fjs/cas/types.d.ts +24 -10
- package/fjs/ci/config/module.f.d.mts +2 -2
- package/fjs/ci/config/module.f.mjs +2 -2
- package/fjs/ci/module.f.d.mts +5 -5
- package/fjs/ci/module.f.mjs +8 -7
- package/fjs/ci/nix/module.f.d.mts +7 -5
- package/fjs/ci/nix/module.f.mjs +13 -12
- package/fjs/ci/nix/proof.f.mjs +2 -2
- package/fjs/ci/proof.f.mjs +9 -5
- package/fjs/cli/module.f.d.mts +4 -6
- package/fjs/cli/module.f.mjs +4 -8
- package/fjs/cli/proof.f.mjs +17 -16
- package/fjs/cli/types.d.ts +2 -3
- package/fjs/common/monoid/types.d.ts +1 -1
- package/fjs/crypto/hmac/module.f.mjs +2 -2
- package/fjs/crypto/sha2/module.f.mjs +3 -1
- package/fjs/crypto/sha2/proof.f.d.mts +1 -0
- package/fjs/crypto/sha2/proof.f.mjs +24 -0
- package/fjs/crypto/sha2/types.d.ts +11 -0
- package/fjs/crypto/sign/module.f.mjs +2 -2
- package/fjs/dev/module.f.d.mts +13 -4
- package/fjs/dev/module.f.mjs +56 -27
- package/fjs/dev/update/module.f.d.mts +9 -4
- package/fjs/dev/update/module.f.mjs +14 -10
- package/fjs/dev/update/proof.f.d.mts +1 -3
- package/fjs/dev/update/proof.f.mjs +10 -5
- package/fjs/djs/module.f.d.mts +13 -5
- package/fjs/djs/module.f.mjs +31 -16
- package/fjs/djs/parser/module.f.d.mts +13 -3
- package/fjs/djs/parser/module.f.mjs +117 -16
- package/fjs/djs/parser/proof.f.d.mts +5 -1
- package/fjs/djs/parser/proof.f.mjs +274 -12
- package/fjs/djs/parser/types.d.ts +7 -1
- package/fjs/djs/proof.f.d.mts +18 -2
- package/fjs/djs/proof.f.mjs +187 -12
- package/fjs/djs/serializer/module.f.d.mts +25 -8
- package/fjs/djs/serializer/module.f.mjs +61 -15
- package/fjs/djs/serializer/proof.f.d.mts +5 -0
- package/fjs/djs/serializer/proof.f.mjs +23 -1
- package/fjs/djs/tokenizer/module.f.d.mts +17 -5
- package/fjs/djs/tokenizer/module.f.mjs +99 -60
- package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
- package/fjs/djs/tokenizer/proof.f.mjs +74 -67
- package/fjs/djs/transpiler/module.f.d.mts +12 -7
- package/fjs/djs/transpiler/module.f.mjs +82 -56
- package/fjs/djs/transpiler/types.d.ts +7 -3
- package/fjs/djs/types.d.ts +7 -1
- package/fjs/effects/list/module.f.d.mts +14 -11
- package/fjs/effects/list/module.f.mjs +13 -11
- package/fjs/effects/list/types.d.ts +27 -7
- package/fjs/effects/memory/module.f.d.mts +2 -1
- package/fjs/effects/memory/module.f.mjs +3 -4
- package/fjs/effects/memory/proof.f.mjs +13 -7
- package/fjs/effects/memory/types.d.ts +4 -3
- package/fjs/effects/mock/module.f.d.mts +20 -4
- package/fjs/effects/mock/module.f.mjs +37 -5
- package/fjs/effects/mock/types.d.ts +10 -1
- package/fjs/effects/module.d.mts +4 -2
- package/fjs/effects/module.f.d.mts +466 -280
- package/fjs/effects/module.f.mjs +537 -299
- package/fjs/effects/module.mjs +2 -1
- package/fjs/effects/node/memory/module.d.mts +4 -2
- package/fjs/effects/node/memory/module.mjs +6 -3
- package/fjs/effects/node/memory/proof.mjs +10 -4
- package/fjs/effects/node/module.d.mts +4 -3
- package/fjs/effects/node/module.f.d.mts +168 -33
- package/fjs/effects/node/module.f.mjs +256 -52
- package/fjs/effects/node/module.mjs +57 -34
- package/fjs/effects/node/proof.f.d.mts +28 -2
- package/fjs/effects/node/proof.f.mjs +161 -42
- package/fjs/effects/node/types.d.ts +106 -18
- package/fjs/effects/node/virtual/module.f.d.mts +18 -4
- package/fjs/effects/node/virtual/module.f.mjs +110 -68
- package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
- package/fjs/effects/node/virtual/proof.f.mjs +190 -9
- package/fjs/effects/proof.f.d.mts +69 -37
- package/fjs/effects/proof.f.mjs +410 -130
- package/fjs/effects/types.d.ts +161 -33
- package/fjs/emergent_testing/module.f.d.mts +19 -12
- package/fjs/emergent_testing/module.f.mjs +93 -33
- package/fjs/emergent_testing/proof.f.d.mts +21 -7
- package/fjs/emergent_testing/proof.f.mjs +166 -32
- package/fjs/emergent_testing/types.d.ts +22 -4
- package/fjs/fsm/module.f.d.mts +14 -4
- package/fjs/fsm/module.f.mjs +54 -37
- package/fjs/fsm/proof.f.d.mts +2 -0
- package/fjs/fsm/proof.f.mjs +83 -114
- package/fjs/js/keywords/module.f.d.mts +52 -0
- package/fjs/js/keywords/module.f.mjs +72 -0
- package/fjs/js/keywords/proof.f.d.mts +3 -0
- package/fjs/js/keywords/proof.f.mjs +13 -0
- package/fjs/js/tokenizer/module.f.d.mts +26 -6
- package/fjs/js/tokenizer/module.f.mjs +145 -159
- package/fjs/js/tokenizer/proof.f.d.mts +1 -0
- package/fjs/js/tokenizer/proof.f.mjs +54 -24
- package/fjs/js/tokenizer/types.d.ts +33 -24
- package/fjs/mcp/cas/module.f.d.mts +1 -6
- package/fjs/mcp/cas/module.f.mjs +55 -51
- package/fjs/mcp/cas/proof.f.d.mts +15 -0
- package/fjs/mcp/cas/proof.f.mjs +174 -0
- package/fjs/mcp/evo/module.f.d.mts +19 -10
- package/fjs/mcp/evo/module.f.mjs +48 -27
- package/fjs/mcp/evo/proof.f.d.mts +6 -1
- package/fjs/mcp/evo/proof.f.mjs +115 -31
- package/fjs/mcp/module.f.d.mts +4 -4
- package/fjs/mcp/module.f.mjs +6 -6
- package/fjs/mcp/proof.f.d.mts +5 -3
- package/fjs/mcp/proof.f.mjs +112 -46
- package/fjs/media/html/module.f.mjs +1 -1
- package/fjs/media/json/extended/module.f.d.mts +82 -0
- package/fjs/media/json/extended/module.f.mjs +153 -0
- package/fjs/media/json/extended/proof.f.d.mts +42 -0
- package/fjs/media/json/extended/proof.f.mjs +127 -0
- package/fjs/media/json/extended/types.d.ts +23 -0
- package/fjs/media/json/module.f.d.mts +8 -2
- package/fjs/media/json/module.f.mjs +43 -41
- package/fjs/media/json/number/module.f.d.mts +59 -0
- package/fjs/media/json/number/module.f.mjs +136 -0
- package/fjs/media/json/number/proof.f.d.mts +24 -0
- package/fjs/media/json/number/proof.f.mjs +86 -0
- package/fjs/media/json/number/types.d.ts +28 -0
- package/fjs/media/json/parser/module.f.d.mts +25 -13
- package/fjs/media/json/parser/module.f.mjs +114 -70
- package/fjs/media/json/parser/proof.f.d.mts +5 -0
- package/fjs/media/json/parser/proof.f.mjs +31 -1
- package/fjs/media/json/parser/types.d.ts +33 -14
- package/fjs/media/json/rtti/module.f.d.mts +1 -1
- package/fjs/media/json/rtti/module.f.mjs +1 -1
- package/fjs/media/json/rtti/proof.f.mjs +9 -9
- package/fjs/media/json/schema/module.f.mjs +3 -13
- package/fjs/media/json/schema/proof.f.d.mts +0 -1
- package/fjs/media/json/schema/proof.f.mjs +1 -2
- package/fjs/media/json/serializer/module.f.d.mts +32 -1
- package/fjs/media/json/serializer/module.f.mjs +64 -2
- package/fjs/media/json/tokenizer/module.f.mjs +7 -3
- package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
- package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
- package/fjs/media/json/types.d.ts +36 -10
- package/fjs/media/lock/module.f.d.mts +100 -0
- package/fjs/media/lock/module.f.mjs +125 -0
- package/fjs/media/lock/proof.f.d.mts +33 -0
- package/fjs/media/lock/proof.f.mjs +196 -0
- package/fjs/media/lock/types.d.ts +15 -0
- package/fjs/media/module.f.d.mts +6 -5
- package/fjs/media/module.f.mjs +8 -7
- package/fjs/media/note/module.f.d.mts +121 -0
- package/fjs/media/note/module.f.mjs +131 -0
- package/fjs/media/note/proof.f.d.mts +29 -0
- package/fjs/media/note/proof.f.mjs +150 -0
- package/fjs/media/note/types.d.ts +10 -0
- package/fjs/media/proof.f.d.mts +4 -1
- package/fjs/media/proof.f.mjs +40 -21
- package/fjs/media/revision/module.f.d.mts +78 -7
- package/fjs/media/revision/module.f.mjs +119 -12
- package/fjs/media/revision/proof.f.d.mts +10 -0
- package/fjs/media/revision/proof.f.mjs +88 -0
- package/fjs/media/revision/types.d.ts +34 -5
- package/fjs/media/type/module.f.d.mts +33 -15
- package/fjs/media/type/module.f.mjs +35 -29
- package/fjs/media/type/proof.f.d.mts +2 -1
- package/fjs/media/type/proof.f.mjs +30 -10
- package/fjs/module.f.mjs +29 -8
- package/fjs/nanvm/proof.f.mjs +3 -3
- package/fjs/nanvm/rust/module.f.mjs +1 -1
- package/fjs/nanvm/update/module.f.d.mts +4 -4
- package/fjs/nanvm/update/module.f.mjs +8 -9
- package/fjs/nanvm/update/proof.f.mjs +4 -3
- package/fjs/proof.f.d.mts +3 -3
- package/fjs/proof.f.mjs +36 -10
- package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
- package/fjs/protocol/json_rpc/module.f.mjs +3 -3
- package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
- package/fjs/protocol/mcp/module.f.d.mts +10 -13
- package/fjs/protocol/mcp/module.f.mjs +74 -58
- package/fjs/protocol/mcp/proof.f.d.mts +13 -4
- package/fjs/protocol/mcp/proof.f.mjs +193 -61
- package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
- package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
- package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
- package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
- package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
- package/fjs/protocol/mcp/types.d.ts +17 -6
- package/fjs/sul/id/module.f.d.mts +0 -1
- package/fjs/sul/id/module.f.mjs +2 -3
- package/fjs/sul/level/hash/module.f.mjs +2 -1
- package/fjs/sul/level/hash/proof.f.mjs +2 -2
- package/fjs/sul/module.f.mjs +18 -13
- package/fjs/text/code_point/module.f.d.mts +8 -0
- package/fjs/text/code_point/module.f.mjs +8 -1
- package/fjs/text/code_point/proof.f.d.mts +1 -0
- package/fjs/text/code_point/proof.f.mjs +11 -0
- package/fjs/text/sgr/module.f.d.mts +4 -6
- package/fjs/text/sgr/module.f.mjs +6 -7
- package/fjs/text/utf16/module.f.mjs +7 -2
- package/fjs/text/utf16/proof.f.mjs +3 -3
- package/fjs/text/utf8/module.f.mjs +4 -2
- package/fjs/types/array/module.f.mjs +14 -2
- package/fjs/types/bit_vec/module.f.d.mts +0 -2
- package/fjs/types/bit_vec/module.f.mjs +46 -32
- package/fjs/types/bit_vec/proof.f.mjs +2 -2
- package/fjs/types/btree/remove/module.f.mjs +1 -1
- package/fjs/types/btree/set/module.f.mjs +9 -11
- package/fjs/types/btree/set/proof.f.mjs +12 -0
- package/fjs/types/byte_set/module.f.d.mts +11 -4
- package/fjs/types/byte_set/module.f.mjs +14 -6
- package/fjs/types/byte_set/proof.f.mjs +7 -7
- package/fjs/types/function/compare/module.f.mjs +10 -3
- package/fjs/types/list/module.f.d.mts +1 -1
- package/fjs/types/list/module.f.mjs +1 -1
- package/fjs/types/nullable/module.f.d.mts +18 -4
- package/fjs/types/nullable/module.f.mjs +21 -4
- package/fjs/types/nullable/proof.f.d.mts +4 -0
- package/fjs/types/nullable/proof.f.mjs +15 -0
- package/fjs/types/object/module.f.d.mts +12 -2
- package/fjs/types/object/module.f.mjs +11 -1
- package/fjs/types/patricia_trie/module.f.mjs +26 -11
- package/fjs/types/result/module.f.d.mts +3 -3
- package/fjs/types/result/module.f.mjs +3 -3
- package/fjs/types/rtti/common/module.f.d.mts +25 -28
- package/fjs/types/rtti/common/module.f.mjs +36 -32
- package/fjs/types/rtti/common/proof.f.mjs +5 -5
- package/fjs/types/rtti/data/module.f.d.mts +14 -0
- package/fjs/types/rtti/data/module.f.mjs +25 -2
- package/fjs/types/rtti/data/proof.f.d.mts +1 -0
- package/fjs/types/rtti/data/proof.f.mjs +25 -2
- package/fjs/types/rtti/parse/module.f.d.mts +24 -14
- package/fjs/types/rtti/parse/module.f.mjs +37 -28
- package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
- package/fjs/types/rtti/parse/proof.f.mjs +33 -14
- package/fjs/types/rtti/proof.f.mjs +3 -1
- package/fjs/types/rtti/ts/module.f.mjs +13 -17
- package/fjs/types/rtti/ts/types.d.ts +14 -1
- package/fjs/types/rtti/validate/module.f.d.mts +81 -19
- package/fjs/types/rtti/validate/module.f.mjs +107 -61
- package/fjs/types/rtti/validate/proof.f.d.mts +13 -10
- package/fjs/types/rtti/validate/proof.f.mjs +186 -197
- package/fjs/types/sorted_set/module.f.d.mts +18 -0
- package/fjs/types/sorted_set/module.f.mjs +22 -0
- package/fjs/types/sorted_set/proof.f.d.mts +1 -0
- package/fjs/types/sorted_set/proof.f.mjs +16 -1
- package/fjs/types/uint8array/module.f.d.mts +1 -1
- package/fjs/types/uint8array/module.f.mjs +1 -1
- package/fjs/website/module.f.d.mts +3 -3
- package/fjs/website/module.f.mjs +4 -7
- package/fjs/website/proof.f.mjs +2 -1
- package/package.json +2 -2
- package/fjs/dev/package_json/module.f.d.mts +0 -39
- package/fjs/dev/package_json/module.f.mjs +0 -40
- package/fjs/dev/package_json/proof.f.d.mts +0 -6
- package/fjs/dev/package_json/proof.f.mjs +0 -32
- package/fjs/effects/eff/module.f.d.mts +0 -20
- package/fjs/effects/eff/module.f.mjs +0 -70
- package/fjs/effects/eff/proof.f.d.mts +0 -15
- package/fjs/effects/eff/proof.f.mjs +0 -69
- package/fjs/effects/eff/types.d.ts +0 -71
- package/fjs/types/rtti/validate/types.d.ts +0 -6
|
@@ -109,32 +109,32 @@ export const proof = {
|
|
|
109
109
|
error: () => assertError(parse(/** @type {const} */ (42))(43)),
|
|
110
110
|
},
|
|
111
111
|
nan: {
|
|
112
|
-
ok: () => assertOk(parse(
|
|
112
|
+
ok: () => assertOk(parse(NaN)(NaN)),
|
|
113
113
|
error: () => {
|
|
114
|
-
assertError(parse(
|
|
114
|
+
assertError(parse(NaN)(0))
|
|
115
115
|
assertError(parse(/** @type {const} */ (0))(NaN))
|
|
116
116
|
assertError(parse(/** @type {const} */ (42))(NaN))
|
|
117
117
|
},
|
|
118
118
|
},
|
|
119
119
|
infinity: {
|
|
120
120
|
ok: () => {
|
|
121
|
-
assertOk(parse(
|
|
122
|
-
assertOk(parse(
|
|
121
|
+
assertOk(parse(Infinity)(Infinity))
|
|
122
|
+
assertOk(parse(-Infinity)(-Infinity))
|
|
123
123
|
},
|
|
124
124
|
error: () => {
|
|
125
|
-
assertError(parse(
|
|
126
|
-
assertError(parse(
|
|
125
|
+
assertError(parse(Infinity)(-Infinity))
|
|
126
|
+
assertError(parse(Infinity)(0))
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
129
|
signedZero: {
|
|
130
130
|
// `Object.is` distinguishes +0 and -0; `===` treats them equal.
|
|
131
131
|
distinct: () => {
|
|
132
132
|
assertError(parse(/** @type {const} */ (0))(-0))
|
|
133
|
-
assertError(parse(
|
|
133
|
+
assertError(parse(-0)(0))
|
|
134
134
|
},
|
|
135
135
|
self: () => {
|
|
136
136
|
assertOk(parse(/** @type {const} */ (0))(0))
|
|
137
|
-
assertOk(parse(
|
|
137
|
+
assertOk(parse(-0)(-0))
|
|
138
138
|
},
|
|
139
139
|
},
|
|
140
140
|
string: {
|
|
@@ -155,14 +155,31 @@ export const proof = {
|
|
|
155
155
|
const r = parse(t)([42, 'hello'])
|
|
156
156
|
assertStructurallySame(unwrap(r), [42, 'hello'])
|
|
157
157
|
},
|
|
158
|
-
//
|
|
159
|
-
|
|
158
|
+
// A tuple is OPEN: a longer array is accepted, and the extras are
|
|
159
|
+
// absent from what `parse` builds. This is deliberate — see
|
|
160
|
+
// "Structs and tuples are open" in ../README.md. Do not add a
|
|
161
|
+
// length check here on the strength of `Ts<readonly [42]>` being
|
|
162
|
+
// an exact tuple; that mapping is exact only because TypeScript
|
|
163
|
+
// could not express the open one (see ../ts/types.ts `TupleTs`),
|
|
164
|
+
// and reading it as a design decision is what produced #1622.
|
|
165
|
+
extraItemsAcceptedAndDropped: () => {
|
|
160
166
|
const r = parse(/** @type {const} */ ([42]))([42, 'extra'])
|
|
161
167
|
assertStructurallySame(unwrap(r), [42])
|
|
168
|
+
const long = parse(/** @type {const} */ ([42]))([42, 1, 2, 3])
|
|
169
|
+
assertStructurallySame(unwrap(long), [42])
|
|
170
|
+
},
|
|
171
|
+
// An absent member reads as `undefined`, so a position is required
|
|
172
|
+
// exactly when its set excludes `undefined` — the same rule the
|
|
173
|
+
// data form states for object keys, applied to arrays.
|
|
174
|
+
shortArrayFillsAnOptionalPosition: () => {
|
|
175
|
+
const r = parse([number, option(string)])([42])
|
|
176
|
+
assertStructurallySame(unwrap(r), [42, undefined])
|
|
162
177
|
},
|
|
163
178
|
error: () => {
|
|
164
179
|
assertError(parse(/** @type {const} */ ([42]))([99]))
|
|
165
180
|
assertError(parse(/** @type {const} */ ([42]))({}))
|
|
181
|
+
// `42` excludes `undefined`, so position 0 is required.
|
|
182
|
+
assertError(parse(/** @type {const} */ ([42]))([]))
|
|
166
183
|
},
|
|
167
184
|
},
|
|
168
185
|
struct: {
|
|
@@ -171,8 +188,10 @@ export const proof = {
|
|
|
171
188
|
const r = parse(t)({ a: 42, b: 'hello' })
|
|
172
189
|
assertStructurallySame(unwrap(r), { a: 42, b: 'hello' })
|
|
173
190
|
},
|
|
174
|
-
//
|
|
175
|
-
|
|
191
|
+
// A struct is OPEN, on the same terms as a tuple: undeclared
|
|
192
|
+
// properties are accepted and absent from what `parse` builds.
|
|
193
|
+
// See "Structs and tuples are open" in ../README.md.
|
|
194
|
+
extraKeysAcceptedAndDropped: () => {
|
|
176
195
|
const r = parse(/** @type {const} */ ({ a: /** @type {const} */ (42) }))({ a: 42, b: 'extra' })
|
|
177
196
|
assertStructurallySame(unwrap(r), { a: 42 })
|
|
178
197
|
},
|
|
@@ -196,7 +215,7 @@ export const proof = {
|
|
|
196
215
|
const input = [1, 2, 3]
|
|
197
216
|
/** @type {readonly number[]} */
|
|
198
217
|
const out = unwrap(parse(array(number))(input))
|
|
199
|
-
assert(out !==
|
|
218
|
+
assert(out !== input, 'expected a fresh array')
|
|
200
219
|
assertStructurallySame(out, [1, 2, 3])
|
|
201
220
|
},
|
|
202
221
|
error: () => {
|
|
@@ -224,7 +243,7 @@ export const proof = {
|
|
|
224
243
|
const input = { a: 1, b: 2 }
|
|
225
244
|
/** @type {Record<string, number>} */
|
|
226
245
|
const out = unwrap(parse(record(number))(input))
|
|
227
|
-
assert(out !==
|
|
246
|
+
assert(out !== input, 'expected a fresh record')
|
|
228
247
|
assertStructurallySame(out, { a: 1, b: 2 })
|
|
229
248
|
},
|
|
230
249
|
error: () => {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @import { StringMap } from '../object/types.ts'
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { assertNotNullish } from '../../asserts/module.f.mjs'
|
|
6
|
+
|
|
5
7
|
/** @typedef {StringMap<readonly unknown[]>} _Tests */
|
|
6
8
|
|
|
7
9
|
/** @type {_Tests} */
|
|
@@ -16,7 +18,7 @@ const tests = {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export const proof = {
|
|
19
|
-
typeof: Object.fromEntries(Object.entries(tests).map(([k, a]) => [k,
|
|
21
|
+
typeof: Object.fromEntries(Object.entries(tests).map(([k, a]) => [k, assertNotNullish(a).map(v => () => {
|
|
20
22
|
if (typeof v !== k) { throw `typeof ${v} !== ${k}` }
|
|
21
23
|
})])),
|
|
22
24
|
}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { assertNotNullish } from '../../../asserts/module.f.mjs'
|
|
22
|
+
import { reservedWords, strictModeReservedWords } from '../../../js/keywords/module.f.mjs'
|
|
22
23
|
import { at, definedEntries } from '../../object/module.f.mjs'
|
|
23
24
|
import { primitive, union, printer as tsPrinter } from '../../ts/module.f.mjs'
|
|
24
25
|
import { cmp, toData, unitBit, unknown as top } from '../data/module.f.mjs'
|
|
@@ -30,27 +31,22 @@ const trueBit = unitBit(true)
|
|
|
30
31
|
const booleanBits = falseBit | trueBit
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
* Names that cannot name a TypeScript type alias: the
|
|
34
|
-
*
|
|
35
|
-
* strict-mode
|
|
36
|
-
* (`TS1214`) —
|
|
34
|
+
* Names that cannot name a TypeScript type alias: the ECMAScript reserved
|
|
35
|
+
* words — from the one source of truth for JavaScript keywords,
|
|
36
|
+
* `fjs/js/keywords`, the strict-mode ones included since every module is
|
|
37
|
+
* strict-mode code (`TS1214`) — plus TypeScript's predefined type names
|
|
38
|
+
* (`TS2457`) and the type keywords that fail in the alias-name position.
|
|
37
39
|
*/
|
|
38
|
-
|
|
40
|
+
/** @type {readonly string[]} */
|
|
41
|
+
const reserved = [
|
|
42
|
+
...reservedWords,
|
|
43
|
+
...strictModeReservedWords,
|
|
39
44
|
// predefined type names
|
|
40
|
-
'any', 'bigint', 'boolean', '
|
|
41
|
-
'
|
|
42
|
-
// ECMAScript reserved words
|
|
43
|
-
'await', 'break', 'case', 'catch', 'class', 'const', 'continue',
|
|
44
|
-
'debugger', 'default', 'delete', 'do', 'else', 'enum', 'export',
|
|
45
|
-
'extends', 'finally', 'for', 'function', 'if', 'import', 'in',
|
|
46
|
-
'instanceof', 'new', 'return', 'super', 'switch', 'this', 'throw', 'try',
|
|
47
|
-
'typeof', 'var', 'while', 'with',
|
|
48
|
-
// reserved in strict-mode code — and every module is strict-mode code
|
|
49
|
-
'implements', 'interface', 'let', 'package', 'private', 'protected',
|
|
50
|
-
'public', 'static', 'yield',
|
|
45
|
+
'any', 'bigint', 'boolean', 'never', 'number', 'object', 'string',
|
|
46
|
+
'symbol', 'undefined', 'unknown',
|
|
51
47
|
// type-operator keywords, and `intrinsic` (TS2795 outside lib.d.ts)
|
|
52
48
|
'infer', 'intrinsic', 'keyof', 'readonly', 'unique',
|
|
53
|
-
]
|
|
49
|
+
]
|
|
54
50
|
|
|
55
51
|
/** @type {(c: string) => boolean} */
|
|
56
52
|
const isIdStart = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '_' || c === '$'
|
|
@@ -51,7 +51,20 @@ export type ArrayTs<T extends Type> = ReadonlyArray<Ts<T>>;
|
|
|
51
51
|
export type RecordTs<T extends Type> = {
|
|
52
52
|
readonly [K in string]?: Ts<T>;
|
|
53
53
|
};
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Maps a tuple schema to a readonly tuple of resolved types.
|
|
56
|
+
*
|
|
57
|
+
* **The commented-out line is the accurate mapping.** A tuple schema is *open*
|
|
58
|
+
* — a longer array is a member of the set it describes (see "Structs and
|
|
59
|
+
* tuples are open" in `../README.md`) — and the open form below says so. It is
|
|
60
|
+
* commented out because TypeScript could not handle it, so this renders the
|
|
61
|
+
* closed approximation instead.
|
|
62
|
+
*
|
|
63
|
+
* That is a limitation of this renderer, **not** a statement about the value
|
|
64
|
+
* model. Do not cite the exact mapping as evidence that tuples are closed and
|
|
65
|
+
* add a length check to `../parse/module.f.mjs`; that inference is what
|
|
66
|
+
* produced #1622.
|
|
67
|
+
*/
|
|
55
68
|
export type TupleTs<T extends Tuple> = {
|
|
56
69
|
readonly [K in keyof T]: Ts<T[K]>;
|
|
57
70
|
};
|
|
@@ -1,41 +1,103 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Runtime validation of unknown values against RTTI schemas
|
|
2
|
+
* Runtime validation of unknown values against RTTI schemas — the verbatim
|
|
3
|
+
* reader.
|
|
3
4
|
*
|
|
4
|
-
* The main entry point is `validate(rtti)`, which takes a schema `Type` and
|
|
5
|
-
* a `Validate<T>` function. When called with an unknown value, it
|
|
6
|
-
* that is either `['ok',
|
|
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 }]`.
|
|
7
9
|
*
|
|
8
|
-
* ##
|
|
10
|
+
* ## What distinguishes it from `parse`
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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 open
|
|
30
|
+
*
|
|
31
|
+
* Openness is the shared rule, not a `parse` detail — see "Structs and tuples
|
|
32
|
+
* are open" in `../README.md`. `validate` iterates the *schema's* entries, so
|
|
33
|
+
* an undeclared key or a longer array is never visited: it is accepted, and it
|
|
34
|
+
* is still there afterwards because the value is returned as-is. An absent
|
|
35
|
+
* member reads as `undefined`, so a member is required exactly when its set
|
|
36
|
+
* excludes `undefined`.
|
|
37
|
+
*
|
|
38
|
+
* **Do not add a length check for tuples here.** `Ts<readonly [42]>` is the
|
|
39
|
+
* exact tuple only because TypeScript cannot express the open one (see
|
|
40
|
+
* `../ts/types.ts` `TupleTs`); reading that rendering as the value model is
|
|
41
|
+
* what produced #1622, whose check lived in this module's ancestor and was
|
|
42
|
+
* deleted with it. A schema that wants exact members says so — see
|
|
43
|
+
* `../todo/close-type.md`.
|
|
13
44
|
*
|
|
14
45
|
* ## Dispatch strategy
|
|
15
46
|
*
|
|
16
47
|
* Schema recognition is delegated to `visit` in `../common/module.f.mjs`,
|
|
17
48
|
* which routes each `Type` variant to a handler in the `Visitor` record
|
|
18
|
-
* defined below
|
|
19
|
-
*
|
|
20
|
-
*
|
|
49
|
+
* defined below; nothing here walks the `Type` ADT itself. The container
|
|
50
|
+
* handlers drive `eachEntry` in its no-accumulator mode — the mode its JSDoc
|
|
51
|
+
* describes for "a caller whose whole question is 'did every entry
|
|
52
|
+
* succeed?'" — so a validation allocates nothing per entry. The data form's
|
|
53
|
+
* `validate` (`../data/module.f.mjs`) is the same shape over `Data`.
|
|
21
54
|
*
|
|
22
55
|
* ## Recursion safety
|
|
23
56
|
*
|
|
24
|
-
* For `array` and `record` schemas, the inner item validator is instantiated
|
|
25
|
-
* only after confirming the container is non-empty. This prevents
|
|
26
|
-
* when validating recursive schemas like
|
|
57
|
+
* For `array` and `record` schemas, the inner item validator is instantiated
|
|
58
|
+
* lazily — only after confirming the container is non-empty. This prevents
|
|
59
|
+
* infinite recursion when validating recursive schemas like
|
|
60
|
+
* `const list = () => ['array', list]`.
|
|
27
61
|
*
|
|
28
|
-
* See `./types.ts` for the `Path`/`Result`/`Validate`/`ValidationError`
|
|
62
|
+
* See `./types.ts` for the `Path`/`Result`/`Validate`/`ValidationError`
|
|
63
|
+
* type-level API.
|
|
29
64
|
*
|
|
30
65
|
* @module
|
|
31
66
|
*
|
|
32
67
|
* @import { Unknown } from '../ts/types.ts'
|
|
33
68
|
* @import { Info1, Struct, Tag1, Tuple, Type } from '../types.ts'
|
|
34
|
-
* @import {
|
|
35
|
-
* @import { Container, IsContainer, Validate, ValidateE, Visitor } from '../common/types.ts'
|
|
69
|
+
* @import { Container, IsContainer, Validate, Visitor } from '../common/types.ts'
|
|
36
70
|
*/
|
|
37
71
|
import type { Type } from '../types.ts';
|
|
38
72
|
import type { Validate } from '../common/types.ts';
|
|
39
|
-
|
|
40
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Creates a validator function for the given RTTI schema: a `Thunk` for
|
|
75
|
+
* tag-based schemas, or a `Const` (primitive literal, tuple, or struct) for
|
|
76
|
+
* exact-value schemas.
|
|
77
|
+
*
|
|
78
|
+
* The returned function takes an unknown value and returns either
|
|
79
|
+
* `['ok', value]` — the very value it was given, not a reconstruction — or
|
|
80
|
+
* `['error', { path, message }]` describing the failure location.
|
|
81
|
+
*
|
|
82
|
+
* Use it when the question is "is this value of this shape?" and the value has
|
|
83
|
+
* to survive the question intact. Use `../parse/module.f.mjs` when the answer
|
|
84
|
+
* wanted is a value built to the schema.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```js
|
|
88
|
+
* const v = validate(array(number))
|
|
89
|
+
* const input = [1, 2, 3]
|
|
90
|
+
* v(input) // ['ok', input] — the same array, not a copy
|
|
91
|
+
* v([1, 'two']) // ['error', { path: ['1'], message: 'unexpected value' }]
|
|
92
|
+
*
|
|
93
|
+
* // open, and the extras are still there afterwards
|
|
94
|
+
* validate([number, number])([1, 2, 3]) // ['ok', [1, 2, 3]]
|
|
95
|
+
* validate({ a: number })({ a: 1, b: 2 }) // ['ok', { a: 1, b: 2 }]
|
|
96
|
+
*
|
|
97
|
+
* // an absent optional member stays absent
|
|
98
|
+
* validate({ a: number, b: option(string) })({ a: 1 }) // ['ok', { a: 1 }]
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @type {<T extends Type>(rtti: T) => Validate<T>}
|
|
102
|
+
*/
|
|
41
103
|
export declare const validate: <T extends Type>(rtti: T) => Validate<T>;
|
|
@@ -1,38 +1,72 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Runtime validation of unknown values against RTTI schemas
|
|
2
|
+
* Runtime validation of unknown values against RTTI schemas — the verbatim
|
|
3
|
+
* reader.
|
|
3
4
|
*
|
|
4
|
-
* The main entry point is `validate(rtti)`, which takes a schema `Type` and
|
|
5
|
-
* a `Validate<T>` function. When called with an unknown value, it
|
|
6
|
-
* that is either `['ok',
|
|
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 }]`.
|
|
7
9
|
*
|
|
8
|
-
* ##
|
|
10
|
+
* ## What distinguishes it from `parse`
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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 open
|
|
30
|
+
*
|
|
31
|
+
* Openness is the shared rule, not a `parse` detail — see "Structs and tuples
|
|
32
|
+
* are open" in `../README.md`. `validate` iterates the *schema's* entries, so
|
|
33
|
+
* an undeclared key or a longer array is never visited: it is accepted, and it
|
|
34
|
+
* is still there afterwards because the value is returned as-is. An absent
|
|
35
|
+
* member reads as `undefined`, so a member is required exactly when its set
|
|
36
|
+
* excludes `undefined`.
|
|
37
|
+
*
|
|
38
|
+
* **Do not add a length check for tuples here.** `Ts<readonly [42]>` is the
|
|
39
|
+
* exact tuple only because TypeScript cannot express the open one (see
|
|
40
|
+
* `../ts/types.ts` `TupleTs`); reading that rendering as the value model is
|
|
41
|
+
* what produced #1622, whose check lived in this module's ancestor and was
|
|
42
|
+
* deleted with it. A schema that wants exact members says so — see
|
|
43
|
+
* `../todo/close-type.md`.
|
|
13
44
|
*
|
|
14
45
|
* ## Dispatch strategy
|
|
15
46
|
*
|
|
16
47
|
* Schema recognition is delegated to `visit` in `../common/module.f.mjs`,
|
|
17
48
|
* which routes each `Type` variant to a handler in the `Visitor` record
|
|
18
|
-
* defined below
|
|
19
|
-
*
|
|
20
|
-
*
|
|
49
|
+
* defined below; nothing here walks the `Type` ADT itself. The container
|
|
50
|
+
* handlers drive `eachEntry` in its no-accumulator mode — the mode its JSDoc
|
|
51
|
+
* describes for "a caller whose whole question is 'did every entry
|
|
52
|
+
* succeed?'" — so a validation allocates nothing per entry. The data form's
|
|
53
|
+
* `validate` (`../data/module.f.mjs`) is the same shape over `Data`.
|
|
21
54
|
*
|
|
22
55
|
* ## Recursion safety
|
|
23
56
|
*
|
|
24
|
-
* For `array` and `record` schemas, the inner item validator is instantiated
|
|
25
|
-
* only after confirming the container is non-empty. This prevents
|
|
26
|
-
* when validating recursive schemas like
|
|
57
|
+
* For `array` and `record` schemas, the inner item validator is instantiated
|
|
58
|
+
* lazily — only after confirming the container is non-empty. This prevents
|
|
59
|
+
* infinite recursion when validating recursive schemas like
|
|
60
|
+
* `const list = () => ['array', list]`.
|
|
27
61
|
*
|
|
28
|
-
* See `./types.ts` for the `Path`/`Result`/`Validate`/`ValidationError`
|
|
62
|
+
* See `./types.ts` for the `Path`/`Result`/`Validate`/`ValidationError`
|
|
63
|
+
* type-level API.
|
|
29
64
|
*
|
|
30
65
|
* @module
|
|
31
66
|
*
|
|
32
67
|
* @import { Unknown } from '../ts/types.ts'
|
|
33
68
|
* @import { Info1, Struct, Tag1, Tuple, Type } from '../types.ts'
|
|
34
|
-
* @import {
|
|
35
|
-
* @import { Container, IsContainer, Validate, ValidateE, Visitor } from '../common/types.ts'
|
|
69
|
+
* @import { Container, IsContainer, Validate, Visitor } from '../common/types.ts'
|
|
36
70
|
*/
|
|
37
71
|
|
|
38
72
|
import { ok } from '../../result/module.f.mjs'
|
|
@@ -47,13 +81,6 @@ import {
|
|
|
47
81
|
visit,
|
|
48
82
|
} from '../common/module.f.mjs'
|
|
49
83
|
|
|
50
|
-
export {
|
|
51
|
-
constPrimitiveValidate,
|
|
52
|
-
prependPath,
|
|
53
|
-
primitive0Validate,
|
|
54
|
-
verror,
|
|
55
|
-
} from '../common/module.f.mjs'
|
|
56
|
-
|
|
57
84
|
const { entries } = Object
|
|
58
85
|
|
|
59
86
|
/** `validate` has nothing to collect from a successful entry — only pass/fail matters. */
|
|
@@ -77,7 +104,7 @@ const containerValidate =
|
|
|
77
104
|
}
|
|
78
105
|
const e = entries(value)
|
|
79
106
|
if (e.length === 0) {
|
|
80
|
-
return ok(value)
|
|
107
|
+
return /** @type {any} */ (ok(value))
|
|
81
108
|
}
|
|
82
109
|
// Note: we shouldn't instantiate `itemValidate` until we make sure `entries` is not empty.
|
|
83
110
|
// Otherwise, we can get infinite recursion on empty arrays and objects
|
|
@@ -93,9 +120,10 @@ const arrayValidate = containerValidate(isArray)
|
|
|
93
120
|
const recordValidate = containerValidate(isObject)
|
|
94
121
|
|
|
95
122
|
/**
|
|
96
|
-
* Builds a validator for `Tuple` or `Struct` const schemas.
|
|
97
|
-
*
|
|
98
|
-
*
|
|
123
|
+
* Builds a validator for `Tuple` or `Struct` const schemas. It iterates the
|
|
124
|
+
* *schema's* entries, which is what makes both kinds open: a longer array or
|
|
125
|
+
* an undeclared key is never visited, so it is accepted — and, the value being
|
|
126
|
+
* returned as it came, it survives.
|
|
99
127
|
*/
|
|
100
128
|
const constContainerValidate =
|
|
101
129
|
/**
|
|
@@ -105,29 +133,34 @@ const constContainerValidate =
|
|
|
105
133
|
* @returns {<T extends Tuple | Struct>(rtti: T) => Validate<T>}
|
|
106
134
|
*/
|
|
107
135
|
(isContainer, getItem) =>
|
|
108
|
-
rtti =>
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
rtti => {
|
|
137
|
+
// Depends on `rtti` alone, so it is computed once per schema rather
|
|
138
|
+
// than once per validated value.
|
|
139
|
+
const rttiEntries = entries(rtti)
|
|
140
|
+
return value => {
|
|
141
|
+
if (!isContainer(value)) {
|
|
142
|
+
return verror('unexpected value')
|
|
143
|
+
}
|
|
144
|
+
const r = eachEntry(
|
|
145
|
+
rttiEntries,
|
|
146
|
+
(k, v) => /** @type {any} */ (validate(v))(getItem(value, k)),
|
|
147
|
+
undefined,
|
|
148
|
+
noAccumulate,
|
|
149
|
+
)
|
|
150
|
+
// `value` is C (Unknown container), but Ts<T> for T extends Tuple|Struct is not
|
|
151
|
+
// structurally equivalent to C — TypeScript can't narrow element types through the loop.
|
|
152
|
+
return r[0] === 'error' ? r : /** @type {any} */ (ok(value))
|
|
111
153
|
}
|
|
112
|
-
const r = eachEntry(
|
|
113
|
-
Object.entries(rtti),
|
|
114
|
-
(k, v) => /** @type {any} */ (validate(v))(getItem(value, k)),
|
|
115
|
-
undefined,
|
|
116
|
-
noAccumulate,
|
|
117
|
-
)
|
|
118
|
-
// `value` is C (Unknown container), but Ts<T> for T extends Tuple|Struct is not
|
|
119
|
-
// structurally equivalent to C — TypeScript can't narrow element types through the loop.
|
|
120
|
-
return r[0] === 'error' ? r : /** @type {any} */ (ok(value))
|
|
121
154
|
}
|
|
122
155
|
|
|
123
156
|
const tupleValidate = constContainerValidate(
|
|
124
157
|
isArray,
|
|
125
|
-
(value, k) => value[Number(k)]
|
|
158
|
+
(value, k) => value[Number(k)],
|
|
126
159
|
)
|
|
127
160
|
|
|
128
161
|
const structValidate = constContainerValidate(
|
|
129
162
|
isObject,
|
|
130
|
-
(value, k) => value[k]
|
|
163
|
+
(value, k) => value[k],
|
|
131
164
|
)
|
|
132
165
|
|
|
133
166
|
const orValidate =
|
|
@@ -137,24 +170,8 @@ const orValidate =
|
|
|
137
170
|
* @returns {Validate<() => readonly ['or', ...T]>}
|
|
138
171
|
*/
|
|
139
172
|
rtti =>
|
|
140
|
-
/** @type {any} */ (orVisit(/** @type {
|
|
173
|
+
/** @type {any} */ (orVisit(/** @type {any} */ (validate))(rtti))
|
|
141
174
|
|
|
142
|
-
/**
|
|
143
|
-
* Creates a validator function for the given RTTI schema.
|
|
144
|
-
*
|
|
145
|
-
* @param rtti - A schema `Type`: a `Thunk` for tag-based schemas, or a `Const`
|
|
146
|
-
* (primitive literal, tuple, or struct) for exact-value schemas.
|
|
147
|
-
* @returns A `Validate<T>` function that checks an unknown value and returns
|
|
148
|
-
* `['ok', value]` or `['error', { path, message }]`.
|
|
149
|
-
*
|
|
150
|
-
* @example
|
|
151
|
-
* ```js
|
|
152
|
-
* const v = validate(array(number))
|
|
153
|
-
* v([1, 2, 3]) // ['ok', [1, 2, 3]]
|
|
154
|
-
* v([1, 'two']) // ['error', { path: ['1'], message: 'unexpected value' }]
|
|
155
|
-
* v(['a']) // ['error', { path: ['0'], message: 'unexpected value' }]
|
|
156
|
-
* ```
|
|
157
|
-
*/
|
|
158
175
|
const validateVisitor = /** @type {any} */ ({
|
|
159
176
|
tuple: tupleValidate,
|
|
160
177
|
struct: structValidate,
|
|
@@ -166,6 +183,35 @@ const validateVisitor = /** @type {any} */ ({
|
|
|
166
183
|
unknown: () => ok,
|
|
167
184
|
})
|
|
168
185
|
|
|
169
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* Creates a validator function for the given RTTI schema: a `Thunk` for
|
|
188
|
+
* tag-based schemas, or a `Const` (primitive literal, tuple, or struct) for
|
|
189
|
+
* exact-value schemas.
|
|
190
|
+
*
|
|
191
|
+
* The returned function takes an unknown value and returns either
|
|
192
|
+
* `['ok', value]` — the very value it was given, not a reconstruction — or
|
|
193
|
+
* `['error', { path, message }]` describing the failure location.
|
|
194
|
+
*
|
|
195
|
+
* Use it when the question is "is this value of this shape?" and the value has
|
|
196
|
+
* to survive the question intact. Use `../parse/module.f.mjs` when the answer
|
|
197
|
+
* wanted is a value built to the schema.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```js
|
|
201
|
+
* const v = validate(array(number))
|
|
202
|
+
* const input = [1, 2, 3]
|
|
203
|
+
* v(input) // ['ok', input] — the same array, not a copy
|
|
204
|
+
* v([1, 'two']) // ['error', { path: ['1'], message: 'unexpected value' }]
|
|
205
|
+
*
|
|
206
|
+
* // open, and the extras are still there afterwards
|
|
207
|
+
* validate([number, number])([1, 2, 3]) // ['ok', [1, 2, 3]]
|
|
208
|
+
* validate({ a: number })({ a: 1, b: 2 }) // ['ok', { a: 1, b: 2 }]
|
|
209
|
+
*
|
|
210
|
+
* // an absent optional member stays absent
|
|
211
|
+
* validate({ a: number, b: option(string) })({ a: 1 }) // ['ok', { a: 1 }]
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @type {<T extends Type>(rtti: T) => Validate<T>}
|
|
215
|
+
*/
|
|
170
216
|
export const validate = rtti =>
|
|
171
|
-
|
|
217
|
+
(visit(validateVisitor)(rtti))
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import { ValidationError } from '../common/types.ts'
|
|
2
|
+
* @import { ValidationError, ValidateE } from '../common/types.ts'
|
|
3
|
+
* @import { Type } from '../types.ts'
|
|
3
4
|
* @import { Equal } from '../../ts/types.ts'
|
|
4
|
-
* @import { Ts } from '../ts/types.ts'
|
|
5
|
+
* @import { Ts, Unknown } from '../ts/types.ts'
|
|
5
6
|
* @import { Unknown as DjsUnknown } from '../../../djs/types.ts'
|
|
6
7
|
* @import { Assert } from '../../../asserts/types.ts'
|
|
7
8
|
*/
|
|
8
9
|
export declare const proof: {
|
|
10
|
+
verbatim: {
|
|
11
|
+
absentOptionalStaysAbsent: () => void;
|
|
12
|
+
undeclaredMemberSurvives: () => void;
|
|
13
|
+
referenceIdentity: () => void;
|
|
14
|
+
};
|
|
15
|
+
sameAcceptanceAsParse: () => void;
|
|
9
16
|
boolean: {
|
|
10
17
|
ok: () => void;
|
|
11
18
|
error: () => void;
|
|
@@ -64,12 +71,13 @@ export declare const proof: {
|
|
|
64
71
|
};
|
|
65
72
|
tuple: {
|
|
66
73
|
ok: () => void;
|
|
67
|
-
|
|
74
|
+
extraItemsAcceptedAndKept: () => void;
|
|
75
|
+
shortArrayKeepsItsLength: () => void;
|
|
76
|
+
empty: () => void;
|
|
68
77
|
error: () => void;
|
|
69
78
|
};
|
|
70
79
|
struct: {
|
|
71
80
|
ok: () => void;
|
|
72
|
-
extraKeys: () => void;
|
|
73
81
|
error: () => void;
|
|
74
82
|
};
|
|
75
83
|
};
|
|
@@ -96,10 +104,7 @@ export declare const proof: {
|
|
|
96
104
|
ok: () => void;
|
|
97
105
|
error: () => void;
|
|
98
106
|
};
|
|
99
|
-
|
|
100
|
-
ok: () => void;
|
|
101
|
-
error: () => void;
|
|
102
|
-
};
|
|
107
|
+
firstMatchWins: () => void;
|
|
103
108
|
};
|
|
104
109
|
option: {
|
|
105
110
|
ok: () => void;
|
|
@@ -120,6 +125,4 @@ export declare const proof: {
|
|
|
120
125
|
arrayOfArrays: () => void;
|
|
121
126
|
recordOfRecords: () => void;
|
|
122
127
|
};
|
|
123
|
-
funcParam: () => () => void;
|
|
124
|
-
funcObj: () => () => void;
|
|
125
128
|
};
|