functionalscript 0.46.1 → 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 +42 -25
- package/fjs/types/rtti/validate/module.f.mjs +187 -53
- package/fjs/types/rtti/validate/proof.f.d.mts +28 -2
- package/fjs/types/rtti/validate/proof.f.mjs +430 -75
- 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
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rtti readers against values **FunctionalScript cannot build**.
|
|
3
|
+
*
|
|
4
|
+
* A `proof.mjs` rather than a `proof.f.mjs`, and deliberately: the fixtures
|
|
5
|
+
* here need in-place mutation — `Object.setPrototypeOf` to give an array a
|
|
6
|
+
* prototype that supplies an index, `Object.assign` to put a key past the
|
|
7
|
+
* index range on one — which [`../../AGENTS.md`](../../AGENTS.md) §3.1 forbids
|
|
8
|
+
* in authored FunctionalScript. `shouldLoad` in
|
|
9
|
+
* [`../../dev/module.f.mjs`](../../dev/module.f.mjs) makes a plain
|
|
10
|
+
* `proof.mjs` the opt-in home for exactly that, so the mutation stays out of
|
|
11
|
+
* the `.f.mjs` proofs rather than being smuggled through them.
|
|
12
|
+
*
|
|
13
|
+
* The values are worth pinning even though the subset cannot express them: a
|
|
14
|
+
* caller in ordinary JavaScript can hand one to an exported reader, and both
|
|
15
|
+
* are cases where reading a member by *entry* and reading it by *index*
|
|
16
|
+
* disagree — which is what these readers had wrong.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*
|
|
20
|
+
* @import { Type } from './types.ts'
|
|
21
|
+
* @import { ValidateE } from './common/types.ts'
|
|
22
|
+
* @import { Unknown } from './ts/types.ts'
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { assert, assertEq, assertStructurallySame } from '../../asserts/module.f.mjs'
|
|
26
|
+
import { undeclaredMembers } from './common/module.f.mjs'
|
|
27
|
+
import { toData, validate as dataValidate } from './data/module.f.mjs'
|
|
28
|
+
import { array, number, rest, string } from './module.f.mjs'
|
|
29
|
+
import { parse } from './parse/module.f.mjs'
|
|
30
|
+
import { validate } from './validate/module.f.mjs'
|
|
31
|
+
|
|
32
|
+
/** The three readers with their payload type erased, as `validate/proof.f.mjs` has them. */
|
|
33
|
+
|
|
34
|
+
/** @type {(t: Type) => ValidateE} */
|
|
35
|
+
const v = t => /** @type {any} */ (validate(t))
|
|
36
|
+
|
|
37
|
+
/** @type {(t: Type) => ValidateE} */
|
|
38
|
+
const p = t => /** @type {any} */ (parse(t))
|
|
39
|
+
|
|
40
|
+
/** @type {(t: Type) => ValidateE} */
|
|
41
|
+
const d = t => dataValidate(toData(t))
|
|
42
|
+
|
|
43
|
+
/** @type {(r: readonly [string, unknown]) => void} */
|
|
44
|
+
const assertOk = ([k]) => { assertEq(k, 'ok', 'expected ok') }
|
|
45
|
+
|
|
46
|
+
/** @type {(r: readonly [string, unknown]) => void} */
|
|
47
|
+
const assertError = ([k]) => { assertEq(k, 'error', 'expected error') }
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* An array whose index 1 is readable through the **prototype**: `length` says
|
|
51
|
+
* 2, index 1 is no own entry, and reading it gives `99`. `Array.isArray` looks
|
|
52
|
+
* at the value and not at its prototype, so this is still an array to every
|
|
53
|
+
* reader — and the member is one a schema has to answer for, or the tail
|
|
54
|
+
* `./ts/types.ts` renders would claim the rest's type over a number.
|
|
55
|
+
*
|
|
56
|
+
* @type {() => readonly Unknown[]}
|
|
57
|
+
*/
|
|
58
|
+
const inheritedIndex = () => {
|
|
59
|
+
const value = [42, ,]
|
|
60
|
+
Object.setPrototypeOf(value, [0, 99])
|
|
61
|
+
return value
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* An array whose prototype supplies an index it **owns anyway**. Nothing about
|
|
66
|
+
* it is unusual to a reader — the member list is the own one — but it is the
|
|
67
|
+
* case that separates "the chain names an index" from "the chain supplies one",
|
|
68
|
+
* which is where the walk decides whether it has anything to merge.
|
|
69
|
+
*
|
|
70
|
+
* @type {() => readonly Unknown[]}
|
|
71
|
+
*/
|
|
72
|
+
const shadowedIndex = () => {
|
|
73
|
+
const value = [42]
|
|
74
|
+
Object.setPrototypeOf(value, [7])
|
|
75
|
+
return value
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* An array carrying `4294967295` — one past the last index the language has.
|
|
80
|
+
* Assigning it creates an ordinary enumerable property and leaves `length` at
|
|
81
|
+
* `1`, so it is an undeclared member that no `length`-bounded walk reaches; a
|
|
82
|
+
* reader treating it as an index found it on neither path and let it through a
|
|
83
|
+
* closed container.
|
|
84
|
+
*
|
|
85
|
+
* @type {() => readonly Unknown[]}
|
|
86
|
+
*/
|
|
87
|
+
const beyondIndexRange = () => Object.assign([1], { '4294967295': 2 })
|
|
88
|
+
|
|
89
|
+
export const proof = {
|
|
90
|
+
// `undeclaredMembers` decides a container's members by what an index
|
|
91
|
+
// *reads*, so both of these are members — one that an own-entry walk
|
|
92
|
+
// misses, and one that an index-keyed walk misses.
|
|
93
|
+
undeclaredMembers: {
|
|
94
|
+
inheritedIndexIsAMember: () => {
|
|
95
|
+
const value = inheritedIndex()
|
|
96
|
+
assertEq(value.length, 2, 'the array reaches that far')
|
|
97
|
+
assert(!Object.hasOwn(value, 1), 'and index 1 is no own entry')
|
|
98
|
+
assertStructurallySame(undeclaredMembers(['0'], value), [['1', 99]])
|
|
99
|
+
},
|
|
100
|
+
// A shadowed one contributes nothing: the value owns the index, so
|
|
101
|
+
// the member list is what the own walk already answered.
|
|
102
|
+
shadowedIndexIsTheOwnOne: () => {
|
|
103
|
+
const value = shadowedIndex()
|
|
104
|
+
assertEq(value[0], 42, 'the own value wins')
|
|
105
|
+
assertStructurallySame(undeclaredMembers([], value), [['0', 42]])
|
|
106
|
+
assertEq(undeclaredMembers(['0'], value).length, 0)
|
|
107
|
+
},
|
|
108
|
+
// `2 ** 32 - 1` is not an index: assigning it creates an ordinary
|
|
109
|
+
// enumerable property and leaves `length` alone, so it is a member by
|
|
110
|
+
// the non-index half. Reading it as an index put it past both halves.
|
|
111
|
+
beyondTheIndexRangeIsAMember: () => {
|
|
112
|
+
const value = beyondIndexRange()
|
|
113
|
+
assertEq(value.length, 1, '`length` never saw the assignment')
|
|
114
|
+
assertStructurallySame(
|
|
115
|
+
undeclaredMembers(['0'], value),
|
|
116
|
+
[['4294967295', 2]],
|
|
117
|
+
)
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
// Every row runs through all three readers, which is the agreement
|
|
121
|
+
// `validate/proof.f.mjs`'s table exists to hold: a value one reader
|
|
122
|
+
// accepts and another rejects is a bug in whichever walk differs, and
|
|
123
|
+
// both of these fixtures found one.
|
|
124
|
+
readersAgree: () => {
|
|
125
|
+
/** @type {readonly (readonly [Type, readonly Unknown[]])[]} */
|
|
126
|
+
const rows = [
|
|
127
|
+
// an index read through the prototype is held to the rest like any
|
|
128
|
+
// other member — on the uniform reader as well as the tuple one
|
|
129
|
+
[rest([number], string), inheritedIndex()],
|
|
130
|
+
[rest([number], number), inheritedIndex()],
|
|
131
|
+
[array(string), inheritedIndex()],
|
|
132
|
+
[array(number), inheritedIndex()],
|
|
133
|
+
// a key past the last index the language has is an ordinary
|
|
134
|
+
// property, so it is a member by the non-index half
|
|
135
|
+
[[number], beyondIndexRange()],
|
|
136
|
+
[rest([number], string), beyondIndexRange()],
|
|
137
|
+
[rest([number], number), beyondIndexRange()],
|
|
138
|
+
]
|
|
139
|
+
for (const [t, value] of rows) {
|
|
140
|
+
const rv = v(t)(value)
|
|
141
|
+
assertEq(rv[0], p(t)(value)[0], 'validate and parse must agree')
|
|
142
|
+
assertEq(rv[0], d(t)(value)[0], 'the data form must agree too')
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
// …and what they agree on, which is what the changelog entry claims.
|
|
146
|
+
inheritedIndexMeetsTheRest: () => {
|
|
147
|
+
const value = inheritedIndex()
|
|
148
|
+
for (const read of [v, p, d]) {
|
|
149
|
+
assertError(read(rest([number], string))(value))
|
|
150
|
+
assertOk(read(rest([number], number))(value))
|
|
151
|
+
// `array(t)` is `rest([], t)`, so it walks the value the same way.
|
|
152
|
+
// An own-entry walk here answered `ok` while the data form's
|
|
153
|
+
// reader rejected the same value against the same schema.
|
|
154
|
+
assertError(read(array(string))(value))
|
|
155
|
+
assertOk(read(array(number))(value))
|
|
156
|
+
}
|
|
157
|
+
assert(Object.is(v(rest([number], number))(value)[1], value),
|
|
158
|
+
'`validate` still hands back the value it was given')
|
|
159
|
+
},
|
|
160
|
+
beyondTheIndexRangeIsAMember: () => {
|
|
161
|
+
const value = beyondIndexRange()
|
|
162
|
+
for (const read of [v, p, d]) {
|
|
163
|
+
// a bare container names every member it admits, and not this one
|
|
164
|
+
assertError(read([number])(value))
|
|
165
|
+
// a stated rest answers for it like any other undeclared member
|
|
166
|
+
assertError(read(rest([number], string))(value))
|
|
167
|
+
assertOk(read(rest([number], number))(value))
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* @import { Includes } from '../array/types.ts'
|
|
8
8
|
* @import { Assert } from '../../asserts/types.ts'
|
|
9
9
|
* @import { Equal } from '../ts/types.ts'
|
|
10
|
-
* @import { Tag0, Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1,
|
|
10
|
+
* @import { Tag0, Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1, _MakeOpen, _MakeRest, Or, Type } from './types.ts'
|
|
11
11
|
*/
|
|
12
12
|
import type { Includes } from '../array/types.ts';
|
|
13
13
|
import type { Assert } from '../../asserts/types.ts';
|
|
14
14
|
import type { Equal } from '../ts/types.ts';
|
|
15
|
-
import type { Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1, Or, Type } from './types.ts';
|
|
15
|
+
import type { Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1, _MakeOpen, _MakeRest, Or, Type } from './types.ts';
|
|
16
16
|
declare const primitive0List: readonly ['bigint', 'boolean', 'number', 'string'];
|
|
17
17
|
export type _Primitive0Pinned = Assert<Equal<Primitive0, typeof primitive0List[number]>>;
|
|
18
18
|
/** @typedef {Assert<Equal<Primitive0, typeof primitive0List[number]>>} _Primitive0Pinned */
|
|
@@ -62,22 +62,67 @@ export declare const record: _MakeType1<'record'>;
|
|
|
62
62
|
* or canonical-form work. All such algebra lives on the serializable data form
|
|
63
63
|
* — see `./data/README.md`.
|
|
64
64
|
*
|
|
65
|
-
* @template {readonly Type[]} T
|
|
65
|
+
* @template {readonly Type[]} const T
|
|
66
66
|
* @param {T} types
|
|
67
67
|
* @returns {Or<T>}
|
|
68
68
|
*/
|
|
69
|
-
export declare const or: <T extends readonly Type[]>(...types: T) => Or<T>;
|
|
69
|
+
export declare const or: <const T extends readonly Type[]>(...types: T) => Or<T>;
|
|
70
70
|
/**
|
|
71
71
|
* Constructs a schema that validates a value matching `T` or `undefined`.
|
|
72
72
|
*
|
|
73
|
-
* @template {Type} T
|
|
73
|
+
* @template {Type} const T
|
|
74
74
|
* @param {T} t
|
|
75
75
|
* @returns {Or<readonly [T, undefined]>}
|
|
76
76
|
*/
|
|
77
|
-
export declare const option: <T extends Type>(t: T) => Or<readonly [T, undefined]>;
|
|
77
|
+
export declare const option: <const T extends Type>(t: T) => Or<readonly [T, undefined]>;
|
|
78
78
|
/**
|
|
79
79
|
* Schema that never matches any value — the empty union, corresponding to TypeScript's `never`.
|
|
80
|
+
*
|
|
80
81
|
* @type {Or<readonly []>}
|
|
81
82
|
*/
|
|
82
83
|
export declare const never: Or<readonly []>;
|
|
84
|
+
/**
|
|
85
|
+
* Constructs a schema for a container whose **undeclared** members belong to
|
|
86
|
+
* `r`: the members `c` declares, plus any number of members belonging to `r`.
|
|
87
|
+
*
|
|
88
|
+
* A `Struct` or a `Tuple` used on its own is closed — it admits the members it
|
|
89
|
+
* declares and no others — which is `rest(c, never)` and needs no spelling.
|
|
90
|
+
* This is how a schema says it wants anything else.
|
|
91
|
+
*
|
|
92
|
+
* ```js
|
|
93
|
+
* rest([number], string) // one number, then any number of strings
|
|
94
|
+
* rest({ a: number }, string) // `a`, plus any number of string-valued keys
|
|
95
|
+
* open({ a: number }) // `a`, plus anything else
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* Both parameters are required. An optional one would need a sentinel for "no
|
|
99
|
+
* undeclared member", and every candidate — `undefined` most of all — is a
|
|
100
|
+
* `Type` in its own right, so the sentinel would collide with the schema it
|
|
101
|
+
* spells. `never` carries no such ambiguity, and a container whose undeclared
|
|
102
|
+
* members must be the *value* `undefined` states that rest as a wrapped const,
|
|
103
|
+
* `() => ['const', undefined]`.
|
|
104
|
+
*
|
|
105
|
+
* On the array kind `r` constrains the members past the prefix, and a `r` that
|
|
106
|
+
* admits nothing bounds the array's length — which is what the bare form
|
|
107
|
+
* already says, so `rest(c, never)` and `c` are one set.
|
|
108
|
+
*
|
|
109
|
+
* @type {_MakeRest}
|
|
110
|
+
*/
|
|
111
|
+
export declare const rest: _MakeRest;
|
|
112
|
+
/**
|
|
113
|
+
* Constructs a schema for an **open** container: the members `c` declares,
|
|
114
|
+
* plus any number of members of any kind. `open(c)` is `rest(c, unknown)`.
|
|
115
|
+
*
|
|
116
|
+
* Openness is what makes a schema forward-compatible with a serialization
|
|
117
|
+
* format that has grown fields, so a schema read against a wire format
|
|
118
|
+
* someone else may extend says `open`.
|
|
119
|
+
*
|
|
120
|
+
* ```js
|
|
121
|
+
* open({ a: number }) // any object whose `a` is a number
|
|
122
|
+
* open([number]) // any array whose position 0 is a number
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @type {_MakeOpen}
|
|
126
|
+
*/
|
|
127
|
+
export declare const open: _MakeOpen;
|
|
83
128
|
export {};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @import { Includes } from '../array/types.ts'
|
|
8
8
|
* @import { Assert } from '../../asserts/types.ts'
|
|
9
9
|
* @import { Equal } from '../ts/types.ts'
|
|
10
|
-
* @import { Tag0, Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1,
|
|
10
|
+
* @import { Tag0, Primitive0, _Type0, Bigint, Unknown, Tag1, _MakeType1, _MakeOpen, _MakeRest, Or, Type } from './types.ts'
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { includes } from '../array/module.f.mjs'
|
|
@@ -88,7 +88,7 @@ export const record = type1('record')
|
|
|
88
88
|
* or canonical-form work. All such algebra lives on the serializable data form
|
|
89
89
|
* — see `./data/README.md`.
|
|
90
90
|
*
|
|
91
|
-
* @template {readonly Type[]} T
|
|
91
|
+
* @template {readonly Type[]} const T
|
|
92
92
|
* @param {T} types
|
|
93
93
|
* @returns {Or<T>}
|
|
94
94
|
*/
|
|
@@ -98,7 +98,7 @@ export const or = (...types) =>
|
|
|
98
98
|
/**
|
|
99
99
|
* Constructs a schema that validates a value matching `T` or `undefined`.
|
|
100
100
|
*
|
|
101
|
-
* @template {Type} T
|
|
101
|
+
* @template {Type} const T
|
|
102
102
|
* @param {T} t
|
|
103
103
|
* @returns {Or<readonly [T, undefined]>}
|
|
104
104
|
*/
|
|
@@ -107,6 +107,53 @@ export const option = t =>
|
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Schema that never matches any value — the empty union, corresponding to TypeScript's `never`.
|
|
110
|
+
*
|
|
110
111
|
* @type {Or<readonly []>}
|
|
111
112
|
*/
|
|
112
113
|
export const never = or()
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Constructs a schema for a container whose **undeclared** members belong to
|
|
117
|
+
* `r`: the members `c` declares, plus any number of members belonging to `r`.
|
|
118
|
+
*
|
|
119
|
+
* A `Struct` or a `Tuple` used on its own is closed — it admits the members it
|
|
120
|
+
* declares and no others — which is `rest(c, never)` and needs no spelling.
|
|
121
|
+
* This is how a schema says it wants anything else.
|
|
122
|
+
*
|
|
123
|
+
* ```js
|
|
124
|
+
* rest([number], string) // one number, then any number of strings
|
|
125
|
+
* rest({ a: number }, string) // `a`, plus any number of string-valued keys
|
|
126
|
+
* open({ a: number }) // `a`, plus anything else
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* Both parameters are required. An optional one would need a sentinel for "no
|
|
130
|
+
* undeclared member", and every candidate — `undefined` most of all — is a
|
|
131
|
+
* `Type` in its own right, so the sentinel would collide with the schema it
|
|
132
|
+
* spells. `never` carries no such ambiguity, and a container whose undeclared
|
|
133
|
+
* members must be the *value* `undefined` states that rest as a wrapped const,
|
|
134
|
+
* `() => ['const', undefined]`.
|
|
135
|
+
*
|
|
136
|
+
* On the array kind `r` constrains the members past the prefix, and a `r` that
|
|
137
|
+
* admits nothing bounds the array's length — which is what the bare form
|
|
138
|
+
* already says, so `rest(c, never)` and `c` are one set.
|
|
139
|
+
*
|
|
140
|
+
* @type {_MakeRest}
|
|
141
|
+
*/
|
|
142
|
+
export const rest = (c, r) => () => /** @type {any} */ (['rest', c, r])
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Constructs a schema for an **open** container: the members `c` declares,
|
|
146
|
+
* plus any number of members of any kind. `open(c)` is `rest(c, unknown)`.
|
|
147
|
+
*
|
|
148
|
+
* Openness is what makes a schema forward-compatible with a serialization
|
|
149
|
+
* format that has grown fields, so a schema read against a wire format
|
|
150
|
+
* someone else may extend says `open`.
|
|
151
|
+
*
|
|
152
|
+
* ```js
|
|
153
|
+
* open({ a: number }) // any object whose `a` is a number
|
|
154
|
+
* open([number]) // any array whose position 0 is a number
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @type {_MakeOpen}
|
|
158
|
+
*/
|
|
159
|
+
export const open = c => /** @type {any} */ (rest(c, unknown))
|
|
@@ -5,31 +5,38 @@
|
|
|
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
|
-
* **Structs and tuples are
|
|
9
|
-
* declares
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* - Structs: undeclared properties are accepted; the result has only the
|
|
15
|
-
* schema's keys.
|
|
8
|
+
* **Structs and tuples are closed.** A bare `Struct` or `Tuple` admits the
|
|
9
|
+
* members it declares and no others, so a value carrying more is rejected:
|
|
10
|
+
*
|
|
11
|
+
* - Tuples: an array longer than the schema is rejected — by length as well as
|
|
12
|
+
* by member, since a hole past the prefix is no member.
|
|
13
|
+
* - Structs: an undeclared property is rejected.
|
|
16
14
|
* - Arrays/records: every element/value is itself parsed, so a fresh container is
|
|
17
15
|
* always returned even if the inner type is a primitive.
|
|
18
16
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* Closedness is about *undeclared* members, and leaves the required/optional
|
|
18
|
+
* rule alone: a member is required exactly when its set excludes `undefined` —
|
|
19
|
+
* an absent member reads as `undefined`, on both kinds — so a shorter array
|
|
20
|
+
* whose trailing position admits `undefined` is accepted and the gap is
|
|
21
|
+
* filled.
|
|
22
|
+
*
|
|
23
|
+
* A tuple schema declares by length, so a hole in the *schema* is a declared
|
|
24
|
+
* position whose schema is `undefined` — see "A hole is a declared position"
|
|
25
|
+
* in `../README.md`.
|
|
22
26
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
27
|
+
* The length check is the model rather than an inference from the rendering.
|
|
28
|
+
* #1622 added one by reading `Ts<readonly[42]>`'s exact tuple as the value
|
|
29
|
+
* model while the model said open, and was reverted for that reason; what has
|
|
30
|
+
* changed since is the model, not the reading.
|
|
26
31
|
*
|
|
27
|
-
* **
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
32
|
+
* **A stated rest widens acceptance, not construction.** `rest(c, r)` holds
|
|
33
|
+
* every member `c` does not declare to `r`, and `open(c)` — `rest(c, unknown)`
|
|
34
|
+
* — admits anything else at all; either way the result carries the declared
|
|
35
|
+
* members and nothing else, so a rest says what an undeclared member must be,
|
|
36
|
+
* not that the reader should keep it. Openness is what makes a parser
|
|
37
|
+
* forward-compatible with an extended serialization format, so a schema read
|
|
38
|
+
* against a wire format someone else may extend says `open`. The reader that
|
|
39
|
+
* keeps every member is `../validate/module.f.mjs`.
|
|
33
40
|
*
|
|
34
41
|
* The error shape, path bookkeeping, primitive checks, and schema
|
|
35
42
|
* recognition (`visit`) come from `../common/module.f.mjs`.
|
|
@@ -38,11 +45,11 @@
|
|
|
38
45
|
*
|
|
39
46
|
* @module
|
|
40
47
|
*
|
|
41
|
-
* @import {
|
|
48
|
+
* @import { ConstObject, Info1, Tag1, Type } from '../types.ts'
|
|
42
49
|
* @import { Result as CommonResult } from '../../result/types.ts'
|
|
43
50
|
* @import { StringMap } from '../../object/types.ts'
|
|
44
51
|
* @import { List } from '../../list/types.ts'
|
|
45
|
-
* @import { Container, IsContainer, ValidationError, Visitor } from '../common/types.ts'
|
|
52
|
+
* @import { Container, Fits, IsContainer, SchemaEntries, ValidateE, ValidationError, Visitor } from '../common/types.ts'
|
|
46
53
|
* @import { Unknown } from '../ts/types.ts'
|
|
47
54
|
* @import { Parse } from './types.ts'
|
|
48
55
|
*/
|
|
@@ -53,5 +60,5 @@ import type { Unknown } from '../ts/types.ts';
|
|
|
53
60
|
import type { Parse } from './types.ts';
|
|
54
61
|
export type _ItemResult = CommonResult<Unknown, ValidationError>;
|
|
55
62
|
export type _Rebuild = (entries: ReadonlyArray<readonly [string, Unknown]>) => Unknown;
|
|
56
|
-
/** @type {<T extends Type>(rtti: T) => Parse<T>} */
|
|
57
|
-
export declare const parse: <T extends Type>(rtti: T) => Parse<T>;
|
|
63
|
+
/** @type {<const T extends Type>(rtti: T) => Parse<T>} */
|
|
64
|
+
export declare const parse: <const T extends Type>(rtti: T) => Parse<T>;
|