-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
73 lines (61 loc) · 2.84 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
export type ValidatorFunction = (value: any) => boolean
export interface ValidationRule {
message: string
validator: ValidatorFunction | ValidatorFunction[]
}
export type ObjectSchema<T> = { [K in keyof T]: ValidationRule[] }
const isFalse = (val: boolean) => val === false
const notNull = (val: any) => val !== null
const upperCaseFirstLetter = (val: string) => val.charAt(0).toUpperCase() + val.slice(1)
const getKeys = <T>(object: T) => Object.keys(object) as Array<keyof T>
export function schema<T>(objectSchema: ObjectSchema<T>) {
const validateRule = (value: any) => (rule: ValidationRule) => {
if (rule.validator instanceof Array) {
const isInvalid = rule.validator.map(validator => validator(value)).some(isFalse)
return isInvalid ? rule.message : null
}
return rule.validator(value) === false ? rule.message : null
}
function validateField(key: keyof T): (value: any) => string | null
function validateField(key: keyof T, value: any): string | null
function validateField(key: keyof T, value?: any) {
if (value === undefined) {
return (value: any) => validateField(key, value)
}
const rules = objectSchema[key]
if (!rules) {
return null
}
return rules.map(validateRule(value)).filter(notNull)[0]
}
function validate(object: T) {
return getKeys(objectSchema)
.map(key => ({
[key]: validateField(key, object[key]),
}))
.reduce((acc, next) => {
for (let key in next) acc[key] = next[key]
return acc
}, {})
}
return { validate, validateField }
}
const EMAIL_REGEXP = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
const URL_REGEXP = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/
export const required = (value: any) => value !== null && value !== undefined
export const string = (value: any) => typeof value === 'string'
export const number = (value: any) => typeof value === 'number'
export const notEmpty = (value: any) => required(value) && value.length != 0
export const email = (value: any) => EMAIL_REGEXP.test(value)
export const url = (value: any) => URL_REGEXP.test(value)
export const array = (value: any) => value.constructor === Array
export const numeric = (value: any) =>
required(value) && !isNaN(parseFloat(value)) && isFinite(value)
export const minLength = (minLenght: number) => (value: any) =>
notEmpty(value) && value.length >= minLenght
export const maxLength = (maxLenght: number) => (value: any) =>
notEmpty(value) && value.length <= maxLenght
export const minNumbersInString = (minNumbers: number) => (value: any) =>
value.replace(/[^0-9]/g, '').length >= minNumbers
export const maxNumbersInString = (maxNumbers: number) => (value: any) =>
value.replace(/[^0-9]/g, '').length <= maxNumbers