ejv 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.json +8 -8
- package/CHANGELOG.md +134 -135
- package/README-KR.md +597 -597
- package/README.md +603 -603
- package/build/cjs/constants.js +1 -0
- package/build/cjs/constants.js.map +1 -1
- package/build/cjs/ejv.js +3 -0
- package/build/cjs/ejv.js.map +1 -1
- package/build/cjs/tester.js +11 -1
- package/build/cjs/tester.js.map +1 -1
- package/build/constants.d.ts +1 -0
- package/build/esm/constants.js +1 -0
- package/build/esm/constants.js.map +1 -1
- package/build/esm/ejv.js +4 -1
- package/build/esm/ejv.js.map +1 -1
- package/build/esm/tester.js +9 -0
- package/build/esm/tester.js.map +1 -1
- package/build/tester.d.ts +1 -0
- package/eslint.config.mjs +66 -59
- package/package.json +54 -54
- package/scripts/add-js-extensions.ts +59 -59
- package/spec/ArrayScheme.ts +1021 -1021
- package/spec/CommonScheme.ts +251 -251
- package/spec/DateScheme.ts +472 -472
- package/spec/NumberScheme.ts +1160 -1160
- package/spec/ObjectScheme.ts +499 -499
- package/spec/RegExpScheme.ts +112 -112
- package/spec/StringScheme.ts +1407 -1336
- package/spec/common-test-util.ts +63 -63
- package/spec/ejv.spec.ts +235 -235
- package/spec/testers.spec.ts +833 -833
- package/src/constants.ts +164 -162
- package/src/ejv.ts +1751 -1746
- package/src/index.ts +14 -14
- package/src/interfaces.ts +144 -144
- package/src/tester.ts +323 -312
- package/src/util.ts +124 -124
- package/tsconfig.cjs.json +8 -8
- package/tsconfig.esm.json +7 -7
- package/tsconfig.json +19 -19
- package/tsconfig.scripts.json +14 -14
- package/tsconfig.types.json +9 -9
package/src/tester.ts
CHANGED
|
@@ -1,312 +1,323 @@
|
|
|
1
|
-
import { DATA_TYPE } from './constants';
|
|
2
|
-
import { AnyObject } from './interfaces';
|
|
3
|
-
|
|
4
|
-
export const typeTester = (value: unknown, type: DATA_TYPE): boolean => {
|
|
5
|
-
let valid: boolean;
|
|
6
|
-
|
|
7
|
-
switch (type) {
|
|
8
|
-
case DATA_TYPE.BOOLEAN:
|
|
9
|
-
valid = booleanTester(value);
|
|
10
|
-
break;
|
|
11
|
-
|
|
12
|
-
case DATA_TYPE.NUMBER:
|
|
13
|
-
valid = numberTester(value);
|
|
14
|
-
break;
|
|
15
|
-
|
|
16
|
-
case DATA_TYPE.STRING:
|
|
17
|
-
valid = stringTester(value);
|
|
18
|
-
break;
|
|
19
|
-
|
|
20
|
-
case DATA_TYPE.OBJECT:
|
|
21
|
-
valid = objectTester(value);
|
|
22
|
-
break;
|
|
23
|
-
|
|
24
|
-
case DATA_TYPE.DATE:
|
|
25
|
-
valid = dateTester(value);
|
|
26
|
-
break;
|
|
27
|
-
|
|
28
|
-
case DATA_TYPE.REGEXP:
|
|
29
|
-
valid = regExpTester(value);
|
|
30
|
-
break;
|
|
31
|
-
|
|
32
|
-
case DATA_TYPE.ARRAY:
|
|
33
|
-
valid = arrayTester(value);
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return valid;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const definedTester = (value: unknown): value is boolean => {
|
|
41
|
-
return value !== undefined;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const enumTester = <T> (value: T, arr: T[]): boolean => {
|
|
45
|
-
return arr.includes(value);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const notEnumTester = <T> (value: T, arr: T[]): boolean => {
|
|
49
|
-
return !enumTester(value, arr);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export const lengthTester = (value: string | unknown[], length: number): boolean => {
|
|
53
|
-
return value.length === length;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export const minLengthTester = (value: string | unknown[], minLength: number): boolean => {
|
|
57
|
-
return value.length >= minLength;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const maxLengthTester = (value: string | unknown[], maxLength: number): boolean => {
|
|
61
|
-
return value.length <= maxLength;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const booleanTester = (value: unknown): value is boolean => {
|
|
65
|
-
return typeof value === 'boolean';
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const numberTester = (value: unknown): value is number => {
|
|
69
|
-
return typeof value === 'number' && !isNaN(value);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const integerTester = (value: number): boolean => {
|
|
73
|
-
return +value.toFixed(0) === value;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export const indexTester = (value: number): value is number => {
|
|
77
|
-
return integerTester(value) && value >= 0;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export const minNumberTester = (value: number, min: number): boolean => {
|
|
81
|
-
return value >= min;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const exclusiveMinNumberTester = (value: number, min: number): boolean => {
|
|
85
|
-
return value > min;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export const maxNumberTester = (value: number, max: number): boolean => {
|
|
89
|
-
return value <= max;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export const exclusiveMaxNumberTester = (value: number, max: number): boolean => {
|
|
93
|
-
return value < max;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const stringTester = (value: unknown): value is string => {
|
|
97
|
-
return typeof value === 'string';
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export const stringRegExpTester = (value: string, regExp: string | RegExp): boolean => {
|
|
101
|
-
let valid = false;
|
|
102
|
-
|
|
103
|
-
let _regExp: RegExp | undefined = undefined;
|
|
104
|
-
|
|
105
|
-
if (regExpTester(regExp)) {
|
|
106
|
-
_regExp = regExp as RegExp;
|
|
107
|
-
}
|
|
108
|
-
else if (stringTester(regExp)) {
|
|
109
|
-
_regExp = new RegExp(regExp);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!!_regExp && regExpTester(_regExp)) {
|
|
113
|
-
valid = _regExp.test(value);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return valid;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// RFC 5322, 3.4.1. spec
|
|
120
|
-
export const emailTester = (value: string): boolean => {
|
|
121
|
-
let valid = false;
|
|
122
|
-
|
|
123
|
-
if (stringTester(value) && stringRegExpTester(value, /^.+@.+$/)) {
|
|
124
|
-
const valueAsString: string = value as string;
|
|
125
|
-
|
|
126
|
-
const atIndex: number = valueAsString.lastIndexOf('@');
|
|
127
|
-
const localPart: string = valueAsString.substr(0, atIndex);
|
|
128
|
-
const domain: string = valueAsString.substr(atIndex + 1);
|
|
129
|
-
|
|
130
|
-
// regular expression sources
|
|
131
|
-
// const aTextRegExpStr : string = '[-a-zA-Z0-9!#$%&\\\'*+/=?^_`{|}~]+';
|
|
132
|
-
|
|
133
|
-
const dotAtomRegExp = /^(\.?[-a-zA-Z0-9!#$%&'*+/=?^_`{|}~]+)*$/;
|
|
134
|
-
const quotedStringRegExp = /^"[\u0020-\u005b\u005d-\u007e\\]*"$/; // include space (\u005b)
|
|
135
|
-
const domainLiteralRegExp = /^\[[\u0020-\u005a\u005c-\u007e\\]*]$/;
|
|
136
|
-
|
|
137
|
-
const validLocalPart: boolean = localPart.length <= 64
|
|
138
|
-
&& (
|
|
139
|
-
dotAtomRegExp.test(localPart)
|
|
140
|
-
|| quotedStringRegExp.test(localPart)
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const validDomain: boolean = !domain.startsWith('.') && !domain.endsWith('.')
|
|
144
|
-
&& (
|
|
145
|
-
dotAtomRegExp.test(domain)
|
|
146
|
-
|| domainLiteralRegExp.test(domain)
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
valid = validLocalPart && validDomain;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return valid;
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return [
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
//
|
|
253
|
-
// export const
|
|
254
|
-
// return stringTester(value)
|
|
255
|
-
// && /^
|
|
256
|
-
// };
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
};
|
|
1
|
+
import { DATA_TYPE } from './constants';
|
|
2
|
+
import { AnyObject } from './interfaces';
|
|
3
|
+
|
|
4
|
+
export const typeTester = (value: unknown, type: DATA_TYPE): boolean => {
|
|
5
|
+
let valid: boolean;
|
|
6
|
+
|
|
7
|
+
switch (type) {
|
|
8
|
+
case DATA_TYPE.BOOLEAN:
|
|
9
|
+
valid = booleanTester(value);
|
|
10
|
+
break;
|
|
11
|
+
|
|
12
|
+
case DATA_TYPE.NUMBER:
|
|
13
|
+
valid = numberTester(value);
|
|
14
|
+
break;
|
|
15
|
+
|
|
16
|
+
case DATA_TYPE.STRING:
|
|
17
|
+
valid = stringTester(value);
|
|
18
|
+
break;
|
|
19
|
+
|
|
20
|
+
case DATA_TYPE.OBJECT:
|
|
21
|
+
valid = objectTester(value);
|
|
22
|
+
break;
|
|
23
|
+
|
|
24
|
+
case DATA_TYPE.DATE:
|
|
25
|
+
valid = dateTester(value);
|
|
26
|
+
break;
|
|
27
|
+
|
|
28
|
+
case DATA_TYPE.REGEXP:
|
|
29
|
+
valid = regExpTester(value);
|
|
30
|
+
break;
|
|
31
|
+
|
|
32
|
+
case DATA_TYPE.ARRAY:
|
|
33
|
+
valid = arrayTester(value);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return valid;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const definedTester = (value: unknown): value is boolean => {
|
|
41
|
+
return value !== undefined;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const enumTester = <T> (value: T, arr: T[]): boolean => {
|
|
45
|
+
return arr.includes(value);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const notEnumTester = <T> (value: T, arr: T[]): boolean => {
|
|
49
|
+
return !enumTester(value, arr);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const lengthTester = (value: string | unknown[], length: number): boolean => {
|
|
53
|
+
return value.length === length;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const minLengthTester = (value: string | unknown[], minLength: number): boolean => {
|
|
57
|
+
return value.length >= minLength;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const maxLengthTester = (value: string | unknown[], maxLength: number): boolean => {
|
|
61
|
+
return value.length <= maxLength;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const booleanTester = (value: unknown): value is boolean => {
|
|
65
|
+
return typeof value === 'boolean';
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const numberTester = (value: unknown): value is number => {
|
|
69
|
+
return typeof value === 'number' && !isNaN(value);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const integerTester = (value: number): boolean => {
|
|
73
|
+
return +value.toFixed(0) === value;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const indexTester = (value: number): value is number => {
|
|
77
|
+
return integerTester(value) && value >= 0;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const minNumberTester = (value: number, min: number): boolean => {
|
|
81
|
+
return value >= min;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const exclusiveMinNumberTester = (value: number, min: number): boolean => {
|
|
85
|
+
return value > min;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const maxNumberTester = (value: number, max: number): boolean => {
|
|
89
|
+
return value <= max;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const exclusiveMaxNumberTester = (value: number, max: number): boolean => {
|
|
93
|
+
return value < max;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const stringTester = (value: unknown): value is string => {
|
|
97
|
+
return typeof value === 'string';
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const stringRegExpTester = (value: string, regExp: string | RegExp): boolean => {
|
|
101
|
+
let valid = false;
|
|
102
|
+
|
|
103
|
+
let _regExp: RegExp | undefined = undefined;
|
|
104
|
+
|
|
105
|
+
if (regExpTester(regExp)) {
|
|
106
|
+
_regExp = regExp as RegExp;
|
|
107
|
+
}
|
|
108
|
+
else if (stringTester(regExp)) {
|
|
109
|
+
_regExp = new RegExp(regExp);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!!_regExp && regExpTester(_regExp)) {
|
|
113
|
+
valid = _regExp.test(value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return valid;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// RFC 5322, 3.4.1. spec
|
|
120
|
+
export const emailTester = (value: string): boolean => {
|
|
121
|
+
let valid = false;
|
|
122
|
+
|
|
123
|
+
if (stringTester(value) && stringRegExpTester(value, /^.+@.+$/)) {
|
|
124
|
+
const valueAsString: string = value as string;
|
|
125
|
+
|
|
126
|
+
const atIndex: number = valueAsString.lastIndexOf('@');
|
|
127
|
+
const localPart: string = valueAsString.substr(0, atIndex);
|
|
128
|
+
const domain: string = valueAsString.substr(atIndex + 1);
|
|
129
|
+
|
|
130
|
+
// regular expression sources
|
|
131
|
+
// const aTextRegExpStr : string = '[-a-zA-Z0-9!#$%&\\\'*+/=?^_`{|}~]+';
|
|
132
|
+
|
|
133
|
+
const dotAtomRegExp = /^(\.?[-a-zA-Z0-9!#$%&'*+/=?^_`{|}~]+)*$/;
|
|
134
|
+
const quotedStringRegExp = /^"[\u0020-\u005b\u005d-\u007e\\]*"$/; // include space (\u005b)
|
|
135
|
+
const domainLiteralRegExp = /^\[[\u0020-\u005a\u005c-\u007e\\]*]$/;
|
|
136
|
+
|
|
137
|
+
const validLocalPart: boolean = localPart.length <= 64
|
|
138
|
+
&& (
|
|
139
|
+
dotAtomRegExp.test(localPart)
|
|
140
|
+
|| quotedStringRegExp.test(localPart)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const validDomain: boolean = !domain.startsWith('.') && !domain.endsWith('.')
|
|
144
|
+
&& (
|
|
145
|
+
dotAtomRegExp.test(domain)
|
|
146
|
+
|| domainLiteralRegExp.test(domain)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
valid = validLocalPart && validDomain;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return valid;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const jsonStrTester = (value: string): boolean => {
|
|
156
|
+
try {
|
|
157
|
+
JSON.parse(value);
|
|
158
|
+
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
catch (e: unknown) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// RFC 3339 (https://www.ietf.org/rfc/rfc3339.txt) : YYYY-MM-DDThh:mm:ss[.SSSZ]
|
|
167
|
+
const rfc3339Tester = (value: string): boolean => {
|
|
168
|
+
return /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3])(:([0-5][0-9])){2}(\.\d+)?(Z|[-+]\d{2}:\d{2})?$/.test(value);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const iso8601DateTester = (value: string): boolean => {
|
|
172
|
+
const years = '(\\d{4})';
|
|
173
|
+
const months = '(0[1-9]|1[0-2])';
|
|
174
|
+
const dates = '(0[1-9]|[1-2][0-9]|3[0-1])';
|
|
175
|
+
const dateOfYear = '(00[1-9]|0[1-9][0-9]|[1-2]\\d{2}|3[0-5]\\d|36[0-6])'; // 366 for leap year
|
|
176
|
+
const weeks = '(W(0[1-9]|[2-4][0-9]|5[0-3]))';
|
|
177
|
+
const days = '[1-7]';
|
|
178
|
+
|
|
179
|
+
return [
|
|
180
|
+
new RegExp(`^[-+]?${ years }$`), // years : YYYY, +YYYY, -YYYY
|
|
181
|
+
new RegExp(`^${ years }-${ months }(-${ dates })?$`), // calendar dates : YYYY-MM-DD, YYYY-MM
|
|
182
|
+
new RegExp(`^${ years }${ months }${ dates }$`), // calendar dates : YYYYMMDD
|
|
183
|
+
new RegExp(`^--${ months }-?${ dates }$`), // calendar dates : --MM-DD, --MMDD
|
|
184
|
+
new RegExp(`^${ years }-${ weeks }(-${ days })?$`), // week dates : YYYY-Www, YYYY-Www-D
|
|
185
|
+
new RegExp(`^${ years }${ weeks }(${ days })?$`), // week dates : YYYYWww, YYYYWwwD
|
|
186
|
+
new RegExp(`^${ years }-?${ dateOfYear }$`) // ordinal dates : YYYY-DDD, YYYYDDD
|
|
187
|
+
].some((regExp: RegExp): boolean => {
|
|
188
|
+
return regExp.test(value);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const iso8601TimeTester = (value: string): boolean => {
|
|
193
|
+
const hours = '([0-1]\\d|2[0-3])';
|
|
194
|
+
const minutes = '([0-5]\\d)';
|
|
195
|
+
const seconds = '([0-5]\\d|60)'; // 60 for leap second
|
|
196
|
+
const ms = '(\\.[0-9]+)';
|
|
197
|
+
|
|
198
|
+
return [
|
|
199
|
+
new RegExp(`^(${ hours }|24)$`), // hh
|
|
200
|
+
new RegExp(`^((${ hours }:${ minutes })|24:00)$`), // hh:mm
|
|
201
|
+
new RegExp(`^((${ hours }:${ minutes }:${ seconds })|24:00:00)$`), // hh:mm:ss
|
|
202
|
+
new RegExp(`^((${ hours }:${ minutes }:${ seconds }${ ms })|24:00:00.0+)$`), // hh:mm:ss
|
|
203
|
+
|
|
204
|
+
new RegExp(`^(${ hours }${ minutes }|2400)$`), // hhmm
|
|
205
|
+
new RegExp(`^(${ hours }${ minutes }${ seconds }|240000)$`), // hhmmss
|
|
206
|
+
new RegExp(`^(${ hours }${ minutes }${ seconds }${ ms }|240000.0+)$`) // hhmmss.sss
|
|
207
|
+
]
|
|
208
|
+
.some((regExp: RegExp): boolean => {
|
|
209
|
+
return regExp.test(value);
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const iso8601DateTimeTester = (value: string): boolean => {
|
|
214
|
+
let valid = false;
|
|
215
|
+
|
|
216
|
+
if (/.+T.+/.test(value) // should have 1 'T'
|
|
217
|
+
&& /(Z|[-+]\d{2}:?\d{2})$/.test(value) // should end with 'Z' or timezone
|
|
218
|
+
) {
|
|
219
|
+
const dateAndTime: string[] = value.split('T');
|
|
220
|
+
const date: string = dateAndTime[0];
|
|
221
|
+
let time: string = dateAndTime[1];
|
|
222
|
+
|
|
223
|
+
if (time.endsWith('Z')) {
|
|
224
|
+
time = time.replace('Z', '');
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
const timezoneStartIndex: number = time.includes('+')
|
|
228
|
+
? time.indexOf('+')
|
|
229
|
+
: time.indexOf('-');
|
|
230
|
+
|
|
231
|
+
time = time.slice(0, timezoneStartIndex);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
valid = iso8601DateTester(date) && iso8601TimeTester(time);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return valid;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const dateFormatTester = (value: string): boolean => {
|
|
241
|
+
return iso8601DateTester(value);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export const timeFormatTester = (value: string): boolean => {
|
|
245
|
+
return iso8601TimeTester(value);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export const dateTimeFormatTester = (value: string): boolean => {
|
|
249
|
+
return rfc3339Tester(value) || iso8601DateTimeTester(value);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// // with port
|
|
253
|
+
// export const urlTester = (value : any) : boolean => {
|
|
254
|
+
// return stringTester(value)
|
|
255
|
+
// && /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value);
|
|
256
|
+
// };
|
|
257
|
+
//
|
|
258
|
+
// // TODO: with port
|
|
259
|
+
// export const ipv4Tester = (value : any) : boolean => {
|
|
260
|
+
// return stringTester(value)
|
|
261
|
+
// && /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value);
|
|
262
|
+
// };
|
|
263
|
+
//
|
|
264
|
+
// export const ipv6Tester = (value : any) : boolean => {
|
|
265
|
+
// return stringTester(value)
|
|
266
|
+
// && /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$;/.test(value);
|
|
267
|
+
// };
|
|
268
|
+
//
|
|
269
|
+
// export const ipTester = (value : any) : boolean => {
|
|
270
|
+
// return ipv4Tester(value) || ipv6Tester(value);
|
|
271
|
+
// };
|
|
272
|
+
|
|
273
|
+
export const objectTester = (value: unknown): boolean => {
|
|
274
|
+
return typeof value === 'object';
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export const hasPropertyTester = (value: AnyObject): boolean => {
|
|
278
|
+
return Object.keys(value).length > 0;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
export const dateTester = (value: unknown): value is Date => {
|
|
282
|
+
return objectTester(value)
|
|
283
|
+
&& value !== null
|
|
284
|
+
&& typeof value === 'object'
|
|
285
|
+
&& value instanceof Date
|
|
286
|
+
&& !isNaN(value.getFullYear());
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export const minDateTester = (value: Date, min: Date): boolean => {
|
|
290
|
+
return +value >= +min;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export const exclusiveMinDateTester = (value: Date, min: Date): boolean => {
|
|
294
|
+
return +value > +min;
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
export const maxDateTester = (value: Date, max: Date): boolean => {
|
|
298
|
+
return +value <= +max;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export const exclusiveMaxDateTester = (value: Date, max: Date): boolean => {
|
|
302
|
+
return +value < +max;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
export const arrayTester = (value: unknown): value is unknown[] => {
|
|
306
|
+
return Array.isArray(value);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export const arrayTypeOfTester = (array: unknown[], type: DATA_TYPE): boolean => {
|
|
310
|
+
return array.every((item: unknown): boolean => {
|
|
311
|
+
return typeTester(item, type);
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
export const uniqueItemsTester = (array: unknown[]): boolean => {
|
|
316
|
+
return array.every((item: unknown): boolean => {
|
|
317
|
+
return array.filter((target: unknown): boolean => target === item).length === 1;
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export const regExpTester = (value: unknown): value is RegExp => {
|
|
322
|
+
return value instanceof RegExp;
|
|
323
|
+
};
|