ejv 1.1.11 → 2.0.0

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.
Files changed (75) hide show
  1. package/.eslintrc.json +88 -0
  2. package/.mocharc.json +8 -0
  3. package/CHANGELOG.md +109 -68
  4. package/LICENSE +21 -21
  5. package/README-KR.md +596 -592
  6. package/README.md +599 -595
  7. package/build/{constants.js → cjs/constants.js} +44 -45
  8. package/build/cjs/constants.js.map +1 -0
  9. package/build/cjs/ejv.js +1263 -0
  10. package/build/cjs/ejv.js.map +1 -0
  11. package/build/{public_api.js → cjs/index.js} +4 -4
  12. package/build/cjs/index.js.map +1 -0
  13. package/build/cjs/interfaces.js +29 -0
  14. package/build/cjs/interfaces.js.map +1 -0
  15. package/build/cjs/package.json +1 -0
  16. package/build/{tester.js → cjs/tester.js} +87 -82
  17. package/build/cjs/tester.js.map +1 -0
  18. package/build/cjs/util.js +103 -0
  19. package/build/cjs/util.js.map +1 -0
  20. package/build/constants.d.ts +36 -39
  21. package/build/esm/constants.js +115 -0
  22. package/build/esm/constants.js.map +1 -0
  23. package/build/esm/ejv.js +1261 -0
  24. package/build/esm/ejv.js.map +1 -0
  25. package/build/esm/index.js +4 -0
  26. package/build/esm/index.js.map +1 -0
  27. package/build/esm/interfaces.js +33 -0
  28. package/build/esm/interfaces.js.map +1 -0
  29. package/build/esm/package.json +1 -0
  30. package/build/esm/tester.js +240 -0
  31. package/build/esm/tester.js.map +1 -0
  32. package/build/esm/util.js +96 -0
  33. package/build/esm/util.js.map +1 -0
  34. package/build/index.d.ts +3 -0
  35. package/build/interfaces.d.ts +53 -13
  36. package/build/scripts/add-js-extensions.js +46 -0
  37. package/build/scripts/add-js-extensions.js.map +1 -0
  38. package/build/tester.d.ts +16 -17
  39. package/build/util.d.ts +7 -1
  40. package/package.json +50 -39
  41. package/scripts/add-js-extensions.ts +59 -0
  42. package/spec/ArrayScheme.ts +1021 -0
  43. package/spec/CommonScheme.ts +251 -0
  44. package/spec/DateScheme.ts +472 -0
  45. package/spec/NumberScheme.ts +1032 -0
  46. package/spec/ObjectScheme.ts +499 -0
  47. package/spec/RegExpScheme.ts +112 -0
  48. package/spec/StringScheme.ts +1239 -0
  49. package/spec/common-test-util.ts +63 -0
  50. package/spec/ejv.spec.ts +209 -4634
  51. package/spec/testers.spec.ts +833 -832
  52. package/src/constants.ts +155 -156
  53. package/src/ejv.ts +1648 -1071
  54. package/src/index.ts +14 -0
  55. package/src/interfaces.ts +149 -63
  56. package/src/tester.ts +308 -302
  57. package/src/util.ts +124 -59
  58. package/tsconfig.cjs.json +8 -0
  59. package/tsconfig.esm.json +7 -0
  60. package/tsconfig.json +22 -19
  61. package/tsconfig.scripts.json +14 -0
  62. package/tsconfig.types.json +9 -0
  63. package/build/constants.js.map +0 -1
  64. package/build/ejv.js +0 -687
  65. package/build/ejv.js.map +0 -1
  66. package/build/interfaces.js +0 -15
  67. package/build/interfaces.js.map +0 -1
  68. package/build/public_api.d.ts +0 -3
  69. package/build/public_api.js.map +0 -1
  70. package/build/tester.js.map +0 -1
  71. package/build/util.js +0 -68
  72. package/build/util.js.map +0 -1
  73. package/spec/common-test-runner.ts +0 -17
  74. package/src/public_api.ts +0 -3
  75. package/tsconfig.spec.json +0 -19
