-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidator.js
135 lines (115 loc) · 3.17 KB
/
validator.js
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
125
126
127
128
129
130
131
132
133
134
135
const { List } = require('immutable-ext')
const { __, equals, where, gt, lt, anyPass } = require('ramda')
const Success = (value) => ({
value,
isFailure: false,
fold: (f, g) => g(value),
concat: (other) => (other.isFailure ? other : Success(value)),
})
const Fail = (value) => ({
value,
isFailure: true,
fold: (f, g) => f(value),
concat: (other) => (other.isFailure ? other : Fail(value)),
})
const Validation = (run) => ({
run,
concat: (other) =>
Validation((key, value) => {
const result = run(key, value)
return result.isFailure ? result : result.concat(other.run(key, value))
}),
})
const isPresent = Validation((key, x) =>
x && !!x.value
? Success(x.raw)
: Fail([`${key} needs to be present. Received ${x}`]),
)
const isValidBirthYear = Validation((key, { value, raw }) =>
value >= 1920 && value <= 2002
? Success(raw)
: Fail([`${key} must be between 1920 and 2002. Received: ${value}`]),
)
const isValidIssueYear = Validation((key, { value }) =>
value >= 2010 && value <= 2020
? Success(value)
: Fail([`${key} must be between 2010 and 2020. Recived ${value}`]),
)
const isValidExpirationYear = Validation((key, { value }) =>
value >= 2020 && value <= 2030
? Success(value)
: Fail([`${key} must be between 2020 and 2030. Received: ${value}`]),
)
const isValidHeight = Validation((key, x) => {
const { unit, value, raw } = x
if (!unit || !['cm', 'in'].includes(unit)) {
return Fail([`${key} must have unit 'cm' or 'in'. Recived ${unit || raw}`])
}
if (
where(
{
unit: equals('cm'),
value: anyPass([lt(__, 150), gt(__, 193)]),
},
x,
)
) {
return Fail([`${key} must be between 150cm and 193cm. Received ${raw}`])
}
if (
where(
{
unit: equals('in'),
value: anyPass([lt(__, 59), gt(__, 76)]),
},
x,
)
) {
return Fail([`${key} must be between 59in and 76in. Recived ${x.raw}`])
}
return Success(value)
})
const isValidHairColor = Validation((key, x) => {
const [hash] = x.value
const hexCode = x.value.slice(1)
if (x.value[0] !== '#') {
return Fail([`${key} must start with #. Recived ${x.raw}`])
}
if (!/^[0-9a-f]{6}$/i.test(hexCode)) {
return Fail([`${key} must end in 6 characters 0-9 a-f. Recived ${x.raw}`])
}
return Success(x.value)
})
const isValidEyeColor = Validation((key, { value }) =>
['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'].includes(value)
? Success(value)
: Fail([
`${key} must be one of 'amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'. Recived ${value}`,
]),
)
const isValidPassportId = Validation((key, { value, raw }) =>
new RegExp('^[0-9]+$').test(value) && value.length === 9
? Success(value)
: Fail([
`${key} must be a 9 digit number. Recived ${raw} Length: ${raw.length}`,
]),
)
const validate = (spec, obj) =>
List(Object.keys(spec)).foldMap(
(key) => spec[key].run(key, obj[key]),
Success([obj]),
)
module.exports = {
Success,
Fail,
Validation,
validate,
isPresent,
isValidBirthYear,
isValidIssueYear,
isValidExpirationYear,
isValidHeight,
isValidHairColor,
isValidEyeColor,
isValidPassportId,
}