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
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared kernel for RTTI consumers
|
|
2
|
+
* Shared kernel for RTTI consumers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
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
|
|
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.
|
|
17
|
-
*
|
|
18
|
-
* - `eachEntry`: the container entry loop (array/record/tuple/struct)
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
|
25
|
-
*
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* "did every entry succeed?"
|
|
86
|
-
* pays no allocation per entry
|
|
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
|
|
95
|
-
*
|
|
96
|
-
*
|
|
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
|
|
2
|
+
* Shared kernel for RTTI consumers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
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
|
|
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.
|
|
17
|
-
*
|
|
18
|
-
* - `eachEntry`: the container entry loop (array/record/tuple/struct)
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
|
25
|
-
*
|
|
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,
|
|
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(
|
|
84
|
-
: v.constPrimitive(
|
|
83
|
+
? (commonIsArray(c) ? v.tuple(c) : v.struct(c))
|
|
84
|
+
: v.constPrimitive(c)
|
|
85
85
|
|
|
86
|
-
/** `IsContainer` guard for arrays
|
|
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
|
|
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
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* "did every entry succeed?"
|
|
106
|
-
* pays no allocation per entry
|
|
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
|
|
137
|
-
*
|
|
138
|
-
*
|
|
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':
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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': {
|
|
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 }] }
|
|
@@ -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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* contains only the fields/elements
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
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
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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`)
|
|
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,
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* contains only the fields/elements
|
|
11
|
-
*
|
|
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
|
|
15
|
-
* - Structs:
|
|
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
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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`)
|
|
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,
|
|
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
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
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 {
|
|
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.
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
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) =>
|
|
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 {
|
|
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
|
-
* //
|
|
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
|
-
* //
|
|
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
|
-
|
|
207
|
+
(visit(parseVisitor)(rtti))
|
|
@@ -64,12 +64,13 @@ export declare const proof: {
|
|
|
64
64
|
};
|
|
65
65
|
tuple: {
|
|
66
66
|
ok: () => void;
|
|
67
|
-
|
|
67
|
+
extraItemsAcceptedAndDropped: () => void;
|
|
68
|
+
shortArrayFillsAnOptionalPosition: () => void;
|
|
68
69
|
error: () => void;
|
|
69
70
|
};
|
|
70
71
|
struct: {
|
|
71
72
|
ok: () => void;
|
|
72
|
-
|
|
73
|
+
extraKeysAcceptedAndDropped: () => void;
|
|
73
74
|
error: () => void;
|
|
74
75
|
};
|
|
75
76
|
};
|