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.
- package/fjs/basen/cbase32/module.f.mjs +18 -10
- package/fjs/basen/cbase32/proof.f.d.mts +3 -0
- package/fjs/basen/cbase32/proof.f.mjs +24 -2
- package/fjs/basen/proof.f.mjs +8 -16
- package/fjs/bnf/ll1/proof.f.d.mts +2 -0
- package/fjs/bnf/ll1/proof.f.mjs +33 -18
- package/fjs/bnf/module.f.d.mts +2 -2
- package/fjs/bnf/module.f.mjs +2 -2
- package/fjs/cas/proof.f.mjs +4 -26
- package/fjs/ci/common/module.f.mjs +6 -0
- package/fjs/ci/config/module.f.d.mts +7 -7
- package/fjs/ci/config/module.f.mjs +7 -7
- package/fjs/cli/module.f.mjs +14 -10
- package/fjs/crypto/vdf/module.f.d.mts +0 -1
- package/fjs/crypto/vdf/module.f.mjs +3 -14
- package/fjs/dev/module.f.mjs +10 -20
- package/fjs/djs/parser/module.f.d.mts +101 -53
- package/fjs/djs/parser/module.f.mjs +732 -525
- package/fjs/djs/parser/proof.f.d.mts +6 -0
- package/fjs/djs/parser/proof.f.mjs +315 -11
- package/fjs/djs/parser/types.d.ts +29 -2
- package/fjs/djs/tokenizer/module.f.mjs +122 -105
- package/fjs/djs/tokenizer/proof.f.mjs +17 -0
- package/fjs/djs/transpiler/module.f.mjs +4 -5
- package/fjs/djs/transpiler/proof.f.d.mts +2 -0
- package/fjs/djs/transpiler/proof.f.mjs +25 -0
- package/fjs/edag/amnesia/module.f.d.mts +20 -0
- package/fjs/edag/amnesia/module.f.mjs +303 -0
- package/fjs/edag/amnesia/proof.f.d.mts +79 -0
- package/fjs/edag/amnesia/proof.f.mjs +573 -0
- package/fjs/edag/amnesia/types.d.ts +15 -0
- package/fjs/edag/module.f.d.mts +410 -0
- package/fjs/edag/module.f.mjs +559 -0
- package/fjs/edag/proof.f.d.mts +116 -0
- package/fjs/edag/proof.f.mjs +686 -0
- package/fjs/edag/types.d.ts +55 -0
- package/fjs/effects/node/memory/module.d.mts +37 -3
- package/fjs/effects/node/memory/module.mjs +38 -4
- package/fjs/effects/node/memory/proof.d.mts +5 -2
- package/fjs/effects/node/memory/proof.mjs +36 -6
- package/fjs/effects/node/module.d.mts +9 -1
- package/fjs/effects/node/module.f.d.mts +39 -0
- package/fjs/effects/node/module.f.mjs +46 -0
- package/fjs/effects/node/module.mjs +234 -32
- package/fjs/effects/node/types.d.ts +28 -2
- package/fjs/effects/node/virtual/module.f.d.mts +19 -10
- package/fjs/effects/node/virtual/module.f.mjs +246 -32
- package/fjs/effects/node/virtual/proof.f.d.mts +17 -2
- package/fjs/effects/node/virtual/proof.f.mjs +232 -8
- package/fjs/effects/node/virtual/types.d.ts +57 -1
- package/fjs/emergent_testing/browser/proof.d.mts +55 -0
- package/fjs/emergent_testing/browser/proof.mjs +352 -0
- package/fjs/emergent_testing/browser/species.proof.d.mts +4 -0
- package/fjs/emergent_testing/browser/species.proof.mjs +45 -0
- package/fjs/emergent_testing/browser.d.mts +79 -0
- package/fjs/emergent_testing/browser.mjs +432 -0
- package/fjs/emergent_testing/proof.f.d.mts +1 -1
- package/fjs/emergent_testing/proof.f.mjs +2 -2
- package/fjs/js/string_escape/module.f.d.mts +47 -0
- package/fjs/js/string_escape/module.f.mjs +95 -0
- package/fjs/js/string_escape/proof.f.d.mts +8 -0
- package/fjs/js/string_escape/proof.f.mjs +68 -0
- package/fjs/js/tokenizer/module.f.mjs +14 -12
- package/fjs/mcp/cas/module.f.d.mts +1 -7
- package/fjs/mcp/cas/module.f.mjs +24 -15
- package/fjs/mcp/evo/module.f.mjs +9 -24
- package/fjs/mcp/module.f.d.mts +3 -1
- package/fjs/mcp/module.f.mjs +4 -2
- package/fjs/media/json/rtti/module.f.d.mts +2 -2
- package/fjs/media/json/rtti/module.f.mjs +1 -1
- package/fjs/media/json/schema/module.f.d.mts +15 -5
- package/fjs/media/json/schema/module.f.mjs +42 -15
- package/fjs/media/json/schema/proof.f.d.mts +10 -1
- package/fjs/media/json/schema/proof.f.mjs +88 -16
- package/fjs/media/json/serializer/module.f.mjs +14 -26
- package/fjs/media/json/types.d.ts +1 -1
- package/fjs/media/lock/module.f.d.mts +8 -3
- package/fjs/media/lock/module.f.mjs +9 -3
- package/fjs/media/lock/proof.f.d.mts +1 -1
- package/fjs/media/lock/proof.f.mjs +2 -2
- package/fjs/media/lock/types.d.ts +1 -3
- package/fjs/media/module.f.d.mts +20 -13
- package/fjs/media/module.f.mjs +29 -16
- package/fjs/media/note/module.f.d.mts +14 -7
- package/fjs/media/note/module.f.mjs +14 -7
- package/fjs/media/note/proof.f.mjs +1 -1
- package/fjs/media/proof.f.mjs +5 -5
- package/fjs/media/revision/module.f.d.mts +8 -2
- package/fjs/media/revision/module.f.mjs +9 -3
- package/fjs/media/revision/proof.f.mjs +1 -1
- package/fjs/media/revision/types.d.ts +1 -1
- package/fjs/media/type/module.f.d.mts +20 -0
- package/fjs/media/type/module.f.mjs +74 -0
- package/fjs/media/type/proof.f.d.mts +5 -0
- package/fjs/media/type/proof.f.mjs +24 -1
- package/fjs/module.f.mjs +6 -0
- package/fjs/path/module.f.d.mts +60 -3
- package/fjs/path/module.f.mjs +138 -14
- package/fjs/path/proof.f.d.mts +3 -0
- package/fjs/path/proof.f.mjs +298 -2
- package/fjs/protocol/json_rpc/module.f.d.mts +65 -28
- package/fjs/protocol/json_rpc/module.f.mjs +49 -13
- package/fjs/protocol/json_rpc/proof.f.d.mts +4 -0
- package/fjs/protocol/json_rpc/proof.f.mjs +29 -0
- package/fjs/protocol/json_rpc/types.d.ts +12 -2
- package/fjs/protocol/mcp/module.f.d.mts +89 -54
- package/fjs/protocol/mcp/module.f.mjs +110 -56
- package/fjs/protocol/mcp/proof.f.d.mts +13 -0
- package/fjs/protocol/mcp/proof.f.mjs +107 -7
- package/fjs/protocol/mcp/stdio/module.f.mjs +3 -4
- package/fjs/protocol/mcp/stdio/proof.f.mjs +2 -2
- package/fjs/protocol/mcp/types.d.ts +14 -2
- package/fjs/text/utf8/module.f.mjs +27 -1
- package/fjs/text/utf8/proof.f.mjs +37 -0
- package/fjs/types/array/module.f.mjs +18 -11
- package/fjs/types/array/proof.f.mjs +27 -1
- package/fjs/types/bigfloat/module.f.d.mts +48 -9
- package/fjs/types/bigfloat/module.f.mjs +147 -59
- package/fjs/types/bigfloat/proof.f.d.mts +2 -0
- package/fjs/types/bigfloat/proof.f.mjs +136 -4
- package/fjs/types/bigfloat/types.d.ts +17 -0
- package/fjs/types/function/module.f.d.mts +11 -2
- package/fjs/types/function/module.f.mjs +20 -2
- package/fjs/types/function/proof.f.mjs +5 -1
- package/fjs/types/phantom/types.d.ts +21 -0
- package/fjs/types/result/module.f.d.mts +4 -4
- package/fjs/types/result/module.f.mjs +2 -2
- package/fjs/types/result/proof.f.d.mts +6 -2
- package/fjs/types/result/proof.f.mjs +17 -1
- package/fjs/types/rtti/common/module.f.d.mts +78 -5
- package/fjs/types/rtti/common/module.f.mjs +168 -3
- package/fjs/types/rtti/common/proof.f.d.mts +14 -0
- package/fjs/types/rtti/common/proof.f.mjs +61 -2
- package/fjs/types/rtti/common/types.d.ts +23 -1
- package/fjs/types/rtti/data/module.f.d.mts +57 -1
- package/fjs/types/rtti/data/module.f.mjs +241 -47
- package/fjs/types/rtti/data/proof.f.d.mts +10 -0
- package/fjs/types/rtti/data/proof.f.mjs +272 -39
- package/fjs/types/rtti/data/types.d.ts +14 -7
- package/fjs/types/rtti/host.proof.d.mts +33 -0
- package/fjs/types/rtti/host.proof.mjs +170 -0
- package/fjs/types/rtti/module.f.d.mts +51 -6
- package/fjs/types/rtti/module.f.mjs +50 -3
- package/fjs/types/rtti/parse/module.f.d.mts +31 -24
- package/fjs/types/rtti/parse/module.f.mjs +197 -59
- package/fjs/types/rtti/parse/proof.f.d.mts +37 -2
- package/fjs/types/rtti/parse/proof.f.mjs +171 -47
- package/fjs/types/rtti/proof.f.d.mts +6 -0
- package/fjs/types/rtti/proof.f.mjs +42 -1
- package/fjs/types/rtti/ts/module.f.d.mts +9 -3
- package/fjs/types/rtti/ts/module.f.mjs +68 -15
- package/fjs/types/rtti/ts/proof.f.d.mts +42 -2
- package/fjs/types/rtti/ts/proof.f.mjs +139 -6
- package/fjs/types/rtti/ts/types.d.ts +164 -16
- package/fjs/types/rtti/types.d.ts +31 -3
- package/fjs/types/rtti/validate/module.f.d.mts +120 -0
- package/fjs/types/rtti/validate/module.f.mjs +351 -0
- package/fjs/types/rtti/validate/proof.f.d.mts +154 -0
- package/fjs/types/rtti/validate/proof.f.mjs +781 -0
- package/fjs/types/ts/types.d.ts +4 -0
- package/fjs/web/module.f.d.mts +115 -0
- package/fjs/web/module.f.mjs +581 -0
- package/fjs/web/proof.f.d.mts +39 -0
- package/fjs/web/proof.f.mjs +413 -0
- package/fjs/web/types.d.ts +39 -0
- package/fjs/website/browser-prepare.d.mts +5 -0
- package/fjs/website/browser-prepare.mjs +115 -0
- package/fjs/website/browser-source.d.mts +37 -0
- package/fjs/website/browser-source.mjs +202 -0
- package/fjs/website/browser-source.proof.d.mts +31 -0
- package/fjs/website/browser-source.proof.mjs +162 -0
- package/fjs/website/browser.d.mts +5 -0
- package/fjs/website/browser.mjs +8 -0
- package/fjs/website/module.f.d.mts +3 -3
- package/fjs/website/module.f.mjs +62 -9
- package/fjs/website/proof.f.d.mts +4 -0
- package/fjs/website/proof.f.mjs +18 -3
- package/package.json +2 -3
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* - `eachEntry`: the container entry loop (array/record/tuple/struct). Callers
|
|
19
19
|
* choose what (if anything) to accumulate, so a caller that only needs
|
|
20
20
|
* pass/fail pays no allocation per entry.
|
|
21
|
+
* - `tupleSchemaEntries`/`structSchemaEntries`: what a container schema
|
|
22
|
+
* declares, per kind — the entry list its readers walk.
|
|
23
|
+
* - `undeclaredMembers`: the other half of the loop — the members a container
|
|
24
|
+
* schema does not name, which a bare schema rejects and a `rest` one holds
|
|
25
|
+
* to its rest. The data form walks it too, so the two readers state one
|
|
26
|
+
* rule.
|
|
21
27
|
* - `orVisit`: the shared `or` handler — try each variant's recursive walker,
|
|
22
28
|
* return the first match.
|
|
23
29
|
*
|
|
@@ -27,16 +33,16 @@
|
|
|
27
33
|
* @module
|
|
28
34
|
*
|
|
29
35
|
* @import { Primitive, Unknown } from '../ts/types.ts'
|
|
30
|
-
* @import { Const, Info0, Primitive0, Tag1, Tuple, Type } from '../types.ts'
|
|
36
|
+
* @import { Const, Info0, Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts'
|
|
31
37
|
* @import { Error, Result as CommonResult } from '../../result/types.ts'
|
|
32
38
|
* @import { StringMap } from '../../object/types.ts'
|
|
33
|
-
* @import { Validate, Visitor, IsContainer, Container, ResultE, ValidateE, ValidationError } from './types.ts'
|
|
39
|
+
* @import { Validate, Visitor, IsContainer, Container, ResultE, SchemaEntries, ValidateE, ValidationError } from './types.ts'
|
|
34
40
|
*/
|
|
35
41
|
import type { Primitive, Unknown } from '../ts/types.ts';
|
|
36
|
-
import type { Info0, Primitive0, Type } from '../types.ts';
|
|
42
|
+
import type { Info0, Primitive0, Struct, Tuple, Type } from '../types.ts';
|
|
37
43
|
import type { Error, Result as CommonResult } from '../../result/types.ts';
|
|
38
44
|
import type { StringMap } from '../../object/types.ts';
|
|
39
|
-
import type { Validate, Visitor, IsContainer, ResultE, ValidateE, ValidationError } from './types.ts';
|
|
45
|
+
import type { Validate, Visitor, IsContainer, ResultE, SchemaEntries, ValidateE, ValidationError } from './types.ts';
|
|
40
46
|
/** Builds an error result with empty path and the given message. */
|
|
41
47
|
/** @type {(message: string) => Error<ValidationError>} */
|
|
42
48
|
export declare const verror: (message: string) => Error<ValidationError>;
|
|
@@ -85,6 +91,73 @@ export declare const isObject: IsContainer<StringMap<Unknown>>;
|
|
|
85
91
|
* instead and pays no allocation per entry.
|
|
86
92
|
*/
|
|
87
93
|
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>;
|
|
94
|
+
/**
|
|
95
|
+
* What a `Tuple` schema declares, read by **length**.
|
|
96
|
+
*
|
|
97
|
+
* `Array.from` yields `undefined` for a hole and preserves the schema's
|
|
98
|
+
* length, so a hole is a declared position whose schema is `undefined` — which
|
|
99
|
+
* is a `Const` schema in its own right, and exactly what reading index `0` of
|
|
100
|
+
* `new Array(1)` gives. That is the reading `../data/module.f.mjs`'s
|
|
101
|
+
* `containerUnion` has always had, so the canonical data form stays fixed.
|
|
102
|
+
*
|
|
103
|
+
* `Array.from` walks the iterator, which is the *same* walk `containerUnion`
|
|
104
|
+
* makes, and that is the point rather than an accident: the two agree by
|
|
105
|
+
* construction. It holds even for a schema carrying an overridden
|
|
106
|
+
* `Symbol.iterator`, where reading indices here would disagree with the data
|
|
107
|
+
* form all over again — verified: such a schema is read as `number` by the
|
|
108
|
+
* entry reading and as `string` by `containerUnion`. Reading *both* by index
|
|
109
|
+
* is defensible, but it changes the canonical, content-addressed data form and
|
|
110
|
+
* belongs with that decision, not here. FunctionalScript cannot build such a
|
|
111
|
+
* schema in the first place: it has no symbols and no mutation, so the case is
|
|
112
|
+
* reachable only from plain JavaScript, which is also why no proof can pin it.
|
|
113
|
+
*
|
|
114
|
+
* `Object.entries` skips holes, which is why it is not used here: it would
|
|
115
|
+
* make `new Array(1)` and `[]` the same schema while `[undefined]` stayed
|
|
116
|
+
* different from both. It also yields a non-index own property, which is no
|
|
117
|
+
* position either — `getItem` reads a tuple by index, so such a key was
|
|
118
|
+
* declared and then matched against `value[NaN]`. `Array.from` answers
|
|
119
|
+
* positions only. On a plain dense array the two agree exactly.
|
|
120
|
+
*
|
|
121
|
+
* @type {SchemaEntries<Tuple>}
|
|
122
|
+
*/
|
|
123
|
+
export declare const tupleSchemaEntries: SchemaEntries<Tuple>;
|
|
124
|
+
/**
|
|
125
|
+
* What a `Struct` schema declares: its enumerable own keys. A struct has no
|
|
126
|
+
* holes, so there is nothing for this to disagree with.
|
|
127
|
+
*
|
|
128
|
+
* @type {SchemaEntries<Struct>}
|
|
129
|
+
*/
|
|
130
|
+
export declare const structSchemaEntries: SchemaEntries<Struct>;
|
|
131
|
+
/**
|
|
132
|
+
* The members of `value` that `declared` does not name — every one the
|
|
133
|
+
* schema's `rest` has to answer for, as `[key, value]` pairs.
|
|
134
|
+
*
|
|
135
|
+
* `declared` is a container schema's own key list, so for a struct these are
|
|
136
|
+
* its undeclared own keys, and for a tuple they are the positions past the
|
|
137
|
+
* prefix together with every own key that is no position at all.
|
|
138
|
+
*
|
|
139
|
+
* **A tuple's positions are read, not enumerated.** `length` is what says how
|
|
140
|
+
* far an array reaches, and every index below it that *reads* a value is a
|
|
141
|
+
* member the `rest` must answer for — including one supplied by the prototype,
|
|
142
|
+
* which no own-entry walk sees ({@link readIndices} is the walk). Filtering
|
|
143
|
+
* `Object.entries` alone accepted `[42, , ]` carrying an inherited `1: 99`
|
|
144
|
+
* against `rest([42], string)`, handing back an array whose index 1 reads a
|
|
145
|
+
* number the rendered tail types as `string`. A genuinely absent index is
|
|
146
|
+
* skipped instead: a hole is no member, so it meets no `rest` — the same rule
|
|
147
|
+
* the struct kind states by walking own keys.
|
|
148
|
+
*
|
|
149
|
+
* An index at or above `length` is a different matter and is not answered
|
|
150
|
+
* here: it is readable through the prototype and no walk bounded by the value
|
|
151
|
+
* reaches it. See "Beyond `length`" in `../README.md`.
|
|
152
|
+
*
|
|
153
|
+
* Passing an empty `declared` asks for every member, which is what the uniform
|
|
154
|
+
* `array`/`record` readers want — so they share this walk rather than reaching
|
|
155
|
+
* for `Object.entries` and disagreeing with the data form on an inherited
|
|
156
|
+
* index.
|
|
157
|
+
*
|
|
158
|
+
* @type {(declared: readonly string[], value: ReadonlyArray<Unknown> | StringMap<Unknown>) => ReadonlyArray<readonly [string, Unknown]>}
|
|
159
|
+
*/
|
|
160
|
+
export declare const undeclaredMembers: (declared: readonly string[], value: ReadonlyArray<Unknown> | StringMap<Unknown>) => ReadonlyArray<readonly [string, Unknown]>;
|
|
88
161
|
/**
|
|
89
162
|
* First variant in `variants` that `recurse` accepts, else `verror('no match')`.
|
|
90
163
|
*
|
|
@@ -103,7 +176,7 @@ export declare const orVisit: (recurse: (t: Type) => ValidateE) => (variants: re
|
|
|
103
176
|
*
|
|
104
177
|
* - `Thunk` schemas are evaluated once to read the `Info` descriptor, then
|
|
105
178
|
* routed by tag (`'const'`, `'array'`, `'record'`, `'unknown'`, `'or'`,
|
|
106
|
-
* or a `Tag0` primitive).
|
|
179
|
+
* `'rest'`, or a `Tag0` primitive).
|
|
107
180
|
* - `Const` schemas (primitives, tuples, structs) are routed directly to
|
|
108
181
|
* `tuple`, `struct`, or `constPrimitive`.
|
|
109
182
|
*/
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* - `eachEntry`: the container entry loop (array/record/tuple/struct). Callers
|
|
19
19
|
* choose what (if anything) to accumulate, so a caller that only needs
|
|
20
20
|
* pass/fail pays no allocation per entry.
|
|
21
|
+
* - `tupleSchemaEntries`/`structSchemaEntries`: what a container schema
|
|
22
|
+
* declares, per kind — the entry list its readers walk.
|
|
23
|
+
* - `undeclaredMembers`: the other half of the loop — the members a container
|
|
24
|
+
* schema does not name, which a bare schema rejects and a `rest` one holds
|
|
25
|
+
* to its rest. The data form walks it too, so the two readers state one
|
|
26
|
+
* rule.
|
|
21
27
|
* - `orVisit`: the shared `or` handler — try each variant's recursive walker,
|
|
22
28
|
* return the first match.
|
|
23
29
|
*
|
|
@@ -27,10 +33,10 @@
|
|
|
27
33
|
* @module
|
|
28
34
|
*
|
|
29
35
|
* @import { Primitive, Unknown } from '../ts/types.ts'
|
|
30
|
-
* @import { Const, Info0, Primitive0, Tag1, Tuple, Type } from '../types.ts'
|
|
36
|
+
* @import { Const, Info0, Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts'
|
|
31
37
|
* @import { Error, Result as CommonResult } from '../../result/types.ts'
|
|
32
38
|
* @import { StringMap } from '../../object/types.ts'
|
|
33
|
-
* @import { Validate, Visitor, IsContainer, Container, ResultE, ValidateE, ValidationError } from './types.ts'
|
|
39
|
+
* @import { Validate, Visitor, IsContainer, Container, ResultE, SchemaEntries, ValidateE, ValidationError } from './types.ts'
|
|
34
40
|
*/
|
|
35
41
|
|
|
36
42
|
import { assert } from '../../../asserts/module.f.mjs'
|
|
@@ -128,6 +134,157 @@ export const eachEntry =
|
|
|
128
134
|
return ok(acc)
|
|
129
135
|
}
|
|
130
136
|
|
|
137
|
+
/**
|
|
138
|
+
* What a `Tuple` schema declares, read by **length**.
|
|
139
|
+
*
|
|
140
|
+
* `Array.from` yields `undefined` for a hole and preserves the schema's
|
|
141
|
+
* length, so a hole is a declared position whose schema is `undefined` — which
|
|
142
|
+
* is a `Const` schema in its own right, and exactly what reading index `0` of
|
|
143
|
+
* `new Array(1)` gives. That is the reading `../data/module.f.mjs`'s
|
|
144
|
+
* `containerUnion` has always had, so the canonical data form stays fixed.
|
|
145
|
+
*
|
|
146
|
+
* `Array.from` walks the iterator, which is the *same* walk `containerUnion`
|
|
147
|
+
* makes, and that is the point rather than an accident: the two agree by
|
|
148
|
+
* construction. It holds even for a schema carrying an overridden
|
|
149
|
+
* `Symbol.iterator`, where reading indices here would disagree with the data
|
|
150
|
+
* form all over again — verified: such a schema is read as `number` by the
|
|
151
|
+
* entry reading and as `string` by `containerUnion`. Reading *both* by index
|
|
152
|
+
* is defensible, but it changes the canonical, content-addressed data form and
|
|
153
|
+
* belongs with that decision, not here. FunctionalScript cannot build such a
|
|
154
|
+
* schema in the first place: it has no symbols and no mutation, so the case is
|
|
155
|
+
* reachable only from plain JavaScript, which is also why no proof can pin it.
|
|
156
|
+
*
|
|
157
|
+
* `Object.entries` skips holes, which is why it is not used here: it would
|
|
158
|
+
* make `new Array(1)` and `[]` the same schema while `[undefined]` stayed
|
|
159
|
+
* different from both. It also yields a non-index own property, which is no
|
|
160
|
+
* position either — `getItem` reads a tuple by index, so such a key was
|
|
161
|
+
* declared and then matched against `value[NaN]`. `Array.from` answers
|
|
162
|
+
* positions only. On a plain dense array the two agree exactly.
|
|
163
|
+
*
|
|
164
|
+
* @type {SchemaEntries<Tuple>}
|
|
165
|
+
*/
|
|
166
|
+
export const tupleSchemaEntries = rtti =>
|
|
167
|
+
Array.from(rtti, (t, i) => [String(i), t])
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* What a `Struct` schema declares: its enumerable own keys. A struct has no
|
|
171
|
+
* holes, so there is nothing for this to disagree with.
|
|
172
|
+
*
|
|
173
|
+
* @type {SchemaEntries<Struct>}
|
|
174
|
+
*/
|
|
175
|
+
export const structSchemaEntries = rtti =>
|
|
176
|
+
Object.entries(rtti)
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The position `k` names, or `undefined` when `k` names no position at all.
|
|
180
|
+
*
|
|
181
|
+
* Only the canonical spelling of a non-negative integer is an index: `'-1'`,
|
|
182
|
+
* `'01'`, `'1.5'` and `' 1'` are ordinary properties of an array object,
|
|
183
|
+
* however `Number` maps them. Round-tripping the number back through `String`
|
|
184
|
+
* is what rejects every non-canonical spelling at once, rather than one at a
|
|
185
|
+
* time.
|
|
186
|
+
*
|
|
187
|
+
* And only one **below `2 ** 32 - 1`**, which is where the language draws the
|
|
188
|
+
* line rather than a bound chosen here: assigning `a['4294967295']` creates an
|
|
189
|
+
* ordinary enumerable property and leaves `a.length` alone. Reading such a key
|
|
190
|
+
* as an index put it past every `length`-bounded walk *and* past the non-index
|
|
191
|
+
* filter, so it was no member on either path and an undeclared property rode
|
|
192
|
+
* through a closed container.
|
|
193
|
+
*
|
|
194
|
+
* @type {(k: string) => number | undefined}
|
|
195
|
+
*/
|
|
196
|
+
const arrayIndex = k => {
|
|
197
|
+
const i = Number(k)
|
|
198
|
+
return Number.isInteger(i) && i >= 0 && i < 2 ** 32 - 1 && String(i) === k ? i : undefined
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Every index below `length` at which `value` reads something, ascending.
|
|
203
|
+
*
|
|
204
|
+
* Bounded by what the value and its prototypes **carry** rather than by
|
|
205
|
+
* `length`: an index that reads a value is an own property of the array or of
|
|
206
|
+
* something on its prototype chain, so enumerating those names finds every one
|
|
207
|
+
* without materializing the range. Walking `0 … length - 1` instead turned a
|
|
208
|
+
* `new Array(2 ** 32 - 1)` — which carries one own property, `length` — into
|
|
209
|
+
* billions of iterations before any check could reject it.
|
|
210
|
+
*
|
|
211
|
+
* The own names are **already the answer** for all but a pathological value:
|
|
212
|
+
* `[[OwnPropertyKeys]]` yields integer indices ascending and without repeats,
|
|
213
|
+
* so an ordinary array pays one linear pass and no sort. Only an index the
|
|
214
|
+
* chain supplies and the value does not is merged in, and that set is empty
|
|
215
|
+
* unless someone has put an index on a prototype — which is why the dedup it
|
|
216
|
+
* needs may be quadratic without costing an ordinary array anything. Deduping
|
|
217
|
+
* the whole list instead made every `array(t)` read quadratic in its length:
|
|
218
|
+
* 829 ms at 40 000 elements against 3 ms at 1 000.
|
|
219
|
+
*
|
|
220
|
+
* No `in` test: a name reached this way is a property of the value or of
|
|
221
|
+
* something it inherits from, so the array reads at it by construction.
|
|
222
|
+
*
|
|
223
|
+
* @type {(value: ReadonlyArray<Unknown>) => readonly number[]}
|
|
224
|
+
*/
|
|
225
|
+
const readIndices = value => {
|
|
226
|
+
const { length } = value
|
|
227
|
+
/** @type {(names: readonly string[]) => readonly number[]} */
|
|
228
|
+
const indices = names => names.flatMap(k => {
|
|
229
|
+
const i = arrayIndex(k)
|
|
230
|
+
return i !== undefined && i < length ? [i] : []
|
|
231
|
+
})
|
|
232
|
+
const own = indices(Object.getOwnPropertyNames(value))
|
|
233
|
+
/** @type {readonly number[]} */
|
|
234
|
+
let chain = []
|
|
235
|
+
for (let o = Object.getPrototypeOf(value); o !== null; o = Object.getPrototypeOf(o)) {
|
|
236
|
+
chain = [...chain, ...indices(Object.getOwnPropertyNames(o))]
|
|
237
|
+
}
|
|
238
|
+
if (chain.length === 0) { return own }
|
|
239
|
+
const inherited = chain
|
|
240
|
+
.filter(i => !Object.hasOwn(value, i))
|
|
241
|
+
.filter((i, at, a) => a.indexOf(i) === at)
|
|
242
|
+
return inherited.length === 0 ? own : [...own, ...inherited].toSorted((a, b) => a - b)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The members of `value` that `declared` does not name — every one the
|
|
247
|
+
* schema's `rest` has to answer for, as `[key, value]` pairs.
|
|
248
|
+
*
|
|
249
|
+
* `declared` is a container schema's own key list, so for a struct these are
|
|
250
|
+
* its undeclared own keys, and for a tuple they are the positions past the
|
|
251
|
+
* prefix together with every own key that is no position at all.
|
|
252
|
+
*
|
|
253
|
+
* **A tuple's positions are read, not enumerated.** `length` is what says how
|
|
254
|
+
* far an array reaches, and every index below it that *reads* a value is a
|
|
255
|
+
* member the `rest` must answer for — including one supplied by the prototype,
|
|
256
|
+
* which no own-entry walk sees ({@link readIndices} is the walk). Filtering
|
|
257
|
+
* `Object.entries` alone accepted `[42, , ]` carrying an inherited `1: 99`
|
|
258
|
+
* against `rest([42], string)`, handing back an array whose index 1 reads a
|
|
259
|
+
* number the rendered tail types as `string`. A genuinely absent index is
|
|
260
|
+
* skipped instead: a hole is no member, so it meets no `rest` — the same rule
|
|
261
|
+
* the struct kind states by walking own keys.
|
|
262
|
+
*
|
|
263
|
+
* An index at or above `length` is a different matter and is not answered
|
|
264
|
+
* here: it is readable through the prototype and no walk bounded by the value
|
|
265
|
+
* reaches it. See "Beyond `length`" in `../README.md`.
|
|
266
|
+
*
|
|
267
|
+
* Passing an empty `declared` asks for every member, which is what the uniform
|
|
268
|
+
* `array`/`record` readers want — so they share this walk rather than reaching
|
|
269
|
+
* for `Object.entries` and disagreeing with the data form on an inherited
|
|
270
|
+
* index.
|
|
271
|
+
*
|
|
272
|
+
* @type {(declared: readonly string[], value: ReadonlyArray<Unknown> | StringMap<Unknown>) => ReadonlyArray<readonly [string, Unknown]>}
|
|
273
|
+
*/
|
|
274
|
+
export const undeclaredMembers = (declared, value) => {
|
|
275
|
+
/** @type {(k: string) => boolean} */
|
|
276
|
+
const undeclared = k => !declared.some(d => d === k)
|
|
277
|
+
if (!commonIsArray(value)) {
|
|
278
|
+
return Object.entries(value).filter(([k]) => undeclared(k))
|
|
279
|
+
}
|
|
280
|
+
return [
|
|
281
|
+
...readIndices(value)
|
|
282
|
+
.filter(i => undeclared(String(i)))
|
|
283
|
+
.map(i => /** @type {const} */ ([String(i), value[i]])),
|
|
284
|
+
...Object.entries(value).filter(([k]) => arrayIndex(k) === undefined && undeclared(k)),
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
|
|
131
288
|
/**
|
|
132
289
|
* First variant in `variants` that `recurse` accepts, else `verror('no match')`.
|
|
133
290
|
*
|
|
@@ -157,7 +314,7 @@ export const orVisit =
|
|
|
157
314
|
*
|
|
158
315
|
* - `Thunk` schemas are evaluated once to read the `Info` descriptor, then
|
|
159
316
|
* routed by tag (`'const'`, `'array'`, `'record'`, `'unknown'`, `'or'`,
|
|
160
|
-
* or a `Tag0` primitive).
|
|
317
|
+
* `'rest'`, or a `Tag0` primitive).
|
|
161
318
|
* - `Const` schemas (primitives, tuples, structs) are routed directly to
|
|
162
319
|
* `tuple`, `struct`, or `constPrimitive`.
|
|
163
320
|
*/
|
|
@@ -182,6 +339,14 @@ export const visit =
|
|
|
182
339
|
case 'record': return v.record(value[0])
|
|
183
340
|
case 'unknown': return v.unknown()
|
|
184
341
|
case 'or': return v.or(value)
|
|
342
|
+
case 'rest': {
|
|
343
|
+
const [c, r] = value
|
|
344
|
+
// `rest`'s container is a `ConstObject`, which is exactly
|
|
345
|
+
// the non-null objects among the `Const`s — a `Thunk` is a
|
|
346
|
+
// function, and every other `Const` is a primitive.
|
|
347
|
+
assert(typeof c === 'object' && c !== null, c)
|
|
348
|
+
return v.rest(c, r)
|
|
349
|
+
}
|
|
185
350
|
}
|
|
186
351
|
return v.primitive0(tag)
|
|
187
352
|
}
|
|
@@ -9,5 +9,19 @@ export declare const proof: {
|
|
|
9
9
|
noAccumulate: () => void;
|
|
10
10
|
firstErrorWins: () => void;
|
|
11
11
|
shortCircuits: () => void;
|
|
12
|
+
undeclared: {
|
|
13
|
+
struct: () => void;
|
|
14
|
+
tuple: () => void;
|
|
15
|
+
none: () => void;
|
|
16
|
+
holeIsNoMember: () => void;
|
|
17
|
+
lengthDoesNotBoundTheWalk: () => void;
|
|
18
|
+
};
|
|
19
|
+
schemaEntries: {
|
|
20
|
+
tuple: () => void;
|
|
21
|
+
tupleHole: () => void;
|
|
22
|
+
tupleHoleIsTheDenseReading: () => void;
|
|
23
|
+
struct: () => void;
|
|
24
|
+
empty: () => void;
|
|
25
|
+
};
|
|
12
26
|
pathPrefixed: () => void;
|
|
13
27
|
};
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @import { ValidationError } from './types.ts'
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { eachEntry } from './module.f.mjs'
|
|
6
|
+
import { eachEntry, structSchemaEntries, tupleSchemaEntries, undeclaredMembers } from './module.f.mjs'
|
|
7
7
|
import { error, ok } from '../../result/module.f.mjs'
|
|
8
|
-
import { assert, assertEq } from '../../../asserts/module.f.mjs'
|
|
8
|
+
import { assert, assertEq, assertStructurallySame } from '../../../asserts/module.f.mjs'
|
|
9
9
|
|
|
10
10
|
/** @typedef {ReadonlyArray<readonly [string, number]>} _Entries */
|
|
11
11
|
|
|
@@ -54,6 +54,65 @@ export const proof = {
|
|
|
54
54
|
assert(r[0] === 'error')
|
|
55
55
|
assertEq(calls, 1)
|
|
56
56
|
},
|
|
57
|
+
// The other half of a container's loop: the members a bare schema rejects
|
|
58
|
+
// and a `rest` one holds to its rest. One function answers both kinds — a
|
|
59
|
+
// struct's undeclared own keys, and an array's positions past the prefix
|
|
60
|
+
// together with the own keys that are no position at all.
|
|
61
|
+
undeclared: {
|
|
62
|
+
struct: () => {
|
|
63
|
+
const r = undeclaredMembers(['a'], { a: 1, b: 2 })
|
|
64
|
+
assertStructurallySame(r, [['b', 2]])
|
|
65
|
+
},
|
|
66
|
+
// The positions come first, in index order, then the keys that name
|
|
67
|
+
// none — so the reported error path is the leftmost failing member.
|
|
68
|
+
tuple: () => {
|
|
69
|
+
const r = undeclaredMembers(['0'], Object.assign([1, 2], { foo: 3, '01': 4 }))
|
|
70
|
+
assertStructurallySame(r, [['1', 2], ['foo', 3], ['01', 4]])
|
|
71
|
+
},
|
|
72
|
+
none: () => assertEq(undeclaredMembers(['a'], { a: 1 }).length, 0),
|
|
73
|
+
// A hole is no member, so it meets no `rest` — which is why the array
|
|
74
|
+
// kind also answers with its `length`; see `fits` in
|
|
75
|
+
// `../parse/module.f.mjs`.
|
|
76
|
+
holeIsNoMember: () => assertEq(undeclaredMembers(['0'], [1, , 3]).length, 1),
|
|
77
|
+
// The walk is bounded by what the value and its prototypes carry, not
|
|
78
|
+
// by `length` — this one carries a single own property, `length`, so
|
|
79
|
+
// it answers at once. Materializing the range instead exhausted memory
|
|
80
|
+
// long before any check could reject the value.
|
|
81
|
+
lengthDoesNotBoundTheWalk: () =>
|
|
82
|
+
assertEq(undeclaredMembers([], new Array(2 ** 32 - 1)).length, 0),
|
|
83
|
+
// An index the prototype supplies is a member too, and a canonical
|
|
84
|
+
// numeric key past the index range is one by the non-index half. Both
|
|
85
|
+
// need in-place mutation to build, so they are pinned in
|
|
86
|
+
// `../host.proof.mjs` — see its module doc.
|
|
87
|
+
},
|
|
88
|
+
// What a container schema declares, per kind. A tuple is read by length,
|
|
89
|
+
// so a hole is a declared position whose schema is `undefined` — the same
|
|
90
|
+
// reading `../data/module.f.mjs` has, and the reason the two kinds need
|
|
91
|
+
// different entry readers at all.
|
|
92
|
+
schemaEntries: {
|
|
93
|
+
tuple: () => assertStructurallySame(
|
|
94
|
+
tupleSchemaEntries([1, 'a']),
|
|
95
|
+
[['0', 1], ['1', 'a']],
|
|
96
|
+
),
|
|
97
|
+
// `Object.entries` would answer `[]` here, and `[['0', undefined]]` for
|
|
98
|
+
// `[undefined]` — two schemas that denote the same set, read as two.
|
|
99
|
+
tupleHole: () => assertStructurallySame(
|
|
100
|
+
tupleSchemaEntries(new Array(1)),
|
|
101
|
+
[['0', undefined]],
|
|
102
|
+
),
|
|
103
|
+
tupleHoleIsTheDenseReading: () => assertStructurallySame(
|
|
104
|
+
tupleSchemaEntries(new Array(1)),
|
|
105
|
+
tupleSchemaEntries([undefined]),
|
|
106
|
+
),
|
|
107
|
+
struct: () => assertStructurallySame(
|
|
108
|
+
structSchemaEntries({ a: 1, b: 'x' }),
|
|
109
|
+
[['a', 1], ['b', 'x']],
|
|
110
|
+
),
|
|
111
|
+
empty: () => {
|
|
112
|
+
assertEq(tupleSchemaEntries([]).length, 0)
|
|
113
|
+
assertEq(structSchemaEntries({}).length, 0)
|
|
114
|
+
},
|
|
115
|
+
},
|
|
57
116
|
pathPrefixed: () => {
|
|
58
117
|
/** @type {(k: string, v: number) => Result<number, ValidationError>} */
|
|
59
118
|
const nested = (k, v) =>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import type { Primitive, Unknown } from '../ts/types.ts';
|
|
7
|
-
import type { Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts';
|
|
7
|
+
import type { ConstObject, Primitive0, Struct, Tag1, Tuple, Type } from '../types.ts';
|
|
8
8
|
import type { Result as CommonResult } from '../../result/types.ts';
|
|
9
9
|
import type { Ts } from '../ts/types.ts';
|
|
10
10
|
import type { StringMap } from '../../object/types.ts';
|
|
@@ -26,6 +26,13 @@ export type Validate<T extends Type> = (value: Unknown) => Result<T>;
|
|
|
26
26
|
export type Visitor<R> = {
|
|
27
27
|
readonly tuple: (rtti: Tuple) => R;
|
|
28
28
|
readonly struct: (rtti: Struct) => R;
|
|
29
|
+
/**
|
|
30
|
+
* A container with a stated rest: the declared members of `rtti`, plus any
|
|
31
|
+
* number of members belonging to `r`. The bare `tuple`/`struct` handlers
|
|
32
|
+
* are the same thing with `r` of `never`, and are kept apart because the
|
|
33
|
+
* common case pays no rest walk.
|
|
34
|
+
*/
|
|
35
|
+
readonly rest: (rtti: ConstObject, r: Type) => R;
|
|
29
36
|
readonly array: (item: Type) => R;
|
|
30
37
|
readonly record: (item: Type) => R;
|
|
31
38
|
readonly or: (variants: readonly Type[]) => R;
|
|
@@ -33,6 +40,21 @@ export type Visitor<R> = {
|
|
|
33
40
|
readonly primitive0: (tag: Primitive0) => R;
|
|
34
41
|
readonly unknown: () => R;
|
|
35
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Reads what a container schema declares, as `[key, Type]` pairs — one per
|
|
45
|
+
* container kind, since a `Tuple` is read by length and a `Struct` by
|
|
46
|
+
* enumerable key. See `tupleSchemaEntries` in `./module.f.mjs` for why the two
|
|
47
|
+
* readings are not interchangeable on a sparse array.
|
|
48
|
+
*/
|
|
49
|
+
export type SchemaEntries<S extends ConstObject> = (rtti: S) => ReadonlyArray<readonly [string, Type]>;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a container `value` reaches no further than the `declared` members
|
|
52
|
+
* of its schema. The array kind is the only one with an answer of its own:
|
|
53
|
+
* `length` says how far an array reaches whether or not anything is there, so
|
|
54
|
+
* a hole past the prefix is caught here and nowhere else. An object has no
|
|
55
|
+
* such measure, and always fits.
|
|
56
|
+
*/
|
|
57
|
+
export type Fits<C extends Unknown> = (value: C, declared: number) => boolean;
|
|
36
58
|
/** Type guard narrowing `Unknown` to a specific container type `C`. */
|
|
37
59
|
export type IsContainer<C extends Unknown> = (value: Unknown) => value is C;
|
|
38
60
|
/** Maps a `Tag1` to its runtime container type. */
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* @import { StringMap } from '../../object/types.ts'
|
|
22
22
|
* @import { ArraySet, Data, KindSet, Node, ObjectSet, RuleSet, UnionSet } from './types.ts'
|
|
23
23
|
*/
|
|
24
|
-
import type { Const, Type } from '../types.ts';
|
|
24
|
+
import type { Const, ConstObject, Type } from '../types.ts';
|
|
25
25
|
import type { Primitive, Unknown } from '../ts/types.ts';
|
|
26
26
|
import type { ResultE } from '../common/types.ts';
|
|
27
27
|
import type { StringMap } from '../../object/types.ts';
|
|
@@ -95,6 +95,22 @@ export type _Keyed = readonly [Node, string | undefined];
|
|
|
95
95
|
* @type {(a: Data) => (b: Data) => boolean}
|
|
96
96
|
*/
|
|
97
97
|
export declare const subset: (a: Data) => (b: Data) => boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether `a` and `b` denote the same set: {@link subset} both ways.
|
|
100
|
+
*
|
|
101
|
+
* Weaker as a test than {@link equal} and stronger as an answer. `equal`
|
|
102
|
+
* compares canonical *structure*, so it reports two α-equivalent recursive
|
|
103
|
+
* definitions — the same shape under different rule names — as different;
|
|
104
|
+
* `subset` resolves references coinductively and sees through the renaming
|
|
105
|
+
* (see `./README.md`). It inherits `subset`'s incompleteness in exchange: an
|
|
106
|
+
* equality that holds only by distributing a union, or through a non-syntactic
|
|
107
|
+
* empty set, is answered `false`. That direction is the safe one — a `false`
|
|
108
|
+
* here never merges two memberships — so a caller may treat a `true` as
|
|
109
|
+
* conclusive and a `false` as "not established".
|
|
110
|
+
*
|
|
111
|
+
* @type {(a: Data) => (b: Data) => boolean}
|
|
112
|
+
*/
|
|
113
|
+
export declare const equivalent: (a: Data) => (b: Data) => boolean;
|
|
98
114
|
export type _NodeMap = (n: Node) => Node;
|
|
99
115
|
export type _Thunk = Exclude<Type, Const>;
|
|
100
116
|
export type _Key = Exclude<Type, Primitive>;
|
|
@@ -123,6 +139,46 @@ export type _State = {
|
|
|
123
139
|
* @type {(t: Type) => Data}
|
|
124
140
|
*/
|
|
125
141
|
export declare const toData: (t: Type) => Data;
|
|
142
|
+
/**
|
|
143
|
+
* Whether `r`, as the rest of the container `c`, admits nothing — so that
|
|
144
|
+
* `rest(c, r)` and the bare, closed `c` denote one set.
|
|
145
|
+
*
|
|
146
|
+
* This is what the schema-form readers bound an array's length by, and it is
|
|
147
|
+
* asked *here* on purpose: `arraySet` is where an empty rest normalizes away,
|
|
148
|
+
* so the readers agree with this form by asking it rather than by re-deriving
|
|
149
|
+
* the same rule and drifting. Stated as **making no difference to the
|
|
150
|
+
* canonical form** — the conversion of `rest(c, r)` denoting the same set as
|
|
151
|
+
* the conversion of `c` — and not as a judgement about `r` on its own, nor as
|
|
152
|
+
* a reading of whether the conversion kept a `rest` key. Five cases fix it
|
|
153
|
+
* between them, and only this equality satisfies all five:
|
|
154
|
+
*
|
|
155
|
+
* - `never`, `or()` and `[or()]` all convert `rest(c, r)` to `c`'s own
|
|
156
|
+
* conversion, so all three are empty. Keying on the exported `never` alone
|
|
157
|
+
* would pass a `never`-only proof with the other two spellings still
|
|
158
|
+
* disagreeing.
|
|
159
|
+
* - `const r = () => ['rest', [r], never]` has no finite inhabitant, yet the
|
|
160
|
+
* conversion keeps `rest: "r"`, so it is *not* empty here. A reader
|
|
161
|
+
* recognizing that emptiness would start rejecting what this form accepts.
|
|
162
|
+
* - `const a = () => ['or', b]; const b = () => ['or', a]` rules out the
|
|
163
|
+
* rest's *own* canonical data as the test: {@link toData} of `a` is `never`,
|
|
164
|
+
* and the conversion still keeps `rest: "a"`.
|
|
165
|
+
* - `unknown` rules out "the conversion kept no `rest` key" as the test:
|
|
166
|
+
* `toData(rest([], unknown))` is `{ array: true }` — the whole kind, with no
|
|
167
|
+
* `rest` key — because a top rest collapses the pattern rather than being
|
|
168
|
+
* dropped from it.
|
|
169
|
+
* - Two separately constructed copies of one recursive rule, one in `c` and
|
|
170
|
+
* one in `r`, rule out {@link equal} as the comparison: converting the rest
|
|
171
|
+
* reserves the name, so `c`'s rule is named `r0` where converting `c` alone
|
|
172
|
+
* names it `r`, and `equal` compares recursive definitions by rule name.
|
|
173
|
+
*
|
|
174
|
+
* {@link equivalent} answers all five. It is incomplete, and in the direction
|
|
175
|
+
* that costs nothing here: an unrecognized empty rest leaves the length
|
|
176
|
+
* unbounded, which is what a *kept* `rest` key means in this form anyway, so
|
|
177
|
+
* the readers still agree with it.
|
|
178
|
+
*
|
|
179
|
+
* @type {(c: ConstObject, r: Type) => boolean}
|
|
180
|
+
*/
|
|
181
|
+
export declare const emptyRest: (c: ConstObject, r: Type) => boolean;
|
|
126
182
|
/**
|
|
127
183
|
* Data-driven validation — the counterpart of `../validate` that consumes a
|
|
128
184
|
* {@link Data} produced by {@link toData} instead of walking the thunk
|