typesea 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +45 -11
- package/dist/aot/index.d.ts +1 -1
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +22 -3
- package/dist/builders/composite.d.ts +6 -3
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +22 -13
- package/dist/builders/index.d.ts +6 -5
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +5 -4
- package/dist/builders/modifier.d.ts +6 -0
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +14 -0
- package/dist/builders/object/guard.d.ts +54 -2
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +117 -7
- package/dist/builders/object/index.d.ts +2 -2
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +1 -1
- package/dist/builders/object/schema.d.ts +33 -2
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +198 -8
- package/dist/builders/object/types.d.ts +15 -0
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/runtime.d.ts +40 -0
- package/dist/builders/runtime.d.ts.map +1 -0
- package/dist/builders/runtime.js +150 -0
- package/dist/builders/scalar.d.ts +20 -1
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +54 -1
- package/dist/builders/table.d.ts +31 -5
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +31 -5
- package/dist/builders/types.d.ts +6 -0
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/compile/check-composite.d.ts +3 -1
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +143 -11
- package/dist/compile/check-scalar.d.ts +10 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +138 -2
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +25 -3
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +2 -0
- package/dist/compile/first.d.ts +26 -0
- package/dist/compile/first.d.ts.map +1 -0
- package/dist/compile/first.js +850 -0
- package/dist/compile/graph-predicate.d.ts.map +1 -1
- package/dist/compile/graph-predicate.js +389 -18
- package/dist/compile/guard.d.ts +2 -1
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +54 -8
- package/dist/compile/predicate.d.ts.map +1 -1
- package/dist/compile/predicate.js +156 -5
- package/dist/compile/runtime.d.ts +20 -1
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +31 -0
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +27 -3
- package/dist/compile/types.d.ts +2 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/decoder/index.d.ts +60 -0
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +164 -1
- package/dist/evaluate/check-composite.d.ts +52 -2
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +193 -6
- package/dist/evaluate/check-scalar.d.ts +9 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +92 -3
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +19 -4
- package/dist/evaluate/shared.d.ts +19 -0
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +35 -0
- package/dist/guard/array.d.ts +48 -0
- package/dist/guard/array.d.ts.map +1 -0
- package/dist/guard/array.js +84 -0
- package/dist/guard/base.d.ts +32 -2
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +74 -3
- package/dist/guard/date.d.ts +34 -0
- package/dist/guard/date.d.ts.map +1 -0
- package/dist/guard/date.js +60 -0
- package/dist/guard/index.d.ts +2 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +2 -0
- package/dist/guard/number.d.ts +60 -0
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +129 -0
- package/dist/guard/read.d.ts +53 -1
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +102 -0
- package/dist/guard/string.d.ts +82 -0
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +213 -0
- package/dist/guard/types.d.ts +18 -0
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/ir/builder.d.ts +3 -3
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +5 -2
- package/dist/ir/freeze.js +7 -0
- package/dist/ir/types.d.ts +4 -1
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/validate.d.ts.map +1 -1
- package/dist/ir/validate.js +35 -1
- package/dist/issue/index.d.ts +1 -1
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +4 -0
- package/dist/json-schema/emit-composite.d.ts +6 -2
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +66 -12
- package/dist/json-schema/emit-scalar.d.ts.map +1 -1
- package/dist/json-schema/emit-scalar.js +54 -1
- package/dist/json-schema/emit.d.ts.map +1 -1
- package/dist/json-schema/emit.js +11 -2
- package/dist/json-schema/types.d.ts +7 -1
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/kind/index.d.ts +25 -0
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +26 -3
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +52 -3
- package/dist/message/index.d.ts +18 -0
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +67 -0
- package/dist/optimize/domain.js +6 -2
- package/dist/optimize/map-node.d.ts.map +1 -1
- package/dist/optimize/map-node.js +3 -0
- package/dist/plan/cache.js +13 -1
- package/dist/plan/predicate.d.ts.map +1 -1
- package/dist/plan/predicate.js +33 -3
- package/dist/plan/schema-predicate.d.ts.map +1 -1
- package/dist/plan/schema-predicate.js +267 -8
- package/dist/schema/freeze.js +22 -0
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/types.d.ts +89 -4
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +8 -1
- package/dist/schema/undefined.d.ts.map +1 -1
- package/dist/schema/undefined.js +5 -0
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +111 -4
- package/docs/api.md +71 -8
- package/docs/engine-notes.md +4 -0
- package/docs/index.html +1340 -722
- package/docs/ko/api.md +375 -0
- package/docs/ko/engine-notes.md +156 -0
- package/docs/ko/readme.md +378 -0
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/schema/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/schema/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH,OAAO,KAAK,EAIR,MAAM,EAET,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAK7D"}
|
package/dist/schema/validate.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @details Schema helpers enforce construction-time invariants before values reach
|
|
5
5
|
* validation, compilation, or export.
|
|
6
6
|
*/
|
|
7
|
-
import { NumberCheckTag, ObjectModeTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
7
|
+
import { ArrayCheckTag, DateCheckTag, NumberCheckTag, ObjectModeTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
8
8
|
import { isLiteralValue } from "./literal.js";
|
|
9
9
|
import { includesString, isMissingDataProperty, isObjectKeyLookup, isPlainRegExp, isRecord, isStringArray, isUnknownArray, readOwnDataProperty } from "./common.js";
|
|
10
10
|
/**
|
|
@@ -69,6 +69,8 @@ function isSchemaRecord(value, state) {
|
|
|
69
69
|
case SchemaTag.Symbol:
|
|
70
70
|
case SchemaTag.Boolean:
|
|
71
71
|
return true;
|
|
72
|
+
case SchemaTag.Date:
|
|
73
|
+
return isDateChecks(readOwnDataProperty(value, "checks"));
|
|
72
74
|
case SchemaTag.String:
|
|
73
75
|
return isStringChecks(readOwnDataProperty(value, "checks"));
|
|
74
76
|
case SchemaTag.Number:
|
|
@@ -82,11 +84,25 @@ function isSchemaRecord(value, state) {
|
|
|
82
84
|
return !isMissingDataProperty(literal) && isLiteralValue(literal);
|
|
83
85
|
}
|
|
84
86
|
case SchemaTag.Array:
|
|
85
|
-
return isSchemaValueInner(readOwnDataProperty(value, "item"), state)
|
|
87
|
+
return isSchemaValueInner(readOwnDataProperty(value, "item"), state) &&
|
|
88
|
+
isArrayChecks(readOwnDataProperty(value, "checks"));
|
|
86
89
|
case SchemaTag.Tuple:
|
|
87
|
-
return isSchemaArray(readOwnDataProperty(value, "items"), state)
|
|
90
|
+
return isSchemaArray(readOwnDataProperty(value, "items"), state) &&
|
|
91
|
+
isOptionalSchemaValue(readOwnDataProperty(value, "rest"), state);
|
|
88
92
|
case SchemaTag.Record:
|
|
89
93
|
return isSchemaValueInner(readOwnDataProperty(value, "value"), state);
|
|
94
|
+
case SchemaTag.Map:
|
|
95
|
+
return isSchemaValueInner(readOwnDataProperty(value, "key"), state) &&
|
|
96
|
+
isSchemaValueInner(readOwnDataProperty(value, "value"), state);
|
|
97
|
+
case SchemaTag.Set:
|
|
98
|
+
return isSchemaValueInner(readOwnDataProperty(value, "item"), state);
|
|
99
|
+
case SchemaTag.InstanceOf:
|
|
100
|
+
return typeof readOwnDataProperty(value, "constructor") === "function" &&
|
|
101
|
+
typeof readOwnDataProperty(value, "name") === "string";
|
|
102
|
+
case SchemaTag.Property:
|
|
103
|
+
return typeof readOwnDataProperty(value, "key") === "string" &&
|
|
104
|
+
isSchemaValueInner(readOwnDataProperty(value, "base"), state) &&
|
|
105
|
+
isSchemaValueInner(readOwnDataProperty(value, "value"), state);
|
|
90
106
|
case SchemaTag.Object:
|
|
91
107
|
return isObjectSchemaValue(value, state);
|
|
92
108
|
case SchemaTag.Union:
|
|
@@ -113,6 +129,15 @@ function isSchemaRecord(value, state) {
|
|
|
113
129
|
return false;
|
|
114
130
|
}
|
|
115
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* @brief Validate an optional schema payload.
|
|
134
|
+
* @param value Candidate child schema or undefined.
|
|
135
|
+
* @param state Recursion state for child schemas.
|
|
136
|
+
* @returns True when the value is absent or a valid schema.
|
|
137
|
+
*/
|
|
138
|
+
function isOptionalSchemaValue(value, state) {
|
|
139
|
+
return value === undefined || isSchemaValueInner(value, state);
|
|
140
|
+
}
|
|
116
141
|
/**
|
|
117
142
|
* @brief Validate the check vector attached to a string schema.
|
|
118
143
|
* @param value Candidate check vector.
|
|
@@ -149,6 +174,13 @@ function isStringChecks(value) {
|
|
|
149
174
|
}
|
|
150
175
|
break;
|
|
151
176
|
case StringCheckTag.Uuid:
|
|
177
|
+
case StringCheckTag.Email:
|
|
178
|
+
case StringCheckTag.Url:
|
|
179
|
+
case StringCheckTag.IsoDate:
|
|
180
|
+
case StringCheckTag.IsoDateTime:
|
|
181
|
+
case StringCheckTag.Ulid:
|
|
182
|
+
case StringCheckTag.Ipv4:
|
|
183
|
+
case StringCheckTag.Ipv6:
|
|
152
184
|
break;
|
|
153
185
|
default:
|
|
154
186
|
return false;
|
|
@@ -176,7 +208,47 @@ function isNumberChecks(value) {
|
|
|
176
208
|
case NumberCheckTag.Integer:
|
|
177
209
|
break;
|
|
178
210
|
case NumberCheckTag.Gte:
|
|
179
|
-
case NumberCheckTag.Lte:
|
|
211
|
+
case NumberCheckTag.Lte:
|
|
212
|
+
case NumberCheckTag.Gt:
|
|
213
|
+
case NumberCheckTag.Lt: {
|
|
214
|
+
const bound = readOwnDataProperty(check, "value");
|
|
215
|
+
if (typeof bound !== "number" || !Number.isFinite(bound)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case NumberCheckTag.MultipleOf: {
|
|
221
|
+
const divisor = readOwnDataProperty(check, "value");
|
|
222
|
+
if (typeof divisor !== "number" ||
|
|
223
|
+
!Number.isFinite(divisor) ||
|
|
224
|
+
divisor <= 0) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
default:
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* @brief Validate the check vector attached to a Date schema.
|
|
237
|
+
* @param value Candidate check vector.
|
|
238
|
+
* @returns True when every Date bound is finite epoch milliseconds.
|
|
239
|
+
*/
|
|
240
|
+
function isDateChecks(value) {
|
|
241
|
+
if (!isUnknownArray(value)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
245
|
+
const check = value[index];
|
|
246
|
+
if (!isRecord(check)) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
switch (readOwnDataProperty(check, "tag")) {
|
|
250
|
+
case DateCheckTag.Min:
|
|
251
|
+
case DateCheckTag.Max: {
|
|
180
252
|
const bound = readOwnDataProperty(check, "value");
|
|
181
253
|
if (typeof bound !== "number" || !Number.isFinite(bound)) {
|
|
182
254
|
return false;
|
|
@@ -189,6 +261,37 @@ function isNumberChecks(value) {
|
|
|
189
261
|
}
|
|
190
262
|
return true;
|
|
191
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* @brief Validate the check vector attached to an array schema.
|
|
266
|
+
* @param value Candidate check vector.
|
|
267
|
+
* @returns True when every array length bound is a non-negative integer.
|
|
268
|
+
* @details Array length checks are admitted once at schema construction so
|
|
269
|
+
* interpreters and code generators can emit direct `length` comparisons later.
|
|
270
|
+
*/
|
|
271
|
+
function isArrayChecks(value) {
|
|
272
|
+
if (!isUnknownArray(value)) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
276
|
+
const check = value[index];
|
|
277
|
+
if (!isRecord(check)) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
switch (readOwnDataProperty(check, "tag")) {
|
|
281
|
+
case ArrayCheckTag.Min:
|
|
282
|
+
case ArrayCheckTag.Max: {
|
|
283
|
+
const bound = readOwnDataProperty(check, "value");
|
|
284
|
+
if (typeof bound !== "number" || !Number.isInteger(bound) || bound < 0) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
default:
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
192
295
|
/**
|
|
193
296
|
* @brief Validate a dense vector of child schemas.
|
|
194
297
|
* @details Schema helpers enforce construction-time invariants before values reach
|
|
@@ -226,10 +329,14 @@ function isObjectSchemaValue(value, state) {
|
|
|
226
329
|
const entries = readOwnDataProperty(value, "entries");
|
|
227
330
|
const keys = readOwnDataProperty(value, "keys");
|
|
228
331
|
const keyLookup = readOwnDataProperty(value, "keyLookup");
|
|
332
|
+
const catchall = readOwnDataProperty(value, "catchall");
|
|
229
333
|
if (!isUnknownArray(entries) || !isStringArray(keys) ||
|
|
230
334
|
!isObjectKeyLookup(keyLookup, keys) || entries.length !== keys.length) {
|
|
231
335
|
return false;
|
|
232
336
|
}
|
|
337
|
+
if (catchall !== undefined && !isSchemaValueInner(catchall, state)) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
233
340
|
const seen = [];
|
|
234
341
|
for (let index = 0; index < entries.length; index += 1) {
|
|
235
342
|
const entry = entries[index];
|
package/docs/api.md
CHANGED
|
@@ -27,6 +27,7 @@ condition.
|
|
|
27
27
|
interface Guard<T> {
|
|
28
28
|
is(value: unknown): value is T;
|
|
29
29
|
check(value: unknown): CheckResult<T>;
|
|
30
|
+
checkFirst(value: unknown): CheckResult<T>;
|
|
30
31
|
assert(value: unknown): asserts value is T;
|
|
31
32
|
graph(): Graph;
|
|
32
33
|
}
|
|
@@ -36,6 +37,7 @@ interface Guard<T> {
|
|
|
36
37
|
| --- | --- | --- |
|
|
37
38
|
| `is` | Hot boolean narrowing | Avoids diagnostic allocation on the success path. |
|
|
38
39
|
| `check` | Validation with issues | Returns frozen `Result<T, Issue[]>` containers. |
|
|
40
|
+
| `checkFirst` | Hot rejection diagnostics | Returns the same frozen `Result` shape, but failure contains at most one issue. Compiled and AOT guards use a dedicated first-fault collector. |
|
|
39
41
|
| `assert` | Throwing integration boundaries | Throws `TypeSeaAssertionError` with copied, frozen issues. |
|
|
40
42
|
| `graph` | Runtime plan introspection | Returns the validated, optimized, frozen Sea-of-Nodes graph held by the validation plan. |
|
|
41
43
|
|
|
@@ -47,14 +49,19 @@ cross the API boundary.
|
|
|
47
49
|
|
|
48
50
|
| Family | Builders |
|
|
49
51
|
| --- | --- |
|
|
50
|
-
| Scalars | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.bigint`, `t.symbol`, `t.boolean` |
|
|
51
|
-
|
|
|
52
|
+
| Scalars | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.date`, `t.bigint`, `t.symbol`, `t.boolean`, `t.null`, `t.undefined`, `t.void` |
|
|
53
|
+
| String checks | `.min`, `.max`, `.length`, `.nonempty`, `.regex`, `.startsWith`, `.endsWith`, `.includes`, `.uuid`, `.email`, `.url`, `.isoDate`, `.isoDateTime`, `.ulid`, `.ipv4`, `.ipv6` |
|
|
54
|
+
| Number checks | `.int`, `.finite`, `.safe`, `.gte`, `.lte`, `.min`, `.max`, `.gt`, `.lt`, `.multipleOf`, `.positive`, `.nonnegative`, `.negative`, `.nonpositive` |
|
|
55
|
+
| Date checks | `.min`, `.max` |
|
|
56
|
+
| Literals and containers | `t.literal(value)`, `t.enum(values)`, `t.array(item)`, `t.tuple([a, b])`, `t.tuple([head], rest)`, `t.record(value)`, `t.map(key, value)`, `t.set(item)`, `t.json()` |
|
|
57
|
+
| Array checks | `.min`, `.max`, `.length`, `.nonempty` |
|
|
52
58
|
| Objects | `t.object(shape)`, `t.strictObject(shape)` |
|
|
53
|
-
| Object transforms | `t.extend`, `t.pick`, `t.omit`, `t.partial`, and matching object guard methods |
|
|
59
|
+
| Object transforms | `t.extend`, `t.safeExtend`, `t.merge`, `t.pick`, `t.omit`, `t.partial`, `t.deepPartial`, `t.required`, `t.strict`, `t.passthrough`, `t.strip`, `t.catchall`, and matching object guard methods |
|
|
60
|
+
| Runtime object contracts | `t.instanceOf(Ctor)`, `t.property(base, key, value)`, `guard.property(key, value)` |
|
|
54
61
|
| Composition | `t.union`, `t.discriminatedUnion`, `t.intersect`, `guard.intersect` |
|
|
55
|
-
| Presence | `t.optional`, `t.undefinedable`, `t.nullable` |
|
|
62
|
+
| Presence | `t.optional`, `t.undefinedable`, `t.nullable`, `t.nullish` |
|
|
56
63
|
| Dynamic guards | `t.lazy`, `t.refine` |
|
|
57
|
-
| Decoders | `t.decoder`, `t.transform`, `t.pipe`, `t.coerce` |
|
|
64
|
+
| Decoders | `t.decoder`, `t.transform`, `t.pipe`, `t.default`, `t.defaultValue`, `t.prefault`, `t.catch`, `t.codec`, `t.coerce`, `t.string.trim()`, `t.string.toLowerCase()`, `t.string.toUpperCase()` |
|
|
58
65
|
| Async decoders | `t.asyncDecoder`, `t.asyncRefine`, `t.asyncTransform`, `t.asyncPipe` |
|
|
59
66
|
|
|
60
67
|
Builder functions validate inputs before a schema can enter the validation plan,
|
|
@@ -80,6 +87,8 @@ const Shape = t.object({
|
|
|
80
87
|
- `name` may be absent. If `name` exists, its value must be a string.
|
|
81
88
|
- `nickname` must be present. Its value may be a string or `undefined`.
|
|
82
89
|
- `t.nullable(inner)` adds `null` to the value domain.
|
|
90
|
+
- `t.nullish(inner)` combines nullable value semantics with optional object-key
|
|
91
|
+
presence.
|
|
83
92
|
- Presence-preserving wrappers keep optional-key semantics through `nullable`,
|
|
84
93
|
`undefinedable`, `brand`, and `refine`.
|
|
85
94
|
|
|
@@ -87,6 +96,18 @@ Object combinators preserve object mode. Strict object guards remain strict
|
|
|
87
96
|
after `extend`, `pick`, `omit`, or `partial`; passthrough object guards keep
|
|
88
97
|
allowing unknown keys.
|
|
89
98
|
|
|
99
|
+
`catchall(schema)` validates every undeclared own key with `schema`.
|
|
100
|
+
`strip()` is validation-only in TypeSea: guards return the original value, so it
|
|
101
|
+
has the same validation behavior as `passthrough()`.
|
|
102
|
+
`pick` and `omit` accept either key arrays or Zod-style `{ key: true }` masks.
|
|
103
|
+
`deepPartial()` recursively partializes pure object, array, tuple, tuple rest,
|
|
104
|
+
record, map, set, property, union, intersection, nullable, undefinedable,
|
|
105
|
+
optional, and brand schemas. Lazy and refinement schemas are semantic barriers.
|
|
106
|
+
|
|
107
|
+
`property` validates only own data descriptors. It is useful for class instances
|
|
108
|
+
with stable fields; prototype getters and accessor-backed properties are rejected
|
|
109
|
+
instead of executed.
|
|
110
|
+
|
|
90
111
|
## Composition
|
|
91
112
|
|
|
92
113
|
`t.union(a, b)` accepts a value that satisfies at least one branch.
|
|
@@ -125,6 +146,16 @@ lazy chain must eventually resolve to a concrete non-lazy schema.
|
|
|
125
146
|
```ts
|
|
126
147
|
const Count = t.pipe(t.coerce.number(), t.number.int().gte(0));
|
|
127
148
|
const result = Count.decode("42");
|
|
149
|
+
|
|
150
|
+
const Name = t.default(t.string.min(1), "anonymous");
|
|
151
|
+
const NumberText = t.codec(
|
|
152
|
+
t.string.regex(/^\d+$/u, "digits"),
|
|
153
|
+
t.number.int().nonnegative(),
|
|
154
|
+
{
|
|
155
|
+
decode: (value) => Number(value),
|
|
156
|
+
encode: (value) => String(value)
|
|
157
|
+
}
|
|
158
|
+
);
|
|
128
159
|
```
|
|
129
160
|
|
|
130
161
|
Decoders are for output-producing operations. They return `Result` from
|
|
@@ -134,8 +165,15 @@ not be the same runtime value as the input.
|
|
|
134
165
|
- `t.transform(source, mapper)` decodes `source`, then maps the decoded value.
|
|
135
166
|
- `t.pipe(source, next)` feeds a successful decoded value into the next guard or
|
|
136
167
|
decoder.
|
|
168
|
+
- `t.default(source, value)` returns a fallback output for `undefined` input.
|
|
169
|
+
- `t.prefault(source, value)` feeds a fallback input through the source.
|
|
170
|
+
- `t.codec(input, output, mapping)` validates both sides of a bidirectional
|
|
171
|
+
decode/encode pair.
|
|
137
172
|
- `t.coerce.string`, `t.coerce.number`, and `t.coerce.boolean` provide explicit
|
|
138
173
|
primitive coercion.
|
|
174
|
+
- `t.string.trim()`, `t.string.toLowerCase()`, and `t.string.toUpperCase()`
|
|
175
|
+
are decoder helpers. They validate the string first, then return transformed
|
|
176
|
+
output from `decode()`.
|
|
139
177
|
- `t.asyncRefine`, `t.asyncTransform`, and `t.asyncPipe` return
|
|
140
178
|
`Promise<Result<T, Issue[]>>` from `decodeAsync()`.
|
|
141
179
|
|
|
@@ -152,14 +190,16 @@ const checked = withMessages(User.check(input), {
|
|
|
152
190
|
});
|
|
153
191
|
```
|
|
154
192
|
|
|
155
|
-
`formatIssue`, `formatIssues`, and `withMessages` render
|
|
156
|
-
validation has finished. This keeps `is()` and ordinary
|
|
157
|
-
message allocation.
|
|
193
|
+
`formatIssue`, `formatIssues`, `flattenIssues`, and `withMessages` render
|
|
194
|
+
diagnostics after validation has finished. This keeps `is()` and ordinary
|
|
195
|
+
`check()` paths free from message allocation.
|
|
158
196
|
|
|
159
197
|
Built-in locales are `en` and `ko`. Custom catalogs can use string templates
|
|
160
198
|
with `{path}`, `{code}`, `{expected}`, and `{actual}`, or formatter callbacks.
|
|
161
199
|
`withMessages(result, options)` preserves successful results and returns a new
|
|
162
200
|
failed `Result` with copied, frozen issues whose `message` fields are populated.
|
|
201
|
+
`flattenIssues(issues, options)` groups rendered messages into `formErrors` and
|
|
202
|
+
top-level `fieldErrors` buckets.
|
|
163
203
|
|
|
164
204
|
## Runtime Compile
|
|
165
205
|
|
|
@@ -270,6 +310,28 @@ const resolver = toReactHookFormResolver(User);
|
|
|
270
310
|
Adapters are structural and zero-dependency. TypeSea does not import tRPC,
|
|
271
311
|
Fastify, or React Hook Form.
|
|
272
312
|
|
|
313
|
+
Compiled guards can be passed to the same adapters. This is the preferred shape
|
|
314
|
+
for hot request paths: compile once during startup, then let the adapter reuse
|
|
315
|
+
the generated predicate.
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
const FastUser = compile(User);
|
|
319
|
+
const fastParser = toTrpcParser(FastUser);
|
|
320
|
+
const fastValidatorCompiler = toFastifyValidatorCompiler(FastUser);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Use the default compiled mode at public input boundaries. For trusted,
|
|
324
|
+
already-normalized internal data, the faster modes can be wired through adapters
|
|
325
|
+
the same way.
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
const UnsafeUser = compile(User, { mode: "unsafe" });
|
|
329
|
+
const internalParser = toTrpcParser(UnsafeUser);
|
|
330
|
+
|
|
331
|
+
const TrustedShapeUser = compile(User, { mode: "unchecked" });
|
|
332
|
+
const internalValidatorCompiler = toFastifyValidatorCompiler(TrustedShapeUser);
|
|
333
|
+
```
|
|
334
|
+
|
|
273
335
|
| Adapter | Export | Behavior |
|
|
274
336
|
| --- | --- | --- |
|
|
275
337
|
| tRPC | `toTrpcParser`, `toAsyncTrpcParser` | Return parser objects that emit decoded values or throw `TypeSeaAssertionError`. |
|
|
@@ -314,6 +376,7 @@ Runtime-only concepts return explicit export issues:
|
|
|
314
376
|
- `undefined`
|
|
315
377
|
- `bigint`
|
|
316
378
|
- `symbol`
|
|
379
|
+
- JavaScript `Date`, `Map`, `Set`, `instanceOf`, and `property` contracts
|
|
317
380
|
- `lazy`
|
|
318
381
|
- `refine`
|
|
319
382
|
- decoder transforms
|
package/docs/engine-notes.md
CHANGED
|
@@ -154,6 +154,10 @@ still checking the original object fields on the outer frame.
|
|
|
154
154
|
Compiled `lazy` and `refine` fallbacks use the same IR-backed runtime path, so
|
|
155
155
|
recursive behavior stays consistent across execution engines.
|
|
156
156
|
|
|
157
|
+
`checkFirst()` has a separate generated collector. It returns one frozen issue
|
|
158
|
+
as soon as the first diagnostic is known, instead of running the full `check()`
|
|
159
|
+
collector and truncating its issue array.
|
|
160
|
+
|
|
157
161
|
## JSON Schema Export
|
|
158
162
|
|
|
159
163
|
JSON Schema export succeeds only when the TypeSea schema can be represented over
|