@oh-my-pi/omptype 17.2.7 → 17.2.9
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 +29 -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 +56 -34
- 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 +153 -100
- 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) {
|
|
@@ -227,9 +267,19 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
|
|
|
227
267
|
upper = { value: opts.exclusiveMaximum, exclusive: true };
|
|
228
268
|
}
|
|
229
269
|
const keyword = integer ? "number.integer" : "number";
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
let
|
|
270
|
+
// The `LO <= TYPE <= HI` range spelling requires both bounds; a min-only
|
|
271
|
+
// bound must use the postfix `TYPE >= LO` form (see parseBounded in ir.ts).
|
|
272
|
+
let src: string;
|
|
273
|
+
if (lower && upper) {
|
|
274
|
+
src = `${lower.value} ${lower.exclusive ? "<" : "<="} ${keyword} ${upper.exclusive ? "<" : "<="} ${upper.value}`;
|
|
275
|
+
} else if (lower) {
|
|
276
|
+
src = `${keyword} ${lower.exclusive ? ">" : ">="} ${lower.value}`;
|
|
277
|
+
} else if (upper) {
|
|
278
|
+
src = `${keyword} ${upper.exclusive ? "<" : "<="} ${upper.value}`;
|
|
279
|
+
} else {
|
|
280
|
+
src = keyword;
|
|
281
|
+
}
|
|
282
|
+
let schema = asRuntime<number>(type.raw(src));
|
|
233
283
|
if (opts?.multipleOf !== undefined) {
|
|
234
284
|
const divisor = opts.multipleOf;
|
|
235
285
|
schema = schema.narrow((value, ctx) => {
|
|
@@ -244,33 +294,32 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
|
|
|
244
294
|
}
|
|
245
295
|
|
|
246
296
|
function tLiteral<const V extends string | number | boolean | null>(value: V, opts?: Meta): TLiteral<V> {
|
|
247
|
-
return applyMeta(type.enumerated(value)
|
|
297
|
+
return applyMeta(asRuntime<V>(type.enumerated(value)), opts);
|
|
248
298
|
}
|
|
249
299
|
|
|
250
300
|
function tNever(opts?: Meta): TNever {
|
|
251
301
|
return applyMeta(
|
|
252
|
-
(type.raw("unknown")
|
|
302
|
+
asRuntime<unknown>(type.raw("unknown")).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
|
|
253
303
|
opts,
|
|
254
304
|
);
|
|
255
305
|
}
|
|
256
306
|
|
|
257
|
-
function tUnion<const E extends readonly
|
|
258
|
-
if (schemas.length === 0) return tNever(opts)
|
|
259
|
-
let result = schemas[0]
|
|
307
|
+
function tUnion<const E extends readonly AnySchema[]>(schemas: E, opts?: Meta): TUnion<E> {
|
|
308
|
+
if (schemas.length === 0) return asSchema<Static<E[number]>>(tNever(opts));
|
|
309
|
+
let result = asRuntime<unknown>(schemas[0]);
|
|
260
310
|
for (let i = 1; i < schemas.length; i++) result = result.or(schemas[i]);
|
|
261
|
-
return applyMeta(result, opts)
|
|
311
|
+
return asSchema<Static<E[number]>>(applyMeta(result, opts));
|
|
262
312
|
}
|
|
263
313
|
|
|
264
|
-
function tIntersect<const E extends readonly
|
|
314
|
+
function tIntersect<const E extends readonly AnySchema[]>(
|
|
265
315
|
schemas: E,
|
|
266
316
|
opts?: Meta,
|
|
267
|
-
):
|
|
268
|
-
if (schemas.length === 0)
|
|
269
|
-
return applyMeta(type.raw("unknown")
|
|
270
|
-
|
|
271
|
-
>;
|
|
317
|
+
): TTyped<UnionToIntersection<Static<E[number]>>> {
|
|
318
|
+
if (schemas.length === 0) {
|
|
319
|
+
return applyMeta(asRuntime<UnionToIntersection<Static<E[number]>>>(type.raw("unknown")), opts);
|
|
320
|
+
}
|
|
272
321
|
const validateAll = (): RuntimeType<UnionToIntersection<Static<E[number]>>> => {
|
|
273
|
-
const base = type.raw("unknown")
|
|
322
|
+
const base = asRuntime<unknown>(type.raw("unknown"));
|
|
274
323
|
return base.narrow((value, ctx): value is UnionToIntersection<Static<E[number]>> => {
|
|
275
324
|
for (const schema of schemas) {
|
|
276
325
|
if (schema(value) instanceof type.errors) return ctx.mustBe("a value satisfying every intersection member");
|
|
@@ -279,14 +328,14 @@ function tIntersect<const E extends readonly TSchema[]>(
|
|
|
279
328
|
});
|
|
280
329
|
};
|
|
281
330
|
if (schemas.some(schema => schema.hasSteps)) return applyMeta(validateAll(), opts);
|
|
282
|
-
let result = schemas[0]
|
|
331
|
+
let result = asRuntime<unknown>(schemas[0]);
|
|
283
332
|
try {
|
|
284
333
|
for (let i = 1; i < schemas.length; i++) result = result.and(schemas[i]);
|
|
285
334
|
} catch (error) {
|
|
286
335
|
if (error instanceof OmpTypeError) return applyMeta(validateAll(), opts);
|
|
287
336
|
throw error;
|
|
288
337
|
}
|
|
289
|
-
return
|
|
338
|
+
return asSchema<UnionToIntersection<Static<E[number]>>>(applyMeta(result, opts));
|
|
290
339
|
}
|
|
291
340
|
type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void
|
|
292
341
|
? I
|
|
@@ -306,16 +355,17 @@ function enumValues(values: Record<string, string | number> | readonly (string |
|
|
|
306
355
|
function tEnum<const E extends Record<string, string | number> | readonly (string | number)[]>(
|
|
307
356
|
values: E,
|
|
308
357
|
opts?: Meta,
|
|
309
|
-
):
|
|
310
|
-
return applyMeta(
|
|
311
|
-
E extends readonly (infer V)[] ? V : E[keyof E]
|
|
312
|
-
|
|
358
|
+
): TTyped<E extends readonly (infer V)[] ? V : E[keyof E]> {
|
|
359
|
+
return applyMeta(
|
|
360
|
+
asRuntime<E extends readonly (infer V)[] ? V : E[keyof E]>(type.enumerated(...enumValues(values))),
|
|
361
|
+
opts,
|
|
362
|
+
);
|
|
313
363
|
}
|
|
314
364
|
|
|
315
|
-
function tArray<E extends
|
|
365
|
+
function tArray<E extends AnySchema>(item: E, opts?: ArrayOpts): TArray<E> {
|
|
316
366
|
checkFiniteOption("minItems", opts?.minItems);
|
|
317
367
|
checkFiniteOption("maxItems", opts?.maxItems);
|
|
318
|
-
let schema =
|
|
368
|
+
let schema = asRuntime<Static<E>>(item).array();
|
|
319
369
|
if (opts?.minItems !== undefined) schema = schema.atLeastLength(opts.minItems);
|
|
320
370
|
if (opts?.maxItems !== undefined) schema = schema.atMostLength(opts.maxItems);
|
|
321
371
|
if (opts?.uniqueItems) {
|
|
@@ -342,8 +392,8 @@ function jsonEqual(left: unknown, right: unknown): boolean {
|
|
|
342
392
|
}
|
|
343
393
|
}
|
|
344
394
|
|
|
345
|
-
function tTuple<const E extends readonly
|
|
346
|
-
const schema = (type.raw("unknown")
|
|
395
|
+
function tTuple<const E extends readonly AnySchema[]>(items: E, opts?: Meta): TTuple<E> {
|
|
396
|
+
const schema = asRuntime<unknown>(type.raw("unknown")).narrow(
|
|
347
397
|
(value, ctx): value is { -readonly [K in keyof E]: Static<E[K]> } => {
|
|
348
398
|
if (!Array.isArray(value) || value.length !== items.length)
|
|
349
399
|
return ctx.mustBe(`a tuple of length ${items.length}`);
|
|
@@ -355,25 +405,29 @@ function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTup
|
|
|
355
405
|
return applyMeta(schema, opts);
|
|
356
406
|
}
|
|
357
407
|
|
|
358
|
-
function tObject<const P extends Record<string,
|
|
408
|
+
function tObject<const P extends Record<string, AnySchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
|
|
359
409
|
const def: Record<string, Def> = {};
|
|
360
|
-
const props: Record<string,
|
|
410
|
+
const props: Record<string, AnySchema> = {};
|
|
361
411
|
for (const key in properties) {
|
|
362
412
|
const schema = properties[key];
|
|
363
|
-
const inner =
|
|
364
|
-
|
|
413
|
+
const inner = asRuntime<unknown>(schema)[OPTIONAL_INNER];
|
|
414
|
+
// A defaulted `Type.Optional(...)` maps to a plain defaulted key:
|
|
415
|
+
// omptype (like ArkType) rejects `key?` with a default, and a default
|
|
416
|
+
// already makes the key omittable on input.
|
|
417
|
+
const optionalKey = inner !== undefined && !asRuntime<unknown>(inner).hasDefault;
|
|
418
|
+
def[optionalKey ? `${key}?` : key] = inner ?? schema;
|
|
365
419
|
props[key] = schema;
|
|
366
420
|
}
|
|
367
421
|
if (opts?.additionalProperties === false) def["+"] = "reject";
|
|
368
422
|
else if (opts?.additionalProperties && opts.additionalProperties !== true)
|
|
369
|
-
def["[string]"] = opts.additionalProperties
|
|
370
|
-
const schema = applyMeta(type.raw(def)
|
|
423
|
+
def["[string]"] = opts.additionalProperties;
|
|
424
|
+
const schema = applyMeta(asRuntime<ObjectStatic<P>>(type.raw(def)), opts);
|
|
371
425
|
schema[OBJECT_INFO] = { props, additionalProperties: opts?.additionalProperties };
|
|
372
426
|
return schema;
|
|
373
427
|
}
|
|
374
428
|
|
|
375
|
-
function tRecord<K extends
|
|
376
|
-
const base = (type.raw({ "[string]": value })
|
|
429
|
+
function tRecord<K extends AnySchema, V extends AnySchema>(key: K, value: V, opts?: Meta): TRecord<K, V> {
|
|
430
|
+
const base = asRuntime<Record<string, Static<V>>>(type.raw({ "[string]": value })).narrow((record, ctx) => {
|
|
377
431
|
for (const name in record)
|
|
378
432
|
if (key(name) instanceof type.errors) return ctx.mustBe("an object with valid record keys");
|
|
379
433
|
return true;
|
|
@@ -381,72 +435,70 @@ function tRecord<K extends TSchema, V extends TSchema>(key: K, value: V, opts?:
|
|
|
381
435
|
return applyMeta(base, opts) as TRecord<K, V>;
|
|
382
436
|
}
|
|
383
437
|
|
|
384
|
-
function tOptional<E extends
|
|
438
|
+
function tOptional<E extends AnySchema>(schema: E, opts?: Meta): TOptional<E> {
|
|
385
439
|
const marker = applyMeta(
|
|
386
|
-
|
|
440
|
+
asRuntime<Static<E>>(schema).or(asRuntime<undefined>(type.raw("undefined"))),
|
|
387
441
|
opts,
|
|
388
442
|
) as RuntimeType<Static<E> | undefined>;
|
|
389
443
|
marker[OPTIONAL_INNER] = schema;
|
|
390
444
|
return marker as unknown as TOptional<E>;
|
|
391
445
|
}
|
|
392
446
|
|
|
393
|
-
function tNullable<E extends
|
|
394
|
-
return applyMeta(
|
|
447
|
+
function tNullable<E extends AnySchema>(schema: E, opts?: Meta): TTyped<Static<E> | null> {
|
|
448
|
+
return applyMeta(asRuntime<Static<E>>(schema).or(asRuntime<null>(type.raw("null"))), opts);
|
|
395
449
|
}
|
|
396
450
|
|
|
397
|
-
function requireObject(schema:
|
|
398
|
-
const info =
|
|
451
|
+
function requireObject(schema: AnySchema, operation: string): ObjectInfo {
|
|
452
|
+
const info = asRuntime<unknown>(schema)[OBJECT_INFO];
|
|
399
453
|
if (!info) throw new OmpTypeError(`Type.${operation} requires a schema created by Type.Object`);
|
|
400
454
|
return info;
|
|
401
455
|
}
|
|
402
456
|
|
|
403
|
-
function tPartial<P extends Record<string,
|
|
457
|
+
function tPartial<P extends Record<string, AnySchema>>(schema: TObject<P>): TTyped<Partial<ObjectStatic<P>>> {
|
|
404
458
|
const info = requireObject(schema, "Partial");
|
|
405
|
-
const props: Record<string,
|
|
459
|
+
const props: Record<string, AnySchema> = {};
|
|
406
460
|
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>>>;
|
|
461
|
+
props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ? info.props[key] : tOptional(info.props[key]);
|
|
462
|
+
return tObject(props, { additionalProperties: info.additionalProperties }) as TTyped<Partial<ObjectStatic<P>>>;
|
|
411
463
|
}
|
|
412
464
|
|
|
413
|
-
function tRequired<P extends Record<string,
|
|
465
|
+
function tRequired<P extends Record<string, AnySchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
|
|
414
466
|
const info = requireObject(schema, "Required");
|
|
415
|
-
const props: Record<string,
|
|
467
|
+
const props: Record<string, AnySchema> = {};
|
|
416
468
|
for (const key in info.props) {
|
|
417
|
-
props[key] = (info.props[key]
|
|
469
|
+
props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ?? info.props[key];
|
|
418
470
|
}
|
|
419
471
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<RequiredProps<P>>;
|
|
420
472
|
}
|
|
421
473
|
|
|
422
|
-
function tPick<P extends Record<string,
|
|
474
|
+
function tPick<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
|
|
423
475
|
schema: TObject<P>,
|
|
424
476
|
keys: K,
|
|
425
477
|
): TObject<Pick<P, K[number]>> {
|
|
426
478
|
const info = requireObject(schema, "Pick");
|
|
427
|
-
const props: Record<string,
|
|
479
|
+
const props: Record<string, AnySchema> = {};
|
|
428
480
|
for (const key of keys) if (typeof key === "string" && info.props[key]) props[key] = info.props[key];
|
|
429
481
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Pick<P, K[number]>>;
|
|
430
482
|
}
|
|
431
483
|
|
|
432
|
-
function tOmit<P extends Record<string,
|
|
484
|
+
function tOmit<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
|
|
433
485
|
schema: TObject<P>,
|
|
434
486
|
keys: K,
|
|
435
487
|
): TObject<Omit<P, K[number]>> {
|
|
436
488
|
const info = requireObject(schema, "Omit");
|
|
437
489
|
const omitted = new Set<PropertyKey>(keys);
|
|
438
|
-
const props: Record<string,
|
|
490
|
+
const props: Record<string, AnySchema> = {};
|
|
439
491
|
for (const key in info.props) if (!omitted.has(key)) props[key] = info.props[key];
|
|
440
492
|
return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Omit<P, K[number]>>;
|
|
441
493
|
}
|
|
442
494
|
|
|
443
|
-
function tComposite<const E extends readonly TObject<Record<string,
|
|
495
|
+
function tComposite<const E extends readonly TObject<Record<string, AnySchema>>[]>(
|
|
444
496
|
schemas: E,
|
|
445
497
|
opts?: ObjectOpts,
|
|
446
|
-
):
|
|
447
|
-
const props: Record<string,
|
|
498
|
+
): TTyped<UnionToIntersection<Static<E[number]>>> {
|
|
499
|
+
const props: Record<string, AnySchema> = {};
|
|
448
500
|
for (const schema of schemas) Object.assign(props, requireObject(schema, "Composite").props);
|
|
449
|
-
return
|
|
501
|
+
return asSchema<UnionToIntersection<Static<E[number]>>>(tObject(props, opts));
|
|
450
502
|
}
|
|
451
503
|
|
|
452
504
|
function tUnsafe<T = unknown>(_jsonSchema: Record<string, unknown> = {}): TUnsafe<T> {
|
|
@@ -459,10 +511,10 @@ export const Type = {
|
|
|
459
511
|
String: tString,
|
|
460
512
|
Number: (opts?: NumberOpts) => tNumber(opts),
|
|
461
513
|
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")
|
|
514
|
+
Boolean: (opts?: Meta) => applyMeta(asRuntime<boolean>(type.raw("boolean")), opts),
|
|
515
|
+
Null: (opts?: Meta) => applyMeta(asRuntime<null>(type.raw("null")), opts),
|
|
516
|
+
Any: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
|
|
517
|
+
Unknown: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
|
|
466
518
|
Never: tNever,
|
|
467
519
|
Literal: tLiteral,
|
|
468
520
|
Union: tUnion,
|
|
@@ -474,7 +526,8 @@ export const Type = {
|
|
|
474
526
|
Record: tRecord,
|
|
475
527
|
Optional: tOptional,
|
|
476
528
|
Nullable: tNullable,
|
|
477
|
-
Readonly: <E extends
|
|
529
|
+
Readonly: <E extends AnySchema>(schema: E): TReadonly<E> =>
|
|
530
|
+
asSchema<Readonly<Static<E>>>(withLegacyCompat(asRuntime<Readonly<Static<E>>>(schema))),
|
|
478
531
|
Partial: tPartial,
|
|
479
532
|
Required: tRequired,
|
|
480
533
|
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
|
}
|