@oh-my-pi/omptype 17.2.7 → 17.2.8
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 +23 -0
- package/dist/js/compile.js +414 -219
- package/dist/js/errors.js +236 -41
- package/dist/js/from-json-schema.js +234 -0
- package/dist/js/index.js +1 -0
- package/dist/js/interp.js +514 -132
- package/dist/js/ir.js +972 -202
- package/dist/js/json-schema.js +73 -34
- package/dist/js/keywords.js +108 -1
- package/dist/js/type.js +2156 -172
- package/dist/js/typebox.js +41 -32
- package/dist/js/zod.js +2 -2
- package/dist/types/compile.d.ts +1 -1
- package/dist/types/errors.d.ts +19 -18
- package/dist/types/from-json-schema.d.ts +9 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/infer.d.ts +45 -6
- package/dist/types/interp.d.ts +9 -2
- package/dist/types/ir.d.ts +57 -6
- package/dist/types/json-schema.d.ts +10 -1
- package/dist/types/type.d.ts +324 -48
- package/dist/types/typebox.d.ts +78 -50
- package/package.json +5 -1
- package/src/compile.ts +598 -243
- package/src/errors.ts +247 -49
- package/src/from-json-schema.ts +231 -0
- package/src/index.ts +1 -0
- package/src/infer.ts +107 -32
- package/src/interp.ts +457 -118
- package/src/ir.ts +981 -212
- package/src/json-schema.ts +82 -34
- package/src/keywords.ts +111 -1
- package/src/type.ts +2760 -271
- package/src/typebox.ts +141 -98
- package/src/zod.ts +1 -1
package/src/typebox.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OmpTypeError } from "./errors";
|
|
2
|
-
import type { Def } from "./ir";
|
|
3
|
-
import { type NarrowContext, type Type as OmpType, type } from "./type";
|
|
2
|
+
import type { Def, EmbeddableSchema } from "./ir";
|
|
3
|
+
import { type NarrowContext, type Type as OmpType, type ToJsonSchemaOptions, type } from "./type";
|
|
4
4
|
|
|
5
5
|
export interface Meta {
|
|
6
6
|
title?: string;
|
|
@@ -32,7 +32,7 @@ export interface ArrayOpts extends Meta {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export interface ObjectOpts extends Meta {
|
|
35
|
-
additionalProperties?: boolean |
|
|
35
|
+
additionalProperties?: boolean | AnySchema;
|
|
36
36
|
}
|
|
37
37
|
const OPTIONAL_INNER = Symbol("omptype.typebox.optionalInner");
|
|
38
38
|
const OBJECT_INFO = Symbol("omptype.typebox.objectInfo");
|
|
@@ -52,53 +52,84 @@ interface LegacyTypeBoxCompat<T> {
|
|
|
52
52
|
safeParse(input: unknown): TypeBoxSafeParseResult<T>;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Erased schema surface accepted anywhere this facade takes a schema, native
|
|
57
|
+
* omptype schemas included (those carry no legacy compat members).
|
|
58
|
+
*
|
|
59
|
+
* Members use method syntax so parameter positions stay bivariant: the typed
|
|
60
|
+
* {@link TTyped} form is invariant in its static type (its `in`/`out`
|
|
61
|
+
* validators are), so a concrete `TString` is not assignable to
|
|
62
|
+
* `TTyped<unknown>`. Erasing here is what keeps `TString`, `TObject<…>` and
|
|
63
|
+
* friends assignable to a plain schema annotation.
|
|
64
|
+
*/
|
|
65
|
+
export interface AnySchema extends EmbeddableSchema {
|
|
66
|
+
(data: unknown): unknown;
|
|
67
|
+
readonly infer: unknown;
|
|
68
|
+
readonly hasSteps: boolean;
|
|
69
|
+
toJsonSchema(options?: ToJsonSchemaOptions): Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Every schema this facade returns: the TypeBox `TSchema` analog. Erased like
|
|
74
|
+
* {@link AnySchema}, plus the legacy compat members builder results carry.
|
|
75
|
+
*/
|
|
76
|
+
export interface TSchema extends AnySchema {
|
|
77
|
+
/** TypeBox compatibility validator used by legacy extension loaders. */
|
|
78
|
+
__validator(data: unknown): unknown;
|
|
79
|
+
/** Zod-style compatibility parser used by legacy extensions. */
|
|
80
|
+
safeParse(input: unknown): TypeBoxSafeParseResult<unknown>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Schema carrying a statically known type; every `TXxx` alias resolves here. */
|
|
84
|
+
export type TTyped<T> = OmpType<T> & LegacyTypeBoxCompat<T>;
|
|
85
|
+
export type Static<T extends AnySchema> = T["infer"];
|
|
86
|
+
export type TAny = TTyped<unknown>;
|
|
87
|
+
export type TUnknown = TTyped<unknown>;
|
|
88
|
+
export type TNever = TTyped<never>;
|
|
89
|
+
export type TNull = TTyped<null>;
|
|
90
|
+
export type TString = TTyped<string>;
|
|
91
|
+
export type TNumber = TTyped<number>;
|
|
92
|
+
export type TInteger = TTyped<number>;
|
|
93
|
+
export type TBoolean = TTyped<boolean>;
|
|
94
|
+
export type TLiteral<V extends string | number | boolean | null> = TTyped<V>;
|
|
95
|
+
export type TArray<E extends AnySchema> = TTyped<Static<E>[]>;
|
|
96
|
+
export type TTuple<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<{
|
|
68
97
|
-readonly [K in keyof E]: Static<E[K]>;
|
|
69
98
|
}>;
|
|
70
|
-
export type TOptional<E extends
|
|
71
|
-
export type TUnion<E extends readonly
|
|
72
|
-
export type TIntersect<E extends readonly
|
|
99
|
+
export type TOptional<E extends AnySchema> = TTyped<Static<E> | undefined> & { readonly [OPTIONAL_INNER]: E };
|
|
100
|
+
export type TUnion<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<Static<E[number]>>;
|
|
101
|
+
export type TIntersect<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<
|
|
73
102
|
UnionToIntersection<Static<E[number]>>
|
|
74
103
|
>;
|
|
75
|
-
export type TEnum<E extends readonly (string | number)[] = readonly (string | number)[]> =
|
|
76
|
-
export type TRecord<K extends
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
export type
|
|
80
|
-
|
|
81
|
-
type
|
|
82
|
-
|
|
104
|
+
export type TEnum<E extends readonly (string | number)[] = readonly (string | number)[]> = TTyped<E[number]>;
|
|
105
|
+
export type TRecord<K extends AnySchema, V extends AnySchema> = TTyped<
|
|
106
|
+
Record<Extract<Static<K>, PropertyKey>, Static<V>>
|
|
107
|
+
>;
|
|
108
|
+
export type TNullable<E extends AnySchema> = TTyped<Static<E> | null>;
|
|
109
|
+
export type TReadonly<E extends AnySchema> = TTyped<Readonly<Static<E>>>;
|
|
110
|
+
export type TUnsafe<T = unknown> = TTyped<T>;
|
|
111
|
+
|
|
112
|
+
type OptionalKeys<P extends Record<string, AnySchema>> = {
|
|
113
|
+
[K in keyof P]-?: P[K] extends { readonly [OPTIONAL_INNER]: AnySchema } ? K : never;
|
|
83
114
|
}[keyof P];
|
|
84
|
-
type RequiredKeys<P extends Record<string,
|
|
85
|
-
type ObjectStatic<P extends Record<string,
|
|
115
|
+
type RequiredKeys<P extends Record<string, AnySchema>> = Exclude<keyof P, OptionalKeys<P>>;
|
|
116
|
+
type ObjectStatic<P extends Record<string, AnySchema>> = {
|
|
86
117
|
[K in RequiredKeys<P>]: Static<P[K]>;
|
|
87
118
|
} & {
|
|
88
119
|
[K in OptionalKeys<P>]?: Exclude<Static<P[K]>, undefined>;
|
|
89
120
|
};
|
|
90
|
-
export type TObject<P extends Record<string,
|
|
91
|
-
type RequiredProps<P extends Record<string,
|
|
121
|
+
export type TObject<P extends Record<string, AnySchema> = Record<string, AnySchema>> = TTyped<ObjectStatic<P>>;
|
|
122
|
+
type RequiredProps<P extends Record<string, AnySchema>> = {
|
|
92
123
|
[K in keyof P]: P[K] extends TOptional<infer E> ? E : P[K];
|
|
93
124
|
};
|
|
94
125
|
|
|
95
126
|
interface RuntimeType<T> extends OmpType<T> {
|
|
96
|
-
[OPTIONAL_INNER]?:
|
|
127
|
+
[OPTIONAL_INNER]?: AnySchema;
|
|
97
128
|
[OBJECT_INFO]?: ObjectInfo;
|
|
98
129
|
describe(description: string): RuntimeType<T>;
|
|
99
130
|
default(value: T | (() => T)): RuntimeType<T>;
|
|
100
|
-
or<
|
|
101
|
-
and<
|
|
131
|
+
or<schema extends AnySchema>(schema: schema): RuntimeType<T | Static<schema>>;
|
|
132
|
+
and<schema extends AnySchema>(schema: schema): RuntimeType<T & Static<schema>>;
|
|
102
133
|
array(): RuntimeType<T[]>;
|
|
103
134
|
atLeastLength(bound: number): RuntimeType<T>;
|
|
104
135
|
atMostLength(bound: number): RuntimeType<T>;
|
|
@@ -109,7 +140,18 @@ interface RuntimeType<T> extends OmpType<T> {
|
|
|
109
140
|
}
|
|
110
141
|
type CompatRuntime<T> = RuntimeType<T> & LegacyTypeBoxCompat<T>;
|
|
111
142
|
|
|
112
|
-
type ObjectInfo = {
|
|
143
|
+
type ObjectInfo = {
|
|
144
|
+
props: Record<string, AnySchema>;
|
|
145
|
+
additionalProperties?: boolean | AnySchema;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function asRuntime<T>(schema: AnySchema): RuntimeType<T> {
|
|
149
|
+
return schema as unknown as RuntimeType<T>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function asSchema<T>(schema: AnySchema): TTyped<T> {
|
|
153
|
+
return schema as unknown as TTyped<T>;
|
|
154
|
+
}
|
|
113
155
|
|
|
114
156
|
function validationFailure(message: string): TypeBoxValidationFailure {
|
|
115
157
|
return { message };
|
|
@@ -161,9 +203,7 @@ function checkFiniteOption(name: string, value: number | undefined): void {
|
|
|
161
203
|
function tString(opts?: StringOpts): TString {
|
|
162
204
|
checkFiniteOption("minLength", opts?.minLength);
|
|
163
205
|
checkFiniteOption("maxLength", opts?.maxLength);
|
|
164
|
-
let schema = type.raw(
|
|
165
|
-
opts?.format === "url" || opts?.format === "uri" ? "string.url" : "string",
|
|
166
|
-
) as RuntimeType<string>;
|
|
206
|
+
let schema = asRuntime<string>(type.raw(opts?.format === "url" || opts?.format === "uri" ? "string.url" : "string"));
|
|
167
207
|
if (opts?.minLength !== undefined) schema = schema.atLeastLength(opts.minLength);
|
|
168
208
|
if (opts?.maxLength !== undefined) schema = schema.atMostLength(opts.maxLength);
|
|
169
209
|
if (opts?.pattern !== undefined) {
|
|
@@ -229,7 +269,7 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
|
|
|
229
269
|
const keyword = integer ? "number.integer" : "number";
|
|
230
270
|
const lowerDsl = lower ? `${lower.value} ${lower.exclusive ? "<" : "<="} ` : "";
|
|
231
271
|
const upperDsl = upper ? ` ${upper.exclusive ? "<" : "<="} ${upper.value}` : "";
|
|
232
|
-
let schema = type.raw(`${lowerDsl}${keyword}${upperDsl}`)
|
|
272
|
+
let schema = asRuntime<number>(type.raw(`${lowerDsl}${keyword}${upperDsl}`));
|
|
233
273
|
if (opts?.multipleOf !== undefined) {
|
|
234
274
|
const divisor = opts.multipleOf;
|
|
235
275
|
schema = schema.narrow((value, ctx) => {
|
|
@@ -244,33 +284,32 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
|
|
|
244
284
|
}
|
|
245
285
|
|
|
246
286
|
function tLiteral<const V extends string | number | boolean | null>(value: V, opts?: Meta): TLiteral<V> {
|
|
247
|
-
return applyMeta(type.enumerated(value)
|
|
287
|
+
return applyMeta(asRuntime<V>(type.enumerated(value)), opts);
|
|
248
288
|
}
|
|
249
289
|
|
|
250
290
|
function tNever(opts?: Meta): TNever {
|
|
251
291
|
return applyMeta(
|
|
252
|
-
(type.raw("unknown")
|
|
292
|
+
asRuntime<unknown>(type.raw("unknown")).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
|
|
253
293
|
opts,
|
|
254
294
|
);
|
|
255
295
|
}
|
|
256
296
|
|
|
257
|
-
function tUnion<const E extends readonly
|
|
258
|
-
if (schemas.length === 0) return tNever(opts)
|
|
259
|
-
let result = schemas[0]
|
|
297
|
+
function tUnion<const E extends readonly AnySchema[]>(schemas: E, opts?: Meta): TUnion<E> {
|
|
298
|
+
if (schemas.length === 0) return asSchema<Static<E[number]>>(tNever(opts));
|
|
299
|
+
let result = asRuntime<unknown>(schemas[0]);
|
|
260
300
|
for (let i = 1; i < schemas.length; i++) result = result.or(schemas[i]);
|
|
261
|
-
return applyMeta(result, opts)
|
|
301
|
+
return asSchema<Static<E[number]>>(applyMeta(result, opts));
|
|
262
302
|
}
|
|
263
303
|
|
|
264
|
-
function tIntersect<const E extends readonly
|
|
304
|
+
function tIntersect<const E extends readonly AnySchema[]>(
|
|
265
305
|
schemas: E,
|
|
266
306
|
opts?: Meta,
|
|
267
|
-
):
|
|
268
|
-
if (schemas.length === 0)
|
|
269
|
-
return applyMeta(type.raw("unknown")
|
|
270
|
-
|
|
271
|
-
>;
|
|
307
|
+
): TTyped<UnionToIntersection<Static<E[number]>>> {
|
|
308
|
+
if (schemas.length === 0) {
|
|
309
|
+
return applyMeta(asRuntime<UnionToIntersection<Static<E[number]>>>(type.raw("unknown")), opts);
|
|
310
|
+
}
|
|
272
311
|
const validateAll = (): RuntimeType<UnionToIntersection<Static<E[number]>>> => {
|
|
273
|
-
const base = type.raw("unknown")
|
|
312
|
+
const base = asRuntime<unknown>(type.raw("unknown"));
|
|
274
313
|
return base.narrow((value, ctx): value is UnionToIntersection<Static<E[number]>> => {
|
|
275
314
|
for (const schema of schemas) {
|
|
276
315
|
if (schema(value) instanceof type.errors) return ctx.mustBe("a value satisfying every intersection member");
|
|
@@ -279,14 +318,14 @@ function tIntersect<const E extends readonly TSchema[]>(
|
|
|
279
318
|
});
|
|
280
319
|
};
|
|
281
320
|
if (schemas.some(schema => schema.hasSteps)) return applyMeta(validateAll(), opts);
|
|
282
|
-
let result = schemas[0]
|
|
321
|
+
let result = asRuntime<unknown>(schemas[0]);
|
|
283
322
|
try {
|
|
284
323
|
for (let i = 1; i < schemas.length; i++) result = result.and(schemas[i]);
|
|
285
324
|
} catch (error) {
|
|
286
325
|
if (error instanceof OmpTypeError) return applyMeta(validateAll(), opts);
|
|
287
326
|
throw error;
|
|
288
327
|
}
|
|
289
|
-
return
|
|
328
|
+
return asSchema<UnionToIntersection<Static<E[number]>>>(applyMeta(result, opts));
|
|
290
329
|
}
|
|
291
330
|
type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void
|
|
292
331
|
? I
|
|
@@ -306,16 +345,17 @@ function enumValues(values: Record<string, string | number> | readonly (string |
|
|
|
306
345
|
function tEnum<const E extends Record<string, string | number> | readonly (string | number)[]>(
|
|
307
346
|
values: E,
|
|
308
347
|
opts?: Meta,
|
|
309
|
-
):
|
|
310
|
-
return applyMeta(
|
|
311
|
-
E extends readonly (infer V)[] ? V : E[keyof E]
|
|
312
|
-
|
|
348
|
+
): TTyped<E extends readonly (infer V)[] ? V : E[keyof E]> {
|
|
349
|
+
return applyMeta(
|
|
350
|
+
asRuntime<E extends readonly (infer V)[] ? V : E[keyof E]>(type.enumerated(...enumValues(values))),
|
|
351
|
+
opts,
|
|
352
|
+
);
|
|
313
353
|
}
|
|
314
354
|
|
|
315
|
-
function tArray<E extends
|
|
355
|
+
function tArray<E extends AnySchema>(item: E, opts?: ArrayOpts): TArray<E> {
|
|
316
356
|
checkFiniteOption("minItems", opts?.minItems);
|
|
317
357
|
checkFiniteOption("maxItems", opts?.maxItems);
|
|
318
|
-
let schema =
|
|
358
|
+
let schema = asRuntime<Static<E>>(item).array();
|
|
319
359
|
if (opts?.minItems !== undefined) schema = schema.atLeastLength(opts.minItems);
|
|
320
360
|
if (opts?.maxItems !== undefined) schema = schema.atMostLength(opts.maxItems);
|
|
321
361
|
if (opts?.uniqueItems) {
|
|
@@ -342,8 +382,8 @@ function jsonEqual(left: unknown, right: unknown): boolean {
|
|
|
342
382
|
}
|
|
343
383
|
}
|
|
344
384
|
|
|
345
|
-
function tTuple<const E extends readonly
|
|
346
|
-
const schema = (type.raw("unknown")
|
|
385
|
+
function tTuple<const E extends readonly AnySchema[]>(items: E, opts?: Meta): TTuple<E> {
|
|
386
|
+
const schema = asRuntime<unknown>(type.raw("unknown")).narrow(
|
|
347
387
|
(value, ctx): value is { -readonly [K in keyof E]: Static<E[K]> } => {
|
|
348
388
|
if (!Array.isArray(value) || value.length !== items.length)
|
|
349
389
|
return ctx.mustBe(`a tuple of length ${items.length}`);
|
|
@@ -355,25 +395,29 @@ function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTup
|
|
|
355
395
|
return applyMeta(schema, opts);
|
|
356
396
|
}
|
|
357
397
|
|
|
358
|
-
function tObject<const P extends Record<string,
|
|
398
|
+
function tObject<const P extends Record<string, AnySchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
|
|
359
399
|
const def: Record<string, Def> = {};
|
|
360
|
-
const props: Record<string,
|
|
400
|
+
const props: Record<string, AnySchema> = {};
|
|
361
401
|
for (const key in properties) {
|
|
362
402
|
const schema = properties[key];
|
|
363
|
-
const inner =
|
|
364
|
-
|
|
403
|
+
const inner = asRuntime<unknown>(schema)[OPTIONAL_INNER];
|
|
404
|
+
// A defaulted `Type.Optional(...)` maps to a plain defaulted key:
|
|
405
|
+
// omptype (like ArkType) rejects `key?` with a default, and a default
|
|
406
|
+
// already makes the key omittable on input.
|
|
407
|
+
const optionalKey = inner !== undefined && !asRuntime<unknown>(inner).hasDefault;
|
|
408
|
+
def[optionalKey ? `${key}?` : key] = inner ?? schema;
|
|
365
409
|
props[key] = schema;
|
|
366
410
|
}
|
|
367
411
|
if (opts?.additionalProperties === false) def["+"] = "reject";
|
|
368
412
|
else if (opts?.additionalProperties && opts.additionalProperties !== true)
|
|
369
|
-
def["[string]"] = opts.additionalProperties
|
|
370
|
-
const schema = applyMeta(type.raw(def)
|
|
413
|
+
def["[string]"] = opts.additionalProperties;
|
|
414
|
+
const schema = applyMeta(asRuntime<ObjectStatic<P>>(type.raw(def)), opts);
|
|
371
415
|
schema[OBJECT_INFO] = { props, additionalProperties: opts?.additionalProperties };
|
|
372
416
|
return schema;
|
|
373
417
|
}
|
|
374
418
|
|
|
375
|
-
function tRecord<K extends
|
|
376
|
-
const base = (type.raw({ "[string]": value })
|
|
419
|
+
function tRecord<K extends AnySchema, V extends AnySchema>(key: K, value: V, opts?: Meta): TRecord<K, V> {
|
|
420
|
+
const base = asRuntime<Record<string, Static<V>>>(type.raw({ "[string]": value })).narrow((record, ctx) => {
|
|
377
421
|
for (const name in record)
|
|
378
422
|
if (key(name) instanceof type.errors) return ctx.mustBe("an object with valid record keys");
|
|
379
423
|
return true;
|
|
@@ -381,72 +425,70 @@ function tRecord<K extends TSchema, V extends TSchema>(key: K, value: V, opts?:
|
|
|
381
425
|
return applyMeta(base, opts) as TRecord<K, V>;
|
|
382
426
|
}
|
|
383
427
|
|
|
384
|
-
function tOptional<E extends
|
|
428
|
+
function tOptional<E extends AnySchema>(schema: E, opts?: Meta): TOptional<E> {
|
|
385
429
|
const marker = applyMeta(
|
|
386
|
-
|
|
430
|
+
asRuntime<Static<E>>(schema).or(asRuntime<undefined>(type.raw("undefined"))),
|
|
387
431
|
opts,
|
|
388
432
|
) as RuntimeType<Static<E> | undefined>;
|
|
389
433
|
marker[OPTIONAL_INNER] = schema;
|
|
390
434
|
return marker as unknown as TOptional<E>;
|
|
391
435
|
}
|
|
392
436
|
|
|
393
|
-
function tNullable<E extends
|
|
394
|
-
return applyMeta(
|
|
437
|
+
function tNullable<E extends AnySchema>(schema: E, opts?: Meta): TTyped<Static<E> | null> {
|
|
438
|
+
return applyMeta(asRuntime<Static<E>>(schema).or(asRuntime<null>(type.raw("null"))), opts);
|
|
395
439
|
}
|
|
396
440
|
|
|
397
|
-
function requireObject(schema:
|
|
398
|
-
const info =
|
|
441
|
+
function requireObject(schema: AnySchema, operation: string): ObjectInfo {
|
|
442
|
+
const info = asRuntime<unknown>(schema)[OBJECT_INFO];
|
|
399
443
|
if (!info) throw new OmpTypeError(`Type.${operation} requires a schema created by Type.Object`);
|
|
400
444
|
return info;
|
|
401
445
|
}
|
|
402
446
|
|
|
403
|
-
function tPartial<P extends Record<string,
|
|
447
|
+
function tPartial<P extends Record<string, AnySchema>>(schema: TObject<P>): TTyped<Partial<ObjectStatic<P>>> {
|
|
404
448
|
const info = requireObject(schema, "Partial");
|
|
405
|
-
const props: Record<string,
|
|
449
|
+
const props: Record<string, AnySchema> = {};
|
|
406
450
|
for (const key in info.props)
|
|
407
|
-
props[key] = (info.props[key]
|
|
408
|
-
|
|
409
|
-
: tOptional(info.props[key]);
|
|
410
|
-
return tObject(props, { additionalProperties: info.additionalProperties }) as TSchema<Partial<ObjectStatic<P>>>;
|
|
451
|
+
props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ? info.props[key] : tOptional(info.props[key]);
|
|
452
|
+
return tObject(props, { additionalProperties: info.additionalProperties }) as TTyped<Partial<ObjectStatic<P>>>;
|
|
411
453
|
}
|
|
412
454
|
|
|
413
|
-
function tRequired<P extends Record<string,
|
|
455
|
+
function tRequired<P extends Record<string, AnySchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
|
|
414
456
|
const info = requireObject(schema, "Required");
|
|
415
|
-
const props: Record<string,
|
|
457
|
+
const props: Record<string, AnySchema> = {};
|
|
416
458
|
for (const key in info.props) {
|
|
417
|
-
props[key] = (info.props[key]
|
|
459
|
+
props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ?? info.props[key];
|
|
418
460
|
}
|
|
419
461
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<RequiredProps<P>>;
|
|
420
462
|
}
|
|
421
463
|
|
|
422
|
-
function tPick<P extends Record<string,
|
|
464
|
+
function tPick<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
|
|
423
465
|
schema: TObject<P>,
|
|
424
466
|
keys: K,
|
|
425
467
|
): TObject<Pick<P, K[number]>> {
|
|
426
468
|
const info = requireObject(schema, "Pick");
|
|
427
|
-
const props: Record<string,
|
|
469
|
+
const props: Record<string, AnySchema> = {};
|
|
428
470
|
for (const key of keys) if (typeof key === "string" && info.props[key]) props[key] = info.props[key];
|
|
429
471
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Pick<P, K[number]>>;
|
|
430
472
|
}
|
|
431
473
|
|
|
432
|
-
function tOmit<P extends Record<string,
|
|
474
|
+
function tOmit<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
|
|
433
475
|
schema: TObject<P>,
|
|
434
476
|
keys: K,
|
|
435
477
|
): TObject<Omit<P, K[number]>> {
|
|
436
478
|
const info = requireObject(schema, "Omit");
|
|
437
479
|
const omitted = new Set<PropertyKey>(keys);
|
|
438
|
-
const props: Record<string,
|
|
480
|
+
const props: Record<string, AnySchema> = {};
|
|
439
481
|
for (const key in info.props) if (!omitted.has(key)) props[key] = info.props[key];
|
|
440
482
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Omit<P, K[number]>>;
|
|
441
483
|
}
|
|
442
484
|
|
|
443
|
-
function tComposite<const E extends readonly TObject<Record<string,
|
|
485
|
+
function tComposite<const E extends readonly TObject<Record<string, AnySchema>>[]>(
|
|
444
486
|
schemas: E,
|
|
445
487
|
opts?: ObjectOpts,
|
|
446
|
-
):
|
|
447
|
-
const props: Record<string,
|
|
488
|
+
): TTyped<UnionToIntersection<Static<E[number]>>> {
|
|
489
|
+
const props: Record<string, AnySchema> = {};
|
|
448
490
|
for (const schema of schemas) Object.assign(props, requireObject(schema, "Composite").props);
|
|
449
|
-
return
|
|
491
|
+
return asSchema<UnionToIntersection<Static<E[number]>>>(tObject(props, opts));
|
|
450
492
|
}
|
|
451
493
|
|
|
452
494
|
function tUnsafe<T = unknown>(_jsonSchema: Record<string, unknown> = {}): TUnsafe<T> {
|
|
@@ -459,10 +501,10 @@ export const Type = {
|
|
|
459
501
|
String: tString,
|
|
460
502
|
Number: (opts?: NumberOpts) => tNumber(opts),
|
|
461
503
|
Integer: (opts?: NumberOpts) => tNumber(opts, true),
|
|
462
|
-
Boolean: (opts?: Meta) => applyMeta(type.raw("boolean")
|
|
463
|
-
Null: (opts?: Meta) => applyMeta(type.raw("null")
|
|
464
|
-
Any: (opts?: Meta) => applyMeta(type.raw("unknown")
|
|
465
|
-
Unknown: (opts?: Meta) => applyMeta(type.raw("unknown")
|
|
504
|
+
Boolean: (opts?: Meta) => applyMeta(asRuntime<boolean>(type.raw("boolean")), opts),
|
|
505
|
+
Null: (opts?: Meta) => applyMeta(asRuntime<null>(type.raw("null")), opts),
|
|
506
|
+
Any: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
|
|
507
|
+
Unknown: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
|
|
466
508
|
Never: tNever,
|
|
467
509
|
Literal: tLiteral,
|
|
468
510
|
Union: tUnion,
|
|
@@ -474,7 +516,8 @@ export const Type = {
|
|
|
474
516
|
Record: tRecord,
|
|
475
517
|
Optional: tOptional,
|
|
476
518
|
Nullable: tNullable,
|
|
477
|
-
Readonly: <E extends
|
|
519
|
+
Readonly: <E extends AnySchema>(schema: E): TReadonly<E> =>
|
|
520
|
+
asSchema<Readonly<Static<E>>>(withLegacyCompat(asRuntime<Readonly<Static<E>>>(schema))),
|
|
478
521
|
Partial: tPartial,
|
|
479
522
|
Required: tRequired,
|
|
480
523
|
Pick: tPick,
|
package/src/zod.ts
CHANGED
|
@@ -71,7 +71,7 @@ function restrictBase<Out>(source: Decoratable<Out>, ir: IR): Decoratable<Out> {
|
|
|
71
71
|
let next = source.hasSteps
|
|
72
72
|
? schemaFromIR<Out>({ k: "morph", input: ir, fn: value => source(value) })
|
|
73
73
|
: schemaFromIR<Out>(ir);
|
|
74
|
-
if (source.
|
|
74
|
+
if (source.ir.desc !== undefined) next = next.describe(source.ir.desc);
|
|
75
75
|
if (source.hasDefault) next = next.default(source.defaultValue as Out | (() => Out));
|
|
76
76
|
return next;
|
|
77
77
|
}
|