This repository has been archived by the owner on Apr 2, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidator.js
204 lines (191 loc) · 6.19 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
'use strict';
let _ = require('underscore'),
qidx = require('quadtile-index'),
qs = require('querystring'),
urllib = require('url'),
Err = require('@kartotherian/err');
module.exports = checkType;
function getDefault(obj, field, mustHave) {
if (mustHave === true) {
throw new Err('Value %j is missing', field);
}
if (mustHave === false || mustHave === undefined) {
delete obj[field];
} else {
obj[field] = mustHave;
}
return false;
}
/**
* Utility method to check the type of the object's property
*/
function checkType(obj, field, expType, mustHave, min, max) {
let value = typeof (obj) === 'object' ? obj[field] : obj;
if (value === undefined) {
return getDefault(obj, field, mustHave);
}
// Try to convert value to expected type
let type = expType[0] === '[' ? Object.prototype.toString.call(value) : typeof value;
if (type === 'string') {
switch (expType) {
case 'number':
value = checkType.strToFloat(value);
type = typeof value;
break;
case 'integer':
case 'zoom':
obj[field] = value = checkType.strToInt(value);
type = typeof value;
break;
case 'boolean':
obj[field] = value = !!value;
type = typeof value;
break;
case 'string-array':
obj[field] = value = [value];
type = typeof value;
break;
case 'number-array':
value = checkType.strToFloat(value);
type = typeof value;
if (type === 'number') {
obj[field] = value = [value];
}
break;
}
} else if (type === 'number' && expType === 'number-array') {
obj[field] = value = [value];
type = typeof value;
}
// validate the type
switch (expType) {
case 'string-array':
if (!Array.isArray(value) ||
!_.all(value, v => typeof v === 'string' && v.length > 0)
) {
throw new Err('Invalid %s param: expecting a string or an array of strings', field);
}
break;
case 'number-array':
let isValid = Array.isArray(value);
if (isValid) {
value = _.map(value, v => {
v = checkType.strToFloat(v);
if (typeof v !== 'number') {
isValid = false;
}
return v;
});
}
if (!isValid) {
throw new Err('Invalid %s param: expecting a number or an array of numbers', field);
}
obj[field] = value;
break;
case 'array':
if (!Array.isArray(value)) {
throw new Err('Invalid %s param type %s given, was expecting an array',
field, type);
}
break;
case 'integer':
if (!Number.isInteger(value)) {
throw new Err('Invalid %s param type %s given, was expecting an integer',
field, type);
}
break;
case 'zoom':
if (!qidx.isValidZoom(value)) {
throw new Err('Invalid %s param - an integer zoom value was expected', field);
}
break;
default:
if (type !== expType) {
throw new Err('Invalid %s param type %s given, was expecting %s',
field, type, expType);
}
break;
}
// validate ranges
switch (expType) {
case 'number':
case 'integer':
case 'zoom':
if (min !== undefined && value < min) {
throw new Err('Invalid %s param - must be at least %d, but given %d',
field, min, value);
}
if (max !== undefined && value > max) {
throw new Err('Invalid %s param - must be at most %d, but given %d',
field, max, value);
}
break;
case 'string':
if (min !== undefined && value.length < min) {
throw new Err('Invalid %s param - the string must be at least %d symbols',
field, min);
}
break;
case 'boolean':
if (value === false) {
// convert false into undefined
delete obj[field];
return false;
}
break;
case 'string-array':
case 'number-array':
if (min !== undefined && value.length < min) {
throw new Err('Invalid %s param - it must have at least %d values, but given %d',
field, min, value.length);
}
if (max !== undefined && value.length > max) {
throw new Err('Invalid %s param - it must have at least %d values, but given %d',
field, max, value.length);
}
break;
}
return true;
}
/**
* Magical float regex found in http://stackoverflow.com/a/21664614/177275
* @type {RegExp}
*/
checkType.floatRe = /^-?\d+(?:[.,]\d*?)?$/;
/**
* Converts value to float if possible, or returns the original
*/
checkType.strToFloat = function strToFloat(value) {
if (typeof value === 'string' && checkType.floatRe.test(value)) {
return parseFloat(value);
}
return value;
};
/**
* Magical int regex
* @type {RegExp}
*/
const intRe = /^-?\d+$/;
/**
* Converts value to integer if possible, or returns the original
*/
checkType.strToInt = function strToInt(value) {
if (typeof value === 'string' && intRe.test(value)) {
return parseInt(value);
}
return value;
};
/**
* Parse and normalize URI, ensuring it returns an object with query object field
* @param uri
* @returns {*}
*/
checkType.normalizeUrl = function normalizeUrl(uri) {
if (typeof uri === 'string') {
uri = urllib.parse(uri, true);
} else if (typeof uri.query === 'string') {
uri.query = qs.parse(uri.query);
}
uri.query = uri.query || {};
return uri;
};