@evolu/common 8.2.0 → 8.3.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/dist/src/Function.d.ts +1 -0
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Http.d.ts +9 -0
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/Object.d.ts +1 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/RefCount.d.ts +1 -0
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/Relation.d.ts +2 -0
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Resource.d.ts +1 -0
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Result.d.ts +383 -548
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +296 -46
- package/dist/src/StackTrace.d.ts +1 -0
- package/dist/src/StackTrace.d.ts.map +1 -1
- package/dist/src/Task.d.ts +985 -1069
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1007 -156
- package/dist/src/Time.d.ts +1 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Type.d.ts +1322 -793
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1192 -244
- package/dist/src/intl/_en.d.ts +126 -0
- package/dist/src/intl/_en.d.ts.map +1 -0
- package/dist/src/intl/_en.js +267 -0
- package/dist/src/intl/ar.d.ts +117 -0
- package/dist/src/intl/ar.d.ts.map +1 -0
- package/dist/src/intl/ar.js +245 -0
- package/dist/src/intl/bn.d.ts +117 -0
- package/dist/src/intl/bn.d.ts.map +1 -0
- package/dist/src/intl/bn.js +258 -0
- package/dist/src/intl/ca.d.ts +117 -0
- package/dist/src/intl/ca.d.ts.map +1 -0
- package/dist/src/intl/ca.js +258 -0
- package/dist/src/intl/cs.d.ts +20 -7
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +54 -27
- package/dist/src/intl/da.d.ts +117 -0
- package/dist/src/intl/da.d.ts.map +1 -0
- package/dist/src/intl/da.js +258 -0
- package/dist/src/intl/de.d.ts +117 -0
- package/dist/src/intl/de.d.ts.map +1 -0
- package/dist/src/intl/de.js +258 -0
- package/dist/src/intl/el.d.ts +117 -0
- package/dist/src/intl/el.d.ts.map +1 -0
- package/dist/src/intl/el.js +265 -0
- package/dist/src/intl/es.d.ts +117 -0
- package/dist/src/intl/es.d.ts.map +1 -0
- package/dist/src/intl/es.js +258 -0
- package/dist/src/intl/fa.d.ts +117 -0
- package/dist/src/intl/fa.d.ts.map +1 -0
- package/dist/src/intl/fa.js +258 -0
- package/dist/src/intl/fi.d.ts +117 -0
- package/dist/src/intl/fi.d.ts.map +1 -0
- package/dist/src/intl/fi.js +258 -0
- package/dist/src/intl/fil.d.ts +117 -0
- package/dist/src/intl/fil.d.ts.map +1 -0
- package/dist/src/intl/fil.js +258 -0
- package/dist/src/intl/fr.d.ts +117 -0
- package/dist/src/intl/fr.d.ts.map +1 -0
- package/dist/src/intl/fr.js +258 -0
- package/dist/src/intl/he.d.ts +117 -0
- package/dist/src/intl/he.d.ts.map +1 -0
- package/dist/src/intl/he.js +258 -0
- package/dist/src/intl/hi.d.ts +117 -0
- package/dist/src/intl/hi.d.ts.map +1 -0
- package/dist/src/intl/hi.js +258 -0
- package/dist/src/intl/hr.d.ts +117 -0
- package/dist/src/intl/hr.d.ts.map +1 -0
- package/dist/src/intl/hr.js +265 -0
- package/dist/src/intl/hu.d.ts +63 -0
- package/dist/src/intl/hu.d.ts.map +1 -0
- package/dist/src/intl/hu.js +204 -0
- package/dist/src/intl/id.d.ts +117 -0
- package/dist/src/intl/id.d.ts.map +1 -0
- package/dist/src/intl/id.js +258 -0
- package/dist/src/intl/index.d.ts +42 -0
- package/dist/src/intl/index.d.ts.map +1 -1
- package/dist/src/intl/index.js +42 -0
- package/dist/src/intl/it.d.ts +117 -0
- package/dist/src/intl/it.d.ts.map +1 -0
- package/dist/src/intl/it.js +258 -0
- package/dist/src/intl/ja.d.ts +117 -0
- package/dist/src/intl/ja.d.ts.map +1 -0
- package/dist/src/intl/ja.js +258 -0
- package/dist/src/intl/ko.d.ts +117 -0
- package/dist/src/intl/ko.d.ts.map +1 -0
- package/dist/src/intl/ko.js +258 -0
- package/dist/src/intl/ml.d.ts +117 -0
- package/dist/src/intl/ml.d.ts.map +1 -0
- package/dist/src/intl/ml.js +258 -0
- package/dist/src/intl/mr.d.ts +117 -0
- package/dist/src/intl/mr.d.ts.map +1 -0
- package/dist/src/intl/mr.js +258 -0
- package/dist/src/intl/ms.d.ts +117 -0
- package/dist/src/intl/ms.d.ts.map +1 -0
- package/dist/src/intl/ms.js +245 -0
- package/dist/src/intl/nb.d.ts +63 -0
- package/dist/src/intl/nb.d.ts.map +1 -0
- package/dist/src/intl/nb.js +191 -0
- package/dist/src/intl/nl.d.ts +117 -0
- package/dist/src/intl/nl.d.ts.map +1 -0
- package/dist/src/intl/nl.js +258 -0
- package/dist/src/intl/pa.d.ts +117 -0
- package/dist/src/intl/pa.d.ts.map +1 -0
- package/dist/src/intl/pa.js +258 -0
- package/dist/src/intl/pl.d.ts +117 -0
- package/dist/src/intl/pl.d.ts.map +1 -0
- package/dist/src/intl/pl.js +242 -0
- package/dist/src/intl/pt-BR.d.ts +117 -0
- package/dist/src/intl/pt-BR.d.ts.map +1 -0
- package/dist/src/intl/pt-BR.js +258 -0
- package/dist/src/intl/pt.d.ts +117 -0
- package/dist/src/intl/pt.d.ts.map +1 -0
- package/dist/src/intl/pt.js +246 -0
- package/dist/src/intl/ro.d.ts +117 -0
- package/dist/src/intl/ro.d.ts.map +1 -0
- package/dist/src/intl/ro.js +258 -0
- package/dist/src/intl/sk.d.ts +117 -0
- package/dist/src/intl/sk.d.ts.map +1 -0
- package/dist/src/intl/sk.js +244 -0
- package/dist/src/intl/sl.d.ts +117 -0
- package/dist/src/intl/sl.d.ts.map +1 -0
- package/dist/src/intl/sl.js +258 -0
- package/dist/src/intl/sv.d.ts +117 -0
- package/dist/src/intl/sv.d.ts.map +1 -0
- package/dist/src/intl/sv.js +258 -0
- package/dist/src/intl/sw.d.ts +63 -0
- package/dist/src/intl/sw.d.ts.map +1 -0
- package/dist/src/intl/sw.js +191 -0
- package/dist/src/intl/ta.d.ts +117 -0
- package/dist/src/intl/ta.d.ts.map +1 -0
- package/dist/src/intl/ta.js +258 -0
- package/dist/src/intl/te.d.ts +117 -0
- package/dist/src/intl/te.d.ts.map +1 -0
- package/dist/src/intl/te.js +258 -0
- package/dist/src/intl/th.d.ts +117 -0
- package/dist/src/intl/th.d.ts.map +1 -0
- package/dist/src/intl/th.js +258 -0
- package/dist/src/intl/tr.d.ts +117 -0
- package/dist/src/intl/tr.d.ts.map +1 -0
- package/dist/src/intl/tr.js +255 -0
- package/dist/src/intl/uk.d.ts +117 -0
- package/dist/src/intl/uk.d.ts.map +1 -0
- package/dist/src/intl/uk.js +258 -0
- package/dist/src/intl/ur.d.ts +117 -0
- package/dist/src/intl/ur.d.ts.map +1 -0
- package/dist/src/intl/ur.js +245 -0
- package/dist/src/intl/vi.d.ts +117 -0
- package/dist/src/intl/vi.d.ts.map +1 -0
- package/dist/src/intl/vi.js +255 -0
- package/dist/src/intl/zh-CN.d.ts +117 -0
- package/dist/src/intl/zh-CN.d.ts.map +1 -0
- package/dist/src/intl/zh-CN.js +258 -0
- package/dist/src/intl/zh-TW.d.ts +117 -0
- package/dist/src/intl/zh-TW.d.ts.map +1 -0
- package/dist/src/intl/zh-TW.js +258 -0
- package/dist/src/local-first/Owner.d.ts +156 -62
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +119 -20
- package/package.json +1 -1
- package/src/Function.ts +2 -0
- package/src/Http.ts +9 -0
- package/src/Object.ts +2 -0
- package/src/RefCount.ts +2 -0
- package/src/Relation.ts +4 -0
- package/src/Resource.ts +2 -0
- package/src/Result.ts +397 -560
- package/src/StackTrace.ts +2 -0
- package/src/Task.ts +1143 -1222
- package/src/Time.ts +2 -0
- package/src/Type.ts +1759 -794
- package/src/intl/_en.ts +497 -0
- package/src/intl/ar.ts +417 -0
- package/src/intl/bn.ts +486 -0
- package/src/intl/ca.ts +488 -0
- package/src/intl/cs.ts +95 -31
- package/src/intl/da.ts +488 -0
- package/src/intl/de.ts +488 -0
- package/src/intl/el.ts +494 -0
- package/src/intl/es.ts +488 -0
- package/src/intl/fa.ts +487 -0
- package/src/intl/fi.ts +487 -0
- package/src/intl/fil.ts +488 -0
- package/src/intl/fr.ts +488 -0
- package/src/intl/he.ts +486 -0
- package/src/intl/hi.ts +487 -0
- package/src/intl/hr.ts +494 -0
- package/src/intl/hu.ts +387 -0
- package/src/intl/id.ts +487 -0
- package/src/intl/index.ts +42 -0
- package/src/intl/it.ts +488 -0
- package/src/intl/ja.ts +488 -0
- package/src/intl/ko.ts +487 -0
- package/src/intl/ml.ts +487 -0
- package/src/intl/mr.ts +487 -0
- package/src/intl/ms.ts +410 -0
- package/src/intl/nb.ts +364 -0
- package/src/intl/nl.ts +488 -0
- package/src/intl/pa.ts +487 -0
- package/src/intl/pl.ts +450 -0
- package/src/intl/pt-BR.ts +487 -0
- package/src/intl/pt.ts +424 -0
- package/src/intl/ro.ts +488 -0
- package/src/intl/sk.ts +412 -0
- package/src/intl/sl.ts +487 -0
- package/src/intl/sv.ts +488 -0
- package/src/intl/sw.ts +324 -0
- package/src/intl/ta.ts +487 -0
- package/src/intl/te.ts +487 -0
- package/src/intl/th.ts +484 -0
- package/src/intl/tr.ts +487 -0
- package/src/intl/uk.ts +488 -0
- package/src/intl/ur.ts +410 -0
- package/src/intl/vi.ts +435 -0
- package/src/intl/zh-CN.ts +482 -0
- package/src/intl/zh-TW.ts +482 -0
- package/src/local-first/Owner.ts +156 -62
package/dist/src/Type.d.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime types.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
1
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
2
|
import type { AtLeastTwoReadonlyArray, NonEmptyReadonlyArray } from "./Array.ts";
|
|
8
3
|
import type { Brand } from "./Brand.ts";
|
|
@@ -12,359 +7,12 @@ import { type Result } from "./Result.ts";
|
|
|
12
7
|
import type { TimeDep } from "./Time.ts";
|
|
13
8
|
import { type CompileTimeError, type IsUnion, type Literal, type Simplify, type ValueWithLength, type WidenLiteral } from "./Types.ts";
|
|
14
9
|
/**
|
|
15
|
-
* A runtime representation of a TypeScript type
|
|
16
|
-
*
|
|
17
|
-
* Evolu Type reports expected decoding failures through {@link Result} rather
|
|
18
|
-
* than exceptions. It represents both an encoded `Input` and its semantic
|
|
19
|
-
* `Output`, supporting validation, transformation, and canonical encoding.
|
|
20
|
-
*
|
|
21
|
-
* Evolu Type is designed for correctness and developer experience. Correctness
|
|
22
|
-
* is especially important for local-first data: application authors cannot
|
|
23
|
-
* inspect or repair a user's data on a server because they do not have access
|
|
24
|
-
* to it. Type declarations must reject invalid data at system boundaries, then
|
|
25
|
-
* preserve those guarantees wherever the data travels.
|
|
26
|
-
*
|
|
27
|
-
* To make correct code the easiest code to write, Evolu Type preserves as much
|
|
28
|
-
* information as TypeScript can express. Invalid declarations produce readable
|
|
29
|
-
* {@link CompileTimeError} types when the compiler can detect them, while
|
|
30
|
-
* runtime assertions enforce construction contracts it cannot prove. Together,
|
|
31
|
-
* these choices create a pit of success.
|
|
32
|
-
*
|
|
33
|
-
* The implementation is optimized for minimal bundle size. Less descriptive
|
|
34
|
-
* assertion messages could make it even smaller, but Evolu keeps actionable
|
|
35
|
-
* messages as a deliberate tradeoff for developer experience.
|
|
36
|
-
*
|
|
37
|
-
* The main properties of Evolu Type are:
|
|
38
|
-
*
|
|
39
|
-
* - **Result-based error handling** – expected failures are explicit values.
|
|
40
|
-
* - **Typed errors with decoupled formatters** – validation logic stays
|
|
41
|
-
* independent of user-facing messages, and errors can be handled
|
|
42
|
-
* exhaustively.
|
|
43
|
-
* - **Type-safe, tree-shakeable localization** – formatter requirements are
|
|
44
|
-
* inferred from selected Types, while apps bundle exactly the locales they
|
|
45
|
-
* support so users can change language offline.
|
|
46
|
-
* - **Consistent constraints through {@link Brand}** – every refinement constraint
|
|
47
|
-
* is represented in the TypeScript type, so an unconstrained parent value
|
|
48
|
-
* cannot be used where the constrained value is required.
|
|
49
|
-
* - **Typed inputs** – prefer `from` and its `.parent` entry points to connect
|
|
50
|
-
* precise producer and consumer contracts while preserving typed remaining
|
|
51
|
-
* errors; reserve `fromUnknown` for genuinely unknown values.
|
|
52
|
-
* - **Lawful codecs** – Types partially decode `Input` to `Output` and totally
|
|
53
|
-
* encode every legitimate `Output` to `CanonicalInput`, the statically known
|
|
54
|
-
* subtype of `Input` returned by complete encoding.
|
|
55
|
-
* - **A top-down implementation** – the source is intended to be read from
|
|
56
|
-
* beginning to end.
|
|
57
|
-
*
|
|
58
|
-
* Evolu Type supports [Standard Schema](https://standardschema.dev/) for
|
|
59
|
-
* interoperability with compatible tools and frameworks while preserving each
|
|
60
|
-
* Type's exact Input and Output.
|
|
61
|
-
*
|
|
62
|
-
* Evolu Type assumes that all executing code, including third-party
|
|
63
|
-
* dependencies, has been audited and is trusted. It validates data contracts
|
|
64
|
-
* under that assumption. Trusting code does not require trusting every value it
|
|
65
|
-
* returns, so uncertain values from legacy code or another realm can still be
|
|
66
|
-
* decoded at an explicit boundary. It does not protect against hostile
|
|
67
|
-
* executable behavior such as sabotaged Proxies or throwing traps; Type
|
|
68
|
-
* validation is not a security boundary for untrusted JavaScript.
|
|
69
|
-
*
|
|
70
|
-
* Type declarations and their callbacks are trusted construction code. Evolu
|
|
71
|
-
* Type leverages that trust for better developer experience and does not try to
|
|
72
|
-
* recover from code that defeats the type system with `any` or casts, including
|
|
73
|
-
* fabricating an `Err` for `Result<_, never>`. Runtime assertions still enforce
|
|
74
|
-
* contracts TypeScript cannot express, and every Type declaration must be
|
|
75
|
-
* tested for its expected successes and failures.
|
|
76
|
-
*
|
|
77
|
-
* `fromUnknown` validates untyped input through the complete pipeline. `from`
|
|
78
|
-
* and its `.parent` operations use their declared boundary to determine which
|
|
79
|
-
* remaining stages can return validation errors, but assert that boundary at
|
|
80
|
-
* runtime. `orThrow` and `orNull` reuse the deepest `from` operation accepting
|
|
81
|
-
* `Input`, while `to` asserts its Output boundary. A failed assertion means
|
|
82
|
-
* application code violated its static contract; it is a developer error, not
|
|
83
|
-
* an expected validation failure. Its message identifies the expected Type and
|
|
84
|
-
* its cause preserves the exact structured Output validation error.
|
|
85
|
-
*
|
|
86
|
-
* Prefer the most precise typed boundary available. A value is not unknown
|
|
87
|
-
* merely because it originated outside the application: forms, components, and
|
|
88
|
-
* other producers often expose a `string` or a branded value that can connect
|
|
89
|
-
* directly to a matching `from` boundary. Reserve `fromUnknown` for values
|
|
90
|
-
* whose TypeScript type is genuinely `unknown`. `is` means exact membership in
|
|
91
|
-
* the output domain, not merely that output-side parsing could succeed. A
|
|
92
|
-
* successful `fromUnknown` result always satisfies `is`.
|
|
93
|
-
*
|
|
94
|
-
* Decoding accepts a representation outside the Output domain only when the
|
|
95
|
-
* Type explicitly declares that representation, such as a transformation Input.
|
|
96
|
-
* Structural Types do not implicitly repair another JavaScript representation.
|
|
97
|
-
* In particular, {@link array} and {@link tuple} require dense own data elements,
|
|
98
|
-
* while the predefined {@link Object}, {@link object}, and {@link record} require
|
|
99
|
-
* plain objects with own enumerable data properties. They do not invoke
|
|
100
|
-
* accessors or materialize inherited and non-enumerable properties.
|
|
101
|
-
*
|
|
102
|
-
* TypeScript object types are structural and do not encode JavaScript realm
|
|
103
|
-
* identity. Structural Types therefore accept legitimate representations from
|
|
104
|
-
* other realms. Prototype checks remain when the prototype defines the semantic
|
|
105
|
-
* domain. Plain-object Types accept a `null` prototype or an immediate root
|
|
106
|
-
* prototype whose own prototype is `null`; ordinary class instances and deeper
|
|
107
|
-
* prototype chains are rejected. When Record decoding must construct a
|
|
108
|
-
* normalized value, it uses a `null` prototype so every string key remains
|
|
109
|
-
* ordinary data.
|
|
110
|
-
*
|
|
111
|
-
* Evolu Type requires TypeScript 7 or newer and expects the
|
|
112
|
-
* `exactOptionalPropertyTypes` compiler option to be enabled.
|
|
113
|
-
*
|
|
114
|
-
* Predefined Types intentionally use the names of corresponding JavaScript
|
|
115
|
-
* built-ins because they represent those familiar value categories. If an
|
|
116
|
-
* imported Type shadows a built-in in the same scope, access the built-in
|
|
117
|
-
* through `globalThis`, JavaScript's standard cross-environment global object,
|
|
118
|
-
* such as `globalThis.String` or `globalThis.Date`.
|
|
119
|
-
*
|
|
120
|
-
* ### Example
|
|
121
|
-
*
|
|
122
|
-
* ```ts
|
|
123
|
-
* import { String, type Result } from "@evolu/common";
|
|
124
|
-
*
|
|
125
|
-
* const value: unknown = "hello";
|
|
126
|
-
* const result = String.fromUnknown(value);
|
|
127
|
-
*
|
|
128
|
-
* expectTypeOf(result).toEqualTypeOf<
|
|
129
|
-
* Result<
|
|
130
|
-
* string,
|
|
131
|
-
* {
|
|
132
|
-
* readonly type: "TypeOf";
|
|
133
|
-
* readonly expected: "String";
|
|
134
|
-
* readonly value: unknown;
|
|
135
|
-
* }
|
|
136
|
-
* >
|
|
137
|
-
* >();
|
|
138
|
-
* expectOk(result, "hello");
|
|
139
|
-
* ```
|
|
140
|
-
*
|
|
141
|
-
* ## FAQ
|
|
142
|
-
*
|
|
143
|
-
* ### What does a Type represent?
|
|
144
|
-
*
|
|
145
|
-
* A Type is a lawful, pure codec for an exact semantic domain:
|
|
146
|
-
*
|
|
147
|
-
* ```text
|
|
148
|
-
* Input ── partial decode ──▶ Output
|
|
149
|
-
* CanonicalInput ◀─── total encode ─── Output
|
|
150
|
-
*
|
|
151
|
-
* CanonicalInput ⊆ Input
|
|
152
|
-
* ```
|
|
153
|
-
*
|
|
154
|
-
* Read each line in the direction of its arrowhead. `Input` is the complete
|
|
155
|
-
* typed decoding boundary, including candidates that validation can reject and
|
|
156
|
-
* noncanonical representations that decoding can normalize. `Output` is the
|
|
157
|
-
* validated semantic value. `CanonicalInput` is the statically known subtype of
|
|
158
|
-
* `Input` returned by the complete `to` operation. It can be wider than the
|
|
159
|
-
* values actually emitted when a refinement follows an arbitrary transformation
|
|
160
|
-
* because TypeScript cannot determine which values its encoder returns for the
|
|
161
|
-
* narrowed Output. `fromUnknown` and the `from` operations decode; `to`
|
|
162
|
-
* encodes.
|
|
163
|
-
*
|
|
164
|
-
* A lawful Type round-trips every Output:
|
|
165
|
-
*
|
|
166
|
-
* ```text
|
|
167
|
-
* fromUnknown(to(output)) ≈ ok(output)
|
|
168
|
-
* ```
|
|
169
|
-
*
|
|
170
|
-
* Encoding can canonicalize a valid Input:
|
|
171
|
-
*
|
|
172
|
-
* ```text
|
|
173
|
-
* "0042" ──decode──▶ 42 ──encode──▶ "42"
|
|
174
|
-
* ```
|
|
175
|
-
*
|
|
176
|
-
* Once canonicalized, repeating the decode-encode cycle must preserve that
|
|
177
|
-
* representation:
|
|
178
|
-
*
|
|
179
|
-
* ```text
|
|
180
|
-
* "42" ──decode──▶ 42 ──encode──▶ "42"
|
|
181
|
-
* ```
|
|
182
|
-
*
|
|
183
|
-
* Here `decode` means running the complete decoding pipeline, as `fromUnknown`
|
|
184
|
-
* does, and `≈` means equality appropriate for the semantic domain. Validation
|
|
185
|
-
* refinements, {@link ArrayType | Array Types}, and
|
|
186
|
-
* {@link ObjectType | Object Types} preserve these laws when their contained
|
|
187
|
-
* Types do. A {@link union} additionally requires compatible dispatch: it
|
|
188
|
-
* encodes through the first member matching the Output and decodes through the
|
|
189
|
-
* first member accepting the Input. Member ordering is lawful only when those
|
|
190
|
-
* choices agree semantically. Encoded representations can overlap even when
|
|
191
|
-
* member Output types are disjoint.
|
|
192
|
-
*
|
|
193
|
-
* When encoding returns a refined value unchanged, the refinement can narrow
|
|
194
|
-
* `CanonicalInput` without changing its JavaScript representation. For example,
|
|
195
|
-
* {@link FiniteNumber} has `number` as its Input, while its Output and
|
|
196
|
-
* CanonicalInput are `FiniteNumber`: decoding can reject non-finite number
|
|
197
|
-
* candidates, and encoding only receives validated finite Outputs. A
|
|
198
|
-
* transformation can change the representation entirely. For
|
|
199
|
-
* {@link Int64FromInt64String}, Input is `string`, Output is `Int64`, and
|
|
200
|
-
* CanonicalInput is `Int64String`. Structural Type factories derive their
|
|
201
|
-
* CanonicalInput recursively from their contained Types.
|
|
202
|
-
*
|
|
203
|
-
* ### Why is to total?
|
|
204
|
-
*
|
|
205
|
-
* Suppose a Type accepts only strings containing decimal digits and decodes
|
|
206
|
-
* them to JavaScript numbers. Parsing `"42"` is possible, but the Type cannot
|
|
207
|
-
* lawfully declare its Output as `number`:
|
|
208
|
-
*
|
|
209
|
-
* ```text
|
|
210
|
-
* digits-only string ──partial decode──▶ number
|
|
211
|
-
* digits-only string ◀─── total encode ── number // impossible
|
|
212
|
-
* ```
|
|
213
|
-
*
|
|
214
|
-
* `number` also contains negative and fractional numbers, `NaN`, positive and
|
|
215
|
-
* negative infinity, and `-0`. None of those values has a digits-only
|
|
216
|
-
* representation, so `to` could not encode every valid Output.
|
|
10
|
+
* A runtime representation of a TypeScript type, including its encoded input,
|
|
11
|
+
* semantic output, structured errors, and canonical encoding.
|
|
217
12
|
*
|
|
218
|
-
*
|
|
13
|
+
* See the {@link @evolu/common!Type | Type overview}.
|
|
219
14
|
*
|
|
220
|
-
*
|
|
221
|
-
* digits-only string ──partial decode──▶ NonNegativeSafeInteger
|
|
222
|
-
* digits-only string ◀─── total encode ── NonNegativeSafeInteger
|
|
223
|
-
*
|
|
224
|
-
* "0042" ──decode──▶ 42 ──encode──▶ "42"
|
|
225
|
-
* ```
|
|
226
|
-
*
|
|
227
|
-
* Another lawful design keeps `number` as the Output but expands the Input
|
|
228
|
-
* representation to include a canonical string for every number, including
|
|
229
|
-
* `"NaN"`, `"Infinity"`, `"-Infinity"`, and `"-0"`, as well as negative and
|
|
230
|
-
* fractional numbers.
|
|
231
|
-
*
|
|
232
|
-
* The same principle applies when converting between two representations. Give
|
|
233
|
-
* each representation its own Type with the same exact Output. For example, a
|
|
234
|
-
* string representation and a number representation can both decode to the
|
|
235
|
-
* shared `SafeInteger` domain:
|
|
236
|
-
*
|
|
237
|
-
* ```text
|
|
238
|
-
* string ──partial decode──▶ SafeInteger
|
|
239
|
-
* string ◀─── total encode ── SafeInteger
|
|
240
|
-
*
|
|
241
|
-
* number ──partial decode──▶ SafeInteger
|
|
242
|
-
* number ◀─── total encode ── SafeInteger
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* Conversion decodes the source representation, then total-encodes the shared
|
|
246
|
-
* Output into the target representation. If no lossless shared domain exists,
|
|
247
|
-
* the operation is a partial conversion, migration, or policy decision and
|
|
248
|
-
* should be an explicit function returning Result, not a Type transformation.
|
|
249
|
-
*
|
|
250
|
-
* ### Why can a typed operation throw?
|
|
251
|
-
*
|
|
252
|
-
* TypeScript proves structural assignability, but it cannot describe every
|
|
253
|
-
* runtime invariant. For example, it cannot express whether an object property
|
|
254
|
-
* is own, enumerable, or a data property. It also permits a wider object with
|
|
255
|
-
* excess properties where a narrower object type is expected.
|
|
256
|
-
*
|
|
257
|
-
* `fromUnknown` treats such invalid external values as expected data and
|
|
258
|
-
* returns a typed error. Typed boundaries instead assert the domain promised by
|
|
259
|
-
* their parameter type. If application code claims an accessor-backed object or
|
|
260
|
-
* an object with excess properties is an Object Output, the assertion throws
|
|
261
|
-
* because the application contract is broken. `orThrow` and `orNull` preserve
|
|
262
|
-
* the assertion at their typed `Input` boundary, then apply {@link getOrThrow}
|
|
263
|
-
* or {@link getOrNull} only to validation failures returned by the remaining
|
|
264
|
-
* pipeline.
|
|
265
|
-
*
|
|
266
|
-
* Consequently, structural representation errors such as sparse Arrays,
|
|
267
|
-
* accessors, and excess properties normally do not enter user-facing validation
|
|
268
|
-
* in typed application flows. They violate the producer's declared contract and
|
|
269
|
-
* throw as developer errors. At a genuinely unknown boundary, such as a
|
|
270
|
-
* schema-authoring tool, import, or external protocol, the same issues are
|
|
271
|
-
* legitimate typed validation errors and their formatter messages are useful.
|
|
272
|
-
*
|
|
273
|
-
* This distinction applies to data failures. Any Type operation, including
|
|
274
|
-
* `fromUnknown`, can throw when trusted Type-declaration code, such as a
|
|
275
|
-
* successful transformation callback, violates its declared contract.
|
|
276
|
-
*
|
|
277
|
-
* Materialize accessor values into plain data, remove properties the Type does
|
|
278
|
-
* not represent, or use a different Type. Silently discarding excess data would
|
|
279
|
-
* make the code constructing it dead while appearing to encode it successfully.
|
|
280
|
-
* One exact Object policy also keeps Output membership independent of parsing
|
|
281
|
-
* configuration. Exact structural policies also keep Output membership
|
|
282
|
-
* independent of whether a transformation happens to allocate a new value.
|
|
283
|
-
* Evolu Type therefore does not invoke accessors, discard excess properties, or
|
|
284
|
-
* make `to` fallible. This keeps `to` total for every legitimate Output and
|
|
285
|
-
* lets transformations compose without an encoding-error channel.
|
|
286
|
-
*
|
|
287
|
-
* ### How should values from another realm be handled?
|
|
288
|
-
*
|
|
289
|
-
* Code trust and data validation are separate decisions. Values returned by
|
|
290
|
-
* trusted legacy code or another realm can still be uncertain and should be
|
|
291
|
-
* validated. Realm-neutral Types accept an otherwise legitimate representation
|
|
292
|
-
* without requiring conversion merely because its built-ins belong to another
|
|
293
|
-
* realm.
|
|
294
|
-
*
|
|
295
|
-
* When an application trusts both the producer and its return contract, it can
|
|
296
|
-
* cast the boundary API's `unknown` because validation is redundant. Use a
|
|
297
|
-
* specialized Type or explicit transformation when the producer actually uses a
|
|
298
|
-
* different representation that needs adaptation or normalization.
|
|
299
|
-
*
|
|
300
|
-
* All executing JavaScript remains trusted. Deliberately forged built-ins,
|
|
301
|
-
* hostile Proxies, throwing traps, or sabotaged executable behavior can throw;
|
|
302
|
-
* Evolu Type does not selectively contain them or claim to be a security
|
|
303
|
-
* boundary for untrusted code.
|
|
304
|
-
*
|
|
305
|
-
* ### Why doesn't Evolu Type extract data from rich objects?
|
|
306
|
-
*
|
|
307
|
-
* Some validation libraries parse an object's data projection. An imaginary
|
|
308
|
-
* validation library can enumerate own enumerable string properties and decode
|
|
309
|
-
* them into a fresh plain object. That lets a class instance decode as plain
|
|
310
|
-
* data while its prototype and methods are ignored. The same general policy can
|
|
311
|
-
* treat a `Date` or `Map` as an empty Record and can invoke enumerable getters.
|
|
312
|
-
* This is a coherent but intentionally forgiving normalization model.
|
|
313
|
-
*
|
|
314
|
-
* Evolu Type validates exactly the runtime representation defined by each Type;
|
|
315
|
-
* it does not implicitly project one representation into another. The
|
|
316
|
-
* predefined {@link Object} defines an open plain-object representation with
|
|
317
|
-
* unknown values, {@link object} defines a closed plain-object representation,
|
|
318
|
-
* and {@link record} defines a plain-dictionary representation whose complete
|
|
319
|
-
* set of own properties are its entries. Their realm-neutral plain-object rule
|
|
320
|
-
* accepts a `null` prototype or an immediate root prototype whose own prototype
|
|
321
|
-
* is `null`; ordinary class instances and deeper prototype chains are rejected.
|
|
322
|
-
* Every property must be an enumerable data property; inherited members are not
|
|
323
|
-
* entries, while accessors and hidden properties are invalid instead of being
|
|
324
|
-
* invoked or ignored. {@link array} similarly defines a dense sequence whose
|
|
325
|
-
* only own properties are `length` and its indexed data properties;
|
|
326
|
-
* {@link tuple} applies the same representation rules with a fixed length and a
|
|
327
|
-
* distinct Type for each position. Only an explicit {@link transform} changes
|
|
328
|
-
* the representation. Consequently, `is` tests exact Output membership and `to`
|
|
329
|
-
* stays total for valid Outputs.
|
|
330
|
-
*
|
|
331
|
-
* ### Why is JsonValue stricter than JSON.stringify?
|
|
332
|
-
*
|
|
333
|
-
* `JSON.stringify` is a forgiving data projection. It can invoke `toJSON` and
|
|
334
|
-
* accessors, discard object properties, replace unsupported array elements and
|
|
335
|
-
* non-finite numbers with `null`, and normalize `-0` to `0`. Those rules are
|
|
336
|
-
* useful for ordinary serialization, but they do not preserve an exact value.
|
|
337
|
-
*
|
|
338
|
-
* {@link JsonValue} instead defines data that is already represented as data.
|
|
339
|
-
* Invalid runtime behavior and values are rejected rather than interpreted or
|
|
340
|
-
* silently discarded. Its encoder is total and stack-safe for every valid
|
|
341
|
-
* Output, and {@link JsonValueFromJson} preserves the semantic value when it is
|
|
342
|
-
* encoded and decoded, including JavaScript's distinction between `-0` and `0`.
|
|
343
|
-
* Use an explicit transformation before this boundary when a projection or
|
|
344
|
-
* other normalization is desired.
|
|
345
|
-
*
|
|
346
|
-
* ### Why are Types pure and synchronous?
|
|
347
|
-
*
|
|
348
|
-
* A Type describes data meaning, not work. Time, I/O, dependencies, external
|
|
349
|
-
* state, authorization, and other contextual decisions belong in a {@link Task}.
|
|
350
|
-
* Use a Type to decode the data required by that work, then pass the decoded
|
|
351
|
-
* value to a Task. A pure synchronous conversion that can fail can be an
|
|
352
|
-
* ordinary function returning Result.
|
|
353
|
-
*
|
|
354
|
-
* Keeping those responsibilities separate prevents an Evolu Type from becoming
|
|
355
|
-
* a hidden application workflow. It also keeps validation deterministic,
|
|
356
|
-
* dependency-free, immediately composable, and straightforward to test.
|
|
357
|
-
*
|
|
358
|
-
* ### What if only decoding is needed?
|
|
359
|
-
*
|
|
360
|
-
* Use `fromUnknown` for unknown data. For typed application data, call `from`
|
|
361
|
-
* at the boundary its input type proves, or use `orThrow` or `orNull` for a
|
|
362
|
-
* flat conversion from `Input`. The canonical `to` encoder still keeps the Type
|
|
363
|
-
* lawful and composable with transformations and structural Types. A genuinely
|
|
364
|
-
* irreversible operation is a separate function or Task, not a Type
|
|
365
|
-
* transformation.
|
|
366
|
-
*
|
|
367
|
-
* @group Core Types
|
|
15
|
+
* @group Core
|
|
368
16
|
*/
|
|
369
17
|
export interface Type<Name extends TypeName, in out Input, in out Output, Error extends TypeError, in out Parent extends TypeNode | null = null, in out Errors extends TypeError = Error | ([Parent] extends [infer P extends TypeNode] ? InferErrors<P> : never), in out CustomFrom extends CustomFromOperation = never, in out CanonicalInput extends Input = Input, in out IdentityEncoding extends boolean = true> extends TypeNode {
|
|
370
18
|
/** The name identifying this Type node. */
|
|
@@ -423,16 +71,42 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
423
71
|
readonly [identityEncodingSymbol]: IdentityEncoding;
|
|
424
72
|
/** The one preceding Type node, or `null` for a root Type. */
|
|
425
73
|
readonly parent: Parent;
|
|
426
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Decodes an unknown value through the complete Type pipeline.
|
|
76
|
+
*
|
|
77
|
+
* ### Example
|
|
78
|
+
*
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { PositiveInt } from "@evolu/common";
|
|
81
|
+
*
|
|
82
|
+
* const value: unknown = 42;
|
|
83
|
+
* const result = PositiveInt.fromUnknown(value);
|
|
84
|
+
*
|
|
85
|
+
* expectOk(result, 42);
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
427
88
|
readonly fromUnknown: (value: unknown, options?: ValidationOptions) => Result<Output, Errors>;
|
|
428
89
|
/**
|
|
429
90
|
* Formats an error returned by `fromUnknown` or `from` as one human-readable
|
|
430
|
-
* message.
|
|
91
|
+
* message. Predefined Types use English; {@link localizeTypes} derives Types
|
|
431
92
|
* with localized formatters.
|
|
432
93
|
*
|
|
433
94
|
* Structural errors retain nested errors and their locations in the typed
|
|
434
95
|
* error value. This formatter does not encode paths or enumerate nested
|
|
435
96
|
* errors in its message.
|
|
97
|
+
*
|
|
98
|
+
* ### Example
|
|
99
|
+
*
|
|
100
|
+
* ```ts
|
|
101
|
+
* import { String } from "@evolu/common";
|
|
102
|
+
*
|
|
103
|
+
* const result = String.fromUnknown(42);
|
|
104
|
+
*
|
|
105
|
+
* expectErr(result, { type: "TypeOf", expected: "String", value: 42 });
|
|
106
|
+
* expect(String.formatError(result.error)).toBe(
|
|
107
|
+
* "A value 42 is not a string.",
|
|
108
|
+
* );
|
|
109
|
+
* ```
|
|
436
110
|
*/
|
|
437
111
|
readonly formatError: TypeErrorFormatter<Errors>;
|
|
438
112
|
/**
|
|
@@ -468,6 +142,52 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
468
142
|
* developer error. The Error message identifies the expected boundary Type,
|
|
469
143
|
* and its cause preserves the structured validation error. Only failures
|
|
470
144
|
* introduced after that boundary are returned through `Result`.
|
|
145
|
+
*
|
|
146
|
+
* ### Example
|
|
147
|
+
*
|
|
148
|
+
* A form already guarantees every constraint on a title, while a new note
|
|
149
|
+
* input guarantees only trimmed text. The note's parent boundary validates
|
|
150
|
+
* only the constraints that the form does not guarantee:
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* import {
|
|
154
|
+
* flatMapResult,
|
|
155
|
+
* NonEmptyTrimmedString100,
|
|
156
|
+
* object,
|
|
157
|
+
* TrimmedString,
|
|
158
|
+
* type MaxLengthError,
|
|
159
|
+
* type MinLengthError,
|
|
160
|
+
* type Result,
|
|
161
|
+
* } from "@evolu/common";
|
|
162
|
+
*
|
|
163
|
+
* const Todo = object({
|
|
164
|
+
* title: NonEmptyTrimmedString100,
|
|
165
|
+
* note: NonEmptyTrimmedString100,
|
|
166
|
+
* });
|
|
167
|
+
*
|
|
168
|
+
* const saveTodo = (
|
|
169
|
+
* title: NonEmptyTrimmedString100,
|
|
170
|
+
* note: TrimmedString,
|
|
171
|
+
* ) => {
|
|
172
|
+
* // @ts-expect-error TrimmedString does not guarantee a non-empty value
|
|
173
|
+
* // with at most 100 characters.
|
|
174
|
+
* Todo.from({ title, note });
|
|
175
|
+
*
|
|
176
|
+
* return flatMapResult(
|
|
177
|
+
* Todo.props.note.from.parent.parent(note),
|
|
178
|
+
* (note) => Todo.from({ title, note }),
|
|
179
|
+
* );
|
|
180
|
+
* };
|
|
181
|
+
*
|
|
182
|
+
* const title = NonEmptyTrimmedString100.orThrow("Buy milk");
|
|
183
|
+
* const note = TrimmedString.orThrow("Remember oat milk");
|
|
184
|
+
* const result = saveTodo(title, note);
|
|
185
|
+
*
|
|
186
|
+
* expectTypeOf(result).toEqualTypeOf<
|
|
187
|
+
* Result<typeof Todo.Output, MaxLengthError<100> | MinLengthError<1>>
|
|
188
|
+
* >();
|
|
189
|
+
* expectOk(result, { title, note });
|
|
190
|
+
* ```
|
|
471
191
|
*/
|
|
472
192
|
readonly from: [CustomFrom] extends [never] ? [Parent] extends [infer P extends TypeNode] ? FromOperation<Output, Error, P> : TypeOperationFn<"from", Output, Output, never> : CustomFrom;
|
|
473
193
|
/**
|
|
@@ -477,6 +197,16 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
477
197
|
* `to` runs the complete encoding pipeline. Its first `.parent` stops at the
|
|
478
198
|
* immediate parent Output, and each additional suffix stops one Type closer
|
|
479
199
|
* to the root. Every entry point accepts this Type's `Output`.
|
|
200
|
+
*
|
|
201
|
+
* ### Example
|
|
202
|
+
*
|
|
203
|
+
* ```ts
|
|
204
|
+
* import { Int64, Int64FromInt64String } from "@evolu/common";
|
|
205
|
+
*
|
|
206
|
+
* const value = Int64.orThrow(42n);
|
|
207
|
+
*
|
|
208
|
+
* expect(Int64FromInt64String.to(value)).toBe("42");
|
|
209
|
+
* ```
|
|
480
210
|
*/
|
|
481
211
|
readonly to: [Parent] extends [infer P extends TypeNode] ? ToOperation<Output, CanonicalInput, P> : (value: Output) => CanonicalInput;
|
|
482
212
|
/**
|
|
@@ -506,6 +236,9 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
506
236
|
*
|
|
507
237
|
* // Equivalent because `from.parent` is this Type's deepest `from` operation:
|
|
508
238
|
* const sameValue = getOrThrow(NonEmptyString.from.parent("Evolu"));
|
|
239
|
+
*
|
|
240
|
+
* expect(value).toBe("Evolu");
|
|
241
|
+
* expect(sameValue).toBe(value);
|
|
509
242
|
* ```
|
|
510
243
|
*/
|
|
511
244
|
readonly orThrow: TypeOperationFn<"orThrow", Input, Output, never>;
|
|
@@ -536,11 +269,19 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
536
269
|
*
|
|
537
270
|
* // Equivalent because `from.parent` is this Type's deepest `from` operation:
|
|
538
271
|
* const sameValue = getOrNull(NonEmptyString.from.parent("Evolu"));
|
|
272
|
+
*
|
|
273
|
+
* expect(value).toBe("Evolu");
|
|
274
|
+
* expect(sameValue).toBe(value);
|
|
275
|
+
* expect(NonEmptyString.orNull("")).toBeNull();
|
|
539
276
|
* ```
|
|
540
277
|
*/
|
|
541
278
|
readonly orNull: TypeOperationFn<"orNull", Input, Output, never>;
|
|
542
279
|
}
|
|
543
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* A capitalized name identifying a {@link Type} node.
|
|
282
|
+
*
|
|
283
|
+
* @group Core
|
|
284
|
+
*/
|
|
544
285
|
export type TypeName = Capitalize<string>;
|
|
545
286
|
/**
|
|
546
287
|
* A plain structured error produced by a {@link Type} operation.
|
|
@@ -552,7 +293,7 @@ export type TypeName = Capitalize<string>;
|
|
|
552
293
|
* only when it intentionally represents the same error contract. Accidental
|
|
553
294
|
* reuse prevents reliable discriminated-union narrowing.
|
|
554
295
|
*
|
|
555
|
-
* @group Core
|
|
296
|
+
* @group Core
|
|
556
297
|
*/
|
|
557
298
|
export interface TypeError<Name extends TypeName = TypeName> {
|
|
558
299
|
readonly type: Name;
|
|
@@ -567,7 +308,7 @@ interface TransparentTypeError {
|
|
|
567
308
|
* Structural errors such as Array and Union errors extend {@link TypeError}
|
|
568
309
|
* instead because they locate nested errors rather than own one value.
|
|
569
310
|
*
|
|
570
|
-
* @group Core
|
|
311
|
+
* @group Core
|
|
571
312
|
*/
|
|
572
313
|
export interface TypeValueError<Name extends TypeName = TypeName> extends TypeError<Name> {
|
|
573
314
|
readonly value: unknown;
|
|
@@ -575,10 +316,15 @@ export interface TypeValueError<Name extends TypeName = TypeName> extends TypeEr
|
|
|
575
316
|
/**
|
|
576
317
|
* Formats a structured {@link TypeError} as a human-readable message.
|
|
577
318
|
*
|
|
578
|
-
* @group Core
|
|
319
|
+
* @group Core
|
|
579
320
|
*/
|
|
580
321
|
export type TypeErrorFormatter<Error extends TypeError> = (error: Error) => string;
|
|
581
|
-
/**
|
|
322
|
+
/**
|
|
323
|
+
* The common structural shape of every {@link Type}, with its specific type
|
|
324
|
+
* parameters erased.
|
|
325
|
+
*
|
|
326
|
+
* @group Core
|
|
327
|
+
*/
|
|
582
328
|
export interface TypeNode {
|
|
583
329
|
readonly name: TypeName;
|
|
584
330
|
readonly "~standard": StandardSchemaV1.Props<unknown, unknown>;
|
|
@@ -601,7 +347,7 @@ export interface TypeNode {
|
|
|
601
347
|
* Asserts that a value belongs to a {@link Type} Output domain.
|
|
602
348
|
*
|
|
603
349
|
* Use this for internal invariants, not external input. Validate external input
|
|
604
|
-
* with `Type.fromUnknown` so
|
|
350
|
+
* with `Type.fromUnknown` so validation failures remain typed values. A failed
|
|
605
351
|
* assertion uses the Type name for its message and preserves the exact Output
|
|
606
352
|
* validation error as the thrown Error's cause.
|
|
607
353
|
*
|
|
@@ -621,38 +367,36 @@ export interface TypeNode {
|
|
|
621
367
|
* >();
|
|
622
368
|
* ```
|
|
623
369
|
*
|
|
624
|
-
* @group Core
|
|
370
|
+
* @group Core
|
|
625
371
|
*/
|
|
626
372
|
export declare const assertType: <T extends TypeNode>(type: T, value: unknown) => asserts value is T["Output"];
|
|
627
373
|
/**
|
|
628
|
-
*
|
|
374
|
+
* Creates localized copies of selected {@link Type} declarations.
|
|
629
375
|
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* Lazy error interfaces.
|
|
376
|
+
* Pass the Types used together in one localization scope and formatter maps
|
|
377
|
+
* keyed by locale. TypeScript infers every formatter required by the selected
|
|
378
|
+
* Types, including errors from nested structural Types and recursive Lazy
|
|
379
|
+
* Types. Every locale must provide the complete inferred formatter set; missing
|
|
380
|
+
* and unrelated formatters are compile-time errors.
|
|
636
381
|
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
382
|
+
* The result preserves the locale names, selected Type names, and exact
|
|
383
|
+
* TypeScript types. A localized Type validates exactly like its source Type;
|
|
384
|
+
* only its human-readable `formatError` and Standard Schema messages change.
|
|
385
|
+
* The source Types remain unchanged.
|
|
640
386
|
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
387
|
+
* Parents and reflected child Types are localized with the same formatter set.
|
|
388
|
+
* Structural Types retain error paths and delegate nested messages to the Type
|
|
389
|
+
* that produced them. Different localized Type sets can coexist in separate
|
|
390
|
+
* application or dependency-injection scopes.
|
|
643
391
|
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
392
|
+
* Localization is scoped to the selected Types instead of a package-wide
|
|
393
|
+
* translation registry. Static imports give bundlers an explicit dependency
|
|
394
|
+
* graph, so unrelated Types, locales, and formatters can be removed. Bundling
|
|
395
|
+
* every locale an app supports also allows language changes without a network
|
|
396
|
+
* connection.
|
|
648
397
|
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* dependency graph from those Types to their formatters, so unrelated Type and
|
|
652
|
-
* localization code can be removed. An app supplies all locales it supports in
|
|
653
|
-
* the same self-contained bundle, allowing users to change language without a
|
|
654
|
-
* network connection. Different localized Type sets can coexist on one page or
|
|
655
|
-
* in separate dependency-injection scopes.
|
|
398
|
+
* The selected Type map, locale map, and formatter maps must be plain objects
|
|
399
|
+
* with own enumerable string-keyed data properties.
|
|
656
400
|
*
|
|
657
401
|
* ### Example
|
|
658
402
|
*
|
|
@@ -662,7 +406,7 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
|
|
|
662
406
|
*
|
|
663
407
|
* const Label = minLength(1)(String);
|
|
664
408
|
*
|
|
665
|
-
* const
|
|
409
|
+
* const typesByLocale = localizeTypes(
|
|
666
410
|
* { Label },
|
|
667
411
|
* {
|
|
668
412
|
* cs: {
|
|
@@ -672,11 +416,66 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
|
|
|
672
416
|
* },
|
|
673
417
|
* );
|
|
674
418
|
*
|
|
675
|
-
* expectTypeOf<typeof
|
|
419
|
+
* expectTypeOf<typeof typesByLocale.cs.Label>().toEqualTypeOf<
|
|
676
420
|
* typeof Label
|
|
677
421
|
* >();
|
|
422
|
+
*
|
|
423
|
+
* const result = typesByLocale.cs.Label.fromUnknown("");
|
|
424
|
+
* expectErr(result, { type: "MinLength1", min: 1, value: "" });
|
|
425
|
+
* expect(typesByLocale.cs.Label.formatError(result.error)).toBe(
|
|
426
|
+
* "Text nesmí být prázdný.",
|
|
427
|
+
* );
|
|
678
428
|
* ```
|
|
679
429
|
*
|
|
430
|
+
* ### Supported locales
|
|
431
|
+
*
|
|
432
|
+
* English is built in; use {@link Type} directly for its default formatters. The
|
|
433
|
+
* following additional locales are available:
|
|
434
|
+
*
|
|
435
|
+
* - Arabic (`ar`)
|
|
436
|
+
* - Bengali (`bn`)
|
|
437
|
+
* - Catalan (`ca`)
|
|
438
|
+
* - Chinese, Simplified (`zhCN`)
|
|
439
|
+
* - Chinese, Traditional (`zhTW`)
|
|
440
|
+
* - Croatian (`hr`)
|
|
441
|
+
* - Czech (`cs`)
|
|
442
|
+
* - Danish (`da`)
|
|
443
|
+
* - Dutch (`nl`)
|
|
444
|
+
* - Filipino (`fil`)
|
|
445
|
+
* - Finnish (`fi`)
|
|
446
|
+
* - French (`fr`)
|
|
447
|
+
* - German (`de`)
|
|
448
|
+
* - Greek (`el`)
|
|
449
|
+
* - Hebrew (`he`)
|
|
450
|
+
* - Hindi (`hi`)
|
|
451
|
+
* - Hungarian (`hu`)
|
|
452
|
+
* - Indonesian (`id`)
|
|
453
|
+
* - Italian (`it`)
|
|
454
|
+
* - Japanese (`ja`)
|
|
455
|
+
* - Korean (`ko`)
|
|
456
|
+
* - Malay (`ms`)
|
|
457
|
+
* - Malayalam (`ml`)
|
|
458
|
+
* - Marathi (`mr`)
|
|
459
|
+
* - Norwegian Bokmål (`nb`)
|
|
460
|
+
* - Persian (`fa`)
|
|
461
|
+
* - Polish (`pl`)
|
|
462
|
+
* - Portuguese (`pt`)
|
|
463
|
+
* - Portuguese, Brazilian (`ptBR`)
|
|
464
|
+
* - Punjabi (`pa`)
|
|
465
|
+
* - Romanian (`ro`)
|
|
466
|
+
* - Slovak (`sk`)
|
|
467
|
+
* - Slovenian (`sl`)
|
|
468
|
+
* - Spanish (`es`)
|
|
469
|
+
* - Swahili (`sw`)
|
|
470
|
+
* - Swedish (`sv`)
|
|
471
|
+
* - Tamil (`ta`)
|
|
472
|
+
* - Telugu (`te`)
|
|
473
|
+
* - Thai (`th`)
|
|
474
|
+
* - Turkish (`tr`)
|
|
475
|
+
* - Ukrainian (`uk`)
|
|
476
|
+
* - Urdu (`ur`)
|
|
477
|
+
* - Vietnamese (`vi`)
|
|
478
|
+
*
|
|
680
479
|
* @group Localization
|
|
681
480
|
*/
|
|
682
481
|
export declare const localizeTypes: LocalizeTypes;
|
|
@@ -762,15 +561,20 @@ declare const identityEncodingSymbol: unique symbol;
|
|
|
762
561
|
* age: optional(PositiveInt),
|
|
763
562
|
* });
|
|
764
563
|
* interface User extends InferType<typeof User> {}
|
|
564
|
+
*
|
|
565
|
+
* const user = User.orThrow({ name: "Ada", age: 37 });
|
|
566
|
+
*
|
|
567
|
+
* expectTypeOf(user).toExtend<User>();
|
|
568
|
+
* expect(user.name).toBe("Ada");
|
|
765
569
|
* ```
|
|
766
570
|
*
|
|
767
|
-
* @group
|
|
571
|
+
* @group Core
|
|
768
572
|
*/
|
|
769
573
|
export type InferType<T extends TypeNode> = T["Output"];
|
|
770
574
|
/**
|
|
771
575
|
* The union of errors a {@link Type} can return from `fromUnknown`.
|
|
772
576
|
*
|
|
773
|
-
* @group
|
|
577
|
+
* @group Core
|
|
774
578
|
*/
|
|
775
579
|
export type InferErrors<T extends TypeNode> = T[typeof errorsSymbol];
|
|
776
580
|
type CanonicalInputOf<T extends TypeNode> = T extends TypeNode ? T["CanonicalInput"] : never;
|
|
@@ -842,7 +646,7 @@ type TypeOperationFn<Kind extends "from" | "orThrow" | "orNull", Input, Output,
|
|
|
842
646
|
/**
|
|
843
647
|
* Configures how container {@link Type} operations report errors.
|
|
844
648
|
*
|
|
845
|
-
* @group Core
|
|
649
|
+
* @group Core
|
|
846
650
|
*/
|
|
847
651
|
export interface ValidationOptions {
|
|
848
652
|
/** Controls whether container {@link Type} operations return one or all errors. */
|
|
@@ -914,10 +718,12 @@ type ConcreteChildTypeNameError = CompileTimeError<"Type", "Name must be one con
|
|
|
914
718
|
* expectErr(Text.fromUnknown(42), { type: "Text", value: 42 });
|
|
915
719
|
* ```
|
|
916
720
|
*
|
|
917
|
-
* @group
|
|
721
|
+
* @group Construction
|
|
918
722
|
*/
|
|
919
723
|
export declare function createType<Name extends TypeName, Output, Error extends TypeError>(name: ValidateConcreteTypeName<Name>, fromUnknown: (value: unknown) => Result<Output, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): Type<Name, Output, Output, Error, null, Error, never, Output>;
|
|
724
|
+
/** Creates an infallible child Type that preserves its parent's Output. */
|
|
920
725
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, fromParent: (value: ParentType["Output"]) => Result<ParentType["Output"], never>): Type<Name, ParentType["Input"], ParentType["Output"], never, ParentType, InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"], never>, CanonicalInputForChild<ParentType, ParentType["Output"]>, IdentityEncodingOf<ParentType>>;
|
|
726
|
+
/** Creates a fallible child Type that narrows its parent's Output. */
|
|
921
727
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode, Output extends ParentType["Output"], Error extends TypeError<Name>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, fromParent: (value: ParentType["Output"]) => Result<Output, Error>, formatError: [Error] extends [never] ? never : TypeErrorFormatter<NoInfer<Error>>): Type<Name, ParentType["Input"], Output, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, Output, Error>, CanonicalInputForChild<ParentType, Output>, IdentityEncodingOf<ParentType>>;
|
|
922
728
|
/**
|
|
923
729
|
* Transform {@link Type}.
|
|
@@ -925,12 +731,19 @@ export declare function createType<Name extends TypeName, ParentType extends Con
|
|
|
925
731
|
* `from` accepts the semantic Output. `from.parent` converts the parent Output
|
|
926
732
|
* to the output Type Input, then runs the complete output Type pipeline. `to`
|
|
927
733
|
* canonically encodes every output Type value before converting it back through
|
|
928
|
-
* the parent Type.
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
*
|
|
734
|
+
* the parent Type.
|
|
735
|
+
*
|
|
736
|
+
* The callbacks must form a lawful codec: decoding `to(output)` must reproduce
|
|
737
|
+
* the same semantic Output for every valid output value. Encoding may
|
|
738
|
+
* canonicalize multiple parent representations, but it must be total and must
|
|
739
|
+
* not lose distinctions present in the Output domain.
|
|
740
|
+
*
|
|
741
|
+
* Transformation callbacks are Type construction code. Their successful results
|
|
742
|
+
* are asserted against the declared boundary so a broken callback fails as a
|
|
743
|
+
* developer error rather than becoming a validation error. Like all
|
|
744
|
+
* Type-construction callbacks, they are trusted to follow their declared
|
|
745
|
+
* TypeScript types. A `Result<_, never>` callback is therefore trusted never to
|
|
746
|
+
* return an `Err`.
|
|
934
747
|
*
|
|
935
748
|
* Errors from the parent and the forward callback remain unchanged. A forward
|
|
936
749
|
* callback error must use the transformation name as its type. Errors from the
|
|
@@ -943,23 +756,30 @@ export declare function createType<Name extends TypeName, ParentType extends Con
|
|
|
943
756
|
* ### Example
|
|
944
757
|
*
|
|
945
758
|
* ```ts
|
|
946
|
-
* import {
|
|
759
|
+
* import { Boolean, literal, ok, transform, union } from "@evolu/common";
|
|
947
760
|
*
|
|
948
|
-
* const
|
|
949
|
-
*
|
|
950
|
-
*
|
|
951
|
-
*
|
|
761
|
+
* const BooleanString = union(literal("false"), literal("true"));
|
|
762
|
+
* const BooleanFromString = transform(
|
|
763
|
+
* "BooleanFromString",
|
|
764
|
+
* BooleanString,
|
|
765
|
+
* Boolean,
|
|
766
|
+
* {
|
|
767
|
+
* from: (value) => ok(value === "true"),
|
|
768
|
+
* to: (value) => (value ? "true" : "false"),
|
|
769
|
+
* },
|
|
770
|
+
* );
|
|
952
771
|
*
|
|
953
|
-
* expectOk(
|
|
954
|
-
*
|
|
772
|
+
* expectOk(BooleanFromString.from.parent("true"), true);
|
|
773
|
+
* expect(BooleanFromString.to(false)).toBe("false");
|
|
955
774
|
* ```
|
|
956
775
|
*
|
|
957
|
-
* @group
|
|
776
|
+
* @group Construction
|
|
958
777
|
*/
|
|
959
778
|
export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"]>(name: ValidateChildTypeName<Name, ParentType>, parent: ValidateParent<ParentType>, output: ValidateOutput<OutputType>, operations: {
|
|
960
779
|
readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], never>;
|
|
961
780
|
readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
|
|
962
781
|
}): TransformType<ParentType, OutputType, Name, never, ToOutput>;
|
|
782
|
+
/** Creates a fallible transformed Type with its own error formatter. */
|
|
963
783
|
export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"], FromError extends {
|
|
964
784
|
readonly type: Name;
|
|
965
785
|
readonly outputError?: never;
|
|
@@ -967,17 +787,26 @@ export declare function transform<Name extends TypeName, ParentType extends Conc
|
|
|
967
787
|
readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], FromError>;
|
|
968
788
|
readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
|
|
969
789
|
}, formatError: [FromError] extends [never] ? never : TypeErrorFormatter<NoInfer<FromError>>): TransformType<ParentType, OutputType, Name, FromError, ToOutput>;
|
|
970
|
-
/**
|
|
790
|
+
/**
|
|
791
|
+
* The {@link Type} returned by {@link transform}.
|
|
792
|
+
*
|
|
793
|
+
* @group Construction
|
|
794
|
+
*/
|
|
971
795
|
export interface TransformType<ParentType extends TypeNode, OutputType extends TypeNode, Name extends TypeName, FromError extends TypeError<Name>, ToOutput extends ParentType["Output"] = ParentType["Output"]> extends Type<Name, ParentType["Input"], OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>, ParentType, TransformError<Name, FromError, TypeFromError<OutputType>> | InferErrors<ParentType>, ChildCustomFrom<ParentType, OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>>, CanonicalInputForChild<ParentType, ToOutput>, false> {
|
|
972
796
|
readonly [reflectedTypesSymbol]?: OutputType;
|
|
973
797
|
readonly output: OutputType;
|
|
974
798
|
}
|
|
975
|
-
/**
|
|
799
|
+
/**
|
|
800
|
+
* An error produced by {@link transform} while decoding or validating its
|
|
801
|
+
* output.
|
|
802
|
+
*
|
|
803
|
+
* @group Construction
|
|
804
|
+
*/
|
|
976
805
|
export type TransformError<Name extends TypeName, OwnError extends TypeError<Name>, OutputError extends TypeError> = OwnError | ([OutputError] extends [never] ? never : TransformOutputError<Name, OutputError>);
|
|
977
806
|
/**
|
|
978
807
|
* Wraps an error produced by the output {@link Type} of {@link transform}.
|
|
979
808
|
*
|
|
980
|
-
* @group
|
|
809
|
+
* @group Construction
|
|
981
810
|
*/
|
|
982
811
|
export interface TransformOutputError<Name extends TypeName, OutputError extends TypeError> extends TypeError<Name>, TransparentTypeError {
|
|
983
812
|
/** The error returned by the output Type. */
|
|
@@ -990,10 +819,23 @@ type DeepestFromError<Operation> = DeepestFromOperation<Operation> extends (...a
|
|
|
990
819
|
type TypeFromError<T extends TypeNode> = unknown extends T[typeof customFromSymbol] ? DeepestFromError<TypeFromOperation<T>> : [T[typeof customFromSymbol]] extends [never] ? NonRootErrors<T> : DeepestFromError<T[typeof customFromSymbol]>;
|
|
991
820
|
declare const templateLiteralSyntaxSymbolType: unique symbol;
|
|
992
821
|
declare const templateLiteralSyntaxSymbol: typeof templateLiteralSyntaxSymbolType;
|
|
993
|
-
/**
|
|
822
|
+
/**
|
|
823
|
+
* An infallible {@link Type} accepting every value.
|
|
824
|
+
*
|
|
825
|
+
* @group Base
|
|
826
|
+
*/
|
|
994
827
|
export declare const Unknown: Type<"Unknown", unknown, unknown, never, null, never, never, unknown, true>;
|
|
995
|
-
/**
|
|
828
|
+
/**
|
|
829
|
+
* A {@link Type} rejecting every value.
|
|
830
|
+
*
|
|
831
|
+
* @group Base
|
|
832
|
+
*/
|
|
996
833
|
export declare const Never: Type<"Never", never, never, NeverError, null, NeverError, never, never, true>;
|
|
834
|
+
/**
|
|
835
|
+
* Error returned by {@link Never} for every value.
|
|
836
|
+
*
|
|
837
|
+
* @group Base
|
|
838
|
+
*/
|
|
997
839
|
export interface NeverError extends TypeError<"Never"> {
|
|
998
840
|
readonly value: unknown;
|
|
999
841
|
}
|
|
@@ -1005,7 +847,11 @@ interface TypeOfOutputByName {
|
|
|
1005
847
|
readonly Symbol: symbol;
|
|
1006
848
|
readonly Function: globalThis.Function;
|
|
1007
849
|
}
|
|
1008
|
-
/**
|
|
850
|
+
/**
|
|
851
|
+
* Error returned when `typeof` does not match the expected JavaScript type.
|
|
852
|
+
*
|
|
853
|
+
* @group Base
|
|
854
|
+
*/
|
|
1009
855
|
export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends TypeError<"TypeOf"> {
|
|
1010
856
|
readonly expected: Name;
|
|
1011
857
|
readonly value: unknown;
|
|
@@ -1033,6 +879,8 @@ export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends Type
|
|
|
1033
879
|
* expectTypeOf<WireValue100>().toEqualTypeOf<
|
|
1034
880
|
* string & Brand<"MaxLength100">
|
|
1035
881
|
* >();
|
|
882
|
+
* expectOk(WireValue100.fromUnknown(""), "");
|
|
883
|
+
* expectOk(WireValue100.fromUnknown(" value "), " value ");
|
|
1036
884
|
* ```
|
|
1037
885
|
*
|
|
1038
886
|
* @group String
|
|
@@ -1107,21 +955,37 @@ export declare const String: Type<"String", string, string, TypeOfError<"String"
|
|
|
1107
955
|
* @group Number
|
|
1108
956
|
*/
|
|
1109
957
|
export declare const Number: Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>;
|
|
1110
|
-
/**
|
|
958
|
+
/**
|
|
959
|
+
* A JavaScript bigint {@link Type}.
|
|
960
|
+
*
|
|
961
|
+
* @group Base
|
|
962
|
+
*/
|
|
1111
963
|
export declare const BigInt: Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>;
|
|
1112
|
-
/**
|
|
964
|
+
/**
|
|
965
|
+
* A JavaScript boolean {@link Type}.
|
|
966
|
+
*
|
|
967
|
+
* @group Base
|
|
968
|
+
*/
|
|
1113
969
|
export declare const Boolean: Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>;
|
|
1114
|
-
/**
|
|
970
|
+
/**
|
|
971
|
+
* A JavaScript symbol {@link Type}.
|
|
972
|
+
*
|
|
973
|
+
* @group Base
|
|
974
|
+
*/
|
|
1115
975
|
export declare const Symbol: Type<"Symbol", symbol, symbol, TypeOfError<"Symbol">, null, TypeOfError<"Symbol">, never, symbol, true>;
|
|
1116
|
-
/**
|
|
976
|
+
/**
|
|
977
|
+
* A JavaScript function {@link Type}.
|
|
978
|
+
*
|
|
979
|
+
* @group Base
|
|
980
|
+
*/
|
|
1117
981
|
export declare const Function: Type<"Function", Function, Function, TypeOfError<"Function">, null, TypeOfError<"Function">, never, Function, true>;
|
|
1118
982
|
/**
|
|
1119
|
-
*
|
|
983
|
+
* A {@link Type} validating Evolu Type declarations.
|
|
1120
984
|
*
|
|
1121
985
|
* This is useful when a Type itself crosses an unknown boundary or must be
|
|
1122
986
|
* asserted with {@link assertType}.
|
|
1123
987
|
*
|
|
1124
|
-
* @group Core
|
|
988
|
+
* @group Core
|
|
1125
989
|
*/
|
|
1126
990
|
export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeError, null, EvoluTypeError, never, AnyType, true>;
|
|
1127
991
|
/**
|
|
@@ -1134,22 +998,22 @@ export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeErr
|
|
|
1134
998
|
* the recursive `TypeNode` shape so composing Types does not repeatedly add its
|
|
1135
999
|
* compiler cost; {@link EvoluType} bridges that runtime evidence to this type.
|
|
1136
1000
|
*
|
|
1137
|
-
* @group Core
|
|
1001
|
+
* @group Core
|
|
1138
1002
|
*/
|
|
1139
1003
|
export interface AnyType extends TypeNode {
|
|
1140
1004
|
readonly [concreteTypeSymbol]: true;
|
|
1141
1005
|
}
|
|
1142
1006
|
/**
|
|
1143
|
-
* Error returned when
|
|
1007
|
+
* Error returned when {@link EvoluType} rejects a value.
|
|
1144
1008
|
*
|
|
1145
|
-
* @group Core
|
|
1009
|
+
* @group Core
|
|
1146
1010
|
*/
|
|
1147
1011
|
export interface EvoluTypeError extends TypeValueError<"EvoluType"> {
|
|
1148
1012
|
}
|
|
1149
1013
|
/**
|
|
1150
1014
|
* Nominal evidence that a value has one object tag.
|
|
1151
1015
|
*
|
|
1152
|
-
* @group Base
|
|
1016
|
+
* @group Base
|
|
1153
1017
|
*/
|
|
1154
1018
|
export interface ObjectTag<Name extends TypeName> {
|
|
1155
1019
|
readonly [objectTagSymbol]: Name;
|
|
@@ -1157,7 +1021,7 @@ export interface ObjectTag<Name extends TypeName> {
|
|
|
1157
1021
|
/**
|
|
1158
1022
|
* The {@link Type} returned by {@link objectTag}.
|
|
1159
1023
|
*
|
|
1160
|
-
* @group Base
|
|
1024
|
+
* @group Base
|
|
1161
1025
|
*/
|
|
1162
1026
|
export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNode & {
|
|
1163
1027
|
readonly Output: object;
|
|
@@ -1168,7 +1032,7 @@ export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNod
|
|
|
1168
1032
|
/**
|
|
1169
1033
|
* An error returned when an object does not report the expected tag.
|
|
1170
1034
|
*
|
|
1171
|
-
* @group Base
|
|
1035
|
+
* @group Base
|
|
1172
1036
|
*/
|
|
1173
1037
|
export interface ObjectTagError<Expected extends TypeName = TypeName> extends TypeError<"ObjectTag"> {
|
|
1174
1038
|
readonly expected: Expected;
|
|
@@ -1182,22 +1046,34 @@ interface ObjectTagOutputByName {
|
|
|
1182
1046
|
/**
|
|
1183
1047
|
* Realm-neutral {@link Type} trusting an object's reported tag.
|
|
1184
1048
|
*
|
|
1185
|
-
* Predefined built-
|
|
1186
|
-
* that trusted code does not forge their tags. They do not
|
|
1187
|
-
* internal slots. A custom tag refines the supplied Type and adds
|
|
1188
|
-
* evidence to its Output, so only a value validated by the resulting
|
|
1189
|
-
* accepted by its typed operations.
|
|
1049
|
+
* Predefined tags for JavaScript built-ins expose their native Output type
|
|
1050
|
+
* under the assumption that trusted code does not forge their tags. They do not
|
|
1051
|
+
* verify native internal slots. A custom tag refines the supplied Type and adds
|
|
1052
|
+
* nominal evidence to its Output, so only a value validated by the resulting
|
|
1053
|
+
* Type is accepted by its typed operations.
|
|
1054
|
+
*
|
|
1055
|
+
* `Object.prototype.toString` recognizes legitimate JavaScript built-ins from
|
|
1056
|
+
* another realm, but any object can customize the result with
|
|
1057
|
+
* `Symbol.toStringTag`. Types returned by this factory therefore classify
|
|
1058
|
+
* trusted values; they are not security boundaries. Passing a forged JavaScript
|
|
1059
|
+
* built-in tag violates the trust assumption of the predefined Type. Primitive
|
|
1060
|
+
* Outputs are rejected at compile time.
|
|
1061
|
+
*
|
|
1062
|
+
* ### Example
|
|
1063
|
+
*
|
|
1064
|
+
* ```ts
|
|
1065
|
+
* import { objectTag } from "@evolu/common";
|
|
1066
|
+
*
|
|
1067
|
+
* const DateType = objectTag("Date");
|
|
1068
|
+
* const date = new globalThis.Date("2025-01-01T00:00:00.000Z");
|
|
1190
1069
|
*
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1193
|
-
* Types returned by this factory therefore classify trusted values; they are
|
|
1194
|
-
* not security boundaries. Passing a forged built-in tag violates the trust
|
|
1195
|
-
* assumption of the predefined Type. Primitive Outputs are rejected at compile
|
|
1196
|
-
* time.
|
|
1070
|
+
* expectOk(DateType.fromUnknown(date), date);
|
|
1071
|
+
* ```
|
|
1197
1072
|
*
|
|
1198
|
-
* @group Base
|
|
1073
|
+
* @group Base
|
|
1199
1074
|
*/
|
|
1200
1075
|
export declare function objectTag<Name extends keyof ObjectTagOutputByName>(name: ValidateConcreteTypeName<Name>): Type<Name, ObjectTagOutputByName[Name], ObjectTagOutputByName[Name], ObjectTagError<Name>, null, ObjectTagError<Name>, never, ObjectTagOutputByName[Name]>;
|
|
1076
|
+
/** Creates an object-tag Type by refining an existing object Type. */
|
|
1201
1077
|
export declare function objectTag<Name extends TypeName, OutputType extends ConcreteTypeNode & {
|
|
1202
1078
|
readonly Output: object;
|
|
1203
1079
|
}>(name: ValidateConcreteTypeName<Name>, outputType: ValidateOutput<OutputType> & ([ChildTypeNameValidationError<"ObjectTag", OutputType>] extends [never] ? unknown : ChildTypeNameValidationError<"ObjectTag", OutputType>)): ObjectTagType<Name, OutputType>;
|
|
@@ -1207,7 +1083,7 @@ declare const objectTagSymbol: unique symbol;
|
|
|
1207
1083
|
*
|
|
1208
1084
|
* It trusts the reported object tag and does not verify Date internal slots.
|
|
1209
1085
|
*
|
|
1210
|
-
* @group Base
|
|
1086
|
+
* @group Base
|
|
1211
1087
|
*/
|
|
1212
1088
|
export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>;
|
|
1213
1089
|
/**
|
|
@@ -1216,7 +1092,7 @@ export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null
|
|
|
1216
1092
|
* It trusts the reported object tag and does not verify Uint8Array internal
|
|
1217
1093
|
* slots.
|
|
1218
1094
|
*
|
|
1219
|
-
* @group Base
|
|
1095
|
+
* @group Base
|
|
1220
1096
|
*/
|
|
1221
1097
|
export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>;
|
|
1222
1098
|
/**
|
|
@@ -1225,7 +1101,7 @@ export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>,
|
|
|
1225
1101
|
* It trusts the reported object tag and does not verify ArrayBuffer internal
|
|
1226
1102
|
* slots.
|
|
1227
1103
|
*
|
|
1228
|
-
* @group Base
|
|
1104
|
+
* @group Base
|
|
1229
1105
|
*/
|
|
1230
1106
|
export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer, ObjectTagError<"ArrayBuffer">, null, ObjectTagError<"ArrayBuffer">, never, ArrayBuffer, true>;
|
|
1231
1107
|
/**
|
|
@@ -1256,25 +1132,33 @@ export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer,
|
|
|
1256
1132
|
* assert(!UserInstance.is({ name: "Ada" }));
|
|
1257
1133
|
* ```
|
|
1258
1134
|
*
|
|
1259
|
-
* @group Base
|
|
1135
|
+
* @group Base
|
|
1260
1136
|
*/
|
|
1261
1137
|
export declare const instanceOf: <Constructor extends InstanceConstructor>(constructor: ValidateInstanceConstructor<Constructor>) => InstanceOfType<Constructor>;
|
|
1262
1138
|
/**
|
|
1263
1139
|
* A JavaScript class constructor accepted by {@link instanceOf}.
|
|
1264
1140
|
*
|
|
1265
|
-
* @group Base
|
|
1141
|
+
* @group Base
|
|
1266
1142
|
*/
|
|
1267
1143
|
export type InstanceConstructor<Instance extends object = object> = (abstract new (...args: ReadonlyArray<never>) => Instance) & {
|
|
1268
1144
|
readonly name: string;
|
|
1269
1145
|
};
|
|
1270
|
-
/**
|
|
1146
|
+
/**
|
|
1147
|
+
* The {@link Type} returned by {@link instanceOf}.
|
|
1148
|
+
*
|
|
1149
|
+
* @group Base
|
|
1150
|
+
*/
|
|
1271
1151
|
export interface InstanceOfType<Constructor extends InstanceConstructor> extends Type<"InstanceOf", InstanceOfOutput<Constructor>, InstanceOfOutput<Constructor>, InstanceOfError, null, InstanceOfError, never, InstanceOfOutput<Constructor>> {
|
|
1272
1152
|
readonly constructor: Constructor;
|
|
1273
1153
|
}
|
|
1274
1154
|
type InstanceOfOutput<Constructor extends InstanceConstructor> = Constructor extends {
|
|
1275
1155
|
readonly prototype: infer Output extends object;
|
|
1276
1156
|
} ? Output : InstanceType<Constructor>;
|
|
1277
|
-
/**
|
|
1157
|
+
/**
|
|
1158
|
+
* Error returned when a value is not an instance of the expected constructor.
|
|
1159
|
+
*
|
|
1160
|
+
* @group Base
|
|
1161
|
+
*/
|
|
1278
1162
|
export interface InstanceOfError extends TypeValueError<"InstanceOf"> {
|
|
1279
1163
|
readonly constructorName: string;
|
|
1280
1164
|
}
|
|
@@ -1311,7 +1195,11 @@ type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor
|
|
|
1311
1195
|
* @group Unions
|
|
1312
1196
|
*/
|
|
1313
1197
|
export declare const literal: <const Expected extends Literal>(expected: ValidateLiteral<Expected>) => LiteralType<Expected>;
|
|
1314
|
-
/**
|
|
1198
|
+
/**
|
|
1199
|
+
* The {@link Type} returned by {@link literal}.
|
|
1200
|
+
*
|
|
1201
|
+
* @group Unions
|
|
1202
|
+
*/
|
|
1315
1203
|
export interface LiteralType<Expected extends Literal> extends Type<"Literal", WidenLiteral<Expected>, Expected, LiteralError<Expected>, LiteralParent<Expected>, LiteralError<Expected> | LiteralParentErrors<Expected>, never, CanonicalInputSubset<WidenLiteral<Expected>, CanonicalInputForParent<LiteralParent<Expected>, Expected>>, IdentityEncodingForParent<LiteralParent<Expected>>> {
|
|
1316
1204
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1317
1205
|
readonly expected: Expected;
|
|
@@ -1320,14 +1208,26 @@ type LiteralParent<Expected extends Literal> = Expected extends string ? typeof
|
|
|
1320
1208
|
type LiteralParentErrors<Expected extends Literal> = LiteralParent<Expected> extends infer Parent extends TypeNode ? InferErrors<Parent> : never;
|
|
1321
1209
|
type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
|
|
1322
1210
|
type LiteralCompileTimeError = CompileTimeError<"Type", "Expected must be one concrete literal value.">;
|
|
1323
|
-
/**
|
|
1211
|
+
/**
|
|
1212
|
+
* Error returned when a value does not equal the expected literal.
|
|
1213
|
+
*
|
|
1214
|
+
* @group Unions
|
|
1215
|
+
*/
|
|
1324
1216
|
export interface LiteralError<Expected extends Literal = Literal> extends TypeError<"Literal"> {
|
|
1325
1217
|
readonly expected: Expected;
|
|
1326
1218
|
readonly value: unknown;
|
|
1327
1219
|
}
|
|
1328
|
-
/**
|
|
1220
|
+
/**
|
|
1221
|
+
* Literal {@link Type} accepting only `undefined`.
|
|
1222
|
+
*
|
|
1223
|
+
* @group Unions
|
|
1224
|
+
*/
|
|
1329
1225
|
export declare const Undefined: LiteralType<undefined>;
|
|
1330
|
-
/**
|
|
1226
|
+
/**
|
|
1227
|
+
* Literal {@link Type} accepting only `null`.
|
|
1228
|
+
*
|
|
1229
|
+
* @group Unions
|
|
1230
|
+
*/
|
|
1331
1231
|
export declare const Null: LiteralType<null>;
|
|
1332
1232
|
/**
|
|
1333
1233
|
* Union {@link Type}.
|
|
@@ -1352,7 +1252,10 @@ export declare const Null: LiteralType<null>;
|
|
|
1352
1252
|
* within each member.
|
|
1353
1253
|
*
|
|
1354
1254
|
* Member order matters when multiple members accept the same value: validation
|
|
1355
|
-
* and encoding use the first matching member.
|
|
1255
|
+
* and encoding use the first matching member. When member Inputs overlap,
|
|
1256
|
+
* decoding the value emitted by the first member selected for an Output must
|
|
1257
|
+
* reproduce that semantic Output; otherwise the Union violates the round-trip
|
|
1258
|
+
* law.
|
|
1356
1259
|
*
|
|
1357
1260
|
* ### Example
|
|
1358
1261
|
*
|
|
@@ -1389,9 +1292,11 @@ export declare function union<const Expected extends AtLeastTwoReadonlyArray<Lit
|
|
|
1389
1292
|
}): UnionType<{
|
|
1390
1293
|
readonly [Index in keyof Expected]: LiteralType<Expected[Index]>;
|
|
1391
1294
|
}>;
|
|
1295
|
+
/** Creates a Union Type from Type members. */
|
|
1392
1296
|
export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode>>(...members: {
|
|
1393
1297
|
readonly [Index in keyof Members]: ValidateUnionTypeMember<Members[Index]>;
|
|
1394
1298
|
}): UnionType<Members>;
|
|
1299
|
+
/** Creates a Union Type from Type and literal members. */
|
|
1395
1300
|
export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>>(...members: {
|
|
1396
1301
|
readonly [Index in keyof Members]: ValidateUnionMember<Members[Index]>;
|
|
1397
1302
|
}): UnionType<NormalizeUnionMembers<Members>>;
|
|
@@ -1401,18 +1306,49 @@ export declare function union<const Members extends AtLeastTwoReadonlyArray<Type
|
|
|
1401
1306
|
* This does not make an object property optional. It changes only the values
|
|
1402
1307
|
* accepted when the property is present.
|
|
1403
1308
|
*
|
|
1309
|
+
* ### Example
|
|
1310
|
+
*
|
|
1311
|
+
* ```ts
|
|
1312
|
+
* import { String, undefinedOr } from "@evolu/common";
|
|
1313
|
+
*
|
|
1314
|
+
* const StringOrUndefined = undefinedOr(String);
|
|
1315
|
+
*
|
|
1316
|
+
* expectOk(StringOrUndefined.fromUnknown(undefined), undefined);
|
|
1317
|
+
* ```
|
|
1318
|
+
*
|
|
1404
1319
|
* @group Unions
|
|
1405
1320
|
*/
|
|
1406
1321
|
export declare const undefinedOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Undefined]>;
|
|
1407
1322
|
/**
|
|
1408
1323
|
* Union {@link Type} containing the supplied Type and `null`.
|
|
1409
1324
|
*
|
|
1325
|
+
* ### Example
|
|
1326
|
+
*
|
|
1327
|
+
* ```ts
|
|
1328
|
+
* import { String, nullOr } from "@evolu/common";
|
|
1329
|
+
*
|
|
1330
|
+
* const NullableString = nullOr(String);
|
|
1331
|
+
*
|
|
1332
|
+
* expectOk(NullableString.fromUnknown(null), null);
|
|
1333
|
+
* ```
|
|
1334
|
+
*
|
|
1410
1335
|
* @group Unions
|
|
1411
1336
|
*/
|
|
1412
1337
|
export declare const nullOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null]>;
|
|
1413
1338
|
/**
|
|
1414
1339
|
* Union {@link Type} containing the supplied Type, `null`, and `undefined`.
|
|
1415
1340
|
*
|
|
1341
|
+
* ### Example
|
|
1342
|
+
*
|
|
1343
|
+
* ```ts
|
|
1344
|
+
* import { String, nullishOr } from "@evolu/common";
|
|
1345
|
+
*
|
|
1346
|
+
* const NullishString = nullishOr(String);
|
|
1347
|
+
*
|
|
1348
|
+
* expectOk(NullishString.fromUnknown(undefined), undefined);
|
|
1349
|
+
* expectOk(NullishString.fromUnknown(null), null);
|
|
1350
|
+
* ```
|
|
1351
|
+
*
|
|
1416
1352
|
* @group Unions
|
|
1417
1353
|
*/
|
|
1418
1354
|
export declare const nullishOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null, typeof Undefined]>;
|
|
@@ -1424,7 +1360,11 @@ type UnionMemberConcreteTypeError = CompileTimeError<"Type", "Union member must
|
|
|
1424
1360
|
type NormalizeUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>> = {
|
|
1425
1361
|
readonly [Index in keyof Members]: Members[Index] extends TypeNode ? Members[Index] : Members[Index] extends Literal ? LiteralType<Members[Index]> : never;
|
|
1426
1362
|
} extends infer Normalized extends AtLeastTwoReadonlyArray<TypeNode> ? Normalized : never;
|
|
1427
|
-
/**
|
|
1363
|
+
/**
|
|
1364
|
+
* The {@link Type} returned by {@link union}.
|
|
1365
|
+
*
|
|
1366
|
+
* @group Unions
|
|
1367
|
+
*/
|
|
1428
1368
|
export interface UnionType<Members extends AtLeastTwoReadonlyArray<TypeNode>> extends Type<"Union", Members[number]["Input"], Members[number]["Output"], UnionTypeError<Members>, UnionInputParent<Members>, UnionTypeError<Members>, never, CanonicalInputOf<Members[number]>, AllTypesUseIdentityEncoding<Members[number]>> {
|
|
1429
1369
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1430
1370
|
readonly [reflectedTypesSymbol]?: Members[number];
|
|
@@ -1442,9 +1382,17 @@ type UnionInputTypeError<Members extends AtLeastTwoReadonlyArray<TypeNode>, Root
|
|
|
1442
1382
|
type RootUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode>> = {
|
|
1443
1383
|
readonly [Index in keyof Members]: RootType<Members[Index]>;
|
|
1444
1384
|
} extends infer RootMembers extends AtLeastTwoReadonlyArray<TypeNode> ? RootMembers : never;
|
|
1445
|
-
/**
|
|
1385
|
+
/**
|
|
1386
|
+
* Error returned when every member of a {@link union} rejects an input.
|
|
1387
|
+
*
|
|
1388
|
+
* @group Unions
|
|
1389
|
+
*/
|
|
1446
1390
|
export type UnionError<Error extends TypeError = TypeError, MemberError extends UnionMemberError<Error> = UnionMemberError<Error>> = [Error] extends [never] ? never : UnionErrorValue<Error, MemberError>;
|
|
1447
|
-
/**
|
|
1391
|
+
/**
|
|
1392
|
+
* An error returned by one {@link union} member and its index.
|
|
1393
|
+
*
|
|
1394
|
+
* @group Unions
|
|
1395
|
+
*/
|
|
1448
1396
|
export interface UnionMemberError<Error extends TypeError, Index extends number = number> {
|
|
1449
1397
|
readonly index: Index;
|
|
1450
1398
|
readonly error: Error;
|
|
@@ -1472,9 +1420,7 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1472
1420
|
readonly errors: NonEmptyReadonlyArray<MemberError>;
|
|
1473
1421
|
}
|
|
1474
1422
|
/**
|
|
1475
|
-
* Template literal {@link Type}
|
|
1476
|
-
*
|
|
1477
|
-
* Parses and creates structured strings.
|
|
1423
|
+
* Template literal {@link Type} that parses canonical strings into Tuples.
|
|
1478
1424
|
*
|
|
1479
1425
|
* Accepts the same template parts as {@link templateLiteral}: fixed string
|
|
1480
1426
|
* literals and Types canonically encoded as strings. Instead of keeping Output
|
|
@@ -1490,10 +1436,10 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1490
1436
|
* reversibility and keeps capture boundaries unambiguous. Different capture
|
|
1491
1437
|
* Tuples must never encode to the same string. The parser provides predictable
|
|
1492
1438
|
* parsing without pathological backtracking and decodes each capture once, so
|
|
1493
|
-
* adversarial input cannot trigger exponential parser work. Fixed-width
|
|
1494
|
-
* may be adjacent, but only one variable-width capture is allowed.
|
|
1495
|
-
* that could join UTF-16 surrogate halves across parts are
|
|
1496
|
-
* construction.
|
|
1439
|
+
* adversarial input cannot trigger exponential parser work. Fixed-width
|
|
1440
|
+
* captures may be adjacent, but only one variable-width capture is allowed.
|
|
1441
|
+
* Declarations that could join UTF-16 surrogate halves across parts are
|
|
1442
|
+
* rejected during construction.
|
|
1497
1443
|
*
|
|
1498
1444
|
* Keep capture unions reasonably small to avoid excessive compiler work.
|
|
1499
1445
|
*
|
|
@@ -1530,10 +1476,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1530
1476
|
*
|
|
1531
1477
|
* // Parse an unknown string into structured data.
|
|
1532
1478
|
* const result = SupportedLocale.fromUnknown("cs-CZ");
|
|
1533
|
-
*
|
|
1479
|
+
* expectOk(result, ["cs", "CZ"]);
|
|
1534
1480
|
* const locale = result.value;
|
|
1535
1481
|
* expectTypeOf(locale).toEqualTypeOf<SupportedLocale>();
|
|
1536
|
-
* expect(locale).toEqual(["cs", "CZ"]);
|
|
1537
1482
|
* expectErr(SupportedLocale.fromUnknown("cs/CZ"), {
|
|
1538
1483
|
* type: "TemplateLiteral",
|
|
1539
1484
|
* value: "cs/CZ",
|
|
@@ -1592,10 +1537,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1592
1537
|
*
|
|
1593
1538
|
* // Decode the string into structured data.
|
|
1594
1539
|
* const result = ItemId.fromUnknown("item-42");
|
|
1595
|
-
*
|
|
1540
|
+
* expectOk(result, [42n]);
|
|
1596
1541
|
* const itemId = result.value;
|
|
1597
1542
|
* expectTypeOf(itemId).toEqualTypeOf<ItemId>();
|
|
1598
|
-
* expect(itemId).toEqual([42n]);
|
|
1599
1543
|
*
|
|
1600
1544
|
* // Encode the structured data into its canonical string.
|
|
1601
1545
|
* const itemIdLiteral = ItemId.to(itemId);
|
|
@@ -1645,14 +1589,22 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1645
1589
|
* @group Template literals
|
|
1646
1590
|
*/
|
|
1647
1591
|
export declare const templateLiteralParser: <const Parts extends TemplateLiteralParts>(...parts: { readonly [Index in keyof Parts]: ValidateTemplateLiteralPart<Parts[Index]>; } & TemplateLiteralValidation<Parts>) => TemplateLiteralParserType<Parts>;
|
|
1648
|
-
/**
|
|
1592
|
+
/**
|
|
1593
|
+
* The parsing {@link Type} returned by {@link templateLiteralParser}.
|
|
1594
|
+
*
|
|
1595
|
+
* @group Template literals
|
|
1596
|
+
*/
|
|
1649
1597
|
export interface TemplateLiteralParserType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralCaptureTuple<Parts>["Output"], never, TemplateLiteralType<Parts>, InferErrors<TemplateLiteralType<Parts>>, never, TemplateLiteralStringOutput<Parts>, false> {
|
|
1650
1598
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1651
1599
|
readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
|
|
1652
1600
|
readonly output: TemplateLiteralCaptureTuple<Parts>;
|
|
1653
1601
|
readonly parts: Parts;
|
|
1654
1602
|
}
|
|
1655
|
-
/**
|
|
1603
|
+
/**
|
|
1604
|
+
* The validating string {@link Type} returned by {@link templateLiteral}.
|
|
1605
|
+
*
|
|
1606
|
+
* @group Template literals
|
|
1607
|
+
*/
|
|
1656
1608
|
export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralStringOutput<Parts>, TemplateLiteralParseError<Parts>, typeof String, TypeOfError<"String"> | TemplateLiteralParseError<Parts>, never, TemplateLiteralStringOutput<Parts>, true> {
|
|
1657
1609
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1658
1610
|
readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
|
|
@@ -1665,8 +1617,8 @@ export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends
|
|
|
1665
1617
|
* Creates a canonical string Type from fixed strings and string-encoded Types.
|
|
1666
1618
|
*
|
|
1667
1619
|
* Use this factory when Output should remain a string. Switch to
|
|
1668
|
-
* {@link templateLiteralParser} when the individual Type parts should be
|
|
1669
|
-
*
|
|
1620
|
+
* {@link templateLiteralParser} when the individual Type parts should be decoded
|
|
1621
|
+
* into a Tuple.
|
|
1670
1622
|
*
|
|
1671
1623
|
* ### Example
|
|
1672
1624
|
*
|
|
@@ -1690,7 +1642,11 @@ export declare const templateLiteral: <const Parts extends TemplateLiteralParts>
|
|
|
1690
1642
|
type TemplateLiteralParseError<Parts extends TemplateLiteralParts> = TransformError<"TemplateLiteral", TemplateLiteralIsFrameless<Parts> extends true ? never : TemplateLiteralError, TemplateLiteralCaptureTupleError<Parts>>;
|
|
1691
1643
|
type TemplateLiteralCaptureTupleError<Parts extends TemplateLiteralParts> = TupleElementsError<TemplateLiteralCaptureFromStringError<TemplateLiteralCaptureTypes<Parts>[number]>>;
|
|
1692
1644
|
type TemplateLiteralCaptureFromStringError<T extends TypeNode> = T extends TypeNode ? string extends RootType<T>["Output"] ? TypeFromError<T> : InferErrors<T> : never;
|
|
1693
|
-
/**
|
|
1645
|
+
/**
|
|
1646
|
+
* Error returned when a string does not match a template literal declaration.
|
|
1647
|
+
*
|
|
1648
|
+
* @group Template literals
|
|
1649
|
+
*/
|
|
1694
1650
|
export interface TemplateLiteralError extends TypeError<"TemplateLiteral"> {
|
|
1695
1651
|
readonly value: string;
|
|
1696
1652
|
}
|
|
@@ -1780,72 +1736,19 @@ type TemplateLiteralStringWidth<Value extends string, Width extends ReadonlyArra
|
|
|
1780
1736
|
* });
|
|
1781
1737
|
* ```
|
|
1782
1738
|
*
|
|
1783
|
-
* To reuse a Brand constraint with different parent Types, define a
|
|
1784
|
-
* {@link BrandFactory}.
|
|
1785
|
-
*
|
|
1786
|
-
* ```ts
|
|
1787
|
-
* import {
|
|
1788
|
-
* String,
|
|
1789
|
-
* brand,
|
|
1790
|
-
* err,
|
|
1791
|
-
* minLength,
|
|
1792
|
-
* ok,
|
|
1793
|
-
* type Brand,
|
|
1794
|
-
* type BrandFactory,
|
|
1795
|
-
* type TypeError,
|
|
1796
|
-
* } from "@evolu/common";
|
|
1797
|
-
*
|
|
1798
|
-
* const trimmed: BrandFactory<"Trimmed", string, TrimmedError> = (
|
|
1799
|
-
* parent,
|
|
1800
|
-
* ) =>
|
|
1801
|
-
* brand(
|
|
1802
|
-
* "Trimmed",
|
|
1803
|
-
* parent,
|
|
1804
|
-
* (value) =>
|
|
1805
|
-
* value === value.trim()
|
|
1806
|
-
* ? ok()
|
|
1807
|
-
* : err<TrimmedError>({ type: "Trimmed", value }),
|
|
1808
|
-
* () => "Expected a string without surrounding whitespace.",
|
|
1809
|
-
* );
|
|
1810
|
-
*
|
|
1811
|
-
* const TrimmedString = trimmed(String);
|
|
1812
|
-
* type TrimmedString = typeof TrimmedString.Output;
|
|
1813
|
-
*
|
|
1814
|
-
* expectTypeOf<TrimmedString>().toEqualTypeOf<string & Brand<"Trimmed">>();
|
|
1815
|
-
*
|
|
1816
|
-
* const NonEmptyString = minLength(1)(String);
|
|
1817
|
-
* type NonEmptyString = typeof NonEmptyString.Output;
|
|
1818
|
-
*
|
|
1819
|
-
* expectTypeOf<NonEmptyString>().toEqualTypeOf<
|
|
1820
|
-
* string & Brand<"MinLength1">
|
|
1821
|
-
* >();
|
|
1822
|
-
*
|
|
1823
|
-
* const NonEmptyTrimmedString = minLength(1)(TrimmedString);
|
|
1824
|
-
* type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
|
|
1825
|
-
*
|
|
1826
|
-
* expectTypeOf<NonEmptyTrimmedString>().toEqualTypeOf<
|
|
1827
|
-
* string & Brand<"Trimmed"> & Brand<"MinLength1">
|
|
1828
|
-
* >();
|
|
1829
|
-
*
|
|
1830
|
-
* interface TrimmedError extends TypeError<"Trimmed"> {
|
|
1831
|
-
* readonly value: string;
|
|
1832
|
-
* }
|
|
1833
|
-
*
|
|
1834
|
-
* // Validation from unknown.
|
|
1835
|
-
* expectOk(NonEmptyTrimmedString.fromUnknown("Evolu"), "Evolu");
|
|
1836
|
-
*
|
|
1837
|
-
* // The typed input selects TrimmedString as the validated boundary.
|
|
1838
|
-
* expectOk(
|
|
1839
|
-
* NonEmptyTrimmedString.from.parent(TrimmedString.orThrow("Evolu")),
|
|
1840
|
-
* "Evolu",
|
|
1841
|
-
* );
|
|
1842
|
-
* ```
|
|
1739
|
+
* To reuse and compose a Brand constraint with different parent Types, define a
|
|
1740
|
+
* {@link BrandFactory}.
|
|
1843
1741
|
*
|
|
1844
|
-
* @group
|
|
1742
|
+
* @group Construction
|
|
1845
1743
|
*/
|
|
1846
1744
|
export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, validate?: (value: ParentType["Output"]) => Result<void, never>): BrandType<ParentType, Name, never>;
|
|
1745
|
+
/** Creates a validated Brand Type with its own error formatter. */
|
|
1847
1746
|
export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode, Error extends TypeError<NoInfer<Name>>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, validate: (value: ParentType["Output"]) => Result<void, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): BrandType<ParentType, Name, Error>;
|
|
1848
|
-
/**
|
|
1747
|
+
/**
|
|
1748
|
+
* The {@link Type} returned by {@link brand}.
|
|
1749
|
+
*
|
|
1750
|
+
* @group Construction
|
|
1751
|
+
*/
|
|
1849
1752
|
export interface BrandType<ParentType extends TypeNode, Name extends TypeName, Error extends TypeError> extends Type<Name, ParentType["Input"], ParentType["Output"] & Brand<Name>, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"] & Brand<Name>, Error>, CanonicalInputForChild<ParentType, ParentType["Output"] & Brand<Name>>, IdentityEncodingOf<ParentType>> {
|
|
1850
1753
|
}
|
|
1851
1754
|
/**
|
|
@@ -1878,17 +1781,37 @@ export interface BrandType<ParentType extends TypeNode, Name extends TypeName, E
|
|
|
1878
1781
|
*/
|
|
1879
1782
|
export declare const DateIso: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>;
|
|
1880
1783
|
export type DateIso = typeof DateIso.Output;
|
|
1881
|
-
/**
|
|
1784
|
+
/**
|
|
1785
|
+
* Error returned when a string is not a canonical {@link DateIso}.
|
|
1786
|
+
*
|
|
1787
|
+
* @group String
|
|
1788
|
+
*/
|
|
1882
1789
|
export interface DateIsoError extends TypeError<"DateIso"> {
|
|
1883
1790
|
readonly value: string;
|
|
1884
1791
|
}
|
|
1885
1792
|
/**
|
|
1886
1793
|
* Safely transforms a {@link Date} into a canonical {@link DateIso}.
|
|
1887
1794
|
*
|
|
1795
|
+
* ### Example
|
|
1796
|
+
*
|
|
1797
|
+
* ```ts
|
|
1798
|
+
* import { DateIsoFromDate } from "@evolu/common";
|
|
1799
|
+
*
|
|
1800
|
+
* const date = new globalThis.Date("2025-01-01T12:00:00.000Z");
|
|
1801
|
+
* const result = DateIsoFromDate.fromUnknown(date);
|
|
1802
|
+
*
|
|
1803
|
+
* expectOk(result, "2025-01-01T12:00:00.000Z");
|
|
1804
|
+
* expect(DateIsoFromDate.to(result.value)).toEqual(date);
|
|
1805
|
+
* ```
|
|
1806
|
+
*
|
|
1888
1807
|
* @group String
|
|
1889
1808
|
*/
|
|
1890
1809
|
export declare const DateIsoFromDate: TransformType<Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>, BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>, "DateIsoFromDate", DateIsoFromDateError, Date>;
|
|
1891
|
-
/**
|
|
1810
|
+
/**
|
|
1811
|
+
* Error returned when a {@link Date} cannot be represented as {@link DateIso}.
|
|
1812
|
+
*
|
|
1813
|
+
* @group String
|
|
1814
|
+
*/
|
|
1892
1815
|
export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
|
|
1893
1816
|
readonly value: globalThis.Date;
|
|
1894
1817
|
}
|
|
@@ -1899,7 +1822,11 @@ export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
|
|
|
1899
1822
|
*/
|
|
1900
1823
|
export declare const Int64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>;
|
|
1901
1824
|
export type Int64 = typeof Int64.Output;
|
|
1902
|
-
/**
|
|
1825
|
+
/**
|
|
1826
|
+
* Error returned when a bigint is outside the signed 64-bit {@link Int64} range.
|
|
1827
|
+
*
|
|
1828
|
+
* @group Number
|
|
1829
|
+
*/
|
|
1903
1830
|
export interface Int64Error extends TypeError<"Int64"> {
|
|
1904
1831
|
readonly value: bigint;
|
|
1905
1832
|
}
|
|
@@ -1910,7 +1837,12 @@ export interface Int64Error extends TypeError<"Int64"> {
|
|
|
1910
1837
|
*/
|
|
1911
1838
|
export declare const UInt64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "UInt64", UInt64Error>;
|
|
1912
1839
|
export type UInt64 = typeof UInt64.Output;
|
|
1913
|
-
/**
|
|
1840
|
+
/**
|
|
1841
|
+
* Error returned when a bigint is outside the unsigned 64-bit {@link UInt64}
|
|
1842
|
+
* range.
|
|
1843
|
+
*
|
|
1844
|
+
* @group Number
|
|
1845
|
+
*/
|
|
1914
1846
|
export interface UInt64Error extends TypeError<"UInt64"> {
|
|
1915
1847
|
readonly value: bigint;
|
|
1916
1848
|
}
|
|
@@ -1966,7 +1898,7 @@ export interface UInt64Error extends TypeError<"UInt64"> {
|
|
|
1966
1898
|
* For numeric parameters encoded in a Brand name, use
|
|
1967
1899
|
* {@link ValidateBrandFactoryNumber}.
|
|
1968
1900
|
*
|
|
1969
|
-
* @group
|
|
1901
|
+
* @group Construction
|
|
1970
1902
|
*/
|
|
1971
1903
|
export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<Name>> = <ParentType extends ConcreteTypeNode & {
|
|
1972
1904
|
readonly Output: Value;
|
|
@@ -2031,7 +1963,7 @@ export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<N
|
|
|
2031
1963
|
* lessThan(100 - 1)(Number);
|
|
2032
1964
|
* ```
|
|
2033
1965
|
*
|
|
2034
|
-
* @group
|
|
1966
|
+
* @group Construction
|
|
2035
1967
|
*/
|
|
2036
1968
|
export type ValidateBrandFactoryNumber<Value extends number> = IsUnion<Value> extends false ? {} extends Record<`${Value}`, never> ? Value & Readonly<Record<BrandFactoryNumberError, never>> : Value : Value & Readonly<Record<BrandFactoryNumberError, never>>;
|
|
2037
1969
|
type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must be one concrete numeric literal instead of a widened, union, or branded number.">;
|
|
@@ -2062,7 +1994,11 @@ type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must
|
|
|
2062
1994
|
* @group String
|
|
2063
1995
|
*/
|
|
2064
1996
|
export declare const capitalized: BrandFactory<"Capitalized", string, CapitalizedError>;
|
|
2065
|
-
/**
|
|
1997
|
+
/**
|
|
1998
|
+
* Error returned when {@link capitalized} rejects a string.
|
|
1999
|
+
*
|
|
2000
|
+
* @group String
|
|
2001
|
+
*/
|
|
2066
2002
|
export interface CapitalizedError extends TypeError<"Capitalized"> {
|
|
2067
2003
|
readonly value: string;
|
|
2068
2004
|
}
|
|
@@ -2076,10 +2012,24 @@ export type CapitalizedString = typeof CapitalizedString.Output;
|
|
|
2076
2012
|
/**
|
|
2077
2013
|
* String {@link Brand} without surrounding whitespace.
|
|
2078
2014
|
*
|
|
2015
|
+
* ### Example
|
|
2016
|
+
*
|
|
2017
|
+
* ```ts
|
|
2018
|
+
* import { String, trimmed } from "@evolu/common";
|
|
2019
|
+
*
|
|
2020
|
+
* const Trimmed = trimmed(String);
|
|
2021
|
+
*
|
|
2022
|
+
* expectOk(Trimmed.fromUnknown("Evolu"), "Evolu");
|
|
2023
|
+
* ```
|
|
2024
|
+
*
|
|
2079
2025
|
* @group String
|
|
2080
2026
|
*/
|
|
2081
2027
|
export declare const trimmed: BrandFactory<"Trimmed", string, TrimmedError>;
|
|
2082
|
-
/**
|
|
2028
|
+
/**
|
|
2029
|
+
* Error returned when {@link trimmed} rejects a string.
|
|
2030
|
+
*
|
|
2031
|
+
* @group String
|
|
2032
|
+
*/
|
|
2083
2033
|
export interface TrimmedError extends TypeError<"Trimmed"> {
|
|
2084
2034
|
readonly value: string;
|
|
2085
2035
|
}
|
|
@@ -2099,17 +2049,41 @@ export type TrimmedString = typeof TrimmedString.Output;
|
|
|
2099
2049
|
/**
|
|
2100
2050
|
* Trims a string and returns a {@link TrimmedString}.
|
|
2101
2051
|
*
|
|
2052
|
+
* ### Example
|
|
2053
|
+
*
|
|
2054
|
+
* ```ts
|
|
2055
|
+
* import { trim } from "@evolu/common";
|
|
2056
|
+
*
|
|
2057
|
+
* expect(trim(" Evolu ")).toBe("Evolu");
|
|
2058
|
+
* ```
|
|
2059
|
+
*
|
|
2102
2060
|
* @group String
|
|
2103
2061
|
*/
|
|
2104
2062
|
export declare const trim: (value: string) => TrimmedString;
|
|
2105
2063
|
/**
|
|
2106
|
-
* Minimum-length {@link Brand}
|
|
2064
|
+
* Minimum-length {@link Brand} for values whose `length` is at least `min`.
|
|
2065
|
+
*
|
|
2066
|
+
* ### Example
|
|
2067
|
+
*
|
|
2068
|
+
* ```ts
|
|
2069
|
+
* import { String, array, minLength } from "@evolu/common";
|
|
2070
|
+
*
|
|
2071
|
+
* const AtLeastThreeCharacters = minLength(3)(String);
|
|
2072
|
+
* const AtLeastTwoItems = minLength(2)(array(String));
|
|
2073
|
+
*
|
|
2074
|
+
* expectOk(AtLeastThreeCharacters.fromUnknown("abc"), "abc");
|
|
2075
|
+
* expectOk(AtLeastTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2076
|
+
* ```
|
|
2107
2077
|
*
|
|
2108
2078
|
* @group String
|
|
2109
2079
|
* @group Collection
|
|
2110
2080
|
*/
|
|
2111
2081
|
export declare const minLength: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`MinLength${Min}`, ValueWithLength, MinLengthError<Min>>;
|
|
2112
|
-
/**
|
|
2082
|
+
/**
|
|
2083
|
+
* Error returned when {@link minLength} rejects a value.
|
|
2084
|
+
*
|
|
2085
|
+
* @group Collection
|
|
2086
|
+
*/
|
|
2113
2087
|
export interface MinLengthError<Min extends number = number> extends TypeError<`MinLength${Min}`> {
|
|
2114
2088
|
readonly value: ValueWithLength;
|
|
2115
2089
|
readonly min: Min;
|
|
@@ -2131,13 +2105,29 @@ export interface MinLengthError<Min extends number = number> extends TypeError<`
|
|
|
2131
2105
|
export declare const NonEmptyTrimmedString: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>;
|
|
2132
2106
|
export type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
|
|
2133
2107
|
/**
|
|
2134
|
-
* Maximum-length {@link Brand}
|
|
2108
|
+
* Maximum-length {@link Brand} for values whose `length` is at most `max`.
|
|
2109
|
+
*
|
|
2110
|
+
* ### Example
|
|
2111
|
+
*
|
|
2112
|
+
* ```ts
|
|
2113
|
+
* import { String, array, maxLength } from "@evolu/common";
|
|
2114
|
+
*
|
|
2115
|
+
* const AtMostThreeCharacters = maxLength(3)(String);
|
|
2116
|
+
* const AtMostTwoItems = maxLength(2)(array(String));
|
|
2117
|
+
*
|
|
2118
|
+
* expectOk(AtMostThreeCharacters.fromUnknown("abc"), "abc");
|
|
2119
|
+
* expectOk(AtMostTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2120
|
+
* ```
|
|
2135
2121
|
*
|
|
2136
2122
|
* @group String
|
|
2137
2123
|
* @group Collection
|
|
2138
2124
|
*/
|
|
2139
2125
|
export declare const maxLength: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`MaxLength${Max}`, ValueWithLength, MaxLengthError<Max>>;
|
|
2140
|
-
/**
|
|
2126
|
+
/**
|
|
2127
|
+
* Error returned when {@link maxLength} rejects a value.
|
|
2128
|
+
*
|
|
2129
|
+
* @group Collection
|
|
2130
|
+
*/
|
|
2141
2131
|
export interface MaxLengthError<Max extends number = number> extends TypeError<`MaxLength${Max}`> {
|
|
2142
2132
|
readonly value: ValueWithLength;
|
|
2143
2133
|
readonly max: Max;
|
|
@@ -2157,13 +2147,29 @@ export type NonEmptyTrimmedString100 = typeof NonEmptyTrimmedString100.Output;
|
|
|
2157
2147
|
export declare const NonEmptyTrimmedString1000: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "MaxLength1000", MaxLengthError<1000>>;
|
|
2158
2148
|
export type NonEmptyTrimmedString1000 = typeof NonEmptyTrimmedString1000.Output;
|
|
2159
2149
|
/**
|
|
2160
|
-
* Exact-length {@link Brand}
|
|
2150
|
+
* Exact-length {@link Brand} for values whose `length` equals `exact`.
|
|
2151
|
+
*
|
|
2152
|
+
* ### Example
|
|
2153
|
+
*
|
|
2154
|
+
* ```ts
|
|
2155
|
+
* import { String, array, length } from "@evolu/common";
|
|
2156
|
+
*
|
|
2157
|
+
* const ThreeCharacters = length(3)(String);
|
|
2158
|
+
* const TwoItems = length(2)(array(String));
|
|
2159
|
+
*
|
|
2160
|
+
* expectOk(ThreeCharacters.fromUnknown("abc"), "abc");
|
|
2161
|
+
* expectOk(TwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2162
|
+
* ```
|
|
2161
2163
|
*
|
|
2162
2164
|
* @group String
|
|
2163
2165
|
* @group Collection
|
|
2164
2166
|
*/
|
|
2165
2167
|
export declare const length: <Exact extends number>(exact: ValidateBrandFactoryNumber<Exact>) => BrandFactory<`Length${Exact}`, ValueWithLength, LengthError<Exact>>;
|
|
2166
|
-
/**
|
|
2168
|
+
/**
|
|
2169
|
+
* Error returned when {@link length} rejects a value.
|
|
2170
|
+
*
|
|
2171
|
+
* @group Collection
|
|
2172
|
+
*/
|
|
2167
2173
|
export interface LengthError<Exact extends number = number> extends TypeError<`Length${Exact}`> {
|
|
2168
2174
|
readonly value: ValueWithLength;
|
|
2169
2175
|
readonly exact: Exact;
|
|
@@ -2197,7 +2203,12 @@ export interface LengthError<Exact extends number = number> extends TypeError<`L
|
|
|
2197
2203
|
* @group String
|
|
2198
2204
|
*/
|
|
2199
2205
|
export declare const regex: <const Name extends TypeName>(name: ValidateConcreteTypeName<Name>, pattern: RegExp) => BrandFactory<Name, string, RegexError<Name>>;
|
|
2200
|
-
/**
|
|
2206
|
+
/**
|
|
2207
|
+
* Error returned when a string does not match the regular expression supplied
|
|
2208
|
+
* to {@link regex}.
|
|
2209
|
+
*
|
|
2210
|
+
* @group String
|
|
2211
|
+
*/
|
|
2201
2212
|
export interface RegexError<Name extends TypeName = TypeName> extends TypeError<Name> {
|
|
2202
2213
|
readonly value: string;
|
|
2203
2214
|
readonly source: string;
|
|
@@ -2217,25 +2228,51 @@ export type UrlSafeString = typeof UrlSafeString.Output;
|
|
|
2217
2228
|
/**
|
|
2218
2229
|
* Base64Url text without padding.
|
|
2219
2230
|
*
|
|
2220
|
-
*
|
|
2221
|
-
* {@link base64UrlToUint8Array}.
|
|
2231
|
+
* Convert bytes to Base64Url with {@link uint8ArrayToBase64Url} and convert
|
|
2232
|
+
* Base64Url to bytes with {@link base64UrlToUint8Array}.
|
|
2222
2233
|
*
|
|
2223
2234
|
* @group String
|
|
2224
2235
|
*/
|
|
2225
2236
|
export declare const Base64Url: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Base64Url", Base64UrlError>;
|
|
2226
2237
|
export type Base64Url = typeof Base64Url.Output;
|
|
2227
|
-
/**
|
|
2238
|
+
/**
|
|
2239
|
+
* Error returned when a string is not valid {@link Base64Url} text.
|
|
2240
|
+
*
|
|
2241
|
+
* @group String
|
|
2242
|
+
*/
|
|
2228
2243
|
export interface Base64UrlError extends TypeError<"Base64Url"> {
|
|
2229
2244
|
readonly value: string;
|
|
2230
2245
|
}
|
|
2231
2246
|
/**
|
|
2232
|
-
*
|
|
2247
|
+
* Converts bytes to {@link Base64Url}.
|
|
2248
|
+
*
|
|
2249
|
+
* ### Example
|
|
2250
|
+
*
|
|
2251
|
+
* ```ts
|
|
2252
|
+
* import { uint8ArrayToBase64Url } from "@evolu/common";
|
|
2253
|
+
*
|
|
2254
|
+
* expect(uint8ArrayToBase64Url(new Uint8Array([0, 1, 2, 255]))).toBe(
|
|
2255
|
+
* "AAEC_w",
|
|
2256
|
+
* );
|
|
2257
|
+
* ```
|
|
2233
2258
|
*
|
|
2234
2259
|
* @group String
|
|
2235
2260
|
*/
|
|
2236
2261
|
export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
|
|
2237
2262
|
/**
|
|
2238
|
-
*
|
|
2263
|
+
* Converts {@link Base64Url} to bytes.
|
|
2264
|
+
*
|
|
2265
|
+
* ### Example
|
|
2266
|
+
*
|
|
2267
|
+
* ```ts
|
|
2268
|
+
* import { Base64Url, base64UrlToUint8Array } from "@evolu/common";
|
|
2269
|
+
*
|
|
2270
|
+
* const value = Base64Url.orThrow("AAEC_w");
|
|
2271
|
+
*
|
|
2272
|
+
* expect(base64UrlToUint8Array(value)).toEqual(
|
|
2273
|
+
* new Uint8Array([0, 1, 2, 255]),
|
|
2274
|
+
* );
|
|
2275
|
+
* ```
|
|
2239
2276
|
*
|
|
2240
2277
|
* @group String
|
|
2241
2278
|
*/
|
|
@@ -2247,7 +2284,11 @@ export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
|
|
|
2247
2284
|
*/
|
|
2248
2285
|
export declare const Name: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "UrlSafeString", RegexError<"UrlSafeString">>, "Name", NameError>;
|
|
2249
2286
|
export type Name = typeof Name.Output;
|
|
2250
|
-
/**
|
|
2287
|
+
/**
|
|
2288
|
+
* Error returned when a string is not a valid {@link Name}.
|
|
2289
|
+
*
|
|
2290
|
+
* @group String
|
|
2291
|
+
*/
|
|
2251
2292
|
export interface NameError extends TypeError<"Name"> {
|
|
2252
2293
|
readonly value: string;
|
|
2253
2294
|
}
|
|
@@ -2271,7 +2312,11 @@ export type SimplePassword = typeof SimplePassword.Output;
|
|
|
2271
2312
|
*/
|
|
2272
2313
|
export declare const Mnemonic: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Mnemonic", MnemonicError>;
|
|
2273
2314
|
export type Mnemonic = typeof Mnemonic.Output;
|
|
2274
|
-
/**
|
|
2315
|
+
/**
|
|
2316
|
+
* Error returned when a string is not a valid English BIP39 {@link Mnemonic}.
|
|
2317
|
+
*
|
|
2318
|
+
* @group String
|
|
2319
|
+
*/
|
|
2275
2320
|
export interface MnemonicError extends TypeError<"Mnemonic"> {
|
|
2276
2321
|
readonly value: string;
|
|
2277
2322
|
}
|
|
@@ -2287,7 +2332,11 @@ export interface MnemonicError extends TypeError<"Mnemonic"> {
|
|
|
2287
2332
|
*/
|
|
2288
2333
|
export declare const Id: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Id", IdError>;
|
|
2289
2334
|
export type Id = typeof Id.Output;
|
|
2290
|
-
/**
|
|
2335
|
+
/**
|
|
2336
|
+
* Error returned when a string is not a valid {@link Id}.
|
|
2337
|
+
*
|
|
2338
|
+
* @group String
|
|
2339
|
+
*/
|
|
2291
2340
|
export interface IdError extends TypeError<"Id"> {
|
|
2292
2341
|
readonly value: string;
|
|
2293
2342
|
}
|
|
@@ -2297,6 +2346,22 @@ export interface IdError extends TypeError<"Id"> {
|
|
|
2297
2346
|
* This is the recommended default because it does not encode creation time.
|
|
2298
2347
|
* Pass a Brand name when the returned Id belongs to one domain entity.
|
|
2299
2348
|
*
|
|
2349
|
+
* ### Example
|
|
2350
|
+
*
|
|
2351
|
+
* ```ts
|
|
2352
|
+
* import {
|
|
2353
|
+
* Id,
|
|
2354
|
+
* createId,
|
|
2355
|
+
* createRandomBytes,
|
|
2356
|
+
* type Brand,
|
|
2357
|
+
* } from "@evolu/common";
|
|
2358
|
+
*
|
|
2359
|
+
* const userId = createId<"User">({ randomBytes: createRandomBytes() });
|
|
2360
|
+
*
|
|
2361
|
+
* expect(Id.is(userId)).toBe(true);
|
|
2362
|
+
* expectTypeOf(userId).toEqualTypeOf<Id & Brand<"User">>();
|
|
2363
|
+
* ```
|
|
2364
|
+
*
|
|
2300
2365
|
* @group String
|
|
2301
2366
|
*/
|
|
2302
2367
|
export declare const createId: <B extends string = never>(deps: RandomBytesDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
|
|
@@ -2331,20 +2396,64 @@ export declare const createIdFromString: <B extends string = never>(value: strin
|
|
|
2331
2396
|
* logs, URLs, and exports. Prefer {@link createId} unless that tradeoff is
|
|
2332
2397
|
* deliberate.
|
|
2333
2398
|
*
|
|
2399
|
+
* ### Example
|
|
2400
|
+
*
|
|
2401
|
+
* ```ts
|
|
2402
|
+
* import {
|
|
2403
|
+
* createIdAsUuidv7,
|
|
2404
|
+
* createRandomBytes,
|
|
2405
|
+
* createTime,
|
|
2406
|
+
* idToIdBytes,
|
|
2407
|
+
* } from "@evolu/common";
|
|
2408
|
+
*
|
|
2409
|
+
* const value = createIdAsUuidv7({
|
|
2410
|
+
* randomBytes: createRandomBytes(),
|
|
2411
|
+
* time: createTime(),
|
|
2412
|
+
* });
|
|
2413
|
+
* const bytes = idToIdBytes(value);
|
|
2414
|
+
*
|
|
2415
|
+
* expect(bytes[6] >> 4).toBe(0x7);
|
|
2416
|
+
* expect(bytes[8] & 0xc0).toBe(0x80);
|
|
2417
|
+
* ```
|
|
2418
|
+
*
|
|
2334
2419
|
* @group String
|
|
2335
2420
|
*/
|
|
2336
2421
|
export declare const createIdAsUuidv7: <B extends string = never>(deps: RandomBytesDep & TimeDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
|
|
2337
2422
|
/**
|
|
2338
2423
|
* Table-specific {@link Id} Type.
|
|
2339
2424
|
*
|
|
2425
|
+
* ### Example
|
|
2426
|
+
*
|
|
2427
|
+
* ```ts
|
|
2428
|
+
* import {
|
|
2429
|
+
* createIdFromString,
|
|
2430
|
+
* id,
|
|
2431
|
+
* type Brand,
|
|
2432
|
+
* type Id,
|
|
2433
|
+
* } from "@evolu/common";
|
|
2434
|
+
*
|
|
2435
|
+
* const TodoId = id("Todo");
|
|
2436
|
+
* const todoId = TodoId.orThrow(createIdFromString("todo"));
|
|
2437
|
+
*
|
|
2438
|
+
* expectTypeOf(todoId).toEqualTypeOf<Id & Brand<"Todo">>();
|
|
2439
|
+
* ```
|
|
2440
|
+
*
|
|
2340
2441
|
* @group String
|
|
2341
2442
|
*/
|
|
2342
2443
|
export declare const id: <Table extends TypeName>(table: ValidateTableName<Table>) => TableId<Table>;
|
|
2343
|
-
/**
|
|
2444
|
+
/**
|
|
2445
|
+
* The {@link Type} returned by {@link id} for one table.
|
|
2446
|
+
*
|
|
2447
|
+
* @group String
|
|
2448
|
+
*/
|
|
2344
2449
|
export interface TableId<Table extends TypeName> extends Type<"TableId", string, Id & Brand<Table>, TableIdError<Table>, typeof String, TableIdError<Table> | InferErrors<typeof String>, ChildCustomFrom<typeof String, Id & Brand<Table>, TableIdError<Table>>, CanonicalInputForChild<typeof String, Id & Brand<Table>>, IdentityEncodingOf<typeof String>> {
|
|
2345
2450
|
readonly table: Table;
|
|
2346
2451
|
}
|
|
2347
|
-
/**
|
|
2452
|
+
/**
|
|
2453
|
+
* Error returned when a string is not a valid {@link Id} for the expected table.
|
|
2454
|
+
*
|
|
2455
|
+
* @group String
|
|
2456
|
+
*/
|
|
2348
2457
|
export interface TableIdError<Table extends TypeName = TypeName> extends TypeError<"TableId"> {
|
|
2349
2458
|
readonly table: Table;
|
|
2350
2459
|
readonly value: string;
|
|
@@ -2364,11 +2473,47 @@ type ConcreteIdBrandError = CompileTimeError<"Id", "Brand must be one concrete s
|
|
|
2364
2473
|
*/
|
|
2365
2474
|
export declare const IdBytes: BrandType<BrandType<Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>, "Length16", LengthError<16>>, "IdBytes", never>;
|
|
2366
2475
|
export type IdBytes = typeof IdBytes.Output;
|
|
2367
|
-
/**
|
|
2476
|
+
/**
|
|
2477
|
+
* Byte length of an {@link IdBytes} value.
|
|
2478
|
+
*
|
|
2479
|
+
* @group String
|
|
2480
|
+
*/
|
|
2368
2481
|
export declare const idBytesTypeValueLength: NonNegativeInt;
|
|
2369
|
-
/**
|
|
2482
|
+
/**
|
|
2483
|
+
* Converts an {@link Id} to {@link IdBytes}.
|
|
2484
|
+
*
|
|
2485
|
+
* ### Example
|
|
2486
|
+
*
|
|
2487
|
+
* ```ts
|
|
2488
|
+
* import { createIdFromString, idToIdBytes } from "@evolu/common";
|
|
2489
|
+
*
|
|
2490
|
+
* const bytes = idToIdBytes(createIdFromString("todo"));
|
|
2491
|
+
*
|
|
2492
|
+
* expect(bytes).toHaveLength(16);
|
|
2493
|
+
* ```
|
|
2494
|
+
*
|
|
2495
|
+
* @group String
|
|
2496
|
+
*/
|
|
2370
2497
|
export declare const idToIdBytes: (value: Id) => IdBytes;
|
|
2371
|
-
/**
|
|
2498
|
+
/**
|
|
2499
|
+
* Converts {@link IdBytes} to an {@link Id}.
|
|
2500
|
+
*
|
|
2501
|
+
* ### Example
|
|
2502
|
+
*
|
|
2503
|
+
* ```ts
|
|
2504
|
+
* import {
|
|
2505
|
+
* createIdFromString,
|
|
2506
|
+
* idBytesToId,
|
|
2507
|
+
* idToIdBytes,
|
|
2508
|
+
* } from "@evolu/common";
|
|
2509
|
+
*
|
|
2510
|
+
* const value = createIdFromString("todo");
|
|
2511
|
+
*
|
|
2512
|
+
* expect(idBytesToId(idToIdBytes(value))).toBe(value);
|
|
2513
|
+
* ```
|
|
2514
|
+
*
|
|
2515
|
+
* @group String
|
|
2516
|
+
*/
|
|
2372
2517
|
export declare const idBytesToId: (value: IdBytes) => Id;
|
|
2373
2518
|
/**
|
|
2374
2519
|
* Decimal string representation of a signed {@link Int64}.
|
|
@@ -2377,7 +2522,11 @@ export declare const idBytesToId: (value: IdBytes) => Id;
|
|
|
2377
2522
|
*/
|
|
2378
2523
|
export declare const Int64String: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>;
|
|
2379
2524
|
export type Int64String = typeof Int64String.Output;
|
|
2380
|
-
/**
|
|
2525
|
+
/**
|
|
2526
|
+
* Error returned when a string is not a canonical {@link Int64String}.
|
|
2527
|
+
*
|
|
2528
|
+
* @group Number
|
|
2529
|
+
*/
|
|
2381
2530
|
export interface Int64StringError extends TypeError<"Int64String"> {
|
|
2382
2531
|
readonly value: string;
|
|
2383
2532
|
}
|
|
@@ -2388,16 +2537,43 @@ export interface Int64StringError extends TypeError<"Int64String"> {
|
|
|
2388
2537
|
* text, including SQLite queries that cast INTEGER values to TEXT to avoid a
|
|
2389
2538
|
* lossy JavaScript number conversion.
|
|
2390
2539
|
*
|
|
2540
|
+
* ### Example
|
|
2541
|
+
*
|
|
2542
|
+
* ```ts
|
|
2543
|
+
* import { Int64FromInt64String } from "@evolu/common";
|
|
2544
|
+
*
|
|
2545
|
+
* const result = Int64FromInt64String.fromUnknown("9223372036854775807");
|
|
2546
|
+
*
|
|
2547
|
+
* expectOk(result, 9223372036854775807n);
|
|
2548
|
+
* expect(Int64FromInt64String.to(result.value)).toBe(
|
|
2549
|
+
* "9223372036854775807",
|
|
2550
|
+
* );
|
|
2551
|
+
* ```
|
|
2552
|
+
*
|
|
2391
2553
|
* @group Number
|
|
2392
2554
|
*/
|
|
2393
2555
|
export declare const Int64FromInt64String: TransformType<BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>, BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>, "Int64FromInt64String", never, string & Brand<"Trimmed"> & Brand<"MinLength1"> & Brand<"Int64String">>;
|
|
2394
2556
|
/**
|
|
2395
2557
|
* Number {@link Brand} requiring a value greater than or equal to zero.
|
|
2396
2558
|
*
|
|
2559
|
+
* ### Example
|
|
2560
|
+
*
|
|
2561
|
+
* ```ts
|
|
2562
|
+
* import { Number, nonNegative } from "@evolu/common";
|
|
2563
|
+
*
|
|
2564
|
+
* const NonNegative = nonNegative(Number);
|
|
2565
|
+
*
|
|
2566
|
+
* expectOk(NonNegative.fromUnknown(0), 0);
|
|
2567
|
+
* ```
|
|
2568
|
+
*
|
|
2397
2569
|
* @group Number
|
|
2398
2570
|
*/
|
|
2399
2571
|
export declare const nonNegative: BrandFactory<"NonNegative", number, NonNegativeError>;
|
|
2400
|
-
/**
|
|
2572
|
+
/**
|
|
2573
|
+
* Error returned when {@link nonNegative} rejects a number.
|
|
2574
|
+
*
|
|
2575
|
+
* @group Number
|
|
2576
|
+
*/
|
|
2401
2577
|
export interface NonNegativeError extends TypeError<"NonNegative"> {
|
|
2402
2578
|
readonly value: number;
|
|
2403
2579
|
}
|
|
@@ -2411,10 +2587,24 @@ export type NonNegativeNumber = typeof NonNegativeNumber.Output;
|
|
|
2411
2587
|
/**
|
|
2412
2588
|
* Number {@link Brand} requiring a value greater than zero.
|
|
2413
2589
|
*
|
|
2590
|
+
* ### Example
|
|
2591
|
+
*
|
|
2592
|
+
* ```ts
|
|
2593
|
+
* import { Number, positive } from "@evolu/common";
|
|
2594
|
+
*
|
|
2595
|
+
* const Positive = positive(Number);
|
|
2596
|
+
*
|
|
2597
|
+
* expectOk(Positive.fromUnknown(1), 1);
|
|
2598
|
+
* ```
|
|
2599
|
+
*
|
|
2414
2600
|
* @group Number
|
|
2415
2601
|
*/
|
|
2416
2602
|
export declare const positive: BrandFactory<"Positive", number, PositiveError>;
|
|
2417
|
-
/**
|
|
2603
|
+
/**
|
|
2604
|
+
* Error returned when {@link positive} rejects a number.
|
|
2605
|
+
*
|
|
2606
|
+
* @group Number
|
|
2607
|
+
*/
|
|
2418
2608
|
export interface PositiveError extends TypeError<"Positive"> {
|
|
2419
2609
|
readonly value: number;
|
|
2420
2610
|
}
|
|
@@ -2431,10 +2621,24 @@ export type PositiveNumber = typeof PositiveNumber.Output;
|
|
|
2431
2621
|
/**
|
|
2432
2622
|
* Number {@link Brand} requiring a value less than or equal to zero.
|
|
2433
2623
|
*
|
|
2624
|
+
* ### Example
|
|
2625
|
+
*
|
|
2626
|
+
* ```ts
|
|
2627
|
+
* import { Number, nonPositive } from "@evolu/common";
|
|
2628
|
+
*
|
|
2629
|
+
* const NonPositive = nonPositive(Number);
|
|
2630
|
+
*
|
|
2631
|
+
* expectOk(NonPositive.fromUnknown(0), 0);
|
|
2632
|
+
* ```
|
|
2633
|
+
*
|
|
2434
2634
|
* @group Number
|
|
2435
2635
|
*/
|
|
2436
2636
|
export declare const nonPositive: BrandFactory<"NonPositive", number, NonPositiveError>;
|
|
2437
|
-
/**
|
|
2637
|
+
/**
|
|
2638
|
+
* Error returned when {@link nonPositive} rejects a number.
|
|
2639
|
+
*
|
|
2640
|
+
* @group Number
|
|
2641
|
+
*/
|
|
2438
2642
|
export interface NonPositiveError extends TypeError<"NonPositive"> {
|
|
2439
2643
|
readonly value: number;
|
|
2440
2644
|
}
|
|
@@ -2448,10 +2652,24 @@ export type NonPositiveNumber = typeof NonPositiveNumber.Output;
|
|
|
2448
2652
|
/**
|
|
2449
2653
|
* Number {@link Brand} requiring a value less than zero.
|
|
2450
2654
|
*
|
|
2655
|
+
* ### Example
|
|
2656
|
+
*
|
|
2657
|
+
* ```ts
|
|
2658
|
+
* import { Number, negative } from "@evolu/common";
|
|
2659
|
+
*
|
|
2660
|
+
* const Negative = negative(Number);
|
|
2661
|
+
*
|
|
2662
|
+
* expectOk(Negative.fromUnknown(-1), -1);
|
|
2663
|
+
* ```
|
|
2664
|
+
*
|
|
2451
2665
|
* @group Number
|
|
2452
2666
|
*/
|
|
2453
2667
|
export declare const negative: BrandFactory<"Negative", number, NegativeError>;
|
|
2454
|
-
/**
|
|
2668
|
+
/**
|
|
2669
|
+
* Error returned when {@link negative} rejects a number.
|
|
2670
|
+
*
|
|
2671
|
+
* @group Number
|
|
2672
|
+
*/
|
|
2455
2673
|
export interface NegativeError extends TypeError<"Negative"> {
|
|
2456
2674
|
readonly value: number;
|
|
2457
2675
|
}
|
|
@@ -2468,10 +2686,24 @@ export type NegativeNumber = typeof NegativeNumber.Output;
|
|
|
2468
2686
|
/**
|
|
2469
2687
|
* Number {@link Brand} requiring a value other than `NaN`.
|
|
2470
2688
|
*
|
|
2689
|
+
* ### Example
|
|
2690
|
+
*
|
|
2691
|
+
* ```ts
|
|
2692
|
+
* import { Number, nonNaN } from "@evolu/common";
|
|
2693
|
+
*
|
|
2694
|
+
* const NonNaN = nonNaN(Number);
|
|
2695
|
+
*
|
|
2696
|
+
* expectOk(NonNaN.fromUnknown(Infinity), Infinity);
|
|
2697
|
+
* ```
|
|
2698
|
+
*
|
|
2471
2699
|
* @group Number
|
|
2472
2700
|
*/
|
|
2473
2701
|
export declare const nonNaN: BrandFactory<"NonNaN", number, NonNaNError>;
|
|
2474
|
-
/**
|
|
2702
|
+
/**
|
|
2703
|
+
* Error returned when {@link nonNaN} rejects `NaN`.
|
|
2704
|
+
*
|
|
2705
|
+
* @group Number
|
|
2706
|
+
*/
|
|
2475
2707
|
export interface NonNaNError extends TypeError<"NonNaN"> {
|
|
2476
2708
|
readonly value: number;
|
|
2477
2709
|
}
|
|
@@ -2490,10 +2722,24 @@ export type NonNaNNumber = typeof NonNaNNumber.Output;
|
|
|
2490
2722
|
/**
|
|
2491
2723
|
* Number {@link Brand} requiring a finite value.
|
|
2492
2724
|
*
|
|
2725
|
+
* ### Example
|
|
2726
|
+
*
|
|
2727
|
+
* ```ts
|
|
2728
|
+
* import { Number, finite } from "@evolu/common";
|
|
2729
|
+
*
|
|
2730
|
+
* const Finite = finite(Number);
|
|
2731
|
+
*
|
|
2732
|
+
* expectOk(Finite.fromUnknown(42), 42);
|
|
2733
|
+
* ```
|
|
2734
|
+
*
|
|
2493
2735
|
* @group Number
|
|
2494
2736
|
*/
|
|
2495
2737
|
export declare const finite: BrandFactory<"Finite", number, FiniteError>;
|
|
2496
|
-
/**
|
|
2738
|
+
/**
|
|
2739
|
+
* Error returned when {@link finite} rejects a non-finite number.
|
|
2740
|
+
*
|
|
2741
|
+
* @group Number
|
|
2742
|
+
*/
|
|
2497
2743
|
export interface FiniteError extends TypeError<"Finite"> {
|
|
2498
2744
|
readonly value: number;
|
|
2499
2745
|
}
|
|
@@ -2541,7 +2787,11 @@ export type PositiveFiniteNumber = typeof PositiveFiniteNumber.Output;
|
|
|
2541
2787
|
* @group Number
|
|
2542
2788
|
*/
|
|
2543
2789
|
export declare const int: BrandFactory<"Int", number, IntError>;
|
|
2544
|
-
/**
|
|
2790
|
+
/**
|
|
2791
|
+
* Error returned when {@link int} rejects a number that is not a safe integer.
|
|
2792
|
+
*
|
|
2793
|
+
* @group Number
|
|
2794
|
+
*/
|
|
2545
2795
|
export interface IntError extends TypeError<"Int"> {
|
|
2546
2796
|
readonly value: number;
|
|
2547
2797
|
}
|
|
@@ -2607,10 +2857,24 @@ export type NegativeInt = typeof NegativeInt.Output;
|
|
|
2607
2857
|
/**
|
|
2608
2858
|
* Number {@link Brand} requiring a value greater than `min`.
|
|
2609
2859
|
*
|
|
2860
|
+
* ### Example
|
|
2861
|
+
*
|
|
2862
|
+
* ```ts
|
|
2863
|
+
* import { Number, greaterThan } from "@evolu/common";
|
|
2864
|
+
*
|
|
2865
|
+
* const GreaterThanTen = greaterThan(10)(Number);
|
|
2866
|
+
*
|
|
2867
|
+
* expectOk(GreaterThanTen.fromUnknown(11), 11);
|
|
2868
|
+
* ```
|
|
2869
|
+
*
|
|
2610
2870
|
* @group Number
|
|
2611
2871
|
*/
|
|
2612
2872
|
export declare const greaterThan: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThan${Min}`, number, GreaterThanError<Min>>;
|
|
2613
|
-
/**
|
|
2873
|
+
/**
|
|
2874
|
+
* Error returned when {@link greaterThan} rejects a number.
|
|
2875
|
+
*
|
|
2876
|
+
* @group Number
|
|
2877
|
+
*/
|
|
2614
2878
|
export interface GreaterThanError<Min extends number = number> extends TypeError<`GreaterThan${Min}`> {
|
|
2615
2879
|
readonly value: number;
|
|
2616
2880
|
readonly min: Min;
|
|
@@ -2618,10 +2882,24 @@ export interface GreaterThanError<Min extends number = number> extends TypeError
|
|
|
2618
2882
|
/**
|
|
2619
2883
|
* Number {@link Brand} requiring a value greater than or equal to `min`.
|
|
2620
2884
|
*
|
|
2885
|
+
* ### Example
|
|
2886
|
+
*
|
|
2887
|
+
* ```ts
|
|
2888
|
+
* import { Number, greaterThanOrEqualTo } from "@evolu/common";
|
|
2889
|
+
*
|
|
2890
|
+
* const AtLeastTen = greaterThanOrEqualTo(10)(Number);
|
|
2891
|
+
*
|
|
2892
|
+
* expectOk(AtLeastTen.fromUnknown(10), 10);
|
|
2893
|
+
* ```
|
|
2894
|
+
*
|
|
2621
2895
|
* @group Number
|
|
2622
2896
|
*/
|
|
2623
2897
|
export declare const greaterThanOrEqualTo: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThanOrEqualTo${Min}`, number, GreaterThanOrEqualToError<Min>>;
|
|
2624
|
-
/**
|
|
2898
|
+
/**
|
|
2899
|
+
* Error returned when {@link greaterThanOrEqualTo} rejects a number.
|
|
2900
|
+
*
|
|
2901
|
+
* @group Number
|
|
2902
|
+
*/
|
|
2625
2903
|
export interface GreaterThanOrEqualToError<Min extends number = number> extends TypeError<`GreaterThanOrEqualTo${Min}`> {
|
|
2626
2904
|
readonly value: number;
|
|
2627
2905
|
readonly min: Min;
|
|
@@ -2629,10 +2907,24 @@ export interface GreaterThanOrEqualToError<Min extends number = number> extends
|
|
|
2629
2907
|
/**
|
|
2630
2908
|
* Number {@link Brand} requiring a value less than `max`.
|
|
2631
2909
|
*
|
|
2910
|
+
* ### Example
|
|
2911
|
+
*
|
|
2912
|
+
* ```ts
|
|
2913
|
+
* import { Number, lessThan } from "@evolu/common";
|
|
2914
|
+
*
|
|
2915
|
+
* const LessThanTen = lessThan(10)(Number);
|
|
2916
|
+
*
|
|
2917
|
+
* expectOk(LessThanTen.fromUnknown(9), 9);
|
|
2918
|
+
* ```
|
|
2919
|
+
*
|
|
2632
2920
|
* @group Number
|
|
2633
2921
|
*/
|
|
2634
2922
|
export declare const lessThan: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThan${Max}`, number, LessThanError<Max>>;
|
|
2635
|
-
/**
|
|
2923
|
+
/**
|
|
2924
|
+
* Error returned when {@link lessThan} rejects a number.
|
|
2925
|
+
*
|
|
2926
|
+
* @group Number
|
|
2927
|
+
*/
|
|
2636
2928
|
export interface LessThanError<Max extends number = number> extends TypeError<`LessThan${Max}`> {
|
|
2637
2929
|
readonly value: number;
|
|
2638
2930
|
readonly max: Max;
|
|
@@ -2647,10 +2939,24 @@ export type Age = typeof Age.Output;
|
|
|
2647
2939
|
/**
|
|
2648
2940
|
* Number {@link Brand} requiring a value less than or equal to `max`.
|
|
2649
2941
|
*
|
|
2942
|
+
* ### Example
|
|
2943
|
+
*
|
|
2944
|
+
* ```ts
|
|
2945
|
+
* import { Number, lessThanOrEqualTo } from "@evolu/common";
|
|
2946
|
+
*
|
|
2947
|
+
* const AtMostTen = lessThanOrEqualTo(10)(Number);
|
|
2948
|
+
*
|
|
2949
|
+
* expectOk(AtMostTen.fromUnknown(10), 10);
|
|
2950
|
+
* ```
|
|
2951
|
+
*
|
|
2650
2952
|
* @group Number
|
|
2651
2953
|
*/
|
|
2652
2954
|
export declare const lessThanOrEqualTo: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThanOrEqualTo${Max}`, number, LessThanOrEqualToError<Max>>;
|
|
2653
|
-
/**
|
|
2955
|
+
/**
|
|
2956
|
+
* Error returned when {@link lessThanOrEqualTo} rejects a number.
|
|
2957
|
+
*
|
|
2958
|
+
* @group Number
|
|
2959
|
+
*/
|
|
2654
2960
|
export interface LessThanOrEqualToError<Max extends number = number> extends TypeError<`LessThanOrEqualTo${Max}`> {
|
|
2655
2961
|
readonly value: number;
|
|
2656
2962
|
readonly max: Max;
|
|
@@ -2707,17 +3013,35 @@ export type Ratio = typeof Ratio.Output;
|
|
|
2707
3013
|
*/
|
|
2708
3014
|
export declare const DecimalString: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>;
|
|
2709
3015
|
export type DecimalString = typeof DecimalString.Output;
|
|
2710
|
-
/**
|
|
3016
|
+
/**
|
|
3017
|
+
* Error returned when a string is not a canonical {@link DecimalString}.
|
|
3018
|
+
*
|
|
3019
|
+
* @group Number
|
|
3020
|
+
*/
|
|
2711
3021
|
export interface DecimalStringError extends TypeError<"DecimalString"> {
|
|
2712
3022
|
readonly value: string;
|
|
2713
3023
|
}
|
|
2714
3024
|
/**
|
|
2715
3025
|
* {@link DecimalString} Brand requiring a value greater than or equal to zero.
|
|
2716
3026
|
*
|
|
3027
|
+
* ### Example
|
|
3028
|
+
*
|
|
3029
|
+
* ```ts
|
|
3030
|
+
* import { DecimalString, nonNegativeDecimalString } from "@evolu/common";
|
|
3031
|
+
*
|
|
3032
|
+
* const NonNegative = nonNegativeDecimalString(DecimalString);
|
|
3033
|
+
*
|
|
3034
|
+
* expectOk(NonNegative.fromUnknown("0.5"), "0.5");
|
|
3035
|
+
* ```
|
|
3036
|
+
*
|
|
2717
3037
|
* @group Number
|
|
2718
3038
|
*/
|
|
2719
3039
|
export declare const nonNegativeDecimalString: BrandFactory<"NonNegativeDecimalString", DecimalString, NonNegativeDecimalStringError>;
|
|
2720
|
-
/**
|
|
3040
|
+
/**
|
|
3041
|
+
* Error returned when {@link nonNegativeDecimalString} rejects a decimal string.
|
|
3042
|
+
*
|
|
3043
|
+
* @group Number
|
|
3044
|
+
*/
|
|
2721
3045
|
export interface NonNegativeDecimalStringError extends TypeError<"NonNegativeDecimalString"> {
|
|
2722
3046
|
readonly value: string;
|
|
2723
3047
|
}
|
|
@@ -2731,10 +3055,24 @@ export type NonNegativeDecimalString = typeof NonNegativeDecimalString.Output;
|
|
|
2731
3055
|
/**
|
|
2732
3056
|
* {@link DecimalString} Brand requiring a value greater than zero.
|
|
2733
3057
|
*
|
|
3058
|
+
* ### Example
|
|
3059
|
+
*
|
|
3060
|
+
* ```ts
|
|
3061
|
+
* import { DecimalString, positiveDecimalString } from "@evolu/common";
|
|
3062
|
+
*
|
|
3063
|
+
* const Positive = positiveDecimalString(DecimalString);
|
|
3064
|
+
*
|
|
3065
|
+
* expectOk(Positive.fromUnknown("0.5"), "0.5");
|
|
3066
|
+
* ```
|
|
3067
|
+
*
|
|
2734
3068
|
* @group Number
|
|
2735
3069
|
*/
|
|
2736
3070
|
export declare const positiveDecimalString: BrandFactory<"PositiveDecimalString", DecimalString, PositiveDecimalStringError>;
|
|
2737
|
-
/**
|
|
3071
|
+
/**
|
|
3072
|
+
* Error returned when {@link positiveDecimalString} rejects a decimal string.
|
|
3073
|
+
*
|
|
3074
|
+
* @group Number
|
|
3075
|
+
*/
|
|
2738
3076
|
export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalString"> {
|
|
2739
3077
|
readonly value: string;
|
|
2740
3078
|
}
|
|
@@ -2751,10 +3089,24 @@ export type PositiveDecimalString = typeof PositiveDecimalString.Output;
|
|
|
2751
3089
|
/**
|
|
2752
3090
|
* {@link DecimalString} Brand requiring a value less than or equal to zero.
|
|
2753
3091
|
*
|
|
3092
|
+
* ### Example
|
|
3093
|
+
*
|
|
3094
|
+
* ```ts
|
|
3095
|
+
* import { DecimalString, nonPositiveDecimalString } from "@evolu/common";
|
|
3096
|
+
*
|
|
3097
|
+
* const NonPositive = nonPositiveDecimalString(DecimalString);
|
|
3098
|
+
*
|
|
3099
|
+
* expectOk(NonPositive.fromUnknown("-0.5"), "-0.5");
|
|
3100
|
+
* ```
|
|
3101
|
+
*
|
|
2754
3102
|
* @group Number
|
|
2755
3103
|
*/
|
|
2756
3104
|
export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
|
|
2757
|
-
/**
|
|
3105
|
+
/**
|
|
3106
|
+
* Error returned when {@link nonPositiveDecimalString} rejects a decimal string.
|
|
3107
|
+
*
|
|
3108
|
+
* @group Number
|
|
3109
|
+
*/
|
|
2758
3110
|
export interface NonPositiveDecimalStringError extends TypeError<"NonPositiveDecimalString"> {
|
|
2759
3111
|
readonly value: string;
|
|
2760
3112
|
}
|
|
@@ -2768,10 +3120,24 @@ export type NonPositiveDecimalString = typeof NonPositiveDecimalString.Output;
|
|
|
2768
3120
|
/**
|
|
2769
3121
|
* {@link DecimalString} Brand requiring a value less than zero.
|
|
2770
3122
|
*
|
|
3123
|
+
* ### Example
|
|
3124
|
+
*
|
|
3125
|
+
* ```ts
|
|
3126
|
+
* import { DecimalString, negativeDecimalString } from "@evolu/common";
|
|
3127
|
+
*
|
|
3128
|
+
* const Negative = negativeDecimalString(DecimalString);
|
|
3129
|
+
*
|
|
3130
|
+
* expectOk(Negative.fromUnknown("-0.5"), "-0.5");
|
|
3131
|
+
* ```
|
|
3132
|
+
*
|
|
2771
3133
|
* @group Number
|
|
2772
3134
|
*/
|
|
2773
3135
|
export declare const negativeDecimalString: BrandFactory<"NegativeDecimalString", DecimalString, NegativeDecimalStringError>;
|
|
2774
|
-
/**
|
|
3136
|
+
/**
|
|
3137
|
+
* Error returned when {@link negativeDecimalString} rejects a decimal string.
|
|
3138
|
+
*
|
|
3139
|
+
* @group Number
|
|
3140
|
+
*/
|
|
2775
3141
|
export interface NegativeDecimalStringError extends TypeError<"NegativeDecimalString"> {
|
|
2776
3142
|
readonly value: string;
|
|
2777
3143
|
}
|
|
@@ -2818,7 +3184,11 @@ export type NegativeDecimalString = typeof NegativeDecimalString.Output;
|
|
|
2818
3184
|
* @group Number
|
|
2819
3185
|
*/
|
|
2820
3186
|
export declare const multipleOf: <const Divisor extends string>(divisor: ValidateMultipleOfDivisor<Divisor>) => BrandFactory<`MultipleOf${Divisor}`, number, MultipleOfError<Divisor>>;
|
|
2821
|
-
/**
|
|
3187
|
+
/**
|
|
3188
|
+
* Error returned when {@link multipleOf} rejects a number.
|
|
3189
|
+
*
|
|
3190
|
+
* @group Number
|
|
3191
|
+
*/
|
|
2822
3192
|
export interface MultipleOfError<Divisor extends string = string> extends TypeError<`MultipleOf${Divisor}`> {
|
|
2823
3193
|
readonly value: number;
|
|
2824
3194
|
readonly divisor: Divisor;
|
|
@@ -2834,10 +3204,24 @@ type MultipleOfDivisorError = CompileTimeError<"MultipleOf", 'Divisor must be on
|
|
|
2834
3204
|
/**
|
|
2835
3205
|
* Number {@link Brand} requiring a value within an inclusive range.
|
|
2836
3206
|
*
|
|
3207
|
+
* ### Example
|
|
3208
|
+
*
|
|
3209
|
+
* ```ts
|
|
3210
|
+
* import { Number, between } from "@evolu/common";
|
|
3211
|
+
*
|
|
3212
|
+
* const Percentage = between(0, 100)(Number);
|
|
3213
|
+
*
|
|
3214
|
+
* expectOk(Percentage.fromUnknown(75), 75);
|
|
3215
|
+
* ```
|
|
3216
|
+
*
|
|
2837
3217
|
* @group Number
|
|
2838
3218
|
*/
|
|
2839
3219
|
export declare const between: <Min extends number, Max extends number>(min: ValidateBrandFactoryNumber<Min>, max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`Between${Min}-${Max}`, number, BetweenError<Min, Max>>;
|
|
2840
|
-
/**
|
|
3220
|
+
/**
|
|
3221
|
+
* Error returned when {@link between} rejects a number.
|
|
3222
|
+
*
|
|
3223
|
+
* @group Number
|
|
3224
|
+
*/
|
|
2841
3225
|
export interface BetweenError<Min extends number = number, Max extends number = number> extends TypeError<`Between${Min}-${Max}`> {
|
|
2842
3226
|
readonly value: number;
|
|
2843
3227
|
readonly min: Min;
|
|
@@ -2894,7 +3278,11 @@ export interface BetweenError<Min extends number = number, Max extends number =
|
|
|
2894
3278
|
* @group Collection
|
|
2895
3279
|
*/
|
|
2896
3280
|
export declare const array: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => ArrayType<ElementType>;
|
|
2897
|
-
/**
|
|
3281
|
+
/**
|
|
3282
|
+
* The homogeneous readonly-array {@link Type} returned by {@link array}.
|
|
3283
|
+
*
|
|
3284
|
+
* @group Collection
|
|
3285
|
+
*/
|
|
2898
3286
|
export interface ArrayType<ElementType extends TypeNode> extends Type<"Array", ReadonlyArray<ElementType["Input"]>, ReadonlyArray<ElementType["Output"]>, ArrayNodeError<ElementType>, ArrayParent<ElementType>, ArrayError<InferErrors<ElementType>>, ArrayCustomFrom<ElementType>, ReadonlyArray<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
|
|
2899
3287
|
readonly [reflectedTypesSymbol]?: ElementType;
|
|
2900
3288
|
readonly element: ElementType;
|
|
@@ -2915,42 +3303,78 @@ type ArrayParent<ElementType extends TypeNode> = [
|
|
|
2915
3303
|
type ArrayNodeError<ElementType extends TypeNode> = [
|
|
2916
3304
|
ElementType["parent"]
|
|
2917
3305
|
] extends [TypeNode] ? ArrayElementsError<ElementType["Error"]> : ArrayError<ElementType["Error"]>;
|
|
2918
|
-
/**
|
|
3306
|
+
/**
|
|
3307
|
+
* Error returned by {@link array} for a non-array value or invalid array items.
|
|
3308
|
+
*
|
|
3309
|
+
* @group Collection
|
|
3310
|
+
*/
|
|
2919
3311
|
export type ArrayError<Error extends TypeError = TypeError> = ArrayNotArrayError | ArrayItemsErrorValue<Error, true>;
|
|
2920
|
-
/**
|
|
3312
|
+
/**
|
|
3313
|
+
* Error returned when an {@link array} input is not an array.
|
|
3314
|
+
*
|
|
3315
|
+
* @group Collection
|
|
3316
|
+
*/
|
|
2921
3317
|
export interface ArrayNotArrayError extends TypeError<"Array"> {
|
|
2922
3318
|
readonly reason: {
|
|
2923
3319
|
readonly kind: "NotArray";
|
|
2924
3320
|
readonly value: unknown;
|
|
2925
3321
|
};
|
|
2926
3322
|
}
|
|
2927
|
-
/**
|
|
3323
|
+
/**
|
|
3324
|
+
* An {@link array} error containing structural or element issues.
|
|
3325
|
+
*
|
|
3326
|
+
* @group Collection
|
|
3327
|
+
*/
|
|
2928
3328
|
export type ArrayItemsError<Error extends TypeError> = ArrayItemsErrorValue<Error, true>;
|
|
2929
|
-
/**
|
|
3329
|
+
/**
|
|
3330
|
+
* One structural or element issue found by {@link array}.
|
|
3331
|
+
*
|
|
3332
|
+
* @group Collection
|
|
3333
|
+
*/
|
|
2930
3334
|
export type ArrayIssue<Error extends TypeError> = ArrayStructuralIssue | ArrayElementIssue<Error>;
|
|
2931
|
-
/**
|
|
3335
|
+
/**
|
|
3336
|
+
* A missing array element.
|
|
3337
|
+
*
|
|
3338
|
+
* @group Collection
|
|
3339
|
+
*/
|
|
2932
3340
|
export interface ArrayHoleIssue {
|
|
2933
3341
|
readonly kind: "Hole";
|
|
2934
3342
|
readonly index: number;
|
|
2935
3343
|
}
|
|
2936
|
-
/**
|
|
3344
|
+
/**
|
|
3345
|
+
* An array element defined by an accessor instead of a data property.
|
|
3346
|
+
*
|
|
3347
|
+
* @group Collection
|
|
3348
|
+
*/
|
|
2937
3349
|
export interface ArrayAccessorIssue {
|
|
2938
3350
|
readonly kind: "Accessor";
|
|
2939
3351
|
readonly index: number;
|
|
2940
3352
|
}
|
|
2941
|
-
/**
|
|
3353
|
+
/**
|
|
3354
|
+
* An own array property other than `length` or an indexed element.
|
|
3355
|
+
*
|
|
3356
|
+
* @group Collection
|
|
3357
|
+
*/
|
|
2942
3358
|
export interface ArrayExcessPropertyIssue {
|
|
2943
3359
|
readonly kind: "ExcessProperty";
|
|
2944
3360
|
readonly key: string | symbol;
|
|
2945
3361
|
}
|
|
2946
3362
|
type ArrayStructuralIssue = ArrayHoleIssue | ArrayAccessorIssue | ArrayExcessPropertyIssue;
|
|
2947
|
-
/**
|
|
3363
|
+
/**
|
|
3364
|
+
* An invalid array element and its index.
|
|
3365
|
+
*
|
|
3366
|
+
* @group Collection
|
|
3367
|
+
*/
|
|
2948
3368
|
export type ArrayElementIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
2949
3369
|
readonly kind: "Element";
|
|
2950
3370
|
readonly index: number;
|
|
2951
3371
|
readonly error: Error;
|
|
2952
3372
|
} : never;
|
|
2953
|
-
/**
|
|
3373
|
+
/**
|
|
3374
|
+
* An {@link array} error containing element errors from a typed boundary.
|
|
3375
|
+
*
|
|
3376
|
+
* @group Collection
|
|
3377
|
+
*/
|
|
2954
3378
|
export type ArrayElementsError<Error extends TypeError> = [Error] extends [
|
|
2955
3379
|
never
|
|
2956
3380
|
] ? never : ArrayItemsErrorValue<Error, false>;
|
|
@@ -2968,10 +3392,25 @@ interface ArrayItemsErrorValue<Error extends TypeError, IncludeStructuralIssues
|
|
|
2968
3392
|
* iteration order. Classification uses the realm-neutral object tag and
|
|
2969
3393
|
* prototype structure under Evolu Type's trusted JavaScript policy.
|
|
2970
3394
|
*
|
|
3395
|
+
* ### Example
|
|
3396
|
+
*
|
|
3397
|
+
* ```ts
|
|
3398
|
+
* import { String, set } from "@evolu/common";
|
|
3399
|
+
*
|
|
3400
|
+
* const Tags = set(String);
|
|
3401
|
+
* const tags = new Set(["local-first", "offline"]);
|
|
3402
|
+
*
|
|
3403
|
+
* expectOk(Tags.fromUnknown(tags), tags);
|
|
3404
|
+
* ```
|
|
3405
|
+
*
|
|
2971
3406
|
* @group Collection
|
|
2972
3407
|
*/
|
|
2973
3408
|
export declare const set: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => SetType<ElementType>;
|
|
2974
|
-
/**
|
|
3409
|
+
/**
|
|
3410
|
+
* The homogeneous readonly-set {@link Type} returned by {@link set}.
|
|
3411
|
+
*
|
|
3412
|
+
* @group Collection
|
|
3413
|
+
*/
|
|
2975
3414
|
export interface SetType<ElementType extends TypeNode> extends Type<"Set", ReadonlySet<ElementType["Input"]>, ReadonlySet<ElementType["Output"]>, SetNodeError<ElementType>, SetParent<ElementType>, SetError<InferErrors<ElementType>>, SetCustomFrom<ElementType>, ReadonlySet<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
|
|
2976
3415
|
readonly [reflectedTypesSymbol]?: ElementType;
|
|
2977
3416
|
readonly element: ElementType;
|
|
@@ -2991,9 +3430,18 @@ type SetParent<ElementType extends TypeNode> = [ElementType["parent"]] extends [
|
|
|
2991
3430
|
type SetNodeError<ElementType extends TypeNode> = [
|
|
2992
3431
|
ElementType["parent"]
|
|
2993
3432
|
] extends [TypeNode] ? SetElementsError<ElementType["Error"]> : SetError<ElementType["Error"]>;
|
|
2994
|
-
/**
|
|
3433
|
+
/**
|
|
3434
|
+
* Error returned by {@link set} for a non-Set value, an invalid Set prototype,
|
|
3435
|
+
* or invalid Set items.
|
|
3436
|
+
*
|
|
3437
|
+
* @group Collection
|
|
3438
|
+
*/
|
|
2995
3439
|
export type SetError<Error extends TypeError = TypeError> = SetNotSetError | SetUnexpectedPrototypeError | SetItemsErrorValue<Error, true>;
|
|
2996
|
-
/**
|
|
3440
|
+
/**
|
|
3441
|
+
* Error returned when a {@link set} input is not a Set.
|
|
3442
|
+
*
|
|
3443
|
+
* @group Collection
|
|
3444
|
+
*/
|
|
2997
3445
|
export interface SetNotSetError extends TypeError<"Set"> {
|
|
2998
3446
|
readonly reason: {
|
|
2999
3447
|
readonly kind: "NotSet";
|
|
@@ -3011,21 +3459,37 @@ export interface SetUnexpectedPrototypeError extends TypeError<"Set"> {
|
|
|
3011
3459
|
readonly value: ReadonlySet<unknown>;
|
|
3012
3460
|
};
|
|
3013
3461
|
}
|
|
3014
|
-
/**
|
|
3462
|
+
/**
|
|
3463
|
+
* An own property found on a Set value.
|
|
3464
|
+
*
|
|
3465
|
+
* @group Collection
|
|
3466
|
+
*/
|
|
3015
3467
|
export interface SetExcessPropertyIssue {
|
|
3016
3468
|
readonly kind: "ExcessProperty";
|
|
3017
3469
|
readonly key: string | symbol;
|
|
3018
3470
|
}
|
|
3019
3471
|
type SetStructuralIssue = SetExcessPropertyIssue;
|
|
3020
|
-
/**
|
|
3472
|
+
/**
|
|
3473
|
+
* An invalid Set element and its iteration index.
|
|
3474
|
+
*
|
|
3475
|
+
* @group Collection
|
|
3476
|
+
*/
|
|
3021
3477
|
export type SetElementIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3022
3478
|
readonly kind: "Element";
|
|
3023
3479
|
readonly index: number;
|
|
3024
3480
|
readonly error: Error;
|
|
3025
3481
|
} : never;
|
|
3026
|
-
/**
|
|
3482
|
+
/**
|
|
3483
|
+
* A {@link set} error containing structural or element issues.
|
|
3484
|
+
*
|
|
3485
|
+
* @group Collection
|
|
3486
|
+
*/
|
|
3027
3487
|
export type SetItemsError<Error extends TypeError> = SetItemsErrorValue<Error, true>;
|
|
3028
|
-
/**
|
|
3488
|
+
/**
|
|
3489
|
+
* A {@link set} error containing element errors from a typed boundary.
|
|
3490
|
+
*
|
|
3491
|
+
* @group Collection
|
|
3492
|
+
*/
|
|
3029
3493
|
export type SetElementsError<Error extends TypeError> = [Error] extends [never] ? never : SetItemsErrorValue<Error, false>;
|
|
3030
3494
|
interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues extends boolean> extends TypeError<"Set"> {
|
|
3031
3495
|
readonly reason: {
|
|
@@ -3058,17 +3522,12 @@ interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues ex
|
|
|
3058
3522
|
* ### Example
|
|
3059
3523
|
*
|
|
3060
3524
|
* ```ts
|
|
3061
|
-
* import {
|
|
3062
|
-
*
|
|
3063
|
-
* const NumberFromString = transform("NumberFromString", String, Number, {
|
|
3064
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3065
|
-
* to: globalThis.String,
|
|
3066
|
-
* });
|
|
3525
|
+
* import { Int64FromInt64String, String, tuple } from "@evolu/common";
|
|
3067
3526
|
*
|
|
3068
|
-
* const Entry = tuple(String,
|
|
3527
|
+
* const Entry = tuple(String, Int64FromInt64String);
|
|
3069
3528
|
*
|
|
3070
|
-
* expectOk(Entry.fromUnknown(["count", "1"]), ["count",
|
|
3071
|
-
* expectOk(Entry.from.parent(["count", "1"]), ["count",
|
|
3529
|
+
* expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1n]);
|
|
3530
|
+
* expectOk(Entry.from.parent(["count", "1"]), ["count", 1n]);
|
|
3072
3531
|
* ```
|
|
3073
3532
|
*
|
|
3074
3533
|
* @group Collection
|
|
@@ -3267,7 +3726,7 @@ type PlainObjectError = ObjectError<Readonly<Record<never, never>>, ObjectProper
|
|
|
3267
3726
|
* values have their own Types, and {@link instanceOf} when an instance belongs
|
|
3268
3727
|
* to the domain.
|
|
3269
3728
|
*
|
|
3270
|
-
* @group Base
|
|
3729
|
+
* @group Base
|
|
3271
3730
|
*/
|
|
3272
3731
|
export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, PlainObjectError, null, PlainObjectError, never, Readonly<Record<string, unknown>>>;
|
|
3273
3732
|
/**
|
|
@@ -3300,20 +3759,13 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3300
3759
|
*
|
|
3301
3760
|
* ```ts
|
|
3302
3761
|
* import {
|
|
3303
|
-
*
|
|
3762
|
+
* Int64FromInt64String,
|
|
3304
3763
|
* String,
|
|
3305
|
-
* ok,
|
|
3306
3764
|
* record,
|
|
3307
|
-
*
|
|
3308
|
-
* type Result,
|
|
3765
|
+
* type Int64,
|
|
3309
3766
|
* } from "@evolu/common";
|
|
3310
3767
|
*
|
|
3311
|
-
* const
|
|
3312
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3313
|
-
* to: globalThis.String,
|
|
3314
|
-
* });
|
|
3315
|
-
*
|
|
3316
|
-
* const ScoresByUser = record(String, ScoreFromString);
|
|
3768
|
+
* const ScoresByUser = record(String, Int64FromInt64String);
|
|
3317
3769
|
* type ScoresByUser = typeof ScoresByUser.Output;
|
|
3318
3770
|
*
|
|
3319
3771
|
* // Validate an unknown value.
|
|
@@ -3322,7 +3774,7 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3322
3774
|
* grace: "20",
|
|
3323
3775
|
* });
|
|
3324
3776
|
*
|
|
3325
|
-
* expectOk(scoresFromUnknown, { ada:
|
|
3777
|
+
* expectOk(scoresFromUnknown, { ada: 10n, grace: 20n });
|
|
3326
3778
|
*
|
|
3327
3779
|
* // Validate keys and values with their root Types.
|
|
3328
3780
|
* const scoresInput = ScoresByUser.parent.fromUnknown({
|
|
@@ -3334,11 +3786,10 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3334
3786
|
* // Run the remaining key and value stages.
|
|
3335
3787
|
* const scoresFromInput = ScoresByUser.from.parent(scoresInput.value);
|
|
3336
3788
|
*
|
|
3337
|
-
*
|
|
3338
|
-
*
|
|
3789
|
+
* expectOk(scoresFromInput, { ada: 10n, grace: 20n });
|
|
3790
|
+
* expectTypeOf(scoresFromInput.value).toEqualTypeOf<
|
|
3791
|
+
* Readonly<Partial<Record<string, Int64>>>
|
|
3339
3792
|
* >();
|
|
3340
|
-
*
|
|
3341
|
-
* expectOk(scoresFromInput, { ada: 10, grace: 20 });
|
|
3342
3793
|
* ```
|
|
3343
3794
|
*
|
|
3344
3795
|
* Note that TypeScript does not model an object's runtime prototype. This can
|
|
@@ -3382,7 +3833,11 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3382
3833
|
* @group Objects
|
|
3383
3834
|
*/
|
|
3384
3835
|
export declare const record: <KeyType extends ConcreteTypeNode, ValueType extends ConcreteTypeNode>(key: ValidateRecordKeyType<KeyType>, value: ValidateRecordValueType<ValueType>) => RecordType<KeyType, ValueType>;
|
|
3385
|
-
/**
|
|
3836
|
+
/**
|
|
3837
|
+
* The {@link Type} returned by {@link record}.
|
|
3838
|
+
*
|
|
3839
|
+
* @group Objects
|
|
3840
|
+
*/
|
|
3386
3841
|
export interface RecordType<KeyType extends TypeNode, ValueType extends TypeNode> extends Type<"Record", RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "Output">, RecordNodeError<KeyType, ValueType>, RecordParent<KeyType, ValueType>, RecordError<InferErrors<KeyType>, InferErrors<ValueType>, RecordCollisionFor<KeyType>>, never, CanonicalInputSubset<RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "CanonicalInput">>, AllTypesUseIdentityEncoding<KeyType | ValueType>> {
|
|
3387
3842
|
readonly [reflectedTypesSymbol]?: KeyType | ValueType;
|
|
3388
3843
|
readonly key: KeyType;
|
|
@@ -3412,16 +3867,28 @@ type ValidateRecordValueType<T extends ConcreteTypeNode> = IsUnion<T> extends fa
|
|
|
3412
3867
|
type RecordKeyConcreteTypeError = CompileTimeError<"Type", "Record key must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
3413
3868
|
type RecordValueConcreteTypeError = CompileTimeError<"Type", "Record value must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
3414
3869
|
type RecordKeyStringTypeError = CompileTimeError<"Type", "Record key Type Input and Output must extend string.">;
|
|
3415
|
-
/**
|
|
3870
|
+
/**
|
|
3871
|
+
* Error returned while validating a {@link record} and its entries.
|
|
3872
|
+
*
|
|
3873
|
+
* @group Objects
|
|
3874
|
+
*/
|
|
3416
3875
|
export type RecordError<KeyError extends TypeError = TypeError, ValueError extends TypeError = TypeError, Collision extends RecordCollisionIssue = RecordCollisionIssue> = RecordNotRecordError | RecordNotPlainRecordError | RecordEntriesErrorValue<KeyError, ValueError, Collision | RecordAccessorIssue | RecordNonEnumerableIssue>;
|
|
3417
|
-
/**
|
|
3876
|
+
/**
|
|
3877
|
+
* Error returned when a {@link record} input is not an object.
|
|
3878
|
+
*
|
|
3879
|
+
* @group Objects
|
|
3880
|
+
*/
|
|
3418
3881
|
export interface RecordNotRecordError extends TypeError<"Record"> {
|
|
3419
3882
|
readonly reason: {
|
|
3420
3883
|
readonly kind: "NotRecord";
|
|
3421
3884
|
readonly value: unknown;
|
|
3422
3885
|
};
|
|
3423
3886
|
}
|
|
3424
|
-
/**
|
|
3887
|
+
/**
|
|
3888
|
+
* Error returned when a {@link record} input is not a plain object.
|
|
3889
|
+
*
|
|
3890
|
+
* @group Objects
|
|
3891
|
+
*/
|
|
3425
3892
|
export interface RecordNotPlainRecordError extends TypeError<"Record"> {
|
|
3426
3893
|
readonly reason: {
|
|
3427
3894
|
readonly kind: "NotPlainRecord";
|
|
@@ -3438,9 +3905,17 @@ export interface RecordNotPlainRecordError extends TypeError<"Record"> {
|
|
|
3438
3905
|
* @group Objects
|
|
3439
3906
|
*/
|
|
3440
3907
|
export type RecordEntriesError<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = [KeyError | ValueError | StructuralIssue] extends [never] ? never : RecordEntriesErrorValue<KeyError, ValueError, StructuralIssue>;
|
|
3441
|
-
/**
|
|
3908
|
+
/**
|
|
3909
|
+
* An invalid key, value, or property structure in a {@link record}.
|
|
3910
|
+
*
|
|
3911
|
+
* @group Objects
|
|
3912
|
+
*/
|
|
3442
3913
|
export type RecordIssue<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = RecordKeyIssue<KeyError> | RecordValueIssue<ValueError> | StructuralIssue;
|
|
3443
|
-
/**
|
|
3914
|
+
/**
|
|
3915
|
+
* A property-structure issue returned by {@link record}.
|
|
3916
|
+
*
|
|
3917
|
+
* @group Objects
|
|
3918
|
+
*/
|
|
3444
3919
|
export type RecordStructuralIssue = RecordAccessorIssue | RecordCollisionIssue | RecordNonEnumerableIssue;
|
|
3445
3920
|
/**
|
|
3446
3921
|
* An accessor property rejected by {@link record}.
|
|
@@ -3460,19 +3935,31 @@ export interface RecordNonEnumerableIssue {
|
|
|
3460
3935
|
readonly kind: "NonEnumerable";
|
|
3461
3936
|
readonly key: string | symbol;
|
|
3462
3937
|
}
|
|
3463
|
-
/**
|
|
3938
|
+
/**
|
|
3939
|
+
* An invalid key and its source property key in a {@link record}.
|
|
3940
|
+
*
|
|
3941
|
+
* @group Objects
|
|
3942
|
+
*/
|
|
3464
3943
|
export type RecordKeyIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3465
3944
|
readonly kind: "Key";
|
|
3466
3945
|
readonly key: string | symbol;
|
|
3467
3946
|
readonly error: Error;
|
|
3468
3947
|
} : never;
|
|
3469
|
-
/**
|
|
3948
|
+
/**
|
|
3949
|
+
* An invalid value and its property key in a {@link record}.
|
|
3950
|
+
*
|
|
3951
|
+
* @group Objects
|
|
3952
|
+
*/
|
|
3470
3953
|
export type RecordValueIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3471
3954
|
readonly kind: "Value";
|
|
3472
3955
|
readonly key: string | symbol;
|
|
3473
3956
|
readonly error: Error;
|
|
3474
3957
|
} : never;
|
|
3475
|
-
/**
|
|
3958
|
+
/**
|
|
3959
|
+
* Two {@link record} keys that decode to the same output key.
|
|
3960
|
+
*
|
|
3961
|
+
* @group Objects
|
|
3962
|
+
*/
|
|
3476
3963
|
export interface RecordCollisionIssue {
|
|
3477
3964
|
readonly kind: "Collision";
|
|
3478
3965
|
readonly key: string | symbol;
|
|
@@ -3563,48 +4050,38 @@ type ObjectProperty = ObjectProps[string];
|
|
|
3563
4050
|
*
|
|
3564
4051
|
* ```ts
|
|
3565
4052
|
* import {
|
|
3566
|
-
*
|
|
4053
|
+
* Int64FromInt64String,
|
|
3567
4054
|
* String,
|
|
3568
4055
|
* object,
|
|
3569
|
-
* ok,
|
|
3570
|
-
* transform,
|
|
3571
4056
|
* type InferType,
|
|
3572
|
-
* type Result,
|
|
3573
4057
|
* } from "@evolu/common";
|
|
3574
4058
|
*
|
|
3575
|
-
* const AgeFromString = transform("AgeFromString", String, Number, {
|
|
3576
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3577
|
-
* to: globalThis.String,
|
|
3578
|
-
* });
|
|
3579
|
-
*
|
|
3580
4059
|
* const User = object({
|
|
3581
4060
|
* name: String,
|
|
3582
|
-
*
|
|
4061
|
+
* loginCount: Int64FromInt64String,
|
|
3583
4062
|
* });
|
|
3584
4063
|
* interface User extends InferType<typeof User> {}
|
|
3585
4064
|
*
|
|
3586
4065
|
* // Validate an unknown value.
|
|
3587
|
-
* const userFromUnknown = User.fromUnknown({
|
|
4066
|
+
* const userFromUnknown = User.fromUnknown({
|
|
4067
|
+
* name: "Ada",
|
|
4068
|
+
* loginCount: "42",
|
|
4069
|
+
* });
|
|
3588
4070
|
*
|
|
3589
|
-
* expectOk(userFromUnknown, { name: "Ada",
|
|
4071
|
+
* expectOk(userFromUnknown, { name: "Ada", loginCount: 42n });
|
|
3590
4072
|
*
|
|
3591
4073
|
* // Validate the object and root property Types.
|
|
3592
4074
|
* const userInput = User.parent.fromUnknown({
|
|
3593
4075
|
* name: "Ada",
|
|
3594
|
-
*
|
|
4076
|
+
* loginCount: "42",
|
|
3595
4077
|
* });
|
|
3596
|
-
* expectOk(userInput, { name: "Ada",
|
|
4078
|
+
* expectOk(userInput, { name: "Ada", loginCount: "42" });
|
|
3597
4079
|
*
|
|
3598
4080
|
* // Run the remaining property stages.
|
|
3599
|
-
* const userFromInput
|
|
3600
|
-
* { readonly name: string; readonly age: number },
|
|
3601
|
-
* never
|
|
3602
|
-
* > = User.from.parent(userInput.value);
|
|
4081
|
+
* const userFromInput = User.from.parent(userInput.value);
|
|
3603
4082
|
*
|
|
3604
|
-
*
|
|
3605
|
-
*
|
|
3606
|
-
* >();
|
|
3607
|
-
* expectOk(userFromInput, { name: "Ada", age: 42 });
|
|
4083
|
+
* expectOk(userFromInput, { name: "Ada", loginCount: 42n });
|
|
4084
|
+
* expectTypeOf(userFromInput.value).toExtend<User>();
|
|
3608
4085
|
* ```
|
|
3609
4086
|
*
|
|
3610
4087
|
* Note that TypeScript does not model an object's runtime prototype. This can
|
|
@@ -3652,6 +4129,7 @@ type ObjectProperty = ObjectProps[string];
|
|
|
3652
4129
|
* @group Objects
|
|
3653
4130
|
*/
|
|
3654
4131
|
export declare function object<const Props extends ObjectProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): StrictObjectType<Props>;
|
|
4132
|
+
/** Creates an Object Type with additional record properties. */
|
|
3655
4133
|
export declare function object<const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
|
|
3656
4134
|
ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
|
|
3657
4135
|
] extends [never] ? [] : [
|
|
@@ -3693,7 +4171,11 @@ type ObjectRecordKeyTypeError = CompileTimeError<"Type", "Object Record key must
|
|
|
3693
4171
|
type ObjectRecordInputTypeError = CompileTimeError<"Type", "Every declared property Type Input must extend the Object Record value Type Input.">;
|
|
3694
4172
|
type ObjectRecordOutputTypeError = CompileTimeError<"Type", "Every declared property Type Output must extend the Object Record value Type Output.">;
|
|
3695
4173
|
type ObjectRecordCanonicalInputTypeError = CompileTimeError<"Type", "Every declared property Type CanonicalInput must extend the Object Record value Type CanonicalInput.">;
|
|
3696
|
-
/**
|
|
4174
|
+
/**
|
|
4175
|
+
* The {@link Type} returned by {@link object}.
|
|
4176
|
+
*
|
|
4177
|
+
* @group Objects
|
|
4178
|
+
*/
|
|
3697
4179
|
export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
|
|
3698
4180
|
type StrictObjectType<Props extends ObjectProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, [
|
|
3699
4181
|
StrictObjectParents<Props>
|
|
@@ -3791,10 +4273,10 @@ export interface ObjectNotObjectError extends TypeError<"Object"> {
|
|
|
3791
4273
|
*
|
|
3792
4274
|
* Object Types accept a `null` prototype or a prototype whose own prototype is
|
|
3793
4275
|
* `null`. This includes ordinary and cross-realm plain objects as well as
|
|
3794
|
-
* objects created from an immediate root prototype. Arrays, built-in
|
|
3795
|
-
* class instances, and objects with deeper custom prototype chains
|
|
3796
|
-
* error instead of having their prototype or inherited state
|
|
3797
|
-
* `reason.value` is the rejected object.
|
|
4276
|
+
* objects created from an immediate root prototype. Arrays, JavaScript built-in
|
|
4277
|
+
* objects, class instances, and objects with deeper custom prototype chains
|
|
4278
|
+
* return this error instead of having their prototype or inherited state
|
|
4279
|
+
* discarded. `reason.value` is the rejected object.
|
|
3798
4280
|
*
|
|
3799
4281
|
* @group Objects
|
|
3800
4282
|
*/
|
|
@@ -3883,7 +4365,11 @@ type ObjectRestFromParentError<Rest extends ObjectRecordTypeNode | undefined> =
|
|
|
3883
4365
|
* @group Objects
|
|
3884
4366
|
*/
|
|
3885
4367
|
export declare const partial: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<PartialObjectProps<Props>>;
|
|
3886
|
-
/**
|
|
4368
|
+
/**
|
|
4369
|
+
* Maps every required object property Type to an optional property.
|
|
4370
|
+
*
|
|
4371
|
+
* @group Objects
|
|
4372
|
+
*/
|
|
3887
4373
|
export type PartialObjectProps<Props extends ObjectProps> = {
|
|
3888
4374
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
|
|
3889
4375
|
};
|
|
@@ -3915,13 +4401,29 @@ export type PartialObjectProps<Props extends ObjectProps> = {
|
|
|
3915
4401
|
* @group Objects
|
|
3916
4402
|
*/
|
|
3917
4403
|
export declare const nullableToOptional: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<NullableToOptionalProps<Props>>;
|
|
3918
|
-
/**
|
|
4404
|
+
/**
|
|
4405
|
+
* Maps object properties whose Union Type includes {@link Null} to optional
|
|
4406
|
+
* properties.
|
|
4407
|
+
*
|
|
4408
|
+
* @group Objects
|
|
4409
|
+
*/
|
|
3919
4410
|
export type NullableToOptionalProps<Props extends ObjectProps> = {
|
|
3920
4411
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends UnionType<infer Members> ? typeof Null extends Members[number] ? OptionalProperty<Props[Key]> : Props[Key] : Props[Key];
|
|
3921
4412
|
};
|
|
3922
4413
|
/**
|
|
3923
4414
|
* Object {@link Type} without the selected declared properties.
|
|
3924
4415
|
*
|
|
4416
|
+
* ### Example
|
|
4417
|
+
*
|
|
4418
|
+
* ```ts
|
|
4419
|
+
* import { String, object, omit } from "@evolu/common";
|
|
4420
|
+
*
|
|
4421
|
+
* const User = object({ name: String, password: String });
|
|
4422
|
+
* const PublicUser = omit(User, "password");
|
|
4423
|
+
*
|
|
4424
|
+
* expectOk(PublicUser.fromUnknown({ name: "Ada" }), { name: "Ada" });
|
|
4425
|
+
* ```
|
|
4426
|
+
*
|
|
3925
4427
|
* @group Objects
|
|
3926
4428
|
*/
|
|
3927
4429
|
export declare const omit: <const Props extends ObjectProps, const Keys extends ReadonlyArray<keyof Props>, Rest extends ObjectRecordTypeNode | undefined = undefined>(objectType: ObjectType<Props, Rest>, ...keys: Keys & ([ValidateOmitKeys<Keys>] extends [never] ? unknown : readonly [ValidationFailure<ValidateOmitKeys<Keys>>])) => ObjectType<Omit<Props, Keys[number]>, Rest>;
|
|
@@ -3931,10 +4433,10 @@ type ValidateOmitKeys<Keys extends ReadonlyArray<PropertyKey>> = number extends
|
|
|
3931
4433
|
type OmitKeysTupleError = CompileTimeError<"Type", "Omitted keys must use one concrete finite tuple.">;
|
|
3932
4434
|
type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must be one concrete property key.">;
|
|
3933
4435
|
/**
|
|
3934
|
-
*
|
|
4436
|
+
* Creates a {@link Type} for {@link Result} values.
|
|
3935
4437
|
*
|
|
3936
4438
|
* Use this to validate Results crossing a storage, worker, API, or other
|
|
3937
|
-
* serialization boundary.
|
|
4439
|
+
* serialization boundary. `fromUnknown` returns an outer validation Result. Its
|
|
3938
4440
|
* successful value is the inner domain Result described by `okType` and
|
|
3939
4441
|
* `errorType`.
|
|
3940
4442
|
*
|
|
@@ -3951,34 +4453,16 @@ type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must
|
|
|
3951
4453
|
*
|
|
3952
4454
|
* const SyncResponse = result(
|
|
3953
4455
|
* object({ timestamp: NonNegativeInt }),
|
|
3954
|
-
* typed("
|
|
4456
|
+
* typed("SyncFailed", { message: String }),
|
|
3955
4457
|
* );
|
|
3956
4458
|
*
|
|
3957
|
-
* const
|
|
3958
|
-
*
|
|
3959
|
-
*
|
|
3960
|
-
*
|
|
3961
|
-
* const response = validated.value;
|
|
3962
|
-
* return response.ok
|
|
3963
|
-
* ? `Synced at ${response.value.timestamp}`
|
|
3964
|
-
* : response.error.message;
|
|
3965
|
-
* };
|
|
4459
|
+
* const validated = SyncResponse.fromUnknown({
|
|
4460
|
+
* ok: true,
|
|
4461
|
+
* value: { timestamp: 42 },
|
|
4462
|
+
* });
|
|
3966
4463
|
*
|
|
3967
|
-
*
|
|
3968
|
-
*
|
|
3969
|
-
* ok: true,
|
|
3970
|
-
* value: { timestamp: 42 },
|
|
3971
|
-
* }),
|
|
3972
|
-
* ).toBe("Synced at 42");
|
|
3973
|
-
* expect(
|
|
3974
|
-
* describeResponse({
|
|
3975
|
-
* ok: false,
|
|
3976
|
-
* error: { type: "SyncError", message: "Offline" },
|
|
3977
|
-
* }),
|
|
3978
|
-
* ).toBe("Offline");
|
|
3979
|
-
* expect(describeResponse({ ok: true, value: { timestamp: -1 } })).toBe(
|
|
3980
|
-
* "Invalid response",
|
|
3981
|
-
* );
|
|
4464
|
+
* expectOk(validated, { ok: true, value: { timestamp: 42 } });
|
|
4465
|
+
* expectOk(validated.value, { timestamp: 42 });
|
|
3982
4466
|
* ```
|
|
3983
4467
|
*
|
|
3984
4468
|
* @group Results
|
|
@@ -4010,7 +4494,7 @@ export declare const UnknownResult: DiscriminatedUnionType<"ok", readonly [Stric
|
|
|
4010
4494
|
}>]>;
|
|
4011
4495
|
export type UnknownResult = typeof UnknownResult.Output;
|
|
4012
4496
|
/**
|
|
4013
|
-
*
|
|
4497
|
+
* Creates an {@link ObjectType} with a literal `type` property.
|
|
4014
4498
|
*
|
|
4015
4499
|
* The discriminator belongs to `typed`, so additional properties cannot declare
|
|
4016
4500
|
* `type`. The discriminator Input is `string`, inherited from {@link String},
|
|
@@ -4022,35 +4506,38 @@ export type UnknownResult = typeof UnknownResult.Output;
|
|
|
4022
4506
|
* ### Example
|
|
4023
4507
|
*
|
|
4024
4508
|
* ```ts
|
|
4025
|
-
* import { String,
|
|
4509
|
+
* import { String, typed } from "@evolu/common";
|
|
4026
4510
|
*
|
|
4027
4511
|
* const Pending = typed("Pending", {
|
|
4028
4512
|
* label: String,
|
|
4029
4513
|
* });
|
|
4030
4514
|
*
|
|
4031
|
-
*
|
|
4032
|
-
* const Status = discriminatedUnion(Pending, Completed);
|
|
4033
|
-
*
|
|
4034
|
-
* expectOk(Status.fromUnknown({ type: "Pending", label: "Waiting" }), {
|
|
4515
|
+
* expectOk(Pending.fromUnknown({ type: "Pending", label: "Waiting" }), {
|
|
4035
4516
|
* type: "Pending",
|
|
4036
4517
|
* label: "Waiting",
|
|
4037
4518
|
* });
|
|
4038
|
-
* expectOk(Status.fromUnknown({ type: "Completed" }), {
|
|
4039
|
-
* type: "Completed",
|
|
4040
|
-
* });
|
|
4041
4519
|
* ```
|
|
4042
4520
|
*
|
|
4043
4521
|
* @group Discriminated unions
|
|
4044
4522
|
*/
|
|
4045
4523
|
export declare function typed<const Tag extends TypeName>(tag: ValidateTypedTag<Tag>): TypedType<Tag>;
|
|
4524
|
+
/** Creates a Tagged Object Type with declared properties. */
|
|
4046
4525
|
export declare function typed<const Tag extends TypeName, const Props extends ObjectProps>(tag: ValidateTypedTag<Tag>, props: Props, ...validation: [TypedValidationError<Props>] extends [never] ? [] : [ValidationFailure<TypedValidationError<Props>>]): TypedType<Tag, Props>;
|
|
4526
|
+
/** Creates a Tagged Object Type with additional record properties. */
|
|
4047
4527
|
export declare function typed<const Tag extends TypeName, const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(tag: ValidateTypedTag<Tag>, props: Props, record: Rest, ...validation: [
|
|
4048
4528
|
TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>
|
|
4049
4529
|
] extends [never] ? [] : [
|
|
4050
4530
|
ValidationFailure<TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>>
|
|
4051
4531
|
]): TypedType<Tag, Props, Rest extends ObjectRecordTypeNode ? Rest : never>;
|
|
4052
4532
|
/**
|
|
4053
|
-
* A
|
|
4533
|
+
* A TypeScript interface with a literal `type` property.
|
|
4534
|
+
*
|
|
4535
|
+
* Use `Typed` for both domain objects in discriminated unions and plain domain
|
|
4536
|
+
* errors returned by {@link Result}. Name a domain error interface `XError`.
|
|
4537
|
+
* When `X` already describes a failure, use `X` for its `type` discriminant
|
|
4538
|
+
* because `Error` describes the interface's role rather than the runtime error
|
|
4539
|
+
* kind. Keep `Error` when it is needed to make the discriminant unambiguous,
|
|
4540
|
+
* such as `TimeoutError`.
|
|
4054
4541
|
*
|
|
4055
4542
|
* Typed unions model mutually exclusive states as separate variants instead of
|
|
4056
4543
|
* combinations of flags and optional properties. TypeScript narrows a union by
|
|
@@ -4061,20 +4548,23 @@ export declare function typed<const Tag extends TypeName, const Props extends Ob
|
|
|
4061
4548
|
* ### Example
|
|
4062
4549
|
*
|
|
4063
4550
|
* ```ts
|
|
4064
|
-
* import { type Typed } from "@evolu/common";
|
|
4551
|
+
* import { err, ok, type Result, type Typed } from "@evolu/common";
|
|
4065
4552
|
*
|
|
4066
|
-
*
|
|
4553
|
+
* interface User extends Typed<"User"> {
|
|
4554
|
+
* readonly id: string;
|
|
4555
|
+
* }
|
|
4067
4556
|
*
|
|
4068
|
-
* const
|
|
4069
|
-
*
|
|
4070
|
-
*
|
|
4071
|
-
*
|
|
4072
|
-
*
|
|
4073
|
-
*
|
|
4074
|
-
*
|
|
4075
|
-
* }
|
|
4557
|
+
* const getUser = (id: string): Result<User, UserNotFoundError> =>
|
|
4558
|
+
* id === "user-1"
|
|
4559
|
+
* ? ok({ type: "User", id })
|
|
4560
|
+
* : err({ type: "UserNotFound", id });
|
|
4561
|
+
*
|
|
4562
|
+
* interface UserNotFoundError extends Typed<"UserNotFound"> {
|
|
4563
|
+
* readonly id: string;
|
|
4564
|
+
* }
|
|
4076
4565
|
*
|
|
4077
|
-
*
|
|
4566
|
+
* expectOk(getUser("user-1"), { type: "User", id: "user-1" });
|
|
4567
|
+
* expectErr(getUser("missing"), { type: "UserNotFound", id: "missing" });
|
|
4078
4568
|
* ```
|
|
4079
4569
|
*
|
|
4080
4570
|
* @group Discriminated unions
|
|
@@ -4085,7 +4575,7 @@ export interface Typed<Tag extends TypeName> {
|
|
|
4085
4575
|
/**
|
|
4086
4576
|
* Extracts members of a {@link Typed} Output union by their `type` literal.
|
|
4087
4577
|
*
|
|
4088
|
-
* The requested
|
|
4578
|
+
* The requested tag is constrained to the union's actual discriminator values,
|
|
4089
4579
|
* so a misspelling is a TypeScript error instead of silently producing
|
|
4090
4580
|
* `never`.
|
|
4091
4581
|
*
|
|
@@ -4131,7 +4621,8 @@ type ConcreteTypedTagError = CompileTimeError<"Type", "Tag must be one concrete
|
|
|
4131
4621
|
type TypedValidationError<Props extends ObjectProps> = "type" extends keyof Props ? TypedTypePropertyError : ObjectValidationError<Props>;
|
|
4132
4622
|
type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties must not declare the reserved "type" property.'>;
|
|
4133
4623
|
/**
|
|
4134
|
-
*
|
|
4624
|
+
* Creates a {@link Type} for producer Results with value, error, or done
|
|
4625
|
+
* outcomes.
|
|
4135
4626
|
*
|
|
4136
4627
|
* The three outcomes are `Ok<Value>`, `Err<Error>`, and `Err<Typed<"Done"> & {
|
|
4137
4628
|
* done: Done }>`. This keeps normal completion distinct from failure while
|
|
@@ -4144,7 +4635,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
4144
4635
|
*
|
|
4145
4636
|
* const StringNextResult = nextResult(
|
|
4146
4637
|
* String,
|
|
4147
|
-
* typed("
|
|
4638
|
+
* typed("ReadFailed", { message: String }),
|
|
4148
4639
|
* String,
|
|
4149
4640
|
* );
|
|
4150
4641
|
*
|
|
@@ -4168,7 +4659,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
4168
4659
|
* expect(
|
|
4169
4660
|
* describeNext({
|
|
4170
4661
|
* ok: false,
|
|
4171
|
-
* error: { type: "
|
|
4662
|
+
* error: { type: "ReadFailed", message: "Offline" },
|
|
4172
4663
|
* }),
|
|
4173
4664
|
* ).toBe("Error: Offline");
|
|
4174
4665
|
* ```
|
|
@@ -4200,7 +4691,7 @@ export declare const UnknownNextResult: DiscriminatedUnionType<"ok", readonly [S
|
|
|
4200
4691
|
}>]>;
|
|
4201
4692
|
export type UnknownNextResult = typeof UnknownNextResult.Output;
|
|
4202
4693
|
/**
|
|
4203
|
-
* Discriminated
|
|
4694
|
+
* Discriminated union {@link Type}.
|
|
4204
4695
|
*
|
|
4205
4696
|
* With no explicit key, the conventional `type` property created by
|
|
4206
4697
|
* {@link typed} is used. Pass a key first to discriminate
|
|
@@ -4231,6 +4722,34 @@ export type UnknownNextResult = typeof UnknownNextResult.Output;
|
|
|
4231
4722
|
* @group Discriminated unions
|
|
4232
4723
|
*/
|
|
4233
4724
|
export declare function discriminatedUnion<const Members extends DiscriminatedUnionMembers>(...members: Members & DiscriminatedUnionValidation<"type", Members>): DiscriminatedUnionType<"type", Members>;
|
|
4725
|
+
/**
|
|
4726
|
+
* Creates a Discriminated Union Type with an explicit discriminator key.
|
|
4727
|
+
*
|
|
4728
|
+
* ### Example
|
|
4729
|
+
*
|
|
4730
|
+
* ```ts
|
|
4731
|
+
* import {
|
|
4732
|
+
* Number,
|
|
4733
|
+
* String,
|
|
4734
|
+
* discriminatedUnion,
|
|
4735
|
+
* literal,
|
|
4736
|
+
* object,
|
|
4737
|
+
* } from "@evolu/common";
|
|
4738
|
+
*
|
|
4739
|
+
* const Added = object({ kind: literal("added"), value: String });
|
|
4740
|
+
* const Removed = object({ kind: literal("removed"), id: Number });
|
|
4741
|
+
* const Event = discriminatedUnion("kind", Added, Removed);
|
|
4742
|
+
*
|
|
4743
|
+
* expectOk(Event.fromUnknown({ kind: "added", value: "Evolu" }), {
|
|
4744
|
+
* kind: "added",
|
|
4745
|
+
* value: "Evolu",
|
|
4746
|
+
* });
|
|
4747
|
+
* expectOk(Event.fromUnknown({ kind: "removed", id: 1 }), {
|
|
4748
|
+
* kind: "removed",
|
|
4749
|
+
* id: 1,
|
|
4750
|
+
* });
|
|
4751
|
+
* ```
|
|
4752
|
+
*/
|
|
4234
4753
|
export declare function discriminatedUnion<const Key extends string, const Members extends DiscriminatedUnionMembers>(key: ValidateDiscriminatedUnionKey<Key>, ...members: Members & DiscriminatedUnionValidation<Key, Members>): DiscriminatedUnionType<Key, Members>;
|
|
4235
4754
|
/**
|
|
4236
4755
|
* The routed {@link Type} returned by {@link discriminatedUnion}.
|
|
@@ -4353,10 +4872,10 @@ type DiscriminatedUnionMemberConcreteTypeError = CompileTimeError<"Type", "Membe
|
|
|
4353
4872
|
type DiscriminatedUnionPropertyError<Key extends string> = CompileTimeError<"Type", `Property "${Key}" must be a required String, Number, BigInt, or Boolean Literal Type in every member.`>;
|
|
4354
4873
|
type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends DiscriminatedUnionLiteral> = CompileTimeError<"Type", `Duplicate value "${Expected}" at property "${Key}".`>;
|
|
4355
4874
|
/**
|
|
4356
|
-
*
|
|
4875
|
+
* Creates a lazy {@link Type} for recursive definitions.
|
|
4357
4876
|
*
|
|
4358
|
-
*
|
|
4359
|
-
* trees and mutually recursive models.
|
|
4877
|
+
* The definition is evaluated on first use and then cached, allowing recursive
|
|
4878
|
+
* data such as trees and mutually recursive models.
|
|
4360
4879
|
*
|
|
4361
4880
|
* A recursive declaration refers to its own variable while that variable is
|
|
4362
4881
|
* being initialized, so TypeScript cannot infer it reliably. Getter-based
|
|
@@ -4376,12 +4895,10 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
|
|
|
4376
4895
|
*
|
|
4377
4896
|
* ```ts
|
|
4378
4897
|
* import {
|
|
4379
|
-
* Number,
|
|
4380
4898
|
* String,
|
|
4381
4899
|
* array,
|
|
4382
4900
|
* lazy,
|
|
4383
4901
|
* object,
|
|
4384
|
-
* optional,
|
|
4385
4902
|
* type ArrayError,
|
|
4386
4903
|
* type LazyType,
|
|
4387
4904
|
* type ObjectError,
|
|
@@ -4402,35 +4919,19 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
|
|
|
4402
4919
|
* () => object({ value: String, children: array(Tree) }),
|
|
4403
4920
|
* );
|
|
4404
4921
|
*
|
|
4405
|
-
*
|
|
4406
|
-
*
|
|
4407
|
-
*
|
|
4408
|
-
* }
|
|
4409
|
-
*
|
|
4410
|
-
* interface Right {
|
|
4411
|
-
* readonly count: number;
|
|
4412
|
-
* readonly left?: Left;
|
|
4413
|
-
* }
|
|
4414
|
-
*
|
|
4415
|
-
* interface LeftError extends ObjectError<{
|
|
4416
|
-
* readonly label: TypeOfError<"String">;
|
|
4417
|
-
* readonly right?: RightError;
|
|
4418
|
-
* }> {}
|
|
4419
|
-
*
|
|
4420
|
-
* interface RightError extends ObjectError<{
|
|
4421
|
-
* readonly count: TypeOfError<"Number">;
|
|
4422
|
-
* readonly left?: LeftError;
|
|
4423
|
-
* }> {}
|
|
4424
|
-
*
|
|
4425
|
-
* const Left: LazyType<Left, Left, never, LeftError, LeftError> = lazy(
|
|
4426
|
-
* () => object({ label: String, right: optional(Right) }),
|
|
4427
|
-
* );
|
|
4922
|
+
* const result = Tree.fromUnknown({
|
|
4923
|
+
* value: "root",
|
|
4924
|
+
* children: [{ value: "leaf", children: [] }],
|
|
4925
|
+
* });
|
|
4428
4926
|
*
|
|
4429
|
-
*
|
|
4430
|
-
*
|
|
4927
|
+
* expectOk(result, {
|
|
4928
|
+
* value: "root",
|
|
4929
|
+
* children: [{ value: "leaf", children: [] }],
|
|
4930
|
+
* });
|
|
4931
|
+
* expectTypeOf(result.value).toEqualTypeOf<Tree>();
|
|
4431
4932
|
* ```
|
|
4432
4933
|
*
|
|
4433
|
-
* @group Recursive
|
|
4934
|
+
* @group Recursive
|
|
4434
4935
|
*/
|
|
4435
4936
|
export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<ValidateLazyTarget<Target>>): LazyType<Target["Input"], Target["Output"], TypeFromError<Target>, InferErrors<RootType<Target>>, InferErrors<Target>, CanonicalInputOf<Target>, IdentityEncodingOf<Target>>;
|
|
4436
4937
|
/**
|
|
@@ -4448,7 +4949,7 @@ export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<Val
|
|
|
4448
4949
|
* recursive declaration finite for TypeScript while preserving structured
|
|
4449
4950
|
* errors at every boundary.
|
|
4450
4951
|
*
|
|
4451
|
-
* @group Recursive
|
|
4952
|
+
* @group Recursive
|
|
4452
4953
|
*/
|
|
4453
4954
|
export interface LazyType<in out Input, in out Output, in out FromError extends TypeError, in out InputError extends TypeError, in out Errors extends TypeError, in out CanonicalInput extends Input = Input, in out UsesIdentityEncoding extends boolean = true> extends Type<"Lazy", Input, Output, FromError, Type<"Lazy", Input, Input, InputError, null, InputError, never, Input>, Errors, never, CanonicalInput, UsesIdentityEncoding> {
|
|
4454
4955
|
readonly [lazyTypeSymbol]: true;
|
|
@@ -4504,7 +5005,7 @@ export interface JsonObject {
|
|
|
4504
5005
|
readonly [key: string]: JsonValue;
|
|
4505
5006
|
}
|
|
4506
5007
|
/**
|
|
4507
|
-
* One issue found while validating an exact {@link JsonValue}.
|
|
5008
|
+
* One issue found while validating a candidate as an exact {@link JsonValue}.
|
|
4508
5009
|
*
|
|
4509
5010
|
* @group JSON
|
|
4510
5011
|
*/
|
|
@@ -4542,7 +5043,8 @@ export type JsonValueIssue = {
|
|
|
4542
5043
|
readonly ancestorPath: ReadonlyArray<string | number | symbol>;
|
|
4543
5044
|
};
|
|
4544
5045
|
/**
|
|
4545
|
-
* An error containing one or more issues found
|
|
5046
|
+
* An error containing one or more issues found while validating a candidate as
|
|
5047
|
+
* an exact {@link JsonValue}.
|
|
4546
5048
|
*
|
|
4547
5049
|
* @group JSON
|
|
4548
5050
|
*/
|
|
@@ -4580,6 +5082,21 @@ export interface JsonError extends TypeError<"Json"> {
|
|
|
4580
5082
|
/**
|
|
4581
5083
|
* Exact root Type for {@link JsonValue} data trees.
|
|
4582
5084
|
*
|
|
5085
|
+
* ### Example
|
|
5086
|
+
*
|
|
5087
|
+
* ```ts
|
|
5088
|
+
* import { JsonValue, type JsonValueInput } from "@evolu/common";
|
|
5089
|
+
*
|
|
5090
|
+
* const input: JsonValueInput = {
|
|
5091
|
+
* name: "Ada",
|
|
5092
|
+
* scores: [10, 20],
|
|
5093
|
+
* };
|
|
5094
|
+
* const result = JsonValue.fromUnknown(input);
|
|
5095
|
+
*
|
|
5096
|
+
* expectOk(result, input);
|
|
5097
|
+
* expectTypeOf(result.value).toEqualTypeOf<JsonValue>();
|
|
5098
|
+
* ```
|
|
5099
|
+
*
|
|
4583
5100
|
* @group JSON
|
|
4584
5101
|
*/
|
|
4585
5102
|
export declare const JsonValue: JsonValueType;
|
|
@@ -4599,7 +5116,7 @@ export declare const JsonObject: JsonObjectType;
|
|
|
4599
5116
|
* A {@link String} Brand proving that its exact text parses to {@link JsonValue}.
|
|
4600
5117
|
*
|
|
4601
5118
|
* The Brand preserves whitespace, property order, and number spelling. Convert
|
|
4602
|
-
* it
|
|
5119
|
+
* it to {@link JsonValue} through {@link JsonValueFromJson} or
|
|
4603
5120
|
* {@link jsonToJsonValue}.
|
|
4604
5121
|
*
|
|
4605
5122
|
* @group JSON
|
|
@@ -4607,88 +5124,100 @@ export declare const JsonObject: JsonObjectType;
|
|
|
4607
5124
|
export declare const Json: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Json", JsonError>;
|
|
4608
5125
|
export type Json = typeof Json.Output;
|
|
4609
5126
|
/**
|
|
4610
|
-
*
|
|
5127
|
+
* Converts proven {@link Json} text to an exact {@link JsonValue}.
|
|
5128
|
+
*
|
|
5129
|
+
* ### Example
|
|
5130
|
+
*
|
|
5131
|
+
* ```ts
|
|
5132
|
+
* import { Json, jsonToJsonValue } from "@evolu/common";
|
|
5133
|
+
*
|
|
5134
|
+
* const value = jsonToJsonValue(Json.orThrow('{"name":"Ada"}'));
|
|
5135
|
+
*
|
|
5136
|
+
* expect(value).toEqual({ name: "Ada" });
|
|
5137
|
+
* ```
|
|
4611
5138
|
*
|
|
4612
5139
|
* @group JSON
|
|
4613
5140
|
*/
|
|
4614
5141
|
export declare const jsonToJsonValue: (value: Json) => JsonValue;
|
|
4615
5142
|
/**
|
|
4616
|
-
*
|
|
5143
|
+
* Converts an exact {@link JsonValue} to canonical {@link Json} text.
|
|
5144
|
+
*
|
|
5145
|
+
* ### Example
|
|
5146
|
+
*
|
|
5147
|
+
* ```ts
|
|
5148
|
+
* import { jsonValueToJson, type JsonValue } from "@evolu/common";
|
|
5149
|
+
*
|
|
5150
|
+
* const value: JsonValue = { name: "Ada" };
|
|
5151
|
+
*
|
|
5152
|
+
* expect(jsonValueToJson(value)).toBe('{"name":"Ada"}');
|
|
5153
|
+
* ```
|
|
4617
5154
|
*
|
|
4618
5155
|
* @group JSON
|
|
4619
5156
|
*/
|
|
4620
5157
|
export declare const jsonValueToJson: (value: JsonValue) => Json;
|
|
4621
5158
|
/**
|
|
4622
|
-
* {@link Json}
|
|
5159
|
+
* Transformation {@link Type} that parses {@link Json} into {@link JsonValue}.
|
|
4623
5160
|
*
|
|
4624
5161
|
* Decoding unknown input first validates the Json Brand. Starting from the
|
|
4625
5162
|
* typed Json parent is infallible. Encoding canonicalizes JSON text.
|
|
4626
5163
|
*
|
|
5164
|
+
* ### Example
|
|
5165
|
+
*
|
|
5166
|
+
* ```ts
|
|
5167
|
+
* import { JsonValueFromJson } from "@evolu/common";
|
|
5168
|
+
*
|
|
5169
|
+
* const result = JsonValueFromJson.fromUnknown('{ "name": "Ada" }');
|
|
5170
|
+
*
|
|
5171
|
+
* expectOk(result, { name: "Ada" });
|
|
5172
|
+
* expect(JsonValueFromJson.to(result.value)).toBe('{"name":"Ada"}');
|
|
5173
|
+
* ```
|
|
5174
|
+
*
|
|
4627
5175
|
* @group JSON
|
|
4628
5176
|
*/
|
|
4629
5177
|
export declare const JsonValueFromJson: TransformType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Json", JsonError>, JsonValueType, "JsonValueFromJson", never, string & Brand<"Json">>;
|
|
4630
5178
|
/**
|
|
4631
|
-
* Branded {@link Json} Type and
|
|
4632
|
-
*
|
|
4633
|
-
* Use this
|
|
4634
|
-
*
|
|
4635
|
-
*
|
|
4636
|
-
*
|
|
4637
|
-
* Output.
|
|
4638
|
-
*
|
|
4639
|
-
* The supplied Type's `CanonicalInput` must be JSON-compatible. The encoder
|
|
4640
|
-
* first uses the Type's canonical `to` operation, then encodes that
|
|
4641
|
-
* representation as canonical Json. Runtime representation constraints
|
|
4642
|
-
* TypeScript cannot prove, such as dense Arrays and enumerable data properties,
|
|
4643
|
-
* are asserted as developer errors.
|
|
4644
|
-
*
|
|
4645
|
-
* The branded Json Type is the validation boundary for unknown JSON text. It
|
|
4646
|
-
* grants its {@link Brand} only when the text is valid Json and decoding it
|
|
4647
|
-
* through the supplied Type succeeds. The supplied Type is responsible for
|
|
4648
|
-
* preserving semantic Outputs across canonical JSON encoding and decoding. This
|
|
4649
|
-
* law cannot be checked generically because Types do not define semantic
|
|
4650
|
-
* equality. Before granting the Brand, the encoder asserts the weaker runtime
|
|
4651
|
-
* guarantee that the final Json successfully decodes through the supplied Type.
|
|
4652
|
-
* Failed decodability therefore throws as a developer error.
|
|
4653
|
-
*
|
|
4654
|
-
* Consequently, the two typed conversions return their values directly without
|
|
4655
|
-
* exposing a validation {@link Result}: an Output satisfying the JSON
|
|
4656
|
-
* representation contract of a correctly declared Type can always be encoded,
|
|
4657
|
-
* and the branded Json proves decoding will succeed. Decoding still runs the
|
|
4658
|
-
* Type pipeline because transformations may need to construct different Output
|
|
4659
|
-
* values.
|
|
5179
|
+
* Branded {@link Json} Type and conversions for another {@link Type}.
|
|
5180
|
+
*
|
|
5181
|
+
* Use this when a value must be stored as JSON text, such as in a JSON column
|
|
5182
|
+
* in an Evolu Schema. It returns a branded Json Type and functions for
|
|
5183
|
+
* converting the supplied Type's Output to and from that branded JSON
|
|
5184
|
+
* representation.
|
|
4660
5185
|
*
|
|
4661
5186
|
* ### Example
|
|
4662
5187
|
*
|
|
4663
5188
|
* ```ts
|
|
4664
5189
|
* import {
|
|
4665
5190
|
* Age,
|
|
5191
|
+
* NonEmptyTrimmedString100,
|
|
4666
5192
|
* json,
|
|
4667
5193
|
* object,
|
|
4668
|
-
* String,
|
|
4669
5194
|
* type Brand,
|
|
4670
|
-
* type InferType,
|
|
4671
|
-
* type Json,
|
|
4672
5195
|
* } from "@evolu/common";
|
|
4673
5196
|
*
|
|
4674
|
-
* const
|
|
4675
|
-
*
|
|
5197
|
+
* const User = object({
|
|
5198
|
+
* name: NonEmptyTrimmedString100,
|
|
5199
|
+
* age: Age,
|
|
5200
|
+
* });
|
|
4676
5201
|
*
|
|
4677
|
-
* const [
|
|
4678
|
-
*
|
|
4679
|
-
* "
|
|
5202
|
+
* const [UserJson, userToUserJson, userJsonToUser] = json(
|
|
5203
|
+
* User,
|
|
5204
|
+
* "UserJson",
|
|
4680
5205
|
* );
|
|
4681
|
-
* type PersonJson = typeof PersonJson.Output;
|
|
4682
|
-
*
|
|
4683
|
-
* expectTypeOf<PersonJson>().toEqualTypeOf<Json & Brand<"PersonJson">>();
|
|
4684
5206
|
*
|
|
4685
|
-
* const
|
|
4686
|
-
* const
|
|
4687
|
-
* const decodedPerson = personJsonToPerson(personJson);
|
|
5207
|
+
* const user = User.orThrow({ name: "Ada", age: 37 });
|
|
5208
|
+
* const userJson = userToUserJson(user);
|
|
4688
5209
|
*
|
|
4689
|
-
*
|
|
5210
|
+
* expectTypeOf(userJson).toEqualTypeOf<
|
|
5211
|
+
* string & Brand<"Json"> & Brand<"UserJson">
|
|
5212
|
+
* >();
|
|
5213
|
+
* expect(userJson).toBe('{"name":"Ada","age":37}');
|
|
5214
|
+
* expect(userJsonToUser(userJson)).toEqual(user);
|
|
4690
5215
|
* ```
|
|
4691
5216
|
*
|
|
5217
|
+
* The supplied Type must have a JSON-compatible `CanonicalInput`. The branded
|
|
5218
|
+
* Json Type accepts only valid JSON text whose parsed value can be decoded by
|
|
5219
|
+
* the supplied Type.
|
|
5220
|
+
*
|
|
4692
5221
|
* @group JSON
|
|
4693
5222
|
*/
|
|
4694
5223
|
export declare const json: <T extends ConcreteTypeNode, Name extends TypeName>(type: T, name: ValidateChildTypeName<Name, typeof Json>, ..._validation: [JsonTypeValidationError<T>] extends [never] ? [] : [ValidationFailure<JsonTypeValidationError<T>>]) => readonly [jsonType: BrandType<typeof Json, Name, TypeError<Name> & TransparentTypeError & {
|