package/src/ejv.ts CHANGED
@@ -1,1071 +1,1648 @@
1
- import { EjvError, InternalOptions, Options, Scheme } from './interfaces';
2
- import { DataType, ErrorMsg, ErrorMsgCursorA, ErrorType, NumberFormat, StringFormat } from './constants';
3
-
4
- import {
5
- arrayTester,
6
- arrayTypeOfTester,
7
- booleanTester,
8
- dateFormatTester,
9
- dateTester,
10
- dateTimeFormatTester,
11
- definedTester,
12
- emailTester,
13
- enumTester,
14
- exclusiveMaxDateTester,
15
- exclusiveMaxNumberTester,
16
- exclusiveMinDateTester,
17
- exclusiveMinNumberTester,
18
- hasPropertyTester,
19
- indexTester,
20
- integerTester,
21
- lengthTester,
22
- maxDateTester,
23
- maxLengthTester,
24
- maxNumberTester,
25
- minDateTester,
26
- minLengthTester,
27
- minNumberTester,
28
- numberTester,
29
- objectTester,
30
- regExpTester,
31
- stringRegExpTester,
32
- stringTester,
33
- timeFormatTester,
34
- typeTester,
35
- uniqueItemsTester
36
- } from './tester';
37
- import { clone } from './util';
38
-
39
-
40
- interface AnyObject {
41
- [key : string] : any;
42
- }
43
-
44
-
45
- const _ejv = <T>(data : T, schemes : Scheme[], options : InternalOptions = {
46
- path : []
47
- }) : null | EjvError => {
48
- // check schemes
49
- if (!arrayTester(schemes)) {
50
- throw new Error(ErrorMsg.NO_ARRAY_SCHEME);
51
- }
52
-
53
- if (!arrayTypeOfTester(schemes, DataType.OBJECT)) {
54
- throw new Error(ErrorMsg.NO_OBJECT_ARRAY_SCHEME);
55
- }
56
-
57
- if (!minLengthTester(schemes, 1)) {
58
- throw new Error(ErrorMsg.EMPTY_SCHEME);
59
- }
60
-
61
- // check data by schemes
62
- let result : EjvError | null = null;
63
-
64
- // use for() instead of forEach() to stop
65
- const schemeLength : number = schemes.length;
66
-
67
- for (let i = 0; i < schemeLength; i++) {
68
- const _options : InternalOptions = clone(options); // divide instance
69
-
70
- if (!definedTester(_options.path)) {
71
- _options.path = [];
72
- }
73
-
74
- const scheme : Scheme = schemes[i];
75
- const key : keyof T = scheme.key as keyof T;
76
-
77
- let value : any;
78
-
79
- if (!!key) {
80
- value = data[key];
81
-
82
- _options.path.push(key as string);
83
- }
84
-
85
- let types : DataType[];
86
-
87
- if (!definedTester(scheme.type)) {
88
- throw new Error(ErrorMsg.SCHEMES_SHOULD_HAVE_TYPE);
89
- }
90
-
91
- if (!arrayTester(scheme.type)) {
92
- types = [scheme.type as DataType];
93
- } else {
94
- types = scheme.type as DataType[];
95
- }
96
-
97
- const allDataType : DataType[] = Object.values(DataType);
98
-
99
-
100
- const errorType : string | undefined = types.find(type => {
101
- return !(stringTester(type) && enumTester(type, allDataType));
102
- });
103
-
104
- if (!!errorType) {
105
- throw new Error(ErrorMsg.SCHEMES_HAS_INVALID_TYPE.replace(ErrorMsgCursorA, errorType));
106
- }
107
-
108
- if (!uniqueItemsTester(types)) {
109
- throw new Error(ErrorMsg.SCHEMES_HAS_DUPLICATED_TYPE);
110
- }
111
-
112
- if (!definedTester(value)) {
113
- if (scheme.optional !== true) {
114
- result = new EjvError(
115
- ErrorType.REQUIRED,
116
- ErrorMsg.REQUIRED,
117
- _options.path,
118
- data,
119
- value
120
- );
121
- break;
122
- } else {
123
- continue;
124
- }
125
- }
126
-
127
- if (value === null) {
128
- if (scheme.nullable !== true) {
129
- result = new EjvError(
130
- ErrorType.REQUIRED,
131
- ErrorMsg.REQUIRED,
132
- _options.path,
133
- data,
134
- value
135
- );
136
- break;
137
- } else {
138
- continue;
139
- }
140
- }
141
-
142
- const typeResolved : DataType | undefined = types.find(type => {
143
- return typeTester(value, type);
144
- });
145
-
146
- if (!typeResolved) {
147
- if (!arrayTester(scheme.type)) {
148
- result = new EjvError(
149
- ErrorType.TYPE_MISMATCH,
150
- ErrorMsg.TYPE_MISMATCH.replace(ErrorMsgCursorA, scheme.type as DataType),
151
- _options.path,
152
- data,
153
- value
154
- );
155
- } else {
156
- result = new EjvError(
157
- ErrorType.TYPE_MISMATCH_ONE_OF,
158
- ErrorMsg.TYPE_MISMATCH_ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(scheme.type)),
159
- _options.path,
160
- data,
161
- value
162
- );
163
- }
164
- break;
165
- }
166
-
167
- // additional check for type resolved
168
- switch (typeResolved) {
169
- case DataType.NUMBER:
170
- const valueAsNumber : number = value as unknown as number;
171
-
172
- if (definedTester(scheme.enum)) {
173
- if (!arrayTester(scheme.enum)) {
174
- throw new Error(ErrorMsg.ENUM_SHOULD_BE_ARRAY);
175
- }
176
-
177
- const enumArr : number[] = scheme.enum as number[];
178
-
179
- if (!arrayTypeOfTester(enumArr, DataType.NUMBER)) {
180
- throw new Error(ErrorMsg.ENUM_SHOULD_BE_NUMBERS);
181
- }
182
-
183
- if (!enumTester(valueAsNumber, enumArr)) {
184
- result = new EjvError(
185
- ErrorType.ONE_OF,
186
- ErrorMsg.ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(enumArr)),
187
- _options.path,
188
- data,
189
- value
190
- );
191
- break;
192
- }
193
- }
194
-
195
- if (definedTester(scheme.enumReverse)) {
196
- const enumReverseArr : number[] = scheme.enumReverse as number[];
197
-
198
- if (!arrayTester(enumReverseArr)) {
199
- throw new Error(ErrorMsg.ENUM_REVERSE_SHOULD_BE_ARRAY);
200
- }
201
-
202
- if (!arrayTypeOfTester(enumReverseArr, DataType.NUMBER)) {
203
- throw new Error(ErrorMsg.ENUM_REVERSE_SHOULD_BE_NUMBERS);
204
- }
205
-
206
- if (enumTester(valueAsNumber, enumReverseArr)) {
207
- result = new EjvError(
208
- ErrorType.NOT_ONE_OF,
209
- ErrorMsg.NOT_ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(enumReverseArr)),
210
- _options.path,
211
- data,
212
- value
213
- );
214
- break;
215
- }
216
- }
217
-
218
- if (definedTester(scheme.min)) {
219
- if (!numberTester(scheme.min)) {
220
- throw new Error(ErrorMsg.MIN_SHOULD_BE_NUMBER);
221
- }
222
-
223
- if (definedTester(scheme.exclusiveMin)) {
224
- if (!booleanTester(scheme.exclusiveMin)) {
225
- throw new Error(ErrorMsg.EXCLUSIVE_MIN_SHOULD_BE_BOOLEAN);
226
- }
227
-
228
- if (scheme.exclusiveMin === true) {
229
- if (!exclusiveMinNumberTester(valueAsNumber, scheme.min as number)) {
230
- result = new EjvError(
231
- ErrorType.GREATER_THAN,
232
- ErrorMsg.GREATER_THAN.replace(ErrorMsgCursorA, '' + scheme.min),
233
- _options.path,
234
- data,
235
- value
236
- );
237
- break;
238
- }
239
- } else {
240
- if (!minNumberTester(valueAsNumber, scheme.min as number)) {
241
- result = new EjvError(
242
- ErrorType.GREATER_THAN_OR_EQUAL,
243
- ErrorMsg.GREATER_THAN_OR_EQUAL.replace(ErrorMsgCursorA, '' + scheme.min),
244
- _options.path,
245
- data,
246
- value
247
- );
248
- break;
249
- }
250
- }
251
- } else {
252
- if (!minNumberTester(valueAsNumber, scheme.min as number)) {
253
- result = new EjvError(
254
- ErrorType.GREATER_THAN_OR_EQUAL,
255
- ErrorMsg.GREATER_THAN_OR_EQUAL.replace(ErrorMsgCursorA, '' + scheme.min),
256
- _options.path,
257
- data,
258
- value
259
- );
260
- break;
261
- }
262
- }
263
- }
264
-
265
- if (definedTester(scheme.max)) {
266
- if (!numberTester(scheme.max)) {
267
- throw new Error(ErrorMsg.MAX_SHOULD_BE_NUMBER);
268
- }
269
-
270
- if (definedTester(scheme.exclusiveMax)) {
271
- if (!booleanTester(scheme.exclusiveMax)) {
272
- throw new Error(ErrorMsg.EXCLUSIVE_MAX_SHOULD_BE_BOOLEAN);
273
- }
274
-
275
- if (scheme.exclusiveMax === true) {
276
- if (!exclusiveMaxNumberTester(valueAsNumber, scheme.max as number)) {
277
- result = new EjvError(
278
- ErrorType.SMALLER_THAN,
279
- ErrorMsg.SMALLER_THAN.replace(ErrorMsgCursorA, '' + scheme.max),
280
- _options.path,
281
- data,
282
- value
283
- );
284
- break;
285
- }
286
- } else {
287
- if (!maxNumberTester(valueAsNumber, scheme.max as number)) {
288
- result = new EjvError(
289
- ErrorType.SMALLER_THAN_OR_EQUAL,
290
- ErrorMsg.SMALLER_THAN_OR_EQUAL.replace(ErrorMsgCursorA, '' + scheme.max),
291
- _options.path,
292
- data,
293
- value
294
- );
295
- break;
296
- }
297
- }
298
- } else {
299
- if (!maxNumberTester(valueAsNumber, scheme.max as number)) {
300
- result = new EjvError(
301
- ErrorType.SMALLER_THAN_OR_EQUAL,
302
- ErrorMsg.SMALLER_THAN_OR_EQUAL.replace(ErrorMsgCursorA, '' + scheme.max),
303
- _options.path,
304
- data,
305
- value
306
- );
307
- break;
308
- }
309
- }
310
- }
311
-
312
- if (definedTester(scheme.format)) {
313
- let formats : NumberFormat[];
314
-
315
- const allNumberFormat : NumberFormat[] = Object.values(NumberFormat);
316
-
317
- if (!arrayTester(scheme.format)) {
318
- const formatAsString : NumberFormat = scheme.format as NumberFormat;
319
-
320
- if (!enumTester(formatAsString, allNumberFormat)) {
321
- throw new Error(ErrorMsg.INVALID_NUMBER_FORMAT.replace(ErrorMsgCursorA, formatAsString));
322
- }
323
-
324
- formats = [scheme.format as NumberFormat];
325
- } else {
326
- const formatAsArray : NumberFormat[] = scheme.format as NumberFormat[];
327
-
328
- const errorFormat : string | undefined = formatAsArray.find(format => {
329
- return !enumTester(format, allNumberFormat);
330
- });
331
-
332
- if (!!errorFormat) {
333
- throw new Error(ErrorMsg.INVALID_NUMBER_FORMAT.replace(ErrorMsgCursorA, errorFormat));
334
- }
335
-
336
- formats = scheme.format as NumberFormat[];
337
- }
338
-
339
- if (!formats.some(format => {
340
- let valid : boolean = false;
341
-
342
- switch (format) {
343
- case NumberFormat.INTEGER:
344
- valid = integerTester(value);
345
- break;
346
-
347
- case NumberFormat.INDEX:
348
- valid = indexTester(value);
349
- break;
350
- }
351
-
352
- return valid;
353
- })) {
354
- if (!arrayTester(scheme.format)) {
355
- result = new EjvError(
356
- ErrorType.FORMAT,
357
- ErrorMsg.FORMAT.replace(ErrorMsgCursorA, scheme.format as NumberFormat),
358
- _options.path,
359
- data,
360
- value
361
- );
362
- } else {
363
- result = new EjvError(
364
- ErrorType.FORMAT_ONE_OF,
365
- ErrorMsg.FORMAT_ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(scheme.format)),
366
- _options.path,
367
- data,
368
- value
369
- );
370
- }
371
- break;
372
- }
373
- }
374
- break;
375
-
376
- case DataType.STRING:
377
- const valueAsString : string = value as unknown as string;
378
-
379
- if (definedTester(scheme.enum)) {
380
- if (!arrayTester(scheme.enum)) {
381
- throw new Error(ErrorMsg.ENUM_SHOULD_BE_ARRAY);
382
- }
383
-
384
- const enumArr : string[] = scheme.enum as string[];
385
-
386
- if (!arrayTypeOfTester(enumArr, DataType.STRING)) {
387
- throw new Error(ErrorMsg.ENUM_SHOULD_BE_STRINGS);
388
- }
389
-
390
- if (!enumTester(valueAsString, enumArr)) {
391
- result = new EjvError(
392
- ErrorType.ONE_OF,
393
- ErrorMsg.ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(scheme.enum)),
394
- _options.path,
395
- data,
396
- value
397
- );
398
- break;
399
- }
400
- }
401
-
402
- if (definedTester(scheme.enumReverse)) {
403
- if (!arrayTester(scheme.enumReverse)) {
404
- throw new Error(ErrorMsg.ENUM_REVERSE_SHOULD_BE_ARRAY);
405
- }
406
-
407
- const enumReverseArr : string[] = scheme.enumReverse as string[];
408
-
409
- if (!arrayTypeOfTester(enumReverseArr, DataType.STRING)) {
410
- throw new Error(ErrorMsg.ENUM_REVERSE_SHOULD_BE_STRINGS);
411
- }
412
-
413
- if (enumTester(valueAsString, enumReverseArr)) {
414
- result = new EjvError(
415
- ErrorType.NOT_ONE_OF,
416
- ErrorMsg.NOT_ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(enumReverseArr)),
417
- _options.path,
418
- data,
419
- value
420
- );
421
- break;
422
- }
423
- }
424
-
425
- if (definedTester(scheme.length)) {
426
- const length : number = scheme.length as number;
427
-
428
- if (!(numberTester(length) && integerTester(length))) {
429
- throw new Error(ErrorMsg.LENGTH_SHOULD_BE_INTEGER);
430
- }
431
-
432
- if (!lengthTester(valueAsString, length)) {
433
- result = new EjvError(
434
- ErrorType.LENGTH,
435
- ErrorMsg.LENGTH.replace(ErrorMsgCursorA, '' + length),
436
- _options.path,
437
- data,
438
- value
439
- );
440
- break;
441
- }
442
- }
443
-
444
- if (definedTester(scheme.minLength)) {
445
- const minLength : number = scheme.minLength as number;
446
-
447
- if (!(numberTester(minLength) && integerTester(minLength))) {
448
- throw new Error(ErrorMsg.MIN_LENGTH_SHOULD_BE_INTEGER);
449
- }
450
-
451
- if (!minLengthTester(valueAsString, minLength)) {
452
- result = new EjvError(
453
- ErrorType.MIN_LENGTH,
454
- ErrorMsg.MIN_LENGTH.replace(ErrorMsgCursorA, '' + minLength),
455
- _options.path,
456
- data,
457
- value
458
- );
459
- break;
460
- }
461
- }
462
-
463
- if (definedTester(scheme.maxLength)) {
464
- const maxLength : number = scheme.maxLength as number;
465
-
466
- if (!(numberTester(maxLength) && integerTester(maxLength))) {
467
- throw new Error(ErrorMsg.MAX_LENGTH_SHOULD_BE_INTEGER);
468
- }
469
-
470
- if (!maxLengthTester(valueAsString, maxLength)) {
471
- result = new EjvError(
472
- ErrorType.MAX_LENGTH,
473
- ErrorMsg.MAX_LENGTH.replace(ErrorMsgCursorA, '' + maxLength),
474
- _options.path,
475
- data,
476
- value
477
- );
478
- break;
479
- }
480
- }
481
-
482
- if (definedTester(scheme.format)) {
483
- let formats : StringFormat[];
484
-
485
- const allStringFormat : StringFormat[] = Object.values(StringFormat);
486
-
487
- if (!arrayTester(scheme.format)) {
488
- const formatAsString : string = scheme.format as string;
489
-
490
- if (!enumTester(formatAsString, allStringFormat)) {
491
- throw new Error(ErrorMsg.INVALID_STRING_FORMAT.replace(ErrorMsgCursorA, formatAsString));
492
- }
493
-
494
- formats = [scheme.format] as StringFormat[];
495
- } else {
496
- const formatAsArray : string[] = scheme.format as string[];
497
- const errorFormat : string | undefined = formatAsArray.find(format => {
498
- return !enumTester(format, allStringFormat);
499
- });
500
-
501
- if (!!errorFormat) {
502
- throw new Error(ErrorMsg.INVALID_STRING_FORMAT.replace(ErrorMsgCursorA, errorFormat));
503
- }
504
-
505
- formats = scheme.format as StringFormat[];
506
- }
507
-
508
- if (!formats.some(format => {
509
- let valid : boolean = false;
510
-
511
- switch (format) {
512
- case StringFormat.EMAIL:
513
- valid = emailTester(value);
514
- break;
515
-
516
- case StringFormat.DATE:
517
- valid = dateFormatTester(value);
518
- break;
519
-
520
- case StringFormat.TIME:
521
- valid = timeFormatTester(value);
522
- break;
523
-
524
- case StringFormat.DATE_TIME:
525
- valid = dateTimeFormatTester(value);
526
- break;
527
- }
528
-
529
- return valid;
530
- })) {
531
- if (!arrayTester(scheme.format)) {
532
- result = new EjvError(
533
- ErrorType.FORMAT,
534
- ErrorMsg.FORMAT.replace(ErrorMsgCursorA, scheme.format as StringFormat),
535
- _options.path,
536
- data,
537
- value
538
- );
539
- } else {
540
- result = new EjvError(
541
- ErrorType.FORMAT_ONE_OF,
542
- ErrorMsg.FORMAT_ONE_OF.replace(ErrorMsgCursorA, JSON.stringify(scheme.format)),
543
- _options.path,
544
- data,
545
- value
546
- );
547
- }
548
- break;
549
- }
550
- }
551
-
552
- if (definedTester(scheme.pattern)) {
553
- // check parameter
554
- if (scheme.pattern === null) {
555
- throw new Error(ErrorMsg.INVALID_STRING_PATTERN
556
- .replace(ErrorMsgCursorA, 'null'));
557
- }
558
-
559
- const isValidPattern = (pattern : string | RegExp) : boolean => {
560
- return (stringTester(pattern) && minLengthTester(pattern as string, 1))
561
- || (regExpTester(pattern) && pattern.toString() !== '/(?:)/' && pattern.toString() !== '/null/');
562
- };
563
-
564
- const patternToString = (pattern : string | RegExp) : string => {
565
- let regExpStr : string;
566
-
567
- if (pattern === null) {
568
- regExpStr = '/null/';
569
- } else if (stringTester(pattern)) {
570
- if (minLengthTester(pattern as string, 1)) {
571
- regExpStr = new RegExp(pattern as string).toString();
572
- } else {
573
- regExpStr = '//';
574
- }
575
- } else {
576
- regExpStr = pattern.toString();
577
- }
578
-
579
- // empty regular expression
580
- if (regExpStr === '/(?:)/') {
581
- regExpStr = '//';
582
- }
583
-
584
- return regExpStr;
585
- };
586
-
587
- const createArrayErrorMsg = (patternsAsArray : (string | RegExp)[]) : string => {
588
- return '[' + patternsAsArray.map(onePattern => {
589
- return patternToString(onePattern);
590
- }).join(', ') + ']';
591
- };
592
-
593
- if (arrayTester(scheme.pattern)) {
594
- const patternsAsArray : (string | RegExp)[] = scheme.pattern as (string | RegExp)[];
595
-
596
- if (!minLengthTester(patternsAsArray, 1)) { // empty array
597
- throw new Error(ErrorMsg.INVALID_STRING_PATTERN
598
- .replace(ErrorMsgCursorA, createArrayErrorMsg(patternsAsArray)));
599
- }
600
-
601
- const regExpPatterns : RegExp[] = patternsAsArray.map(pattern => {
602
- if (!isValidPattern(pattern)) {
603
- throw new Error(ErrorMsg.INVALID_STRING_PATTERN
604
- .replace(ErrorMsgCursorA, createArrayErrorMsg(patternsAsArray)));
605
- }
606
-
607
- return new RegExp(pattern);
608
- }) as RegExp[];
609
-
610
- // check value
611
- if (!regExpPatterns.some((regexp : RegExp) => {
612
- return stringRegExpTester(value, regexp);
613
- })) {
614
- result = new EjvError(
615
- ErrorType.PATTERN_ONE_OF,
616
- ErrorMsg.PATTERN_ONE_OF
617
- .replace(ErrorMsgCursorA, createArrayErrorMsg(patternsAsArray)),
618
- _options.path,
619
- data,
620
- value
621
- );
622
- break;
623
- }
624
-
625
- } else {
626
- const patternAsOne : string | RegExp = scheme.pattern as string | RegExp;
627
-
628
- if (!isValidPattern(patternAsOne)) {
629
- throw new Error(ErrorMsg.INVALID_STRING_PATTERN
630
- .replace(ErrorMsgCursorA, patternToString(patternAsOne)));
631
- }
632
-
633
- // check value
634
- const regExp : RegExp = new RegExp(patternAsOne);
635
-
636
- if (!stringRegExpTester(valueAsString, regExp)) {
637
- result = new EjvError(
638
- ErrorType.PATTERN,
639
- ErrorMsg.PATTERN.replace(ErrorMsgCursorA, patternToString(patternAsOne)),
640
- _options.path,
641
- data,
642
- value
643
- );
644
- break;
645
- }
646
- }
647
- }
648
- break;
649
-
650
- case DataType.OBJECT:
651
- const valueAsObject = value as unknown as { [key : string] : any };
652
-
653
- if (definedTester(scheme.allowNoProperty)) {
654
- if (!booleanTester(scheme.allowNoProperty)) {
655
- throw new Error(ErrorMsg.ALLOW_NO_PROPERTY_SHOULD_BE_BOOLEAN);
656
- }
657
-
658
- if (scheme.allowNoProperty !== true && !hasPropertyTester(valueAsObject)) {
659
- result = new EjvError(
660
- ErrorType.NO_PROPERTY,
661
- ErrorMsg.NO_PROPERTY,
662
- _options.path,
663
- data,
664
- value
665
- );
666
- break;
667
- }
668
- }
669
-
670
- if (definedTester(scheme.properties)) {
671
- if (!arrayTester(scheme.properties)) {
672
- throw new Error(ErrorMsg.PROPERTIES_SHOULD_BE_ARRAY);
673
- }
674
-
675
- const properties : Scheme[] = scheme.properties as Scheme[];
676
-
677
- if (!minLengthTester(properties, 1)) {
678
- throw new Error(ErrorMsg.PROPERTIES_SHOULD_HAVE_ITEMS);
679
- }
680
-
681
- if (!arrayTypeOfTester(properties, DataType.OBJECT)) {
682
- throw new Error(ErrorMsg.PROPERTIES_SHOULD_BE_ARRAY_OF_OBJECT);
683
- }
684
-
685
- if (!objectTester(value)) {
686
- result = new EjvError(
687
- ErrorType.TYPE_MISMATCH,
688
- ErrorMsg.TYPE_MISMATCH.replace(ErrorMsgCursorA, 'object'),
689
- _options.path,
690
- data,
691
- value
692
- );
693
- break;
694
- }
695
-
696
- const partialData : T[keyof T] = data[key];
697
- const partialScheme : Scheme[] = scheme.properties as Scheme[];
698
-
699
- // call recursively
700
- result = _ejv(partialData, partialScheme, _options);
701
-
702
- if (!!result) {
703
- // inject original data
704
- result.data = data;
705
- }
706
- }
707
- break;
708
-
709
- case DataType.DATE:
710
- const valueAsDate : Date = value as unknown as Date;
711
-
712
- if (definedTester(scheme.min)) {
713
- if (!(
714
- (stringTester(scheme.min) && (dateFormatTester(scheme.min as string) || dateTimeFormatTester(scheme.min as string)))
715
- || dateTester(scheme.min)
716
- )) {
717
- throw new Error(ErrorMsg.MIN_DATE_SHOULD_BE_DATE_OR_STRING);
718
- }
719
-
720
- if (definedTester(scheme.exclusiveMin) && !booleanTester(scheme.exclusiveMin)) {
721
- throw new Error(ErrorMsg.EXCLUSIVE_MIN_SHOULD_BE_BOOLEAN);
722
- }
723
-
724
- let minDate : Date = new Date(scheme.min as string | Date);
725
-
726
- // adjust timezone
727
- if (stringTester(scheme.min)) {
728
- // by minutes
729
- const timezoneOffset : number = minDate.getTimezoneOffset();
730
-
731
- minDate = new Date(+minDate + (timezoneOffset * 60 * 1000));
732
- }
733
-
734
- if (scheme.exclusiveMin !== true) {
735
- if (!minDateTester(valueAsDate, minDate)) {
736
- result = new EjvError(
737
- ErrorType.AFTER_OR_SAME_DATE,
738
- ErrorMsg.AFTER_OR_SAME_DATE.replace(ErrorMsgCursorA, minDate.toISOString()),
739
- _options.path,
740
- data,
741
- value
742
- );
743
- break;
744
- }
745
-
746
- } else {
747
- if (!exclusiveMinDateTester(valueAsDate, minDate)) {
748
- result = new EjvError(
749
- ErrorType.AFTER_DATE,
750
- ErrorMsg.AFTER_DATE.replace(ErrorMsgCursorA, minDate.toISOString()),
751
- _options.path,
752
- data,
753
- value
754
- );
755
- break;
756
- }
757
- }
758
- }
759
-
760
- if (definedTester(scheme.max)) {
761
- if (!(
762
- (stringTester(scheme.max) && (dateFormatTester(scheme.max as string) || dateTimeFormatTester(scheme.max as string)))
763
- || dateTester(scheme.max)
764
- )) {
765
- throw new Error(ErrorMsg.MAX_DATE_SHOULD_BE_DATE_OR_STRING);
766
- }
767
-
768
- if (definedTester(scheme.exclusiveMax) && !booleanTester(scheme.exclusiveMax)) {
769
- throw new Error(ErrorMsg.EXCLUSIVE_MAX_SHOULD_BE_BOOLEAN);
770
- }
771
-
772
- let maxDate : Date = new Date(scheme.max as string | Date);
773
-
774
- // adjust timezone
775
- if (stringTester(scheme.max)) {
776
- // by minutes
777
- const timezoneOffset : number = maxDate.getTimezoneOffset();
778
-
779
- maxDate = new Date(+maxDate + (timezoneOffset * 60 * 1000));
780
- }
781
-
782
- if (scheme.exclusiveMax !== true) {
783
- if (!maxDateTester(valueAsDate, maxDate)) {
784
- result = new EjvError(
785
- ErrorType.BEFORE_OR_SAME_DATE,
786
- ErrorMsg.BEFORE_OR_SAME_DATE.replace(ErrorMsgCursorA, maxDate.toISOString()),
787
- _options.path,
788
- data,
789
- value
790
- );
791
- break;
792
- }
793
-
794
- } else {
795
- if (!exclusiveMaxDateTester(valueAsDate, maxDate)) {
796
- result = new EjvError(
797
- ErrorType.BEFORE_DATE,
798
- ErrorMsg.BEFORE_DATE.replace(ErrorMsgCursorA, maxDate.toISOString()),
799
- _options.path,
800
- data,
801
- value
802
- );
803
- break;
804
- }
805
- }
806
- }
807
- break;
808
-
809
- case DataType.ARRAY:
810
- const valueAsArray : any[] = value as unknown as any[];
811
-
812
- if (definedTester(scheme.length)) {
813
- const length : number = scheme.length as number;
814
-
815
- if (!(numberTester(length) && integerTester(length))) {
816
- throw new Error(ErrorMsg.LENGTH_SHOULD_BE_INTEGER);
817
- }
818
-
819
- if (!lengthTester(valueAsArray, length)) {
820
- result = new EjvError(
821
- ErrorType.LENGTH,
822
- ErrorMsg.LENGTH.replace(ErrorMsgCursorA, '' + length),
823
- _options.path,
824
- data,
825
- value
826
- );
827
- break;
828
- }
829
- }
830
-
831
- if (definedTester(scheme.minLength)) {
832
- const minLength : number = scheme.minLength as number;
833
-
834
- if (!(numberTester(scheme.minLength) && integerTester(minLength))) {
835
- throw new Error(ErrorMsg.MIN_LENGTH_SHOULD_BE_INTEGER);
836
- }
837
-
838
- if (!minLengthTester(valueAsArray, minLength)) {
839
- result = new EjvError(
840
- ErrorType.MIN_LENGTH,
841
- ErrorMsg.MIN_LENGTH.replace(ErrorMsgCursorA, '' + minLength),
842
- _options.path,
843
- data,
844
- value
845
- );
846
- break;
847
- }
848
- }
849
-
850
- if (definedTester(scheme.maxLength)) {
851
- const maxLength : number = scheme.maxLength as number;
852
-
853
- if (!(numberTester(scheme.maxLength) && integerTester(maxLength))) {
854
- throw new Error(ErrorMsg.MAX_LENGTH_SHOULD_BE_INTEGER);
855
- }
856
-
857
- if (!maxLengthTester(valueAsArray, maxLength)) {
858
- result = new EjvError(
859
- ErrorType.MAX_LENGTH,
860
- ErrorMsg.MAX_LENGTH.replace(ErrorMsgCursorA, '' + maxLength),
861
- _options.path,
862
- data,
863
- value
864
- );
865
- break;
866
- }
867
- }
868
-
869
- if (definedTester(scheme.unique)) {
870
- if (!booleanTester(scheme.unique)) {
871
- throw new Error(ErrorMsg.UNIQUE_SHOULD_BE_BOOLEAN);
872
- }
873
-
874
- if (scheme.unique === true && !uniqueItemsTester(valueAsArray)) {
875
- result = new EjvError(
876
- ErrorType.UNIQUE_ITEMS,
877
- ErrorMsg.UNIQUE_ITEMS,
878
- _options.path,
879
- data,
880
- value
881
- );
882
- break;
883
- }
884
- }
885
-
886
- if (definedTester(scheme.items)) {
887
- // convert array to object
888
- if (valueAsArray.length > 0) {
889
- const now : Date = new Date;
890
- const tempKeyArr : string[] = valueAsArray.map((value : any, i : number) => {
891
- return '' + (+now + i);
892
- });
893
-
894
- if (stringTester(scheme.items) // by DataType
895
- || (arrayTester(scheme.items) && arrayTypeOfTester(scheme.items as DataType[], DataType.STRING)) // by DataType[]
896
- ) {
897
- const itemTypes : DataType[] = (arrayTester(scheme.items) ? scheme.items : [scheme.items]) as DataType[];
898
-
899
- const partialData : AnyObject = {};
900
- const partialSchemes : Scheme[] = [];
901
-
902
- tempKeyArr.forEach((tempKey : string, i : number) => {
903
- partialData[tempKey] = valueAsArray[i];
904
- partialSchemes.push({
905
- key : tempKey,
906
- type : itemTypes
907
- });
908
- });
909
-
910
- // call recursively
911
- const partialResult : EjvError | null = _ejv(partialData, partialSchemes, _options);
912
-
913
- // convert new EjvError
914
- if (!!partialResult) {
915
- let errorMsg : string;
916
-
917
- if (arrayTester(scheme.items)) {
918
- errorMsg = ErrorMsg.ITEMS_TYPE.replace(ErrorMsgCursorA, JSON.stringify(itemTypes));
919
- } else {
920
- errorMsg = ErrorMsg.ITEMS_TYPE.replace(ErrorMsgCursorA, scheme.items as string);
921
- }
922
-
923
- const partialKeys : string[] = partialResult.path.split('/');
924
- const partialKey : string = partialKeys[partialKeys.length - 1];
925
-
926
- const partialScheme : Scheme = partialSchemes.find(scheme => {
927
- return scheme.key === partialKey;
928
- }) as Scheme;
929
-
930
- const partialKeyIndex : number = partialSchemes.indexOf(partialScheme);
931
-
932
- result = new EjvError(
933
- ErrorType.ITEMS_TYPE,
934
- errorMsg,
935
- [..._options.path, '' + partialKeyIndex],
936
- data,
937
- partialData[partialKey]
938
- );
939
- }
940
- break;
941
- } else if ((objectTester(scheme.items) && scheme.items !== null) // by Scheme
942
- || (arrayTester(scheme.items) && arrayTypeOfTester(scheme.items as Scheme[], DataType.OBJECT)) // by Scheme[]
943
- ) {
944
- const itemsAsSchemes : Scheme[] = (arrayTester(scheme.items) ? scheme.items : [scheme.items]) as Scheme[];
945
-
946
- let partialError : EjvError | null | undefined = null;
947
-
948
- // use for() instead of forEach() to break
949
- const valueLength : number = valueAsArray.length;
950
-
951
- for (let arrIndex = 0; arrIndex < valueLength; arrIndex++) {
952
- const oneValue : any = valueAsArray[arrIndex];
953
-
954
- const partialData : AnyObject = {};
955
- const partialSchemes : Scheme[] = [];
956
-
957
- const tempKeyForThisValue : string = tempKeyArr[arrIndex];
958
-
959
- partialData[tempKeyForThisValue] = oneValue;
960
-
961
- partialSchemes.push(...itemsAsSchemes.map((oneScheme : Scheme) => {
962
- const newScheme : Scheme = clone(oneScheme); // divide instance
963
-
964
- newScheme.key = tempKeyForThisValue;
965
-
966
- return newScheme;
967
- }));
968
-
969
- const partialResults : (EjvError | null)[] = partialSchemes.map((partialScheme : Scheme) => {
970
- // call recursively
971
- const partialResult : EjvError | null = _ejv(partialData, [partialScheme], _options);
972
-
973
- if (!!partialResult) {
974
- partialResult.path = partialResult.path.replace(tempKeyForThisValue, '' + arrIndex);
975
- }
976
-
977
- return partialResult;
978
- });
979
-
980
- if (!partialResults.some(oneResult => oneResult === null)) {
981
- partialError = partialResults.find(oneResult => {
982
- return !!oneResult;
983
- });
984
- break;
985
- }
986
- }
987
-
988
- if (!!partialError) {
989
- let errorType : ErrorType;
990
- let errorMsg : string;
991
-
992
- if (!!itemsAsSchemes && itemsAsSchemes.length > 1) {
993
- errorType = ErrorType.ITEMS_SCHEMES;
994
- errorMsg = ErrorMsg.ITEMS_SCHEMES.replace(ErrorMsgCursorA, JSON.stringify(itemsAsSchemes));
995
- } else {
996
- errorType = partialError.type;
997
- errorMsg = partialError.message;
998
-
999
- if (errorType === ErrorType.REQUIRED) {
1000
- // REQUIRED in array is TYPE_MISMATCH except with nullable === true
1001
- errorType = ErrorType.TYPE_MISMATCH;
1002
- errorMsg = ErrorMsg.TYPE_MISMATCH.replace(ErrorMsgCursorA, JSON.stringify(scheme.items));
1003
- }
1004
- }
1005
-
1006
- result = new EjvError(
1007
- errorType,
1008
- errorMsg,
1009
- partialError.path.split('/'),
1010
- data,
1011
- partialError.errorData
1012
- );
1013
- break;
1014
- }
1015
- } else {
1016
- throw new Error(ErrorMsg.INVALID_ITEMS_SCHEME.replace(ErrorMsgCursorA, JSON.stringify(scheme.items)));
1017
- }
1018
- }
1019
- }
1020
- break;
1021
- }
1022
-
1023
- if (!!result) {
1024
- break;
1025
- }
1026
- }
1027
-
1028
- if (definedTester(result) && definedTester(options.customErrorMsg)) {
1029
- const resultAsNotNull : EjvError = result as NonNullable<EjvError>;
1030
- const customErrorMsgObj : {
1031
- [key in ErrorType]? : string;
1032
- } = options.customErrorMsg as {
1033
- [key in ErrorType]? : string;
1034
- };
1035
-
1036
- // override error message
1037
- const customMsg : string = customErrorMsgObj[resultAsNotNull.type] as string;
1038
-
1039
- if (definedTester(customMsg)) {
1040
- resultAsNotNull.message = customMsg;
1041
- }
1042
- }
1043
-
1044
- return result;
1045
- };
1046
-
1047
- export const ejv = (data : object, schemes : Scheme[], options? : Options) : null | EjvError => {
1048
- // check data itself
1049
- if (!definedTester(data) || !objectTester(data) || data === null) {
1050
- return new EjvError(ErrorType.REQUIRED, ErrorMsg.NO_DATA, ['/'], data, data);
1051
- }
1052
-
1053
- // check schemes itself
1054
- if (!definedTester(schemes) || schemes === null) {
1055
- throw new Error(ErrorMsg.NO_SCHEME);
1056
- }
1057
-
1058
- if (!arrayTester(schemes)) {
1059
- throw new Error(ErrorMsg.NO_ARRAY_SCHEME);
1060
- }
1061
-
1062
- if (!arrayTypeOfTester(schemes, DataType.OBJECT)) {
1063
- throw new Error(ErrorMsg.NO_OBJECT_ARRAY_SCHEME);
1064
- }
1065
-
1066
- if (!minLengthTester(schemes, 1)) {
1067
- throw new Error(ErrorMsg.EMPTY_SCHEME);
1068
- }
1069
-
1070
- return _ejv(data, schemes, options as InternalOptions);
1071
- };
1
+ import {
2
+ AllDataType,
3
+ AnyObject,
4
+ ArrayScheme,
5
+ DateScheme,
6
+ EjvError,
7
+ InternalOptions,
8
+ NumberScheme,
9
+ ObjectScheme,
10
+ Options,
11
+ Scheme,
12
+ StringScheme
13
+ } from './interfaces';
14
+ import { DataType, ErrorMsg, ErrorType, NumberFormat, StringFormat } from './constants';
15
+
16
+ import {
17
+ arrayTester,
18
+ arrayTypeOfTester,
19
+ booleanTester,
20
+ dateFormatTester,
21
+ dateTester,
22
+ dateTimeFormatTester,
23
+ definedTester,
24
+ emailTester,
25
+ enumTester,
26
+ exclusiveMaxDateTester,
27
+ exclusiveMaxNumberTester,
28
+ exclusiveMinDateTester,
29
+ exclusiveMinNumberTester,
30
+ hasPropertyTester,
31
+ indexTester,
32
+ integerTester,
33
+ lengthTester,
34
+ maxDateTester,
35
+ maxLengthTester,
36
+ maxNumberTester,
37
+ minDateTester,
38
+ minLengthTester,
39
+ minNumberTester,
40
+ numberTester,
41
+ objectTester,
42
+ regExpTester,
43
+ stringRegExpTester,
44
+ stringTester,
45
+ timeFormatTester,
46
+ typeTester,
47
+ uniqueItemsTester
48
+ } from './tester';
49
+ import { clone, createErrorMsg, sift } from './util';
50
+
51
+
52
+ function _getEffectiveTypes (scheme: Scheme): DataType[] | undefined {
53
+ let result: DataType[] | undefined;
54
+
55
+ if (definedTester(scheme.type)) {
56
+ result = (arrayTester(scheme.type)
57
+ ? scheme.type
58
+ : [scheme.type]) as DataType[];
59
+ }
60
+ else if (definedTester(scheme.parent)) {
61
+ result = _getEffectiveTypes(scheme.parent);
62
+ }
63
+
64
+ return result;
65
+ }
66
+
67
+ const _ejv = <T> (data: T, schemes: Scheme[], options: InternalOptions): null | EjvError => {
68
+ // check schemes
69
+ if (!definedTester(schemes) || schemes === null) {
70
+ return new EjvError({
71
+ type: ErrorType.NO_SCHEME,
72
+ message: ErrorMsg.NO_SCHEME,
73
+
74
+ data: data,
75
+
76
+ errorScheme: schemes,
77
+ isSchemeError: true
78
+ });
79
+ }
80
+
81
+ if (!arrayTester(schemes)) {
82
+ return new EjvError({
83
+ type: ErrorType.INVALID_SCHEMES,
84
+ message: ErrorMsg.NO_ARRAY_SCHEME,
85
+
86
+ data: data,
87
+
88
+ errorScheme: schemes,
89
+ isSchemeError: true
90
+ });
91
+ }
92
+
93
+ if (!arrayTypeOfTester(schemes, DataType.OBJECT)) {
94
+ return new EjvError({
95
+ type: ErrorType.INVALID_SCHEMES,
96
+ message: ErrorMsg.NO_OBJECT_ARRAY_SCHEME,
97
+
98
+ data: data,
99
+
100
+ errorScheme: schemes,
101
+ isSchemeError: true
102
+ });
103
+ }
104
+
105
+ if (!minLengthTester(schemes, 1)) {
106
+ return new EjvError({
107
+ type: ErrorType.INVALID_SCHEMES,
108
+ message: ErrorMsg.EMPTY_SCHEME,
109
+
110
+ data: data,
111
+
112
+ errorScheme: schemes,
113
+ isSchemeError: true
114
+ });
115
+ }
116
+
117
+ // check data by schemes
118
+ let result: EjvError | null = null;
119
+
120
+ // use for() instead of forEach() to stop
121
+ for (const scheme of schemes) {
122
+ const key: keyof T = scheme.key as keyof T;
123
+
124
+ const _options: InternalOptions = clone(options); // divide instance
125
+
126
+ let value: unknown;
127
+
128
+ if (key) {
129
+ value = data[key];
130
+
131
+ _options.path.push(key as string);
132
+ }
133
+
134
+ const types: DataType[] | undefined = _getEffectiveTypes(scheme);
135
+
136
+ if (!definedTester(types)) {
137
+ return new EjvError({
138
+ type: ErrorType.INVALID_SCHEMES,
139
+ message: ErrorMsg.SCHEMES_SHOULD_HAVE_TYPE,
140
+
141
+ data: data,
142
+
143
+ errorScheme: scheme,
144
+ isSchemeError: true
145
+ });
146
+ }
147
+
148
+
149
+ const allDataType: DataType[] = Object.values(DataType);
150
+
151
+ const typeError: string | undefined = types.find((type: DataType): boolean => {
152
+ return !definedTester(type)
153
+ || !stringTester(type)
154
+ || !enumTester(type, allDataType);
155
+ });
156
+
157
+ if (typeError) {
158
+ return new EjvError({
159
+ type: ErrorType.INVALID_SCHEMES,
160
+ message: createErrorMsg(ErrorMsg.SCHEMES_HAS_INVALID_TYPE, {
161
+ placeholders: [typeError]
162
+ }),
163
+
164
+ data: data,
165
+
166
+ errorScheme: scheme,
167
+ isSchemeError: true
168
+ });
169
+ }
170
+
171
+ if (!uniqueItemsTester(types)) {
172
+ const notUniqueItems: string[] = types.filter((type: string): boolean => {
173
+ return types.filter((_type: unknown): boolean => _type === type).length > 1;
174
+ });
175
+
176
+ const notUniqueItemsSifted: string[] = sift(notUniqueItems);
177
+
178
+ return new EjvError({
179
+ type: ErrorType.INVALID_SCHEMES,
180
+ message: createErrorMsg(ErrorMsg.SCHEMES_HAS_DUPLICATED_TYPE, {
181
+ placeholders: [notUniqueItemsSifted.join(', ')]
182
+ }),
183
+
184
+ data: data,
185
+
186
+ errorScheme: scheme,
187
+ isSchemeError: true
188
+ });
189
+ }
190
+
191
+ if (!definedTester(value)) {
192
+ if (scheme.optional !== true) {
193
+ result = new EjvError({
194
+ type: ErrorType.REQUIRED,
195
+ message: createErrorMsg(ErrorMsg.REQUIRED),
196
+
197
+ data,
198
+ path: _options.path,
199
+
200
+ errorScheme: scheme,
201
+ errorData: value
202
+ });
203
+ break;
204
+ }
205
+ else {
206
+ continue;
207
+ }
208
+ }
209
+
210
+ if (value === null) {
211
+ if (scheme.nullable !== true) {
212
+ result = new EjvError({
213
+ type: ErrorType.REQUIRED,
214
+ message: createErrorMsg(ErrorMsg.REQUIRED),
215
+
216
+ data,
217
+ path: _options.path,
218
+
219
+ errorScheme: scheme,
220
+ errorData: value
221
+ });
222
+ break;
223
+ }
224
+ else {
225
+ continue;
226
+ }
227
+ }
228
+
229
+ const typeResolved: DataType | undefined = types.find((type: DataType): type is DataType => {
230
+ return typeTester(value, type);
231
+ });
232
+
233
+ if (typeResolved) {
234
+ if (definedTester(scheme.type)) {
235
+ if (!arrayTester(scheme.type)) {
236
+ if (scheme.type !== typeResolved) {
237
+ result = new EjvError({
238
+ type: ErrorType.TYPE_MISMATCH,
239
+ message: createErrorMsg(ErrorMsg.TYPE_MISMATCH, {
240
+ placeholders: [scheme.type]
241
+ }),
242
+
243
+ data,
244
+ path: _options.path,
245
+
246
+ errorScheme: scheme,
247
+ errorData: value
248
+ });
249
+ }
250
+ }
251
+ else {
252
+ if (!scheme.type.includes(typeResolved)) {
253
+ result = new EjvError({
254
+ type: ErrorType.TYPE_MISMATCH_ONE_OF,
255
+ message: createErrorMsg(ErrorMsg.TYPE_MISMATCH_ONE_OF, {
256
+ placeholders: [JSON.stringify(scheme.type)]
257
+ }),
258
+
259
+ data,
260
+ path: _options.path,
261
+
262
+ errorScheme: scheme,
263
+ errorData: value
264
+ });
265
+ }
266
+ }
267
+ }
268
+ // else do additional validation
269
+ }
270
+ else {
271
+ // type is not resolved
272
+ const typesForMsg: AllDataType = scheme.type || scheme.parent?.type as AllDataType;
273
+
274
+ if (!arrayTester(typesForMsg)) {
275
+ result = new EjvError({
276
+ type: ErrorType.TYPE_MISMATCH,
277
+ message: createErrorMsg(ErrorMsg.TYPE_MISMATCH, {
278
+ placeholders: [typesForMsg]
279
+ }),
280
+
281
+ data,
282
+ path: _options.path,
283
+
284
+ errorScheme: scheme,
285
+ errorData: value
286
+ });
287
+ }
288
+ else {
289
+ result = new EjvError({
290
+ type: ErrorType.TYPE_MISMATCH_ONE_OF,
291
+ message: createErrorMsg(ErrorMsg.TYPE_MISMATCH_ONE_OF, {
292
+ placeholders: [JSON.stringify(typesForMsg)]
293
+ }),
294
+
295
+ data,
296
+ path: _options.path,
297
+
298
+ errorScheme: scheme,
299
+ errorData: value
300
+ });
301
+ }
302
+
303
+ break;
304
+ }
305
+
306
+ // additional check for type resolved
307
+ switch (typeResolved) {
308
+ case DataType.NUMBER: {
309
+ const valueAsNumber: number = value as unknown as number;
310
+ const numberScheme: NumberScheme = scheme as NumberScheme;
311
+
312
+ if (definedTester(numberScheme.enum)) {
313
+ if (!arrayTester(numberScheme.enum)) {
314
+ return new EjvError({
315
+ type: ErrorType.INVALID_SCHEMES,
316
+ message: createErrorMsg(ErrorMsg.ENUM_SHOULD_BE_ARRAY),
317
+
318
+ data: data,
319
+
320
+ errorScheme: numberScheme,
321
+ isSchemeError: true
322
+ });
323
+ }
324
+
325
+ const enumArr: number[] = numberScheme.enum;
326
+
327
+ if (!arrayTypeOfTester(enumArr, DataType.NUMBER)) {
328
+ return new EjvError({
329
+ type: ErrorType.INVALID_SCHEMES,
330
+ message: createErrorMsg(ErrorMsg.ENUM_SHOULD_BE_NUMBERS),
331
+
332
+ data: data,
333
+
334
+ errorScheme: numberScheme,
335
+ isSchemeError: true
336
+ });
337
+ }
338
+
339
+ if (!enumTester(valueAsNumber, enumArr)) {
340
+ result = new EjvError({
341
+ type: ErrorType.ONE_OF,
342
+ message: createErrorMsg(ErrorMsg.ONE_VALUE_OF, {
343
+ placeholders: [JSON.stringify(enumArr)]
344
+ }),
345
+
346
+ data,
347
+ path: _options.path,
348
+
349
+ errorScheme: numberScheme,
350
+ errorData: value
351
+ });
352
+ break;
353
+ }
354
+ }
355
+
356
+ if (
357
+ definedTester(numberScheme.min)
358
+ || definedTester((scheme.parent as NumberScheme)?.min)
359
+ ) {
360
+ const effectiveMin: number = numberScheme.min || (scheme.parent as NumberScheme)?.min as number;
361
+
362
+ if (!numberTester(effectiveMin)) {
363
+ return new EjvError({
364
+ type: ErrorType.INVALID_SCHEMES,
365
+ message: createErrorMsg(ErrorMsg.MIN_SHOULD_BE_NUMBER),
366
+
367
+ data: data,
368
+
369
+ errorScheme: numberScheme,
370
+ isSchemeError: true
371
+ });
372
+ }
373
+
374
+ if (definedTester(numberScheme.exclusiveMin)) {
375
+ if (!booleanTester(numberScheme.exclusiveMin)) {
376
+ return new EjvError({
377
+ type: ErrorType.INVALID_SCHEMES,
378
+ message: createErrorMsg(ErrorMsg.EXCLUSIVE_MIN_SHOULD_BE_BOOLEAN),
379
+
380
+ data: data,
381
+
382
+ errorScheme: numberScheme,
383
+ isSchemeError: true
384
+ });
385
+ }
386
+ }
387
+
388
+ if (numberScheme.exclusiveMin) {
389
+ if (!exclusiveMinNumberTester(valueAsNumber, effectiveMin)) {
390
+ result = new EjvError({
391
+ type: ErrorType.BIGGER_THAN,
392
+ message: createErrorMsg(ErrorMsg.BIGGER_THAN, {
393
+ placeholders: [effectiveMin]
394
+ }),
395
+
396
+ data,
397
+ path: _options.path,
398
+
399
+ errorScheme: numberScheme,
400
+ errorData: value
401
+ });
402
+ break;
403
+ }
404
+ }
405
+ else {
406
+ if (!minNumberTester(valueAsNumber, effectiveMin)) {
407
+ result = new EjvError({
408
+ type: ErrorType.BIGGER_THAN_OR_EQUAL,
409
+ message: createErrorMsg(ErrorMsg.BIGGER_THAN_OR_EQUAL, {
410
+ placeholders: [effectiveMin]
411
+ }),
412
+
413
+ data,
414
+ path: _options.path,
415
+
416
+ errorScheme: numberScheme,
417
+ errorData: value
418
+ });
419
+ break;
420
+ }
421
+ }
422
+ }
423
+
424
+ if (definedTester(numberScheme.max)
425
+ || definedTester((scheme.parent as NumberScheme)?.max)) {
426
+ const effectiveMax: number = numberScheme.max || (scheme.parent as NumberScheme)?.max as number;
427
+
428
+ if (!numberTester(effectiveMax)) {
429
+ return new EjvError({
430
+ type: ErrorType.INVALID_SCHEMES,
431
+ message: createErrorMsg(ErrorMsg.MAX_SHOULD_BE_NUMBER),
432
+
433
+ data: data,
434
+
435
+ errorScheme: numberScheme,
436
+ isSchemeError: true
437
+ });
438
+ }
439
+
440
+ if (definedTester(numberScheme.exclusiveMax)) {
441
+ if (!booleanTester(numberScheme.exclusiveMax)) {
442
+ return new EjvError({
443
+ type: ErrorType.INVALID_SCHEMES,
444
+ message: createErrorMsg(ErrorMsg.EXCLUSIVE_MAX_SHOULD_BE_BOOLEAN),
445
+
446
+ data: data,
447
+
448
+ errorScheme: numberScheme,
449
+ isSchemeError: true
450
+ });
451
+ }
452
+ }
453
+
454
+ if (numberScheme.exclusiveMax) {
455
+ if (!exclusiveMaxNumberTester(valueAsNumber, effectiveMax)) {
456
+ result = new EjvError({
457
+ type: ErrorType.SMALLER_THAN,
458
+ message: createErrorMsg(ErrorMsg.SMALLER_THAN, {
459
+ placeholders: [effectiveMax]
460
+ }),
461
+
462
+ data,
463
+ path: _options.path,
464
+
465
+ errorScheme: numberScheme,
466
+ errorData: value
467
+ });
468
+ break;
469
+ }
470
+ }
471
+ else {
472
+ if (!maxNumberTester(valueAsNumber, effectiveMax)) {
473
+ result = new EjvError({
474
+ type: ErrorType.SMALLER_THAN_OR_EQUAL,
475
+ message: createErrorMsg(ErrorMsg.SMALLER_THAN_OR_EQUAL, {
476
+ placeholders: [effectiveMax]
477
+ }),
478
+
479
+ data,
480
+ path: _options.path,
481
+
482
+ errorScheme: numberScheme,
483
+ errorData: value
484
+ });
485
+ break;
486
+ }
487
+ }
488
+ }
489
+
490
+ if (definedTester(numberScheme.format)) {
491
+ let formats: NumberFormat[];
492
+
493
+ const allNumberFormat: NumberFormat[] = Object.values(NumberFormat);
494
+
495
+ if (!arrayTester(numberScheme.format)) {
496
+ const formatAsString: NumberFormat = numberScheme.format as NumberFormat;
497
+
498
+ if (!enumTester(formatAsString, allNumberFormat)) {
499
+ return new EjvError({
500
+ type: ErrorType.INVALID_SCHEMES,
501
+ message: createErrorMsg(ErrorMsg.INVALID_NUMBER_FORMAT, {
502
+ placeholders: [formatAsString]
503
+ }),
504
+
505
+ data: data,
506
+
507
+ errorScheme: numberScheme,
508
+ isSchemeError: true
509
+ });
510
+ }
511
+
512
+ formats = [numberScheme.format as NumberFormat];
513
+ }
514
+ else {
515
+ const formatAsArray: NumberFormat[] = numberScheme.format as NumberFormat[];
516
+
517
+ const errorFormat: string | undefined = formatAsArray.find((format: NumberFormat): boolean => {
518
+ return !enumTester(format, allNumberFormat);
519
+ });
520
+
521
+ if (errorFormat) {
522
+ return new EjvError({
523
+ type: ErrorType.INVALID_SCHEMES,
524
+ message: createErrorMsg(ErrorMsg.INVALID_NUMBER_FORMAT, {
525
+ placeholders: [errorFormat]
526
+ }),
527
+
528
+ data: data,
529
+
530
+ errorScheme: numberScheme,
531
+ isSchemeError: true
532
+ });
533
+ }
534
+
535
+ formats = numberScheme.format as NumberFormat[];
536
+ }
537
+
538
+ const someFormatIsWrong: boolean = formats.some((format: NumberFormat): boolean => {
539
+ let valid: boolean = false;
540
+
541
+ switch (format) {
542
+ case NumberFormat.INTEGER:
543
+ valid = integerTester(valueAsNumber);
544
+ break;
545
+
546
+ case NumberFormat.INDEX:
547
+ valid = indexTester(valueAsNumber);
548
+ break;
549
+ }
550
+
551
+ return valid;
552
+ });
553
+
554
+ if (!someFormatIsWrong) {
555
+ if (!arrayTester(numberScheme.format)) {
556
+ result = new EjvError({
557
+ type: ErrorType.FORMAT,
558
+ message: createErrorMsg(ErrorMsg.FORMAT, {
559
+ placeholders: [numberScheme.format]
560
+ }),
561
+
562
+ data,
563
+ path: _options.path,
564
+
565
+ errorScheme: numberScheme,
566
+ errorData: value
567
+ });
568
+ }
569
+ else {
570
+ result = new EjvError({
571
+ type: ErrorType.FORMAT_ONE_OF,
572
+ message: createErrorMsg(ErrorMsg.FORMAT_ONE_OF, {
573
+ placeholders: [JSON.stringify(numberScheme.format)]
574
+ }),
575
+
576
+ data,
577
+ path: _options.path,
578
+
579
+ errorScheme: numberScheme,
580
+ errorData: value
581
+ });
582
+ }
583
+ break;
584
+ }
585
+ }
586
+ break;
587
+ }
588
+
589
+ case DataType.STRING: {
590
+ const valueAsString: string = value as unknown as string;
591
+ const stringScheme: StringScheme = scheme as StringScheme;
592
+
593
+ if (definedTester(stringScheme.enum)) {
594
+ if (!arrayTester(stringScheme.enum)) {
595
+ return new EjvError({
596
+ type: ErrorType.INVALID_SCHEMES,
597
+ message: createErrorMsg(ErrorMsg.ENUM_SHOULD_BE_ARRAY),
598
+
599
+ data: data,
600
+
601
+ errorScheme: stringScheme,
602
+ isSchemeError: true
603
+ });
604
+ }
605
+
606
+ const enumArr: string[] = stringScheme.enum;
607
+
608
+ if (!arrayTypeOfTester(enumArr, DataType.STRING)) {
609
+ return new EjvError({
610
+ type: ErrorType.INVALID_SCHEMES,
611
+ message: createErrorMsg(ErrorMsg.ENUM_SHOULD_BE_STRINGS),
612
+
613
+ data: data,
614
+
615
+ errorScheme: stringScheme,
616
+ isSchemeError: true
617
+ });
618
+ }
619
+
620
+ if (!enumTester(valueAsString, enumArr)) {
621
+ result = new EjvError({
622
+ type: ErrorType.ONE_OF,
623
+ message: createErrorMsg(ErrorMsg.ONE_VALUE_OF, {
624
+ placeholders: [JSON.stringify(stringScheme.enum)]
625
+ }),
626
+
627
+ data,
628
+ path: _options.path,
629
+
630
+ errorScheme: stringScheme,
631
+ errorData: value
632
+ });
633
+ break;
634
+ }
635
+ }
636
+
637
+ if (definedTester(stringScheme.length)) {
638
+ const length: number = stringScheme.length;
639
+
640
+ if (!(numberTester(length) && integerTester(length))) {
641
+ return new EjvError({
642
+ type: ErrorType.INVALID_SCHEMES,
643
+ message: createErrorMsg(ErrorMsg.LENGTH_SHOULD_BE_INTEGER),
644
+
645
+ data: data,
646
+
647
+ errorScheme: stringScheme,
648
+ isSchemeError: true
649
+ });
650
+ }
651
+
652
+ if (!lengthTester(valueAsString, length)) {
653
+ result = new EjvError({
654
+ type: ErrorType.LENGTH,
655
+ message: createErrorMsg(ErrorMsg.LENGTH, {
656
+ placeholders: [length]
657
+ }),
658
+
659
+ data,
660
+ path: _options.path,
661
+
662
+ errorScheme: stringScheme,
663
+ errorData: value
664
+ });
665
+ break;
666
+ }
667
+ }
668
+
669
+ if (definedTester(stringScheme.minLength)) {
670
+ const minLength: number = stringScheme.minLength;
671
+
672
+ if (!(numberTester(minLength) && integerTester(minLength))) {
673
+ return new EjvError({
674
+ type: ErrorType.INVALID_SCHEMES,
675
+ message: createErrorMsg(ErrorMsg.MIN_LENGTH_SHOULD_BE_INTEGER),
676
+
677
+ data: data,
678
+
679
+ errorScheme: stringScheme,
680
+ isSchemeError: true
681
+ });
682
+ }
683
+
684
+ if (!minLengthTester(valueAsString, minLength)) {
685
+ result = new EjvError({
686
+ type: ErrorType.MIN_LENGTH,
687
+ message: createErrorMsg(ErrorMsg.MIN_LENGTH, {
688
+ placeholders: ['' + minLength]
689
+ }),
690
+
691
+ data,
692
+ path: _options.path,
693
+
694
+ errorScheme: stringScheme,
695
+ errorData: value
696
+ });
697
+ break;
698
+ }
699
+ }
700
+
701
+ if (definedTester(stringScheme.maxLength)) {
702
+ const maxLength: number = stringScheme.maxLength;
703
+
704
+ if (!(numberTester(maxLength) && integerTester(maxLength))) {
705
+ return new EjvError({
706
+ type: ErrorType.INVALID_SCHEMES,
707
+ message: createErrorMsg(ErrorMsg.MAX_LENGTH_SHOULD_BE_INTEGER),
708
+
709
+ data: data,
710
+
711
+ errorScheme: stringScheme,
712
+ isSchemeError: true
713
+ });
714
+ }
715
+
716
+ if (!maxLengthTester(valueAsString, maxLength)) {
717
+ result = new EjvError({
718
+ type: ErrorType.MAX_LENGTH,
719
+ message: createErrorMsg(ErrorMsg.MAX_LENGTH, {
720
+ placeholders: ['' + maxLength]
721
+ }),
722
+
723
+ data,
724
+ path: _options.path,
725
+
726
+ errorScheme: stringScheme,
727
+ errorData: value
728
+ });
729
+ break;
730
+ }
731
+ }
732
+
733
+ if (definedTester(stringScheme.format)) {
734
+ let formats: StringFormat[];
735
+
736
+ const allStringFormat: StringFormat[] = Object.values(StringFormat);
737
+
738
+ if (!arrayTester(stringScheme.format)) {
739
+ const formatAsString: string = stringScheme.format;
740
+
741
+ if (!enumTester(formatAsString, allStringFormat)) {
742
+ return new EjvError({
743
+ type: ErrorType.INVALID_SCHEMES,
744
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_FORMAT, {
745
+ placeholders: [formatAsString]
746
+ }),
747
+
748
+ data: data,
749
+
750
+ errorScheme: stringScheme,
751
+ isSchemeError: true
752
+ });
753
+ }
754
+
755
+ formats = [stringScheme.format] as StringFormat[];
756
+ }
757
+ else {
758
+ const formatAsArray: string[] = stringScheme.format;
759
+ const errorFormat: string | undefined = formatAsArray.find((format: string): boolean => {
760
+ return !enumTester(format, allStringFormat);
761
+ });
762
+
763
+ if (errorFormat) {
764
+ return new EjvError({
765
+ type: ErrorType.INVALID_SCHEMES,
766
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_FORMAT, {
767
+ placeholders: [errorFormat]
768
+ }),
769
+
770
+ data: data,
771
+
772
+ errorScheme: stringScheme,
773
+ isSchemeError: true
774
+ });
775
+ }
776
+
777
+ formats = stringScheme.format as StringFormat[];
778
+ }
779
+
780
+ const foundFormatMatching: boolean = formats.some((format: StringFormat): boolean => {
781
+ let valid: boolean = false;
782
+
783
+ switch (format) {
784
+ case StringFormat.EMAIL:
785
+ valid = emailTester(valueAsString);
786
+ break;
787
+
788
+ case StringFormat.DATE:
789
+ valid = dateFormatTester(valueAsString);
790
+ break;
791
+
792
+ case StringFormat.TIME:
793
+ valid = timeFormatTester(valueAsString);
794
+ break;
795
+
796
+ case StringFormat.DATE_TIME:
797
+ valid = dateTimeFormatTester(valueAsString);
798
+ break;
799
+ }
800
+
801
+ return valid;
802
+ });
803
+
804
+ if (!foundFormatMatching) {
805
+ if (!arrayTester(stringScheme.format)) {
806
+ result = new EjvError({
807
+ type: ErrorType.FORMAT,
808
+ message: createErrorMsg(ErrorMsg.FORMAT, {
809
+ placeholders: [stringScheme.format as StringFormat]
810
+ }),
811
+
812
+ data,
813
+ path: _options.path,
814
+
815
+ errorScheme: stringScheme,
816
+ errorData: value
817
+ });
818
+ }
819
+ else {
820
+ result = new EjvError({
821
+ type: ErrorType.FORMAT_ONE_OF,
822
+ message: createErrorMsg(ErrorMsg.FORMAT_ONE_OF, {
823
+ placeholders: [JSON.stringify(stringScheme.format)]
824
+ }),
825
+
826
+ data,
827
+ path: _options.path,
828
+
829
+ errorScheme: stringScheme,
830
+ errorData: value
831
+ });
832
+ }
833
+ break;
834
+ }
835
+ }
836
+
837
+ if (definedTester(stringScheme.pattern)) {
838
+ // check parameter
839
+ if (stringScheme.pattern === null) {
840
+ return new EjvError({
841
+ type: ErrorType.INVALID_SCHEMES,
842
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_PATTERN, {
843
+ placeholders: ['null']
844
+ }),
845
+
846
+ data: data,
847
+
848
+ errorScheme: stringScheme,
849
+ isSchemeError: true
850
+ });
851
+ }
852
+
853
+ const isValidPattern = (pattern: string | RegExp): boolean => {
854
+ return (stringTester(pattern) && minLengthTester(pattern as string, 1))
855
+ || (regExpTester(pattern) && pattern.toString() !== '/(?:)/' && pattern.toString() !== '/null/');
856
+ };
857
+
858
+ const patternToString = (pattern: string | RegExp): string => {
859
+ let regExpStr: string;
860
+
861
+ if (pattern === null) {
862
+ regExpStr = '/null/';
863
+ }
864
+ else if (stringTester(pattern)) {
865
+ if (minLengthTester(pattern as string, 1)) {
866
+ regExpStr = new RegExp(pattern as string).toString();
867
+ }
868
+ else {
869
+ regExpStr = '//';
870
+ }
871
+ }
872
+ else {
873
+ regExpStr = pattern.toString();
874
+ }
875
+
876
+ // empty regular expression
877
+ if (regExpStr === '/(?:)/') {
878
+ regExpStr = '//';
879
+ }
880
+
881
+ return regExpStr;
882
+ };
883
+
884
+ const createArrayErrorMsg = (patternsAsArray: (string | RegExp)[]): string => {
885
+ return '[' + patternsAsArray.map((onePattern: string | RegExp): string => {
886
+ return patternToString(onePattern);
887
+ }).join(', ') + ']';
888
+ };
889
+
890
+ if (arrayTester(stringScheme.pattern)) {
891
+ const patternsAsArray: (string | RegExp)[] = stringScheme.pattern as (string | RegExp)[];
892
+
893
+ if (!minLengthTester(patternsAsArray, 1)) { // empty array
894
+ return new EjvError({
895
+ type: ErrorType.INVALID_SCHEMES,
896
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_PATTERN, {
897
+ placeholders: [createArrayErrorMsg(patternsAsArray)]
898
+ }),
899
+
900
+ data: data,
901
+
902
+ errorScheme: stringScheme,
903
+ isSchemeError: true
904
+ });
905
+ }
906
+
907
+ try {
908
+ const regExpPatterns: RegExp[] = patternsAsArray.map((pattern: string | RegExp): RegExp => {
909
+ if (!isValidPattern(pattern)) {
910
+ throw new Error(createErrorMsg(ErrorMsg.INVALID_STRING_PATTERN, {
911
+ placeholders: [createArrayErrorMsg(patternsAsArray)]
912
+ }));
913
+ }
914
+
915
+ return new RegExp(pattern);
916
+ }) as RegExp[];
917
+
918
+ // check value
919
+ const foundMatchPattern: boolean = regExpPatterns.some((regexp: RegExp): boolean => {
920
+ return stringRegExpTester(valueAsString, regexp);
921
+ });
922
+
923
+ if (!foundMatchPattern) {
924
+ result = new EjvError({
925
+ type: ErrorType.PATTERN_ONE_OF,
926
+ message: createErrorMsg(ErrorMsg.PATTERN_ONE_OF, {
927
+ placeholders: [createArrayErrorMsg(patternsAsArray)]
928
+ }),
929
+
930
+ data,
931
+ path: _options.path,
932
+
933
+ errorScheme: stringScheme,
934
+ errorData: value
935
+ });
936
+ break;
937
+ }
938
+ }
939
+ catch (e: unknown) {
940
+ return new EjvError({
941
+ type: ErrorType.INVALID_SCHEMES,
942
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_PATTERN, {
943
+ placeholders: [createArrayErrorMsg(patternsAsArray)]
944
+ }),
945
+
946
+ data: data,
947
+
948
+ errorScheme: stringScheme,
949
+ isSchemeError: true
950
+ });
951
+ }
952
+ }
953
+ else {
954
+ const patternAsOne: string | RegExp = stringScheme.pattern as string | RegExp;
955
+
956
+ if (!isValidPattern(patternAsOne)) {
957
+ return new EjvError({
958
+ type: ErrorType.INVALID_SCHEMES,
959
+ message: createErrorMsg(ErrorMsg.INVALID_STRING_PATTERN, {
960
+ placeholders: [patternToString(patternAsOne)]
961
+ }),
962
+
963
+ data: data,
964
+
965
+ errorScheme: stringScheme,
966
+ isSchemeError: true
967
+ });
968
+ }
969
+
970
+ // check value
971
+ const regExp: RegExp = new RegExp(patternAsOne);
972
+
973
+ if (!stringRegExpTester(valueAsString, regExp)) {
974
+ result = new EjvError({
975
+ type: ErrorType.PATTERN,
976
+ message: createErrorMsg(ErrorMsg.PATTERN, {
977
+ placeholders: [patternToString(patternAsOne)]
978
+ }),
979
+
980
+ data,
981
+ path: _options.path,
982
+
983
+ errorScheme: stringScheme,
984
+ errorData: value
985
+ });
986
+ break;
987
+ }
988
+ }
989
+ }
990
+ break;
991
+ }
992
+
993
+ case DataType.OBJECT: {
994
+ const valueAsObject: AnyObject = value as unknown as AnyObject;
995
+ const objectScheme: ObjectScheme = scheme as ObjectScheme;
996
+
997
+ if (definedTester(objectScheme.allowNoProperty)) {
998
+ if (!booleanTester(objectScheme.allowNoProperty)) {
999
+ return new EjvError({
1000
+ type: ErrorType.INVALID_SCHEMES,
1001
+ message: createErrorMsg(ErrorMsg.ALLOW_NO_PROPERTY_SHOULD_BE_BOOLEAN),
1002
+
1003
+ data: data,
1004
+
1005
+ errorScheme: objectScheme,
1006
+ isSchemeError: true
1007
+ });
1008
+ }
1009
+
1010
+ if (!objectScheme.allowNoProperty && !hasPropertyTester(valueAsObject)) {
1011
+ result = new EjvError({
1012
+ type: ErrorType.PROPERTY,
1013
+ message: ErrorMsg.PROPERTY,
1014
+
1015
+ data,
1016
+ path: _options.path,
1017
+
1018
+ errorScheme: objectScheme,
1019
+ errorData: value
1020
+ });
1021
+ break;
1022
+ }
1023
+ }
1024
+
1025
+ if (definedTester(objectScheme.properties)) {
1026
+ if (!arrayTester(objectScheme.properties)) {
1027
+ return new EjvError({
1028
+ type: ErrorType.INVALID_SCHEMES,
1029
+ message: createErrorMsg(ErrorMsg.PROPERTIES_SHOULD_BE_ARRAY),
1030
+
1031
+ data: data,
1032
+
1033
+ errorScheme: objectScheme,
1034
+ isSchemeError: true
1035
+ });
1036
+ }
1037
+
1038
+ const properties: Scheme[] = objectScheme.properties as Scheme[];
1039
+
1040
+ if (!minLengthTester(properties, 1)) {
1041
+ return new EjvError({
1042
+ type: ErrorType.INVALID_SCHEMES,
1043
+ message: createErrorMsg(ErrorMsg.PROPERTIES_SHOULD_HAVE_ITEMS),
1044
+
1045
+ data: data,
1046
+
1047
+ errorScheme: objectScheme,
1048
+ isSchemeError: true
1049
+ });
1050
+ }
1051
+
1052
+ if (!arrayTypeOfTester(properties, DataType.OBJECT)) {
1053
+ return new EjvError({
1054
+ type: ErrorType.INVALID_SCHEMES,
1055
+ message: createErrorMsg(ErrorMsg.PROPERTIES_SHOULD_BE_ARRAY_OF_OBJECT),
1056
+
1057
+ data: data,
1058
+
1059
+ errorScheme: objectScheme,
1060
+ isSchemeError: true
1061
+ });
1062
+ }
1063
+
1064
+ if (!objectTester(value)) {
1065
+ result = new EjvError({
1066
+ type: ErrorType.TYPE_MISMATCH,
1067
+ message: createErrorMsg(ErrorMsg.TYPE_MISMATCH, {
1068
+ placeholders: ['object']
1069
+ }),
1070
+
1071
+ data,
1072
+ path: _options.path,
1073
+
1074
+ errorScheme: objectScheme,
1075
+ errorData: value
1076
+ });
1077
+ break;
1078
+ }
1079
+
1080
+ const partialData: T[keyof T] = data[key];
1081
+ const partialScheme: Scheme[] = objectScheme.properties as Scheme[];
1082
+ scheme.parent = objectScheme;
1083
+
1084
+ // call recursively
1085
+ result = _ejv(partialData, partialScheme, _options);
1086
+
1087
+ if (result) {
1088
+ // inject original data
1089
+ result.data = data;
1090
+ }
1091
+ }
1092
+ break;
1093
+ }
1094
+
1095
+ case DataType.DATE: {
1096
+ const valueAsDate: Date = value as unknown as Date;
1097
+ const dateScheme: DateScheme = scheme as DateScheme;
1098
+ const parentDateScheme: DateScheme | undefined = scheme.parent as DateScheme | undefined;
1099
+
1100
+ if (definedTester(dateScheme.min)
1101
+ || definedTester(parentDateScheme?.min)) {
1102
+ const minDateCandidate: string | Date = dateScheme.min || parentDateScheme?.min as string | Date;
1103
+
1104
+ if (!(
1105
+ (stringTester(minDateCandidate)
1106
+ && (
1107
+ dateFormatTester(minDateCandidate as string)
1108
+ || dateTimeFormatTester(minDateCandidate as string)
1109
+ )
1110
+ )
1111
+ || dateTester(minDateCandidate)
1112
+ )) {
1113
+ return new EjvError({
1114
+ type: ErrorType.INVALID_SCHEMES,
1115
+ message: createErrorMsg(ErrorMsg.MIN_DATE_SHOULD_BE_DATE_OR_STRING),
1116
+
1117
+ data: data,
1118
+
1119
+ errorScheme: dateScheme,
1120
+ isSchemeError: true
1121
+ });
1122
+ }
1123
+
1124
+ const effectiveMin: Date = new Date(minDateCandidate);
1125
+
1126
+ if (definedTester(dateScheme.exclusiveMin)) {
1127
+ if (!booleanTester(dateScheme.exclusiveMin)) {
1128
+ return new EjvError({
1129
+ type: ErrorType.INVALID_SCHEMES,
1130
+ message: createErrorMsg(ErrorMsg.EXCLUSIVE_MIN_SHOULD_BE_BOOLEAN),
1131
+
1132
+ data: data,
1133
+
1134
+ errorScheme: dateScheme,
1135
+ isSchemeError: true
1136
+ });
1137
+ }
1138
+
1139
+
1140
+ if (dateScheme.exclusiveMin) {
1141
+ if (!exclusiveMinDateTester(valueAsDate, effectiveMin)) {
1142
+ result = new EjvError({
1143
+ type: ErrorType.AFTER_DATE,
1144
+ message: createErrorMsg(ErrorMsg.AFTER_DATE, {
1145
+ placeholders: [effectiveMin.toISOString()]
1146
+ }),
1147
+
1148
+ data,
1149
+ path: _options.path,
1150
+
1151
+ errorScheme: dateScheme,
1152
+ errorData: value
1153
+ });
1154
+ break;
1155
+
1156
+ }
1157
+ }
1158
+ else {
1159
+ if (!minDateTester(valueAsDate, effectiveMin)) {
1160
+ result = new EjvError({
1161
+ type: ErrorType.AFTER_OR_SAME_DATE,
1162
+ message: createErrorMsg(ErrorMsg.AFTER_OR_SAME_DATE, {
1163
+ placeholders: [effectiveMin.toISOString()]
1164
+ }),
1165
+
1166
+ data,
1167
+ path: _options.path,
1168
+
1169
+ errorScheme: dateScheme,
1170
+ errorData: value
1171
+ });
1172
+ break;
1173
+ }
1174
+ }
1175
+
1176
+
1177
+ }
1178
+ else {
1179
+ if (!minDateTester(valueAsDate, effectiveMin)) {
1180
+ result = new EjvError({
1181
+ type: ErrorType.AFTER_OR_SAME_DATE,
1182
+ message: createErrorMsg(ErrorMsg.AFTER_OR_SAME_DATE, {
1183
+ placeholders: [effectiveMin.toISOString()]
1184
+ }),
1185
+
1186
+ data,
1187
+ path: _options.path,
1188
+
1189
+ errorScheme: dateScheme,
1190
+ errorData: value
1191
+ });
1192
+ break;
1193
+ }
1194
+ }
1195
+ }
1196
+
1197
+ if (definedTester(dateScheme.max)
1198
+ || definedTester(parentDateScheme?.max)) {
1199
+ const maxDateCandidate: string | Date = dateScheme.max || parentDateScheme?.max as string | Date;
1200
+
1201
+ if (!(
1202
+ (stringTester(maxDateCandidate)
1203
+ && (
1204
+ dateFormatTester(maxDateCandidate as string)
1205
+ || dateTimeFormatTester(maxDateCandidate as string)
1206
+ )
1207
+ )
1208
+ || dateTester(maxDateCandidate)
1209
+ )) {
1210
+ return new EjvError({
1211
+ type: ErrorType.INVALID_SCHEMES,
1212
+ message: createErrorMsg(ErrorMsg.MAX_DATE_SHOULD_BE_DATE_OR_STRING),
1213
+
1214
+ data: data,
1215
+
1216
+ errorScheme: dateScheme,
1217
+ isSchemeError: true
1218
+ });
1219
+ }
1220
+
1221
+ const effectiveMax: Date = new Date(maxDateCandidate);
1222
+
1223
+ if (definedTester(dateScheme.exclusiveMax)) {
1224
+ if (!booleanTester(dateScheme.exclusiveMax)) {
1225
+ return new EjvError({
1226
+ type: ErrorType.INVALID_SCHEMES,
1227
+ message: createErrorMsg(ErrorMsg.EXCLUSIVE_MAX_SHOULD_BE_BOOLEAN),
1228
+
1229
+ data: data,
1230
+
1231
+ errorScheme: dateScheme,
1232
+ isSchemeError: true
1233
+ });
1234
+ }
1235
+ }
1236
+
1237
+ if (dateScheme.exclusiveMax) {
1238
+ if (!exclusiveMaxDateTester(valueAsDate, effectiveMax)) {
1239
+ result = new EjvError({
1240
+ type: ErrorType.BEFORE_DATE,
1241
+ message: createErrorMsg(ErrorMsg.BEFORE_DATE, {
1242
+ placeholders: [effectiveMax.toISOString()]
1243
+ }),
1244
+
1245
+ data,
1246
+ path: _options.path,
1247
+
1248
+ errorScheme: dateScheme,
1249
+ errorData: value
1250
+ });
1251
+ break;
1252
+ }
1253
+ }
1254
+ else {
1255
+ if (!maxDateTester(valueAsDate, effectiveMax)) {
1256
+ result = new EjvError({
1257
+ type: ErrorType.BEFORE_OR_SAME_DATE,
1258
+ message: createErrorMsg(ErrorMsg.BEFORE_OR_SAME_DATE, {
1259
+ placeholders: [effectiveMax.toISOString()]
1260
+ }),
1261
+
1262
+ data,
1263
+ path: _options.path,
1264
+
1265
+ errorScheme: dateScheme,
1266
+ errorData: value
1267
+ });
1268
+ break;
1269
+ }
1270
+ }
1271
+ }
1272
+ break;
1273
+ }
1274
+
1275
+ case DataType.ARRAY: {
1276
+ const valueAsArray: unknown[] = value as unknown as unknown[];
1277
+ const arrayScheme: ArrayScheme = scheme as ArrayScheme;
1278
+
1279
+ if (definedTester(arrayScheme.length)) {
1280
+ const length: number = arrayScheme.length;
1281
+
1282
+ if (!(numberTester(length) && integerTester(length))) {
1283
+ return new EjvError({
1284
+ type: ErrorType.INVALID_SCHEMES,
1285
+ message: createErrorMsg(ErrorMsg.LENGTH_SHOULD_BE_INTEGER),
1286
+
1287
+ data: data,
1288
+
1289
+ errorScheme: arrayScheme,
1290
+ isSchemeError: true
1291
+ });
1292
+ }
1293
+
1294
+ if (!lengthTester(valueAsArray, length)) {
1295
+ result = new EjvError({
1296
+ type: ErrorType.LENGTH,
1297
+ message: createErrorMsg(ErrorMsg.LENGTH, {
1298
+ placeholders: ['' + length]
1299
+ }),
1300
+
1301
+ data,
1302
+ path: _options.path,
1303
+
1304
+ errorScheme: arrayScheme,
1305
+ errorData: value
1306
+ });
1307
+ break;
1308
+ }
1309
+ }
1310
+
1311
+ if (definedTester(arrayScheme.minLength)) {
1312
+ const minLength: number = arrayScheme.minLength;
1313
+
1314
+ if (!(numberTester(arrayScheme.minLength) && integerTester(minLength))) {
1315
+ return new EjvError({
1316
+ type: ErrorType.INVALID_SCHEMES,
1317
+ message: createErrorMsg(ErrorMsg.MIN_LENGTH_SHOULD_BE_INTEGER),
1318
+
1319
+ data: data,
1320
+
1321
+ errorScheme: arrayScheme,
1322
+ isSchemeError: true
1323
+ });
1324
+ }
1325
+
1326
+ if (!minLengthTester(valueAsArray, minLength)) {
1327
+ result = new EjvError({
1328
+ type: ErrorType.MIN_LENGTH,
1329
+ message: createErrorMsg(ErrorMsg.MIN_LENGTH, {
1330
+ placeholders: ['' + minLength]
1331
+ }),
1332
+
1333
+ data,
1334
+ path: _options.path,
1335
+
1336
+ errorScheme: arrayScheme,
1337
+ errorData: value
1338
+ });
1339
+ break;
1340
+ }
1341
+ }
1342
+
1343
+ if (definedTester(arrayScheme.maxLength)) {
1344
+ const maxLength: number = arrayScheme.maxLength;
1345
+
1346
+ if (!(numberTester(arrayScheme.maxLength) && integerTester(maxLength))) {
1347
+ return new EjvError({
1348
+ type: ErrorType.INVALID_SCHEMES,
1349
+ message: createErrorMsg(ErrorMsg.MAX_LENGTH_SHOULD_BE_INTEGER),
1350
+
1351
+ data: data,
1352
+
1353
+ errorScheme: arrayScheme,
1354
+ isSchemeError: true
1355
+ });
1356
+ }
1357
+
1358
+ if (!maxLengthTester(valueAsArray, maxLength)) {
1359
+ result = new EjvError({
1360
+ type: ErrorType.MAX_LENGTH,
1361
+ message: createErrorMsg(ErrorMsg.MAX_LENGTH, {
1362
+ placeholders: ['' + maxLength]
1363
+ }),
1364
+
1365
+ data,
1366
+ path: _options.path,
1367
+
1368
+ errorScheme: arrayScheme,
1369
+ errorData: value
1370
+ });
1371
+ break;
1372
+ }
1373
+ }
1374
+
1375
+ if (definedTester(arrayScheme.unique)) {
1376
+ if (!booleanTester(arrayScheme.unique)) {
1377
+ return new EjvError({
1378
+ type: ErrorType.INVALID_SCHEMES,
1379
+ message: createErrorMsg(ErrorMsg.UNIQUE_SHOULD_BE_BOOLEAN),
1380
+
1381
+ data: data,
1382
+
1383
+ errorScheme: arrayScheme,
1384
+ isSchemeError: true
1385
+ });
1386
+ }
1387
+
1388
+ if (arrayScheme.unique && !uniqueItemsTester(valueAsArray)) {
1389
+ result = new EjvError({
1390
+ type: ErrorType.UNIQUE_ITEMS,
1391
+ message: ErrorMsg.UNIQUE_ITEMS,
1392
+
1393
+ data,
1394
+ path: _options.path,
1395
+
1396
+ errorScheme: arrayScheme,
1397
+ errorData: value
1398
+ });
1399
+ break;
1400
+ }
1401
+ }
1402
+
1403
+ if (definedTester(arrayScheme.items)) {
1404
+ // convert array to object
1405
+ if (valueAsArray.length > 0) {
1406
+ const now: Date = new Date();
1407
+ const tempKeyArr: string[] = valueAsArray.map((_value: unknown, i: number): string => {
1408
+ return '' + (+now + i);
1409
+ });
1410
+
1411
+ if (stringTester(arrayScheme.items) // by DataType
1412
+ || (arrayTester(arrayScheme.items) && arrayTypeOfTester(arrayScheme.items as DataType[], DataType.STRING)) // by DataType[]
1413
+ ) {
1414
+ const itemTypes: DataType[] = (arrayTester(arrayScheme.items)
1415
+ ? arrayScheme.items
1416
+ : [arrayScheme.items]) as DataType[];
1417
+
1418
+ const itemTypeError: string | undefined = itemTypes.find((type: DataType): boolean => {
1419
+ return !definedTester(type)
1420
+ || !stringTester(type)
1421
+ || !enumTester(type, allDataType);
1422
+ });
1423
+
1424
+ if (itemTypeError) {
1425
+ return new EjvError({
1426
+ type: ErrorType.INVALID_SCHEMES,
1427
+ message: createErrorMsg(ErrorMsg.SCHEMES_HAS_INVALID_TYPE, {
1428
+ placeholders: [itemTypeError]
1429
+ }),
1430
+
1431
+ data: data,
1432
+
1433
+ errorScheme: scheme,
1434
+ isSchemeError: true
1435
+ });
1436
+ }
1437
+
1438
+
1439
+ const partialData: AnyObject = {};
1440
+ const partialSchemes: Scheme[] = [];
1441
+
1442
+ tempKeyArr.forEach((tempKey: string, i: number): void => {
1443
+ partialData[tempKey] = valueAsArray[i];
1444
+ partialSchemes.push({
1445
+ key: tempKey,
1446
+ type: itemTypes
1447
+ });
1448
+ });
1449
+
1450
+ scheme.parent = arrayScheme;
1451
+
1452
+ // call recursively
1453
+ const partialResult: EjvError | null = _ejv(partialData, partialSchemes, _options);
1454
+
1455
+ // convert new EjvError
1456
+ if (partialResult) {
1457
+ let errorMsg: string;
1458
+
1459
+ if (arrayTester(arrayScheme.items)) {
1460
+ errorMsg = createErrorMsg(ErrorMsg.ITEMS_TYPE, {
1461
+ placeholders: [JSON.stringify(itemTypes)]
1462
+ });
1463
+ }
1464
+ else {
1465
+ errorMsg = createErrorMsg(ErrorMsg.ITEMS_TYPE, {
1466
+ placeholders: [arrayScheme.items as string]
1467
+ });
1468
+ }
1469
+
1470
+ const partialKeys: string[] = (partialResult.path || '').split('/');
1471
+ const partialKey: string = partialKeys[partialKeys.length - 1];
1472
+
1473
+ const partialScheme: Scheme = partialSchemes.find((_scheme: Scheme): boolean => {
1474
+ return _scheme.key === partialKey;
1475
+ }) as Scheme;
1476
+
1477
+ const partialKeyIndex: number = partialSchemes.indexOf(partialScheme);
1478
+
1479
+ result = new EjvError({
1480
+ type: ErrorType.ITEMS_TYPE,
1481
+ message: errorMsg,
1482
+
1483
+ data,
1484
+ path: [..._options.path, '' + partialKeyIndex],
1485
+
1486
+ errorScheme: partialScheme,
1487
+ errorData: partialData[partialKey]
1488
+ });
1489
+ }
1490
+ break;
1491
+ }
1492
+ else if ((objectTester(arrayScheme.items) && arrayScheme.items !== null) // by Scheme
1493
+ || (arrayTester(arrayScheme.items) && arrayTypeOfTester(arrayScheme.items as Scheme[], DataType.OBJECT)) // by Scheme[]
1494
+ ) {
1495
+ const itemsAsSchemes: Scheme[] = arrayTester(arrayScheme.items)
1496
+ ? arrayScheme.items
1497
+ : [arrayScheme.items] as Scheme[];
1498
+
1499
+ let partialError: EjvError | null | undefined = null;
1500
+
1501
+ // use for() instead of forEach() to break
1502
+ const valueLength: number = valueAsArray.length;
1503
+
1504
+ for (let arrIndex = 0; arrIndex < valueLength; arrIndex++) {
1505
+ const oneValue: unknown = valueAsArray[arrIndex];
1506
+
1507
+ const partialData: AnyObject = {};
1508
+ const partialSchemes: Scheme[] = [];
1509
+
1510
+ const tempKeyForThisValue: string = tempKeyArr[arrIndex];
1511
+
1512
+ partialData[tempKeyForThisValue] = oneValue;
1513
+
1514
+ partialSchemes.push(...itemsAsSchemes.map((oneScheme: Scheme): Scheme => {
1515
+ const newScheme: Scheme = clone(oneScheme); // divide instance
1516
+
1517
+ newScheme.key = tempKeyForThisValue;
1518
+
1519
+ return newScheme;
1520
+ }));
1521
+
1522
+ const partialResults: (EjvError | null)[] = partialSchemes.map((partialScheme: Scheme): EjvError | null => {
1523
+ // call recursively
1524
+ const partialResult: EjvError | null = _ejv(partialData, [partialScheme], _options);
1525
+
1526
+ if (partialResult) {
1527
+ partialResult.path = (partialResult.path || '').replace(tempKeyForThisValue, '' + arrIndex);
1528
+ }
1529
+
1530
+ return partialResult;
1531
+ });
1532
+
1533
+ if (!partialResults.some((oneResult: EjvError | null): boolean => oneResult === null)) {
1534
+ partialError = partialResults.find((oneResult: EjvError | null): boolean => {
1535
+ return !!oneResult;
1536
+ }) as EjvError;
1537
+ break;
1538
+ }
1539
+ }
1540
+
1541
+ if (partialError) {
1542
+ let errorType: ErrorType;
1543
+ let errorMsg: string;
1544
+
1545
+ if (!!itemsAsSchemes && itemsAsSchemes.length > 1) {
1546
+ errorType = ErrorType.ITEMS_SCHEMES;
1547
+ errorMsg = createErrorMsg(ErrorMsg.ITEMS_SCHEMES, {
1548
+ placeholders: [JSON.stringify(itemsAsSchemes)]
1549
+ });
1550
+ }
1551
+ else {
1552
+ errorType = partialError.type;
1553
+ errorMsg = partialError.message;
1554
+
1555
+ if (errorType === ErrorType.REQUIRED) {
1556
+ // REQUIRED in array is TYPE_MISMATCH except with nullable === true
1557
+ errorType = ErrorType.TYPE_MISMATCH;
1558
+ errorMsg = createErrorMsg(ErrorMsg.TYPE_MISMATCH, {
1559
+ placeholders: [JSON.stringify(arrayScheme.items)]
1560
+ });
1561
+ }
1562
+ }
1563
+
1564
+ result = new EjvError({
1565
+ type: errorType,
1566
+ message: errorMsg,
1567
+
1568
+ data
1569
+ });
1570
+
1571
+ if (errorType === ErrorType.INVALID_SCHEMES) {
1572
+ result.errorScheme = arrayScheme;
1573
+ result.isSchemeError = true;
1574
+ result.isDataError = false;
1575
+ }
1576
+ else {
1577
+ result.path = partialError.path;
1578
+ result.errorData = partialError.errorData;
1579
+ }
1580
+ break;
1581
+ }
1582
+ }
1583
+ else {
1584
+ return new EjvError({
1585
+ type: ErrorType.INVALID_SCHEMES,
1586
+ message: createErrorMsg(ErrorMsg.INVALID_ITEMS_SCHEME, {
1587
+ placeholders: [JSON.stringify(arrayScheme.items)]
1588
+ }),
1589
+
1590
+ data: data,
1591
+
1592
+ errorScheme: arrayScheme,
1593
+ isSchemeError: true
1594
+ });
1595
+ }
1596
+ }
1597
+ }
1598
+ break;
1599
+ }
1600
+ }
1601
+
1602
+ if (result) {
1603
+ break;
1604
+ }
1605
+ }
1606
+
1607
+ if (result !== null && definedTester(options.customErrorMsg)) {
1608
+ const customErrorMsgObj: {
1609
+ [key in ErrorType]?: string;
1610
+ } = options.customErrorMsg as {
1611
+ [key in ErrorType]?: string;
1612
+ };
1613
+
1614
+ // override error message
1615
+ const customMsg: string | undefined = customErrorMsgObj[result.type];
1616
+
1617
+ if (definedTester(customMsg)) {
1618
+ result.message = customMsg;
1619
+ }
1620
+ }
1621
+
1622
+ return result;
1623
+ };
1624
+
1625
+ export const ejv = (data: object, schemes: Scheme[], options?: Options): null | EjvError => {
1626
+ // check data itself
1627
+ if (!definedTester(data) || !objectTester(data) || data === null) {
1628
+ return new EjvError({
1629
+ type: ErrorType.NO_DATA,
1630
+ message: ErrorMsg.NO_DATA,
1631
+
1632
+ data: data,
1633
+ errorData: data
1634
+ });
1635
+ }
1636
+
1637
+ const internalOption: InternalOptions = (options
1638
+ ? {
1639
+ ...options
1640
+ }
1641
+ : {}) as InternalOptions;
1642
+
1643
+ if (!definedTester(internalOption.path)) {
1644
+ internalOption.path = [];
1645
+ }
1646
+
1647
+ return _ejv(data, schemes, internalOption);
1648
+ };