From 10b088b7fbfc08b383b3716e7c1ef7fd1dfd65e7 Mon Sep 17 00:00:00 2001 From: khaled Date: Sat, 28 Aug 2021 12:49:07 +0300 Subject: [PATCH] refactor: refactor type-utils & DRY shaped and of validator --- src/createErrors.ts | 112 +++++++++++++++++--------------------------- src/type-utils.ts | 22 +++++++++ src/utils.ts | 7 +-- 3 files changed, 68 insertions(+), 73 deletions(-) diff --git a/src/createErrors.ts b/src/createErrors.ts index 9ed1dca..a053b43 100644 --- a/src/createErrors.ts +++ b/src/createErrors.ts @@ -6,6 +6,7 @@ import { ObjectKeys, toObj, shouldAddToResult, + isArray, } from './utils'; import { BooleanValidator, @@ -20,6 +21,7 @@ import { UnionValidator, Validator, } from './validatorTypes'; +import { InferResult, InferCallbackResult } from './type-utils'; import { TYPEERR } from './constants'; import invariant from 'tiny-invariant'; @@ -37,26 +39,42 @@ function enterNode(validator: Validator, value: unknown, eager = false) { return fn(validator, value, eager); } -type InferCallbackResult = V extends - | StringValidator - | NumberValidator - | BooleanValidator - | ConstantValidator - | UnionValidator - ? string - : V extends ListValidator - ? { [key in number]?: InferCallbackResult } - : V extends ListofValidator - ? { [key: number]: InferCallbackResult | undefined } - : V extends RecordValidator - ? { [key in keyof U]?: InferCallbackResult } - : V extends RecordofValidator - ? { [key: string]: InferCallbackResult | undefined } - : never; - -type InferResult = { - [key in keyof S]?: InferCallbackResult; -}; +function parseShapeValidator( + validator: RecordValidator | ListValidator, + value: unknown, + eager = false +) { + const shape = toObj(validator).shape; + const keys = ObjectKeys(shape); + const values = toObj(value); + const result: Record = {}; + for (let i = 0; i < keys.length; i++) { + const currentResult = enterNode(shape[keys[i]], values[keys[i]]); + if (shouldAddToResult(currentResult)) { + result[keys[i]] = currentResult; + if (eager) return result; + } + } + return normalizeResult(result); +} + +function parseOfValidator( + validator: RecordofValidator | ListofValidator, + value: unknown, + eager = false +) { + const values = toObj(value); + const keys = ObjectKeys(values); + const result: Record = {}; + for (let i = 0; i < keys.length; i++) { + const currentResult = enterNode(validator.of, values[keys[i]]); + if (shouldAddToResult(currentResult)) { + result[keys[i]] = currentResult; + if (eager) return result; + } + } + return normalizeResult(result); +} const validators = { string(validator: StringValidator, value: unknown) { @@ -117,65 +135,23 @@ const validators = { }, list(validator: ListValidator, value: unknown, eager = false) { if (shouldSkipValidation(value, validator)) return null; - if (!Array.isArray(value)) return TYPEERR; - const shape = toObj(validator).shape; - const keys = ObjectKeys(shape); - const values = toObj(value); - const result: Record = {}; - for (let i = 0; i < keys.length; i++) { - const currentResult = enterNode(shape[keys[i]], values[keys[i]]); - if (shouldAddToResult(currentResult)) { - result[keys[i]] = currentResult; - if (eager) return result; - } - } - return normalizeResult(result); + if (!isArray(value)) return TYPEERR; + return parseShapeValidator(validator, value, eager); }, listof(validator: ListofValidator, value: unknown, eager = false) { if (shouldSkipValidation(value, validator)) return null; - if (!Array.isArray(value)) return TYPEERR; - const values = toObj(value); - const keys = ObjectKeys(values); - const result: Record = {}; - for (let i = 0; i < keys.length; i++) { - const currentResult = enterNode(validator.of, values[keys[i]]); - if (shouldAddToResult(currentResult)) { - result[keys[i]] = currentResult; - if (eager) return result; - } - } - return normalizeResult(result); + if (!isArray(value)) return TYPEERR; + return parseOfValidator(validator, value, eager); }, record(validator: RecordValidator, value: unknown, eager = false) { if (shouldSkipValidation(value, validator)) return null; if (!isPlainObject(value)) return TYPEERR; - const shape = toObj(validator).shape; - const keys = ObjectKeys(shape); - const values = toObj(value); - const result: Record = {}; - for (let i = 0; i < keys.length; i++) { - const currentResult = enterNode(shape[keys[i]], values[keys[i]]); - if (shouldAddToResult(currentResult)) { - result[keys[i]] = currentResult; - if (eager) return result; - } - } - return normalizeResult(result); + return parseShapeValidator(validator, value, eager); }, recordof(validator: RecordofValidator, value: unknown, eager = false) { if (shouldSkipValidation(value, validator)) return null; if (!isPlainObject(value)) return TYPEERR; - const values = toObj(value); - const keys = ObjectKeys(values); - const result: Record = {}; - for (let i = 0; i < keys.length; i++) { - const currentResult = enterNode(validator.of, values[keys[i]]); - if (shouldAddToResult(currentResult)) { - result[keys[i]] = currentResult; - if (eager) return result; - } - } - return normalizeResult(result); + return parseOfValidator(validator, value, eager); }, }; diff --git a/src/type-utils.ts b/src/type-utils.ts index c75fe6e..ceba9ce 100644 --- a/src/type-utils.ts +++ b/src/type-utils.ts @@ -10,6 +10,7 @@ import { Schema, ConstantValidator, UnionValidator, + Validator, } from './validatorTypes'; type InferTypeWithOptional = T extends O ? U | undefined : U; @@ -43,3 +44,24 @@ type InferDataType = T extends UnionValidator export type DataFrom = { [K in keyof S]: InferDataType; }; + +export type InferCallbackResult = V extends + | StringValidator + | NumberValidator + | BooleanValidator + | ConstantValidator + | UnionValidator + ? string + : V extends ListValidator + ? { [key in number]?: InferCallbackResult } + : V extends ListofValidator + ? { [key: number]: InferCallbackResult | undefined } + : V extends RecordValidator + ? { [key in keyof U]?: InferCallbackResult } + : V extends RecordofValidator + ? { [key: string]: InferCallbackResult | undefined } + : never; + +export type InferResult = { + [key in keyof S]?: InferCallbackResult; +}; diff --git a/src/utils.ts b/src/utils.ts index dbc4290..01396bf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,5 @@ export const ObjectKeys = Object.keys.bind(Object); +export const isArray = (value: unknown): value is any[] => Array.isArray(value); export const isBool = (value: unknown): value is boolean => typeof value == 'boolean'; export const isString = (value: unknown): value is string => typeof value == 'string'; export const isNumber = (value: unknown): value is number => @@ -24,9 +25,5 @@ export function shouldAddToResult(res: unknown) { } export function toObj(value: any) { - return Array.isArray(value) - ? { ...value } - : isPlainObject(value) - ? value - : ({} as Record); + return isArray(value) ? { ...value } : isPlainObject(value) ? value : ({} as Record); }