-
Notifications
You must be signed in to change notification settings - Fork 0
/
model.ts
89 lines (76 loc) · 2.83 KB
/
model.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// types
interface Validator {
(types: object, required: object, data: object): boolean;
}
export interface Model {
is(type, value:any): boolean;
check(types: object, required: object, data: object): boolean;
init(types: object): ModelInstance;
init(types: object, validator: Function): ModelInstance;
init(types: object, required: object, validator: Function): ModelInstance;
init(types: object, required: object): ModelInstance;
ArrayOf(M: Function): ModelInstance;
}
export interface ModelInstance {
isValid(data: object): boolean;
whenValid(data: object): Promise<object>;
}
// code
// Validate JS objects for their "shape"
const model:Model = {
is(type, value) {
if(type && type.isValid instanceof Function){
return type.isValid(value)
} else if((type === String && ((value instanceof String) || typeof value === 'string'))
|| (type === Number && ((value instanceof Number) || typeof value === 'number'))
|| (type === Boolean && ((value instanceof Boolean) || typeof value === 'boolean'))
|| (type === Function && ((value instanceof Function) || typeof value === 'function'))
|| (type === Object && ((value instanceof Object) || typeof value === 'object'))
|| (type === undefined)
){
return true
}
return false
},
check(types, required, data) {
Object.keys(types).forEach(key => {
let t = types[key],
value = data[key]
if(required[key] || value !== undefined){
if(!(t instanceof Array)) t = [t]
let i = t.reduce((a,_type) => a || model.is(_type, value), false)
if(!i) {
throw `{${key}: ${JSON.stringify(value)}} is not one of ${t.map(x => `\n - ${x}`)}`
}
}
})
return true
},
init(...args) {
let types, required, logic
args.map(x => {
if(x instanceof Function && !logic){ logic = x }
else if(typeof x === 'object') {
if(!types){ types = x }
else if(!required){ required = x }
}
})
const isValid = (data) => {
const pipe = logic ? [model.check, logic] : [model.check]
return pipe.reduce((a,v) => a && v(types||{},required||{},data), true)
}
const whenValid = (data) => new Promise((res,rej) => isValid(data) && res(data))
return {isValid, whenValid}
},
ArrayOf(M) {
return model.init((t,r,data) => {
if(!(data instanceof Array)) throw `${data} not an Array`
data.map(x => {
if(!model.is(M, x))
throw `${x} is not a model instance`
})
return true
})
}
}
export default model