Comparing version 0.0.31 to 0.0.32
@@ -1,3 +0,3 @@ | ||
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'; | ||
import { ValidationError, Type, StringType, NumberType, LiteralType, ObjectType, ArrayType, UnionType, PartialType, TupleType, DateType, LazyType, UndefinedType, NullType, EnumType, BooleanType, UnknownType, Literal, ObjectShape, ObjectOptions, AnyType, UnionOptions, PartialOpts, IntersectionResult, DeepPartialShape, PartialShape, Eval, ToUnion, keySignature, StringTypes } from './types'; | ||
export { ValidationError, Type, Infer, keySignature } from './types'; | ||
export declare const string: (opts?: Partial<{ | ||
@@ -18,3 +18,3 @@ pattern: RegExp; | ||
export declare const literal: <T extends Literal>(literal: T) => LiteralType<T>; | ||
export declare const object: <T extends Record<string, AnyType>>(shape: T, opts?: ObjectOptions | undefined) => ObjectType<T>; | ||
export declare const object: <T extends ObjectShape>(shape: T, opts?: ObjectOptions | undefined) => ObjectType<T>; | ||
export declare const array: <T extends AnyType>(schema: T, opts?: Partial<{ | ||
@@ -28,4 +28,8 @@ length: number; | ||
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 record: <T extends AnyType>(schema: T) => ObjectType<{ | ||
[keySignature]: T; | ||
}>; | ||
export declare const dictionary: <T extends AnyType>(schema: T) => ObjectType<{ | ||
[keySignature]: import("./types").OptionalType<Type<any>>; | ||
}>; | ||
export declare const tuple: <T extends [] | [AnyType, ...AnyType[]]>(schemas: T) => TupleType<T>; | ||
@@ -38,9 +42,12 @@ export declare const date: () => DateType; | ||
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>; | ||
export declare function pick<T extends ObjectType<any>, K extends T extends ObjectType<infer Shape> ? Shape extends { | ||
[keySignature]: AnyType; | ||
} ? string : StringTypes<keyof Shape> : never>(schema: T, keys: K[]): T extends ObjectType<infer Shape> ? ObjectType<Eval<Pick<Shape, Extract<StringTypes<keyof Shape>, ToUnion<typeof keys>>> & (Shape extends { | ||
[keySignature]: AnyType; | ||
} ? Shape extends { | ||
[keySignature]: infer KeySig; | ||
} ? { | ||
[key in Exclude<ToUnion<typeof keys>, keyof Shape>]: KeySig; | ||
} : {} : {})>> : never; | ||
export declare function omit<T extends ObjectType<any>, K extends T extends ObjectType<infer Shape> ? StringTypes<keyof Shape> : never>(schema: T, keys: K[]): T extends ObjectType<infer Shape> ? ObjectType<Eval<Omit<Shape, ToUnion<typeof keys>>>> : never; | ||
declare const undefinedValue: () => UndefinedType; | ||
@@ -68,3 +75,3 @@ declare const nullValue: () => NullType; | ||
date: () => DateType; | ||
object: <T_1 extends Record<string, AnyType>>(shape: T_1, opts?: ObjectOptions | undefined) => ObjectType<T_1>; | ||
object: <T_1 extends ObjectShape>(shape: T_1, opts?: ObjectOptions | undefined) => ObjectType<T_1>; | ||
array: <T_2 extends AnyType>(schema: T_2, opts?: Partial<{ | ||
@@ -78,4 +85,8 @@ length: number; | ||
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>>>; | ||
record: <T_5 extends AnyType>(schema: T_5) => ObjectType<{ | ||
[keySignature]: T_5; | ||
}>; | ||
dictionary: <T_6 extends AnyType>(schema: T_6) => ObjectType<{ | ||
[keySignature]: import("./types").OptionalType<Type<any>>; | ||
}>; | ||
tuple: <T_7 extends [] | [AnyType, ...AnyType[]]>(schemas: T_7) => TupleType<T_7>; | ||
@@ -89,3 +100,4 @@ partial: typeof partial; | ||
ValidationError: typeof ValidationError; | ||
keySignature: symbol; | ||
}; | ||
export default _default; |
@@ -7,2 +7,3 @@ "use strict"; | ||
exports.Type = types_2.Type; | ||
exports.keySignature = types_2.keySignature; | ||
exports.string = (opts) => new types_1.StringType(opts); | ||
@@ -17,4 +18,4 @@ exports.boolean = () => new types_1.BooleanType(); | ||
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.record = (schema) => new types_1.ObjectType({ [types_1.keySignature]: schema }); | ||
exports.dictionary = (schema) => new types_1.ObjectType({ [types_1.keySignature]: schema.optional() }); | ||
exports.tuple = (schemas) => new types_1.TupleType(schemas); | ||
@@ -31,16 +32,7 @@ exports.date = () => new types_1.DateType(); | ||
function pick(schema, keys) { | ||
if (schema instanceof types_1.ObjectType) { | ||
return schema.pick(keys); | ||
} | ||
if (schema instanceof types_1.RecordType) { | ||
return schema.pick(keys); | ||
} | ||
return new types_1.PickType(schema, keys); | ||
return schema.pick(keys); | ||
} | ||
exports.pick = pick; | ||
function omit(schema, keys) { | ||
if (schema instanceof types_1.ObjectType) { | ||
return schema.omit(keys); | ||
} | ||
return new types_1.OmitType(schema, keys); | ||
return schema.omit(keys); | ||
} | ||
@@ -77,2 +69,7 @@ exports.omit = omit; | ||
ValidationError: types_1.ValidationError, | ||
keySignature: types_1.keySignature, | ||
}; | ||
// type AssertEqual<T, K> = [T] extends [K] ? ([K] extends [T] ? true : false) : false; | ||
// const schema = object({ a: string(), b: number(), [keySignature]: boolean() }).omit(['a']); | ||
// const x: Infer<typeof schema> = { a: 1 }; | ||
// x; |
@@ -19,3 +19,3 @@ export declare abstract class Type<T> { | ||
export declare type Infer<T extends AnyType> = T extends Type<infer K> ? Eval<K> : any; | ||
export 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>; | ||
export 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> : IntersectionType<T, K>; | ||
export declare type StringOptions = Partial<{ | ||
@@ -92,8 +92,19 @@ pattern: RegExp; | ||
} | ||
export declare type ObjectShape = Record<string, AnyType>; | ||
export declare const keySignature: unique symbol; | ||
export declare type ObjectShape = { | ||
[key: string]: AnyType; | ||
[keySignature]?: AnyType; | ||
}; | ||
declare type OptionalKeys<T extends ObjectShape> = { | ||
[key in keyof T]: undefined extends Infer<T[key]> ? key : never; | ||
[key in keyof T]: undefined extends Infer<T[key]> ? (key extends symbol ? never : key) : never; | ||
}[keyof T]; | ||
declare type RequiredKeys<T extends ObjectShape> = Exclude<keyof T, OptionalKeys<T>>; | ||
declare type InferObjectShape<T extends ObjectShape> = { | ||
declare type RequiredKeys<T extends ObjectShape> = Exclude<string & keyof T, OptionalKeys<T>>; | ||
declare type InferKeySignature<T extends ObjectShape> = T extends { | ||
[keySignature]: AnyType; | ||
} ? T extends { | ||
[keySignature]: infer KeySig; | ||
} ? KeySig extends AnyType ? { | ||
[key: string]: Infer<KeySig>; | ||
} : {} : {} : {}; | ||
declare type InferObjectShape<T extends ObjectShape> = InferKeySignature<T> & { | ||
[key in OptionalKeys<T>]?: T[key] extends Type<infer K> ? K : any; | ||
@@ -105,3 +116,3 @@ } & { | ||
export declare type PartialShape<T extends ObjectShape> = { | ||
[key in keyof T]: UnionType<[T[key], UndefinedType]>; | ||
[key in keyof T]: T[key] extends OptionalType<any> ? T[key] : OptionalType<T[key]>; | ||
}; | ||
@@ -114,2 +125,3 @@ export declare type DeepPartialShape<T extends ObjectShape> = { | ||
}; | ||
export declare type StringTypes<T> = T extends string ? T : never; | ||
export declare type PathOptions = { | ||
@@ -127,4 +139,12 @@ suppressPathErrMsg?: boolean; | ||
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>>>>; | ||
pick<K extends T extends { | ||
[keySignature]: AnyType; | ||
} ? string : StringTypes<keyof T>>(keys: K[], opts?: ObjectOptions): ObjectType<Eval<Pick<T, Extract<StringTypes<keyof T>, ToUnion<typeof keys>>> & (T extends { | ||
[keySignature]: AnyType; | ||
} ? T extends { | ||
[keySignature]: infer KeySig; | ||
} ? { | ||
[key in Exclude<ToUnion<typeof keys>, keyof T>]: KeySig; | ||
} : {} : {})>>; | ||
omit<K extends StringTypes<keyof T>>(keys: K[], opts?: ObjectOptions): ObjectType<Eval<Omit<T, ToUnion<typeof keys>>>>; | ||
partial<K extends ObjectOptions & PartialOpts>(opts?: K): ObjectType<Eval<K extends { | ||
@@ -134,12 +154,2 @@ deep: true; | ||
} | ||
export 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>; | ||
pick<K extends string>(keys: K[]): ObjectType<{ | ||
[key in ToUnion<typeof keys>]: T; | ||
}>; | ||
} | ||
export declare type ArrayOptions = Partial<{ | ||
@@ -190,3 +200,2 @@ length: number; | ||
and<K extends AnyType>(schema: K): IntersectionType<this, K>; | ||
private parseRecordObjectIntersection; | ||
} | ||
@@ -217,16 +226,2 @@ declare type ValueOf<T> = T[keyof T]; | ||
} | ||
export 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>; | ||
} | ||
export 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>; | ||
} | ||
export declare class LazyType<T extends () => AnyType> extends Type<Infer<ReturnType<T>>> { | ||
@@ -233,0 +228,0 @@ private readonly fn; |
@@ -264,2 +264,3 @@ "use strict"; | ||
exports.DateType = DateType; | ||
exports.keySignature = Symbol.for('keySignature'); | ||
class ObjectType extends Type { | ||
@@ -273,3 +274,6 @@ constructor(objectShape, opts) { | ||
this[shapekeysSymbol] = keys; | ||
this[coercionTypeSybol] = Object.values(this.objectShape).some(schema => schema[coercionTypeSybol]); | ||
this[coercionTypeSybol] = | ||
Object.values(this.objectShape).some(schema => schema[coercionTypeSybol]) || | ||
!!(this.objectShape[exports.keySignature] && this.objectShape[exports.keySignature][coercionTypeSybol]); | ||
this[exports.keySignature] = this.objectShape[exports.keySignature]; | ||
} | ||
@@ -289,3 +293,4 @@ parse(value, parseOpts = {}) { | ||
const allowUnknown = typeof parseOpts.allowUnknown === 'boolean' ? parseOpts.allowUnknown : (_a = this.opts) === null || _a === void 0 ? void 0 : _a.allowUnknown; | ||
if (!allowUnknown) { | ||
const keySig = this.objectShape[exports.keySignature]; | ||
if (!allowUnknown && !keySig) { | ||
const illegalKeys = []; | ||
@@ -301,2 +306,25 @@ for (const k in value) { | ||
} | ||
if (keySig) { | ||
const convVal = this[coercionTypeSybol] ? {} : undefined; | ||
for (const key in value) { | ||
try { | ||
if (convVal) { | ||
// @ts-ignore | ||
convVal[key] = (this.objectShape[key] || keySig).parse(value[key], { suppressPathErrMsg: true }); | ||
} | ||
else { | ||
// @ts-ignore | ||
(this.objectShape[key] || keySig).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; | ||
} | ||
const convVal = this[coercionTypeSybol] ? (allowUnknown ? Object.assign({}, value) : {}) : undefined; | ||
@@ -341,2 +369,10 @@ for (const key of keys) { | ||
}, {}); | ||
const selfKeySig = this.objectShape[exports.keySignature]; | ||
const targetKeySig = schema[exports.keySignature]; | ||
if (selfKeySig && targetKeySig) { | ||
intersectShape[exports.keySignature] = selfKeySig.and(targetKeySig); | ||
} | ||
else if (selfKeySig || targetKeySig) { | ||
intersectShape[exports.keySignature] = selfKeySig || targetKeySig; | ||
} | ||
return new ObjectType(intersectShape); | ||
@@ -348,4 +384,4 @@ } | ||
const pickedShape = keys.reduce((acc, key) => { | ||
if (this.objectShape[key]) { | ||
acc[key] = this.objectShape[key]; | ||
if (this.objectShape[key] || this.objectShape[exports.keySignature]) { | ||
acc[key] = this.objectShape[key] || this.objectShape[exports.keySignature]; | ||
} | ||
@@ -358,3 +394,6 @@ return acc; | ||
const pickedKeys = this[shapekeysSymbol].filter((x) => !keys.includes(x)); | ||
return this.pick(pickedKeys, opts); | ||
if (!this[exports.keySignature]) { | ||
return this.pick(pickedKeys, opts); | ||
} | ||
return this.pick(pickedKeys, opts).and(new ObjectType({ [exports.keySignature]: this[exports.keySignature] })); | ||
} | ||
@@ -367,55 +406,2 @@ partial(opts) { | ||
exports.ObjectType = ObjectType; | ||
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); | ||
} | ||
pick(keys) { | ||
return new ObjectType(keys.reduce((acc, key) => { | ||
acc[key] = this.schema; | ||
return acc; | ||
}, {})); | ||
} | ||
} | ||
exports.RecordType = RecordType; | ||
class ArrayType extends Type { | ||
@@ -557,3 +543,2 @@ constructor(schema, opts = {}) { | ||
exports.UnionType = UnionType; | ||
const isPickOrOmitType = (schema) => schema instanceof PickType || schema instanceof OmitType; | ||
class IntersectionType extends Type { | ||
@@ -574,10 +559,2 @@ constructor(left, right) { | ||
} | ||
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 | ||
@@ -590,14 +567,2 @@ if (this.left instanceof PartialType) { | ||
} | ||
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; | ||
}; | ||
} | ||
return (value) => { | ||
@@ -624,25 +589,2 @@ this.left.parse(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; | ||
} | ||
} | ||
@@ -681,10 +623,13 @@ exports.IntersectionType = IntersectionType; | ||
}, {}); | ||
const keysig = originalShape[exports.keySignature]; | ||
if (keysig) { | ||
if (opts === null || opts === void 0 ? void 0 : opts.deep) { | ||
shape[exports.keySignature] = toPartialSchema(keysig, opts).optional(); | ||
} | ||
else { | ||
shape[exports.keySignature] = keysig.optional(); | ||
} | ||
} | ||
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) { | ||
@@ -718,141 +663,2 @@ return new IntersectionType(toPartialSchema(schema.left, opts), toPartialSchema(schema.right, opts)); | ||
exports.PartialType = PartialType; | ||
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) { | ||
return schema.pick(pickedKeys); | ||
} | ||
if (schema instanceof RecordType) { | ||
return schema.pick(pickedKeys); | ||
} | ||
if (schema instanceof IntersectionType) { | ||
const l = schema.left; | ||
const r = schema.right; | ||
if (l instanceof ObjectType && r instanceof RecordType) { | ||
const objectKeys = l[shapekeysSymbol]; | ||
const recordKeys = pickedKeys.filter(key => !objectKeys.includes(key)); | ||
return l.pick(pickedKeys).and(r.pick(recordKeys)); | ||
} | ||
if (l instanceof RecordType && r instanceof ObjectType) { | ||
const objectKeys = r[shapekeysSymbol]; | ||
const recordKeys = pickedKeys.filter(key => !objectKeys.includes(key)); | ||
return r.pick(pickedKeys).and(l.pick(recordKeys)); | ||
} | ||
const newLeft = createPickedSchema(l, pickedKeys); | ||
const newRight = createPickedSchema(r, 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); | ||
console.log('BANANA BOAT'); | ||
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)); | ||
} | ||
} | ||
return this.schema.parse(value); | ||
} | ||
and(schema) { | ||
return new IntersectionType(this, schema); | ||
} | ||
} | ||
exports.PickType = PickType; | ||
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); | ||
} | ||
} | ||
exports.OmitType = OmitType; | ||
class LazyType extends Type { | ||
@@ -859,0 +665,0 @@ constructor(fn) { |
{ | ||
"name": "myzod", | ||
"version": "0.0.31", | ||
"version": "0.0.32", | ||
"description": "", | ||
@@ -27,3 +27,2 @@ "main": "./libs/index.js", | ||
"devDependencies": { | ||
"@types/benchmark": "^1.0.31", | ||
"@types/mocha": "^7.0.2", | ||
@@ -66,3 +65,4 @@ "@types/node": "^13.11.1", | ||
] | ||
} | ||
}, | ||
"dependencies": {} | ||
} |
@@ -77,5 +77,5 @@ # myzod | ||
- [object](#object) | ||
- [record](#record) | ||
- [array](#array) | ||
- [tuple](#tuple) | ||
- [record](#record) | ||
- [enum](#enum) | ||
@@ -323,41 +323,18 @@ - [date](#date) | ||
#### Array | ||
##### Key Signatures | ||
options: | ||
In the next section myzod goes over "records" which is the simple and idiomatic way in typescript of describing an object with solely a key signature. | ||
However you can use key signatures directly in your object schema definitions if you like using the myzod.keySignature symbol. | ||
- length: `number` - the expected length of the array | ||
- min: `number` - the minimum length of the array | ||
- max: `number` - the maximum length of the array | ||
- unique: `boolean` - should the array be unique. default `false` | ||
Signature: | ||
```typescript | ||
function array(schema: Type<T>, opts?: Options); | ||
``` | ||
const scores = myzod.object({ [myzod.keySignature]: myzod.number() }); // same as: myzod.record(myzod.number()); | ||
Example: | ||
```typescript | ||
const schema = myzod.array(myzod.number()).unique(); | ||
type Schema = Infer<typeof schema>; // => string[] | ||
schema.parse([1, 1, 2]); // => throws ValidationError | ||
type Scores = myzod.Infer<typeof scores>; // => { [x: string]: number } | ||
``` | ||
#### Tuple | ||
The advantage of this approach is to mix statically known keys with a keysignature without intersecting records and objects. | ||
Tuples are similar to arrays but allow for mixed types of static length. | ||
Note that myzod does not support intersections of tuple types at this time. | ||
```typescript | ||
const schema = myzod.tuple([myzod.string(), myzod.object({ key: myzod.boolean() }), myzod.array(myzod.number())]); | ||
type Schema = Infer<typeof schema>; // => [string, { key: boolean; }, number[]]; | ||
``` | ||
#### Record | ||
The record type emulates as the equivalent typescript type: `Record<string, T>`. | ||
The record function emulates as the equivalent typescript type: `Record<string, T>`. | ||
@@ -419,2 +396,38 @@ ```typescript | ||
#### Array | ||
options: | ||
- length: `number` - the expected length of the array | ||
- min: `number` - the minimum length of the array | ||
- max: `number` - the maximum length of the array | ||
- unique: `boolean` - should the array be unique. default `false` | ||
Signature: | ||
```typescript | ||
function array(schema: Type<T>, opts?: Options); | ||
``` | ||
Example: | ||
```typescript | ||
const schema = myzod.array(myzod.number()).unique(); | ||
type Schema = Infer<typeof schema>; // => string[] | ||
schema.parse([1, 1, 2]); // => throws ValidationError | ||
``` | ||
#### Tuple | ||
Tuples are similar to arrays but allow for mixed types of static length. | ||
Note that myzod does not support intersections of tuple types at this time. | ||
```typescript | ||
const schema = myzod.tuple([myzod.string(), myzod.object({ key: myzod.boolean() }), myzod.array(myzod.number())]); | ||
type Schema = Infer<typeof schema>; // => [string, { key: boolean; }, number[]]; | ||
``` | ||
#### Enum | ||
@@ -421,0 +434,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
8
590
0
61786
1087