-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
124 lines (98 loc) · 2.85 KB
/
Copy pathindex.ts
File metadata and controls
124 lines (98 loc) · 2.85 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
type PojoType = "undefined" | "boolean" | "number" | "string" | "symbol" | "object" | "array"
type PojoSchema<T> = { [key in keyof T]: PojoType[] }
type ArrayType<T extends any[]> = T extends (infer I)[] ? I : never
function isUndefined(thing: any) : thing is undefined {
return thing === void 0;
}
function isNumber(thing: any) : thing is number {
return !isNaN(thing)
}
function isBoolean(thing: any) : thing is boolean {
return thing === true || thing === false;
}
function isString(thing: any) : thing is string {
return typeof thing === 'string'
}
function isArray(thing: any) : thing is any[] {
return Array.isArray(thing);
}
function isObject(thing: any) : thing is object {
return !isArray(thing) && typeof thing === 'object'
}
function isSymbol(thing: any) : thing is symbol {
return typeof thing === 'symbol'
}
function has<T extends {}>(obj: T, prop: string) : boolean {
return isObject(obj) && obj.hasOwnProperty(prop);
}
function contains<T extends any[]>(arr: T, pred: (it: ArrayType<T>) => boolean) : boolean {
for (const it of arr) {
if (pred(it)) return true;
}
return false;
}
/**
* Returns true if obj matches the type
*
* @export
* @param {unknown} obj
* @param {PojoType} type
* @returns {boolean}
*/
export function isType(thing: unknown, type: PojoType) : boolean {
switch (type) {
case "undefined": return isUndefined(thing)
case "number": return isNumber(thing)
case "boolean": return isBoolean(thing)
case "string": return isString(thing)
case "object": return isObject(thing)
case "array": return isArray(thing)
case "symbol": return isSymbol(thing)
default: return false
}
}
export type WeeSchema<T extends {}> = {
ok: (obj: any) => obj is T,
assert: (obj: any) => asserts obj is T,
inspect: (obj: any) => string[]
}
/**
* Returns a mini schema validator :)
*
* @export
* @param {PojoSchema} sch
* @returns
*/
export function weeschema<T extends {}>(sch: PojoSchema<T>) : WeeSchema<T> {
const inspect = (obj: any) : string[] => {
const props = Object.keys(sch);
const errors = [];
for (const key in obj) {
if (!contains(props, p => p === key)) {
errors.push(`Invalid key '${key}'`);
}
}
for (const prop in sch) {
const types = sch[prop];
if (!has(obj, prop)) {
errors.push(`Missing key '${prop}'`)
continue
}
if (!contains(types, (t) => isType(obj[prop], t))) {
errors.push(`Invalid type for key '${prop}'`);
}
}
return errors;
}
const ok = (obj: any) : obj is T => {
return inspect(obj).length === 0
}
const assert = (obj: any) : asserts obj is T => {
const errors = inspect(obj)
if (errors.length) {
throw new Error(errors.join(', '));
}
}
return { ok, inspect, assert };
}
export default weeschema;