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