Comparing version 0.0.30 to 0.0.31
@@ -1,228 +0,3 @@ | ||
export declare abstract class Type<T> { | ||
constructor(); | ||
abstract parse(value: unknown): T; | ||
abstract and<K extends AnyType>(schema: K): any; | ||
or<K extends AnyType>(schema: K): UnionType<[Type<T>, K]>; | ||
optional(): OptionalType<Type<T>>; | ||
nullable(): NullableType<Type<T>>; | ||
} | ||
export declare class ValidationError extends Error { | ||
name: string; | ||
path?: (string | number)[]; | ||
constructor(message: string, path?: (string | number)[]); | ||
} | ||
declare type AnyType = Type<any>; | ||
declare type Eval<T> = T extends any[] | Date ? T : { | ||
[Key in keyof T]: T[Key]; | ||
} & {}; | ||
export declare type Infer<T extends AnyType> = T extends Type<infer K> ? Eval<K> : any; | ||
declare type IntersectionResult<T extends AnyType, K extends AnyType> = T extends ObjectType<any> ? K extends ObjectType<any> ? T extends ObjectType<infer Shape1> ? K extends ObjectType<infer Shape2> ? ObjectType<Eval<MergeShapes<Shape1, Shape2>>> : IntersectionType<T, K> : IntersectionType<T, K> : IntersectionType<T, K> : T extends ArrayType<any> ? K extends ArrayType<any> ? T extends ArrayType<infer S1> ? K extends ArrayType<infer S2> ? ArrayType<IntersectionResult<S1, S2>> : IntersectionType<T, K> : IntersectionType<T, K> : IntersectionType<T, K> : T extends RecordType<any> ? K extends RecordType<any> ? T extends RecordType<infer S1> ? K extends RecordType<infer S2> ? RecordType<IntersectionResult<S1, S2>> : IntersectionType<T, K> : IntersectionType<T, K> : IntersectionType<T, K> : IntersectionType<T, K>; | ||
declare type StringOptions = Partial<{ | ||
pattern: RegExp; | ||
min: number; | ||
max: number; | ||
predicate: (value: string) => boolean; | ||
predicateErrMsg: string; | ||
}>; | ||
declare class StringType extends Type<string> { | ||
private opts; | ||
constructor(opts?: StringOptions); | ||
parse(value: unknown): string; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
pattern(regexp: RegExp): this; | ||
min(x: number): this; | ||
max(x: number): this; | ||
predicate(fn: StringOptions['predicate'], errMsg?: string): this; | ||
} | ||
declare class BooleanType extends Type<boolean> { | ||
parse(value: unknown): boolean; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare type NumberOptions = Partial<{ | ||
min: number; | ||
max: number; | ||
coerce: boolean; | ||
}>; | ||
declare class NumberType extends Type<number> { | ||
private opts; | ||
constructor(opts?: NumberOptions); | ||
parse(value: unknown): number; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
min(x: number): this; | ||
max(x: number): this; | ||
coerce(value?: boolean): this; | ||
} | ||
declare class UndefinedType extends Type<undefined> { | ||
parse(value: unknown): undefined; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class NullType extends Type<null> { | ||
parse(value: unknown): null; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare type Literal = string | number | boolean | undefined | null; | ||
declare class LiteralType<T extends Literal> extends Type<T> { | ||
private readonly literal; | ||
constructor(literal: T); | ||
parse(value: unknown): T; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class UnknownType extends Type<unknown> { | ||
parse(value: unknown): unknown; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class OptionalType<T extends AnyType> extends Type<Infer<T> | undefined> { | ||
private readonly schema; | ||
constructor(schema: T); | ||
parse(value: unknown, opts?: any): Infer<T> | undefined; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class NullableType<T extends AnyType> extends Type<Infer<T> | null> { | ||
private readonly schema; | ||
constructor(schema: T); | ||
parse(value: unknown): Infer<T> | null; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class DateType extends Type<Date> { | ||
constructor(); | ||
parse(value: unknown): Date; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare type ObjectShape = Record<string, AnyType>; | ||
declare type OptionalKeys<T extends ObjectShape> = { | ||
[key in keyof T]: undefined extends Infer<T[key]> ? key : never; | ||
}[keyof T]; | ||
declare type RequiredKeys<T extends ObjectShape> = Exclude<keyof T, OptionalKeys<T>>; | ||
declare type InferObjectShape<T extends ObjectShape> = { | ||
[key in OptionalKeys<T>]?: T[key] extends Type<infer K> ? K : any; | ||
} & { | ||
[key in RequiredKeys<T>]: T[key] extends Type<infer K> ? K : any; | ||
}; | ||
declare type PathOptions = { | ||
suppressPathErrMsg?: boolean; | ||
}; | ||
declare type ObjectOptions = { | ||
allowUnknown?: boolean; | ||
}; | ||
declare type ToUnion<T extends any[]> = T[number]; | ||
declare type PartialShape<T extends ObjectShape> = { | ||
[key in keyof T]: UnionType<[T[key], UndefinedType]>; | ||
}; | ||
declare type DeepPartialShape<T extends ObjectShape> = { | ||
[key in keyof T]: T[key] extends ObjectType<infer K> ? OptionalType<ObjectType<DeepPartialShape<K>>> : OptionalType<T[key]>; | ||
}; | ||
declare type MergeShapes<T extends ObjectShape, K extends ObjectShape> = { | ||
[key in keyof (T & K)]: key extends keyof T ? key extends keyof K ? IntersectionType<T[key], K[key]> : T[key] : key extends keyof K ? K[key] : never; | ||
}; | ||
declare class ObjectType<T extends ObjectShape> extends Type<Eval<InferObjectShape<T>>> { | ||
private readonly objectShape; | ||
private readonly opts?; | ||
constructor(objectShape: T, opts?: ObjectOptions | undefined); | ||
parse(value: unknown, parseOpts?: ObjectOptions & PathOptions): Eval<InferObjectShape<T>>; | ||
and<K extends AnyType>(schema: K): IntersectionResult<this, K>; | ||
pick<K extends keyof T>(keys: K[], opts?: ObjectOptions): ObjectType<Eval<Pick<T, ToUnion<typeof keys>>>>; | ||
omit<K extends keyof T>(keys: K[], opts?: ObjectOptions): ObjectType<Eval<Omit<T, ToUnion<typeof keys>>>>; | ||
partial<K extends ObjectOptions & PartialOpts>(opts?: K): ObjectType<Eval<K extends { | ||
deep: true; | ||
} ? DeepPartialShape<T> : PartialShape<T>>>; | ||
} | ||
declare class RecordType<T extends AnyType> extends Type<Record<string, Infer<T>>> { | ||
private readonly schema; | ||
private _parse; | ||
constructor(schema: T); | ||
parse(value: unknown, opts?: PathOptions & ObjectOptions): Record<string, Infer<T>>; | ||
and<K extends AnyType>(schema: K): IntersectionResult<this, K>; | ||
} | ||
declare type ArrayOptions = Partial<{ | ||
length: number; | ||
min: number; | ||
max: number; | ||
unique: boolean; | ||
}>; | ||
declare class ArrayType<T extends AnyType> extends Type<Infer<T>[]> { | ||
private readonly schema; | ||
private readonly opts; | ||
private readonly _parse; | ||
constructor(schema: T, opts?: ArrayOptions); | ||
parse(value: unknown, parseOptions?: PathOptions & ObjectOptions): Infer<T>[]; | ||
length(value: number): this; | ||
min(value: number): this; | ||
max(value: number): this; | ||
unique(value?: boolean): this; | ||
and<K extends AnyType>(schema: K): IntersectionResult<this, K>; | ||
} | ||
declare type InferTuple<T extends [AnyType, ...AnyType[]] | []> = { | ||
[key in keyof T]: T[key] extends Type<infer K> ? K : never; | ||
}; | ||
declare class TupleType<T extends [AnyType, ...AnyType[]] | []> extends Type<InferTuple<T>> { | ||
private readonly schemas; | ||
constructor(schemas: T); | ||
parse(value: unknown): InferTuple<T>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare type InferTupleUnion<T extends any[]> = Infer<T[number]>; | ||
declare type UnionOptions = { | ||
strict?: boolean; | ||
}; | ||
declare class UnionType<T extends AnyType[]> extends Type<InferTupleUnion<T>> { | ||
private readonly schemas; | ||
private readonly opts?; | ||
constructor(schemas: T, opts?: UnionOptions | undefined); | ||
parse(value: unknown): InferTupleUnion<T>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class IntersectionType<T extends AnyType, K extends AnyType> extends Type<Eval<Infer<T> & Infer<K>>> { | ||
private readonly left; | ||
private readonly right; | ||
private readonly _parse; | ||
constructor(left: T, right: K); | ||
parse(value: unknown, opts?: PathOptions & ObjectOptions): Eval<Infer<T> & Infer<K>>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
private parseObjectIntersection; | ||
private parseRecordObjectIntersection; | ||
} | ||
declare type ValueOf<T> = T[keyof T]; | ||
declare class EnumType<T> extends Type<ValueOf<T>> { | ||
private values; | ||
constructor(enumeration: T); | ||
parse(value: unknown): ValueOf<T>; | ||
check(value: unknown): value is ValueOf<T>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare type DeepPartial<T> = { | ||
[key in keyof T]?: T[key] extends Object ? Eval<DeepPartial<T[key]>> : T[key]; | ||
}; | ||
declare type PartialOpts = { | ||
deep: boolean; | ||
}; | ||
declare class PartialType<T extends AnyType, K extends PartialOpts> extends Type<K extends { | ||
deep: true; | ||
} ? Eval<DeepPartial<Infer<T>>> : Partial<Infer<T>>> { | ||
private readonly schema; | ||
constructor(schema: T, opts?: K); | ||
parse(value: unknown): K extends { | ||
deep: true; | ||
} ? Eval<DeepPartial<Infer<T>>> : Partial<Infer<T>>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class PickType<T extends AnyType, K extends keyof Infer<T>> extends Type<Pick<Infer<T>, K>> { | ||
private readonly pickedKeys; | ||
private readonly schema; | ||
constructor(rootSchema: T, pickedKeys: K[]); | ||
parse(value: unknown, parseOptions?: ObjectOptions): Eval<Pick<Infer<T>, K>>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class OmitType<T extends AnyType, K extends keyof Infer<T>> extends Type<Omit<Infer<T>, K>> { | ||
private readonly omittedKeys; | ||
private readonly schema; | ||
constructor(rootSchema: T, omittedKeys: K[]); | ||
parse(value: unknown, opts?: ObjectOptions): Eval<Omit<Infer<T>, K>>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
declare class LazyType<T extends () => AnyType> extends Type<Infer<ReturnType<T>>> { | ||
private readonly fn; | ||
constructor(fn: T); | ||
parse(value: unknown, opts?: PathOptions): Infer<ReturnType<T>>; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
} | ||
import { ValidationError, Type, StringType, NumberType, LiteralType, ObjectType, ArrayType, UnionType, RecordType, PartialType, PickType, OmitType, TupleType, DateType, LazyType, UndefinedType, NullType, EnumType, BooleanType, UnknownType, Literal, ObjectOptions, AnyType, UnionOptions, Infer, PartialOpts, IntersectionResult, DeepPartialShape, PartialShape, Eval, ToUnion } from './types'; | ||
export { ValidationError, Type, Infer } from './types'; | ||
export declare const string: (opts?: Partial<{ | ||
@@ -244,3 +19,3 @@ pattern: RegExp; | ||
export declare const object: <T extends Record<string, AnyType>>(shape: T, opts?: ObjectOptions | undefined) => ObjectType<T>; | ||
export declare const array: <T extends AnyType>(type: T, opts?: Partial<{ | ||
export declare const array: <T extends AnyType>(schema: T, opts?: Partial<{ | ||
length: number; | ||
@@ -252,11 +27,19 @@ min: number; | ||
export declare const union: <T extends AnyType[]>(schemas: T, opts?: UnionOptions | undefined) => UnionType<T>; | ||
export declare const intersection: <T extends AnyType, K extends AnyType>(l: T, r: K) => IntersectionType<T, K>; | ||
export declare const record: <T extends AnyType>(type: T) => RecordType<T>; | ||
export declare const dictionary: <T extends AnyType>(type: T) => RecordType<UnionType<(UndefinedType | T)[]>>; | ||
export declare const partial: <T extends AnyType, K extends PartialOpts>(type: T, opts?: K | undefined) => PartialType<T, K>; | ||
export declare const pick: <T extends AnyType, K extends keyof Infer<T>>(type: T, keys: K[]) => PickType<T, K>; | ||
export declare const omit: <T extends AnyType, K extends keyof Infer<T>>(type: T, keys: K[]) => OmitType<T, K>; | ||
export declare const intersection: <T extends AnyType, K extends AnyType>(l: T, r: K) => IntersectionResult<T, K>; | ||
export declare const record: <T extends AnyType>(schema: T) => RecordType<T>; | ||
export declare const dictionary: <T extends AnyType>(schema: T) => RecordType<import("./types").OptionalType<Type<any>>>; | ||
export declare const tuple: <T extends [] | [AnyType, ...AnyType[]]>(schemas: T) => TupleType<T>; | ||
export declare const date: () => DateType; | ||
export declare const lazy: <T extends () => AnyType>(fn: T) => LazyType<T>; | ||
export declare function partial<T extends ObjectType<any>, K extends PartialOpts>(schema: T, opts?: K): T extends ObjectType<infer Shape> ? ObjectType<Eval<K extends { | ||
deep: true; | ||
} ? DeepPartialShape<Shape> : PartialShape<Shape>>> : never; | ||
export declare function partial<T extends AnyType, K extends PartialOpts>(schema: T, opts?: K): PartialType<T, K>; | ||
export declare function pick<T extends ObjectType<any>, K extends T extends ObjectType<infer Shape> ? keyof Shape : never>(schema: T, keys: K[]): T extends ObjectType<infer Shape> ? ObjectType<Eval<Pick<Shape, ToUnion<typeof keys>>>> : never; | ||
export declare function pick<T extends RecordType<any>, K extends string>(schema: T, keys: K[]): T extends RecordType<infer Schema> ? ObjectType<{ | ||
[key in ToUnion<typeof keys>]: Schema; | ||
}> : never; | ||
export declare function pick<T extends AnyType, K extends keyof Infer<T>>(type: T, keys: K[]): PickType<T, K>; | ||
export declare function omit<T extends ObjectType<any>, K extends T extends ObjectType<infer Shape> ? keyof Shape : never>(schema: T, keys: K[]): T extends ObjectType<infer Shape> ? ObjectType<Eval<Omit<Shape, ToUnion<typeof keys>>>> : never; | ||
export declare function omit<T extends AnyType, K extends keyof Infer<T>>(schema: T, keys: K[]): OmitType<T, K>; | ||
declare const undefinedValue: () => UndefinedType; | ||
@@ -285,3 +68,3 @@ declare const nullValue: () => NullType; | ||
object: <T_1 extends Record<string, AnyType>>(shape: T_1, opts?: ObjectOptions | undefined) => ObjectType<T_1>; | ||
array: <T_2 extends AnyType>(type: T_2, opts?: Partial<{ | ||
array: <T_2 extends AnyType>(schema: T_2, opts?: Partial<{ | ||
length: number; | ||
@@ -293,14 +76,14 @@ min: number; | ||
union: <T_3 extends AnyType[]>(schemas: T_3, opts?: UnionOptions | undefined) => UnionType<T_3>; | ||
intersection: <T_4 extends AnyType, K extends AnyType>(l: T_4, r: K) => IntersectionType<T_4, K>; | ||
record: <T_5 extends AnyType>(type: T_5) => RecordType<T_5>; | ||
dictionary: <T_6 extends AnyType>(type: T_6) => RecordType<UnionType<(UndefinedType | T_6)[]>>; | ||
intersection: <T_4 extends AnyType, K extends AnyType>(l: T_4, r: K) => IntersectionResult<T_4, K>; | ||
record: <T_5 extends AnyType>(schema: T_5) => RecordType<T_5>; | ||
dictionary: <T_6 extends AnyType>(schema: T_6) => RecordType<import("./types").OptionalType<Type<any>>>; | ||
tuple: <T_7 extends [] | [AnyType, ...AnyType[]]>(schemas: T_7) => TupleType<T_7>; | ||
partial: <T_8 extends AnyType, K_1 extends PartialOpts>(type: T_8, opts?: K_1 | undefined) => PartialType<T_8, K_1>; | ||
pick: <T_9 extends AnyType, K_2 extends keyof Infer<T_9>>(type: T_9, keys: K_2[]) => PickType<T_9, K_2>; | ||
omit: <T_10 extends AnyType, K_3 extends keyof Infer<T_10>>(type: T_10, keys: K_3[]) => OmitType<T_10, K_3>; | ||
partial: typeof partial; | ||
pick: typeof pick; | ||
omit: typeof omit; | ||
undefined: () => UndefinedType; | ||
null: () => NullType; | ||
enum: <T_11>(e: T_11) => EnumType<T_11>; | ||
enum: <T_8>(e: T_8) => EnumType<T_8>; | ||
ValidationError: typeof ValidationError; | ||
}; | ||
export default _default; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class Type { | ||
constructor() { } | ||
or(schema) { | ||
return new UnionType([this, schema]); | ||
const types_1 = require("./types"); | ||
var types_2 = require("./types"); | ||
exports.ValidationError = types_2.ValidationError; | ||
exports.Type = types_2.Type; | ||
exports.string = (opts) => new types_1.StringType(opts); | ||
exports.boolean = () => new types_1.BooleanType(); | ||
exports.number = (opts) => new types_1.NumberType(opts); | ||
exports.unknown = () => new types_1.UnknownType(); | ||
exports.literal = (literal) => new types_1.LiteralType(literal); | ||
exports.object = (shape, opts) => new types_1.ObjectType(shape, opts); | ||
exports.array = (schema, opts) => new types_1.ArrayType(schema, opts); | ||
exports.union = (schemas, opts) => new types_1.UnionType(schemas, opts); | ||
exports.intersection = (l, r) => l.and(r); | ||
exports.record = (schema) => new types_1.RecordType(schema); | ||
exports.dictionary = (schema) => new types_1.RecordType(schema.optional()); | ||
exports.tuple = (schemas) => new types_1.TupleType(schemas); | ||
exports.date = () => new types_1.DateType(); | ||
exports.lazy = (fn) => new types_1.LazyType(fn); | ||
function partial(schema, opts) { | ||
if (schema instanceof types_1.ObjectType) { | ||
return schema.partial(opts); | ||
} | ||
optional() { | ||
return new OptionalType(this); | ||
} | ||
nullable() { | ||
return new NullableType(this); | ||
} | ||
return new types_1.PartialType(schema, opts); | ||
} | ||
exports.Type = Type; | ||
class ValidationError extends Error { | ||
constructor(message, path) { | ||
super(message); | ||
this.name = 'MyZodError'; | ||
this.path = path; | ||
exports.partial = partial; | ||
function pick(schema, keys) { | ||
if (schema instanceof types_1.ObjectType) { | ||
return schema.pick(keys); | ||
} | ||
} | ||
exports.ValidationError = ValidationError; | ||
function typeOf(value) { | ||
if (value === null) { | ||
return 'null'; | ||
if (schema instanceof types_1.RecordType) { | ||
return schema.pick(keys); | ||
} | ||
if (Array.isArray(value)) { | ||
return 'array'; | ||
} | ||
return typeof value; | ||
return new types_1.PickType(schema, keys); | ||
} | ||
function prettyPrintPath(path) { | ||
return path.reduce((acc, elem, idx) => { | ||
if (typeof elem === 'number') { | ||
acc += `[${elem}]`; | ||
} | ||
else if (idx === 0) { | ||
acc += elem; | ||
} | ||
else { | ||
acc += '.' + elem; | ||
} | ||
return acc; | ||
}, ''); | ||
} | ||
const allowUnknownSymbol = Symbol.for('allowUnknown'); | ||
const shapekeysSymbol = Symbol.for('shapeKeys'); | ||
const coercionTypeSybol = Symbol.for('coersion'); | ||
class StringType extends Type { | ||
constructor(opts = {}) { | ||
super(); | ||
this.opts = opts; | ||
exports.pick = pick; | ||
function omit(schema, keys) { | ||
if (schema instanceof types_1.ObjectType) { | ||
return schema.omit(keys); | ||
} | ||
parse(value) { | ||
if (typeof value !== 'string') { | ||
throw new ValidationError('expected type to be string but got ' + typeOf(value)); | ||
} | ||
if (typeof this.opts.min === 'number' && value.length < this.opts.min) { | ||
throw new ValidationError(`expected string to have length greater than or equal to ${this.opts.min} but had length ${value.length}`); | ||
} | ||
if (typeof this.opts.max === 'number' && value.length > this.opts.max) { | ||
throw new ValidationError(`expected string to have length less than or equal to ${this.opts.max} but had length ${value.length}`); | ||
} | ||
if (this.opts.pattern instanceof RegExp && !this.opts.pattern.test(value)) { | ||
throw new ValidationError(`expected string to match pattern ${this.opts.pattern} but did not`); | ||
} | ||
if (this.opts.predicate) { | ||
try { | ||
if (this.opts.predicate(value) === false) { | ||
throw new ValidationError(this.opts.predicateErrMsg || 'expected string to pass predicate function'); | ||
} | ||
} | ||
catch (err) { | ||
if (err instanceof ValidationError) { | ||
throw err; | ||
} | ||
throw new ValidationError(err.message); | ||
} | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
pattern(regexp) { | ||
this.opts.pattern = regexp; | ||
return this; | ||
} | ||
min(x) { | ||
this.opts.min = x; | ||
return this; | ||
} | ||
max(x) { | ||
this.opts.max = x; | ||
return this; | ||
} | ||
predicate(fn, errMsg) { | ||
this.opts.predicate = fn; | ||
if (errMsg) { | ||
this.opts.predicateErrMsg = errMsg; | ||
} | ||
return this; | ||
} | ||
return new types_1.OmitType(schema, keys); | ||
} | ||
class BooleanType extends Type { | ||
parse(value) { | ||
if (typeof value !== 'boolean') { | ||
throw new ValidationError('expected type to be boolean but got ' + typeOf(value)); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class NumberType extends Type { | ||
constructor(opts = {}) { | ||
super(); | ||
this.opts = opts; | ||
this[coercionTypeSybol] = false; | ||
} | ||
parse(value) { | ||
if (this.opts.coerce && typeof value === 'string') { | ||
const number = parseFloat(value); | ||
if (isNaN(number)) { | ||
throw new ValidationError('expected type to be number but got string'); | ||
} | ||
return this.parse(number); | ||
} | ||
if (typeof value !== 'number') { | ||
throw new ValidationError('expected type to be number but got ' + typeOf(value)); | ||
} | ||
if (typeof this.opts.min === 'number' && value < this.opts.min) { | ||
throw new ValidationError(`expected number to be greater than or equal to ${this.opts.min} but got ${value}`); | ||
} | ||
if (typeof this.opts.max === 'number' && value > this.opts.max) { | ||
throw new ValidationError(`expected number to be less than or equal to ${this.opts.max} but got ${value}`); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
min(x) { | ||
this.opts.min = x; | ||
return this; | ||
} | ||
max(x) { | ||
this.opts.max = x; | ||
return this; | ||
} | ||
coerce(value) { | ||
this.opts.coerce = typeof value === 'undefined' ? true : value; | ||
this[coercionTypeSybol] = this.opts.coerce; | ||
return this; | ||
} | ||
} | ||
class UndefinedType extends Type { | ||
parse(value) { | ||
if (value !== undefined) { | ||
throw new ValidationError('expected type to be undefined but got ' + typeOf(value)); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class NullType extends Type { | ||
parse(value) { | ||
if (value !== null) { | ||
throw new ValidationError('expected type to be null but got ' + typeOf(value)); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class LiteralType extends Type { | ||
constructor(literal) { | ||
super(); | ||
this.literal = literal; | ||
} | ||
parse(value) { | ||
if (value !== this.literal) { | ||
const typeofValue = typeof value !== 'object' ? JSON.stringify(value) : typeOf(value); | ||
throw new ValidationError(`expected value to be literal ${JSON.stringify(this.literal)} but got ${typeofValue}`); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class UnknownType extends Type { | ||
parse(value) { | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class OptionalType extends Type { | ||
constructor(schema) { | ||
super(); | ||
this.schema = schema; | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
this[shapekeysSymbol] = this.schema[shapekeysSymbol]; | ||
this[allowUnknownSymbol] = this.schema[allowUnknownSymbol]; | ||
} | ||
parse(value, opts) { | ||
if (value === undefined) { | ||
return undefined; | ||
} | ||
//@ts-ignore | ||
return this.schema.parse(value, opts); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class NullableType extends Type { | ||
constructor(schema) { | ||
super(); | ||
this.schema = schema; | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
this[shapekeysSymbol] = this.schema[shapekeysSymbol]; | ||
this[allowUnknownSymbol] = this.schema[allowUnknownSymbol]; | ||
} | ||
parse(value) { | ||
if (value === null) { | ||
return null; | ||
} | ||
return this.schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
// Non Primitive types | ||
class DateType extends Type { | ||
constructor() { | ||
super(); | ||
this[coercionTypeSybol] = true; | ||
} | ||
parse(value) { | ||
if (typeof value === 'string') { | ||
const date = new Date(value); | ||
if (isNaN(date.getTime())) { | ||
throw new ValidationError(`expected date string to be valid date`); | ||
} | ||
return date; | ||
} | ||
if (!(value instanceof Date)) { | ||
throw new ValidationError('expected type Date but got ' + typeOf(value)); | ||
} | ||
return value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class ObjectType extends Type { | ||
constructor(objectShape, opts) { | ||
super(); | ||
this.objectShape = objectShape; | ||
this.opts = opts; | ||
const keys = Object.keys(this.objectShape); | ||
this[allowUnknownSymbol] = !!(opts === null || opts === void 0 ? void 0 : opts.allowUnknown); | ||
this[shapekeysSymbol] = keys; | ||
this[coercionTypeSybol] = Object.values(this.objectShape).some(schema => schema[coercionTypeSybol]); | ||
} | ||
parse(value, parseOpts = {}) { | ||
var _a; | ||
if (typeof value !== 'object') { | ||
throw new ValidationError('expected type to be object but got ' + typeOf(value)); | ||
} | ||
if (value === null) { | ||
throw new ValidationError('expected object but got null'); | ||
} | ||
if (Array.isArray(value)) { | ||
throw new ValidationError('expected type to be regular object but got array'); | ||
} | ||
const keys = this[shapekeysSymbol]; | ||
const allowUnknown = typeof parseOpts.allowUnknown === 'boolean' ? parseOpts.allowUnknown : (_a = this.opts) === null || _a === void 0 ? void 0 : _a.allowUnknown; | ||
if (!allowUnknown) { | ||
const illegalKeys = []; | ||
for (const k in value) { | ||
if (!keys.includes(k)) { | ||
illegalKeys.push(k); | ||
} | ||
} | ||
if (illegalKeys.length > 0) { | ||
throw new ValidationError('unexpected keys on object: ' + JSON.stringify(illegalKeys)); | ||
} | ||
} | ||
const convVal = this[coercionTypeSybol] ? (allowUnknown ? Object.assign({}, value) : {}) : undefined; | ||
for (const key of keys) { | ||
try { | ||
const schema = this.objectShape[key]; | ||
if (schema instanceof UnknownType && !value.hasOwnProperty(key)) { | ||
throw new ValidationError(`expected key "${key}" of unknown type to be present on object`); | ||
} | ||
if (convVal) { | ||
convVal[key] = schema.parse(value[key], { suppressPathErrMsg: true }); | ||
} | ||
else { | ||
schema.parse(value[key], { suppressPathErrMsg: true }); | ||
} | ||
} | ||
catch (err) { | ||
const path = err.path ? [key, ...err.path] : [key]; | ||
const msg = parseOpts.suppressPathErrMsg | ||
? err.message | ||
: `error parsing object at path: "${prettyPrintPath(path)}" - ${err.message}`; | ||
throw new ValidationError(msg, path); | ||
} | ||
} | ||
return convVal || value; | ||
} | ||
and(schema) { | ||
if (schema instanceof ObjectType) { | ||
const keySet = new Set([...this[shapekeysSymbol], ...schema[shapekeysSymbol]]); | ||
const intersectShape = Array.from(keySet).reduce((acc, key) => { | ||
if (this.objectShape[key] && schema.objectShape[key]) { | ||
acc[key] = new IntersectionType(this.objectShape[key], schema.objectShape[key]); | ||
} | ||
else if (this.objectShape[key]) { | ||
acc[key] = this.objectShape[key]; | ||
} | ||
else { | ||
acc[key] = schema.objectShape[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
return new ObjectType(intersectShape); | ||
} | ||
return new IntersectionType(this, schema); | ||
} | ||
pick(keys, opts) { | ||
const pickedShape = keys.reduce((acc, key) => { | ||
acc[key] = this.objectShape[key]; | ||
return acc; | ||
}, {}); | ||
return new ObjectType(pickedShape, opts); | ||
} | ||
omit(keys, opts) { | ||
const pickedKeys = this[shapekeysSymbol].filter((x) => !keys.includes(x)); | ||
return this.pick(pickedKeys, opts); | ||
} | ||
partial(opts) { | ||
const schema = toPartialSchema(this, { deep: (opts === null || opts === void 0 ? void 0 : opts.deep) || false }).objectShape; | ||
return new ObjectType(schema, { allowUnknown: opts === null || opts === void 0 ? void 0 : opts.allowUnknown }); | ||
} | ||
} | ||
class RecordType extends Type { | ||
constructor(schema) { | ||
super(); | ||
this.schema = schema; | ||
this[coercionTypeSybol] = schema[coercionTypeSybol]; | ||
this._parse = (() => { | ||
if (this.schema instanceof ObjectType || | ||
this.schema instanceof ArrayType || | ||
this.schema instanceof RecordType || | ||
this.schema instanceof IntersectionType) { | ||
//@ts-ignore | ||
return (value) => this.schema.parse(value, { suppressPathErrMsg: true }); | ||
} | ||
return (value) => this.schema.parse(value); | ||
})(); | ||
} | ||
parse(value, opts) { | ||
if (typeof value !== 'object') { | ||
throw new ValidationError('expected type to be object but got ' + typeOf(value)); | ||
} | ||
const convValue = this[coercionTypeSybol] ? {} : undefined; | ||
for (const key in value) { | ||
try { | ||
if (convValue) { | ||
convValue[key] = this._parse(value[key], opts); | ||
} | ||
else { | ||
this._parse(value[key], opts); | ||
} | ||
} | ||
catch (err) { | ||
const path = err.path ? [key, ...err.path] : [key]; | ||
const msg = (opts === null || opts === void 0 ? void 0 : opts.suppressPathErrMsg) ? err.message | ||
: `error parsing record at path "${prettyPrintPath(path)}" - ${err.message}`; | ||
throw new ValidationError(msg, path); | ||
} | ||
} | ||
return convValue || value; | ||
} | ||
and(schema) { | ||
if (schema instanceof RecordType) { | ||
return new RecordType(this.schema.and(schema.schema)); | ||
} | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class ArrayType extends Type { | ||
constructor(schema, opts = {}) { | ||
super(); | ||
this.schema = schema; | ||
this.opts = opts; | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
this._parse = | ||
this.schema instanceof ObjectType || this.schema instanceof ArrayType || this.schema instanceof LazyType | ||
? (elem, parseOptions) => this.schema.parse(elem, { allowUnknown: parseOptions === null || parseOptions === void 0 ? void 0 : parseOptions.allowUnknown, suppressPathErrMsg: true }) | ||
: (elem) => this.schema.parse(elem); | ||
} | ||
parse(value, parseOptions) { | ||
if (!Array.isArray(value)) { | ||
throw new ValidationError('expected an array but got ' + typeOf(value)); | ||
} | ||
if (typeof this.opts.length === 'number' && this.opts.length >= 0 && value.length !== this.opts.length) { | ||
throw new ValidationError(`expected array to have length ${this.opts.length} but got ${value.length}`); | ||
} | ||
if (typeof this.opts.min === 'number' && value.length < this.opts.min) { | ||
throw new ValidationError(`expected array to have length greater than or equal to ${this.opts.min} but got ${value.length}`); | ||
} | ||
if (typeof this.opts.max === 'number' && value.length > this.opts.max) { | ||
throw new ValidationError(`expected array to have length less than or equal to ${this.opts.max} but got ${value.length}`); | ||
} | ||
if (this.opts.unique === true && new Set(value).size !== value.length) { | ||
const seenMap = new Map(); | ||
value.forEach((elem, idx) => { | ||
const seenAt = seenMap.get(elem); | ||
if (!seenAt) { | ||
seenMap.set(elem, [idx]); | ||
} | ||
else { | ||
throw new ValidationError(`expected array to be unique but found same element at indexes ${seenAt[0]} and ${idx}`); | ||
} | ||
}); | ||
} | ||
const convValue = this[coercionTypeSybol] ? [] : undefined; | ||
for (let i = 0; i < value.length; i++) { | ||
try { | ||
if (convValue) { | ||
convValue[i] = this._parse(value[i]); | ||
} | ||
else { | ||
this._parse(value[i], parseOptions); | ||
} | ||
} | ||
catch (err) { | ||
const path = err.path ? [i, ...err.path] : [i]; | ||
const msg = (parseOptions === null || parseOptions === void 0 ? void 0 : parseOptions.suppressPathErrMsg) ? err.message | ||
: `error at ${prettyPrintPath(path)} - ${err.message}`; | ||
throw new ValidationError(msg, path); | ||
} | ||
} | ||
return convValue || value; | ||
} | ||
length(value) { | ||
this.opts.length = value; | ||
return this; | ||
} | ||
min(value) { | ||
this.opts.min = value; | ||
return this; | ||
} | ||
max(value) { | ||
this.opts.max = value; | ||
return this; | ||
} | ||
unique(value = true) { | ||
this.opts.unique = value; | ||
return this; | ||
} | ||
and(schema) { | ||
if (schema instanceof ArrayType) { | ||
return new ArrayType(this.schema.and(schema.schema)); | ||
} | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class TupleType extends Type { | ||
constructor(schemas) { | ||
super(); | ||
this.schemas = schemas; | ||
this[coercionTypeSybol] = schemas.some(schema => schema[coercionTypeSybol]); | ||
} | ||
parse(value) { | ||
if (!Array.isArray(value)) { | ||
throw new ValidationError('expected tuple value to be type array but got ' + typeOf(value)); | ||
} | ||
if (value.length !== this.schemas.length) { | ||
throw new ValidationError(`expected tuple length to be ${this.schemas.length} but got ${value.length}`); | ||
} | ||
const convValue = this[coercionTypeSybol] ? [] : undefined; | ||
for (let i = 0; i < this.schemas.length; i++) { | ||
try { | ||
if (convValue) { | ||
convValue.push(this.schemas[i].parse(value[i])); | ||
} | ||
else { | ||
this.schemas[i].parse(value[i]); | ||
} | ||
} | ||
catch (err) { | ||
throw new ValidationError(`error parsing tuple at index ${i}: ${err.message}`); | ||
} | ||
} | ||
return convValue || value; | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class UnionType extends Type { | ||
constructor(schemas, opts) { | ||
super(); | ||
this.schemas = schemas; | ||
this.opts = opts; | ||
} | ||
parse(value) { | ||
var _a; | ||
const errors = []; | ||
for (const schema of this.schemas) { | ||
try { | ||
if (((_a = this.opts) === null || _a === void 0 ? void 0 : _a.strict) === false && schema instanceof ObjectType) { | ||
return schema.parse(value, { allowUnknown: true }); | ||
} | ||
return schema.parse(value); | ||
} | ||
catch (err) { | ||
errors.push(err.message); | ||
} | ||
} | ||
throw new ValidationError('No union satisfied:\n ' + errors.join('\n ')); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
const isPickOrOmitType = (schema) => schema instanceof PickType || schema instanceof OmitType; | ||
class IntersectionType extends Type { | ||
constructor(left, right) { | ||
super(); | ||
this.left = left; | ||
this.right = right; | ||
this[coercionTypeSybol] = this.left[coercionTypeSybol] || this.right[coercionTypeSybol]; | ||
this[allowUnknownSymbol] = !!(this.left[allowUnknownSymbol] || this.right[allowUnknownSymbol]); | ||
if (this.left[shapekeysSymbol] && this.right[shapekeysSymbol]) { | ||
//@ts-ignore | ||
this[shapekeysSymbol] = Array.from(new Set([...this.left[shapekeysSymbol], ...this.right[shapekeysSymbol]])); | ||
} | ||
this._parse = (() => { | ||
if (this.left instanceof TupleType || this.right instanceof TupleType) { | ||
throw new Error('tuple intersection not supported'); | ||
} | ||
if (this.left instanceof ObjectType && this.right instanceof ObjectType) { | ||
return (value, opts) => this.parseObjectIntersection(value, opts); | ||
} | ||
if (this.left instanceof RecordType && this.right instanceof RecordType) { | ||
const leftSchema = this.left.schema; | ||
const rightSchema = this.right.schema; | ||
const record = new RecordType(leftSchema.and(rightSchema)); | ||
return (value) => record.parse(value); | ||
} | ||
if (this.left instanceof RecordType && this.right instanceof ObjectType) { | ||
//@ts-ignore | ||
return (value) => this.parseRecordObjectIntersection(value, this.left, this.right); | ||
} | ||
if (this.right instanceof RecordType && this.left instanceof ObjectType) { | ||
//@ts-ignore | ||
return (value) => this.parseRecordObjectIntersection(value, this.right, this.left); | ||
} | ||
// TODO Investigate why I unwrap partials in a new intersection again | ||
if (this.left instanceof PartialType) { | ||
return (value) => new IntersectionType(this.left.schema, this.right).parse(value); | ||
} | ||
if (this.right instanceof PartialType) { | ||
return (value) => new IntersectionType(this.left, this.right.schema).parse(value); | ||
} | ||
if (isPickOrOmitType(this.left) || isPickOrOmitType(this.right)) { | ||
return (value) => { | ||
if (this[coercionTypeSybol]) { | ||
return Object.assign(Object.assign({}, this.left.parse(value, { allowUnknown: true })), this.right.parse(value, { allowUnknown: true })); | ||
} | ||
//@ts-ignore | ||
this.left.parse(value, { allowUnknown: true }); | ||
//@ts-ignore | ||
this.right.parse(value, { allowUnknown: true }); | ||
return value; | ||
}; | ||
} | ||
if (this.left instanceof ArrayType && | ||
this.right instanceof ArrayType && | ||
this.left.schema instanceof ObjectType && | ||
this.right.schema instanceof ObjectType) { | ||
if (this[coercionTypeSybol]) { | ||
// todo best effort? Can figure something out if only one subschema is coerced. seems annoying though. | ||
throw new Error('cannot create generic intersection of two object arrays containing coerced values. Try creating intersection via "and"'); | ||
} | ||
return (value) => { | ||
//@ts-ignore | ||
this.left.parse(value, { allowUnknown: true }); | ||
//@ts-ignore | ||
this.right.parse(value, { allowUnknown: true }); | ||
return value; | ||
}; | ||
} | ||
return (value) => { | ||
this.left.parse(value); | ||
this.right.parse(value); | ||
return value; | ||
}; | ||
})(); | ||
} | ||
parse(value, opts) { | ||
const allowUnknown = (opts === null || opts === void 0 ? void 0 : opts.allowUnknown) || this[allowUnknownSymbol]; | ||
if (!allowUnknown && this[shapekeysSymbol]) { | ||
const expectedShapeKeys = this[shapekeysSymbol]; | ||
const invalidKeys = Object.keys(value).filter((key) => !expectedShapeKeys.includes(key)); | ||
if (invalidKeys.length > 0) { | ||
throw new ValidationError('unexpected keys on object ' + JSON.stringify(invalidKeys)); | ||
} | ||
} | ||
return this._parse(value, opts); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
parseObjectIntersection(value, opts) { | ||
const parsingOptions = { suppressPathErrMsg: opts === null || opts === void 0 ? void 0 : opts.suppressPathErrMsg, allowUnknown: true }; | ||
if (this[coercionTypeSybol]) { | ||
return Object.assign(Object.assign({}, this.left.parse(value, parsingOptions)), this.right.parse(value, parsingOptions)); | ||
} | ||
this.left.parse(value, parsingOptions); | ||
this.right.parse(value, parsingOptions); | ||
return value; | ||
} | ||
parseRecordObjectIntersection(value, recordSchema, objectSchema) { | ||
if (this[coercionTypeSybol]) { | ||
const convObj = objectSchema.parse(value, { allowUnknown: true }); | ||
const proxy = Object.keys(value).reduce((acc, key) => { | ||
if (!objectKeys.includes(key)) { | ||
acc[key] = value[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
const convRecord = recordSchema.parse(proxy); | ||
return Object.assign(Object.assign({}, convObj), convRecord); | ||
} | ||
objectSchema.parse(value, { allowUnknown: true }); | ||
const objectKeys = objectSchema[shapekeysSymbol]; | ||
const proxy = Object.keys(value).reduce((acc, key) => { | ||
if (!objectKeys.includes(key)) { | ||
acc[key] = value[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
recordSchema.parse(proxy); | ||
return value; | ||
} | ||
} | ||
class EnumType extends Type { | ||
constructor(enumeration) { | ||
super(); | ||
this.values = Object.values(enumeration); | ||
} | ||
parse(value) { | ||
if (!this.values.includes(value)) { | ||
throw new ValidationError(`error ${JSON.stringify(value)} not part of enum values`); | ||
} | ||
return value; | ||
} | ||
check(value) { | ||
return this.values.includes(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
function toPartialSchema(schema, opts) { | ||
if (schema instanceof ObjectType) { | ||
const originalShape = schema.objectShape; | ||
const shape = Object.keys(originalShape).reduce((acc, key) => { | ||
if (opts === null || opts === void 0 ? void 0 : opts.deep) { | ||
acc[key] = toPartialSchema(originalShape[key], opts).optional(); | ||
} | ||
else { | ||
acc[key] = originalShape[key].optional(); | ||
} | ||
return acc; | ||
}, {}); | ||
return new ObjectType(shape, schema.opts); | ||
} | ||
if (schema instanceof RecordType) { | ||
if (opts === null || opts === void 0 ? void 0 : opts.deep) { | ||
return new RecordType(toPartialSchema(schema.schema, opts).optional()); | ||
} | ||
return new RecordType(schema.schema.optional()); | ||
} | ||
if (schema instanceof IntersectionType) { | ||
return new IntersectionType(toPartialSchema(schema.left, opts), toPartialSchema(schema.right, opts)); | ||
} | ||
if (schema instanceof UnionType) { | ||
return new UnionType(schema.schemas.map((schema) => toPartialSchema(schema, opts))); | ||
} | ||
if (schema instanceof ArrayType) { | ||
if (opts === null || opts === void 0 ? void 0 : opts.deep) { | ||
return new ArrayType(toPartialSchema(schema.schema, opts).optional()); | ||
} | ||
return new ArrayType(schema.schema.optional()); | ||
} | ||
return schema; | ||
} | ||
class PartialType extends Type { | ||
constructor(schema, opts) { | ||
super(); | ||
this.schema = toPartialSchema(schema, opts); | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
} | ||
parse(value) { | ||
return this.schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
const primitiveTypes = [NumberType, StringType, UnknownType, BooleanType, UndefinedType, NullType, LiteralType]; | ||
function isPrimitiveSchema(schema) { | ||
if (primitiveTypes.some(primitiveType => schema instanceof primitiveType)) { | ||
return true; | ||
} | ||
if (schema instanceof IntersectionType) { | ||
return isPrimitiveSchema(schema.left) || isPrimitiveSchema(schema.right); | ||
} | ||
if (schema instanceof UnionType) { | ||
return schema.schemas.every(isPrimitiveSchema); | ||
} | ||
return false; | ||
} | ||
function createPickedSchema(schema, pickedKeys) { | ||
if (schema instanceof ObjectType) { | ||
const shape = schema.objectShape; | ||
const pickedShape = pickedKeys.reduce((acc, key) => { | ||
if (shape[key]) { | ||
acc[key] = shape[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
return new ObjectType(pickedShape, { allowUnknown: true }); | ||
} | ||
if (schema instanceof IntersectionType) { | ||
const newLeft = createPickedSchema(schema.left, pickedKeys); | ||
const newRight = createPickedSchema(schema.right, pickedKeys); | ||
return new IntersectionType(newLeft, newRight); | ||
} | ||
if (schema instanceof PickType || schema instanceof OmitType) { | ||
// This might not hold true at runtime in a JS environment but typescript | ||
// will not allow you to pick keys you've previously omitted, or keys that | ||
// you have not picked. Since this is a TS package lets depend on it a little. | ||
return new PickType(schema.schema, pickedKeys); | ||
} | ||
if (schema instanceof UnionType) { | ||
// TODO ??? | ||
throw new Error('pick of union types not supported'); | ||
} | ||
return schema; | ||
} | ||
class PickType extends Type { | ||
constructor(rootSchema, pickedKeys) { | ||
super(); | ||
this.pickedKeys = pickedKeys; | ||
if (isPrimitiveSchema(rootSchema)) { | ||
throw new Error('cannot instantiate a PickType with a primitive schema'); | ||
} | ||
this.schema = createPickedSchema(rootSchema, pickedKeys); | ||
const rootShapeKeys = rootSchema[shapekeysSymbol]; | ||
this[shapekeysSymbol] = rootShapeKeys && rootShapeKeys.filter((key) => pickedKeys.includes(key)); | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
} | ||
parse(value, parseOptions) { | ||
if (value === null || typeof value !== 'object') { | ||
throw new ValidationError('expected type to be object but got ' + typeOf(value)); | ||
} | ||
if (!(parseOptions === null || parseOptions === void 0 ? void 0 : parseOptions.allowUnknown)) { | ||
const keys = Object.keys(value); | ||
const illegalKeys = keys.filter(key => !this.pickedKeys.includes(key)); | ||
if (illegalKeys.length > 0) { | ||
throw new ValidationError('unexpected keys on object: ' + JSON.stringify(illegalKeys)); | ||
} | ||
} | ||
// For records if the key isn't present the record won't be able to validate it. | ||
if (this.schema instanceof RecordType) { | ||
for (const key of this.pickedKeys) { | ||
if (!value.hasOwnProperty(key)) { | ||
value[key] = undefined; | ||
} | ||
} | ||
} | ||
return this.schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
function createOmittedSchema(schema, omittedKeys) { | ||
if (schema instanceof ObjectType) { | ||
const shape = schema.objectShape; | ||
const omittedShape = Object.keys(shape).reduce((acc, key) => { | ||
if (!omittedKeys.includes(key)) { | ||
acc[key] = shape[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
return new ObjectType(omittedShape, { allowUnknown: true }); | ||
} | ||
if (schema instanceof IntersectionType) { | ||
const newLeft = createOmittedSchema(schema.left, omittedKeys); | ||
const newRight = createOmittedSchema(schema.right, omittedKeys); | ||
return new IntersectionType(newLeft, newRight); | ||
} | ||
if (schema instanceof PickType) { | ||
const pickedKeys = schema.pickedKeys.filter((key) => !omittedKeys.includes(key)); | ||
return new PickType(schema.schema, pickedKeys); | ||
} | ||
if (schema instanceof OmitType) { | ||
return new OmitType(schema.schema, omittedKeys.concat(schema.omittedKeys)); | ||
} | ||
if (schema instanceof UnionType) { | ||
// TODO ??? | ||
throw new Error('omit of union types not supported'); | ||
} | ||
return schema; | ||
} | ||
class OmitType extends Type { | ||
constructor(rootSchema, omittedKeys) { | ||
super(); | ||
this.omittedKeys = omittedKeys; | ||
if (isPrimitiveSchema(rootSchema)) { | ||
throw new Error('cannot instantiate a OmitType with a primitive schema'); | ||
} | ||
this.schema = createOmittedSchema(rootSchema, omittedKeys); | ||
const rootShapeKeys = rootSchema[shapekeysSymbol]; | ||
this[shapekeysSymbol] = rootShapeKeys && rootShapeKeys.filter((key) => !omittedKeys.includes(key)); | ||
this[coercionTypeSybol] = this.schema[coercionTypeSybol]; | ||
} | ||
parse(value, opts) { | ||
if (value === null || typeof value !== 'object') { | ||
throw new ValidationError('expected type to be object but got ' + typeOf(value)); | ||
} | ||
if (!(opts === null || opts === void 0 ? void 0 : opts.allowUnknown)) { | ||
const keys = Object.keys(value); | ||
const illegalKeys = keys.filter(key => this.omittedKeys.includes(key)); | ||
if (illegalKeys.length > 0) { | ||
throw new ValidationError('unexpected keys on object: ' + JSON.stringify(illegalKeys)); | ||
} | ||
} | ||
return this.schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
class LazyType extends Type { | ||
constructor(fn) { | ||
super(); | ||
this.fn = fn; | ||
// Since we can't know what the schema is we can't assume its not a coersionType and we need to disable the optimization | ||
this[coercionTypeSybol] = true; | ||
} | ||
parse(value, opts) { | ||
const schema = this.fn(); | ||
if ((opts === null || opts === void 0 ? void 0 : opts.suppressPathErrMsg) && schema instanceof ObjectType) { | ||
return schema.parse(value, opts); | ||
} | ||
return schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
exports.string = (opts) => new StringType(opts); | ||
exports.boolean = () => new BooleanType(); | ||
exports.number = (opts) => new NumberType(opts); | ||
exports.unknown = () => new UnknownType(); | ||
exports.literal = (literal) => new LiteralType(literal); | ||
exports.object = (shape, opts) => new ObjectType(shape, opts); | ||
exports.array = (type, opts) => new ArrayType(type, opts); | ||
exports.union = (schemas, opts) => new UnionType(schemas, opts); | ||
exports.intersection = (l, r) => new IntersectionType(l, r); | ||
exports.record = (type) => new RecordType(type); | ||
exports.dictionary = (type) => new RecordType(exports.union([type, undefinedValue()])); | ||
exports.partial = (type, opts) => new PartialType(type, opts); | ||
exports.pick = (type, keys) => new PickType(type, keys); | ||
exports.omit = (type, keys) => new OmitType(type, keys); | ||
exports.tuple = (schemas) => new TupleType(schemas); | ||
exports.date = () => new DateType(); | ||
exports.lazy = (fn) => new LazyType(fn); | ||
const undefinedValue = () => new UndefinedType(); | ||
exports.omit = omit; | ||
const undefinedValue = () => new types_1.UndefinedType(); | ||
exports.undefined = undefinedValue; | ||
const nullValue = () => new NullType(); | ||
const nullValue = () => new types_1.NullType(); | ||
exports.null = nullValue; | ||
const enumValue = (e) => new EnumType(e); | ||
const enumValue = (e) => new types_1.EnumType(e); | ||
exports.enum = enumValue; | ||
// Support default imports | ||
exports.default = { | ||
Type, | ||
Type: types_1.Type, | ||
string: exports.string, | ||
@@ -921,9 +67,9 @@ boolean: exports.boolean, | ||
tuple: exports.tuple, | ||
partial: exports.partial, | ||
pick: exports.pick, | ||
omit: exports.omit, | ||
partial, | ||
pick, | ||
omit, | ||
undefined: undefinedValue, | ||
null: nullValue, | ||
enum: enumValue, | ||
ValidationError, | ||
ValidationError: types_1.ValidationError, | ||
}; |
{ | ||
"name": "myzod", | ||
"version": "0.0.30", | ||
"version": "0.0.31", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "./libs/index.js", |
@@ -392,2 +392,14 @@ # myzod | ||
As a utility you can pick directly from a recordSchema and get an equivalent objectSchema: | ||
```typescript | ||
const recordSchema = z.record(z.string()); | ||
type RecordType = z.Infer<typeof recordSchema>; // => { [x: string]: string } | ||
const objSchema = recordSchema.pick(['a', 'b']); | ||
type ObjType = z.Infer<typeof objSchema>; // => { a: string; b: string; } | ||
``` | ||
As a utility for creating records whose values are by default optional, you can use the myzod.dictionary function. | ||
@@ -394,0 +406,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
69539
7
1277
577
1