@cleverbrush/schema 0.0.17 → 1.0.0-beta.1

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 (47) hide show
  1. package/README.md +213 -163
  2. package/package.json +3 -3
  3. package/src/builders/ArraySchemaBuilder.test.ts +270 -0
  4. package/src/builders/ArraySchemaBuilder.ts +381 -0
  5. package/src/builders/BooleanSchemaBuilder.test.ts +196 -0
  6. package/src/builders/BooleanSchemaBuilder.ts +155 -0
  7. package/src/builders/FunctionSchemaBuilder.test.ts +134 -0
  8. package/src/builders/FunctionSchemaBuilder.ts +109 -0
  9. package/src/builders/NumberSchemaBuilder.test.ts +493 -0
  10. package/src/builders/NumberSchemaBuilder.ts +789 -0
  11. package/src/builders/ObjectSchemaBuilder.test.ts +657 -0
  12. package/src/builders/ObjectSchemaBuilder.ts +794 -0
  13. package/src/builders/SchemaBuilder.test.ts +73 -0
  14. package/src/builders/SchemaBuilder.ts +135 -0
  15. package/src/builders/StringSchemaBuilder.test.ts +318 -0
  16. package/src/builders/StringSchemaBuilder.ts +392 -0
  17. package/src/builders/UnionSchemaBuilder.test.ts +162 -0
  18. package/src/builders/UnionSchemaBuilder.ts +154 -0
  19. package/src/defaultSchemas.ts +44 -0
  20. package/src/index.ts +58 -190
  21. package/src/schema.ts +827 -0
  22. package/src/schemaRegistry.builders.test.ts +1393 -0
  23. package/src/schemaRegistry.test.ts +118 -0
  24. package/src/schemaRegistry.ts +461 -0
  25. package/src/validators/validateArray.ts +4 -7
  26. package/src/validators/validateBoolean.ts +2 -11
  27. package/src/validators/validateFunction.ts +25 -0
  28. package/src/validators/validateNumber.ts +2 -7
  29. package/src/validators/validateObject.ts +32 -21
  30. package/src/validators/validateString.ts +2 -7
  31. package/src/validators/validateUnion.ts +36 -0
  32. package/dist/index.d.ts +0 -94
  33. package/dist/index.js +0 -9
  34. package/dist/schemaValidator.d.ts +0 -16
  35. package/dist/schemaValidator.js +0 -234
  36. package/dist/validators/validateArray.d.ts +0 -2
  37. package/dist/validators/validateArray.js +0 -60
  38. package/dist/validators/validateBoolean.d.ts +0 -2
  39. package/dist/validators/validateBoolean.js +0 -33
  40. package/dist/validators/validateNumber.d.ts +0 -2
  41. package/dist/validators/validateNumber.js +0 -69
  42. package/dist/validators/validateObject.d.ts +0 -2
  43. package/dist/validators/validateObject.js +0 -73
  44. package/dist/validators/validateString.d.ts +0 -2
  45. package/dist/validators/validateString.js +0 -50
  46. package/src/schemaValidator.test.ts +0 -1656
  47. package/src/schemaValidator.ts +0 -367
@@ -1,1656 +0,0 @@
1
- import { deepEqual, deepExtend } from '@cleverbrush/deep';
2
- import { ValidationResult } from '../dist/index.js';
3
-
4
- import {
5
- NumberSchemaDefinition,
6
- ObjectSchemaDefinitionParam,
7
- ObjectSchemaDefinition,
8
- Schema
9
- } from './index';
10
- import SchemaValidator from './schemaValidator';
11
-
12
- type User = {
13
- id: number;
14
- name: {
15
- first: string;
16
- last: string;
17
- };
18
- bornAt: Date;
19
- diedAt?: Date;
20
- incomePerMonth: number;
21
- aliases: string[];
22
- spouse?: User;
23
- };
24
-
25
- const getUserSchema = (): ObjectSchemaDefinitionParam<User> => ({
26
- properties: {
27
- id: 'number',
28
- name: {
29
- type: 'object',
30
- isNullable: false,
31
- isRequired: true,
32
- properties: {
33
- first: {
34
- type: 'string',
35
- isNullable: false,
36
- isRequired: true,
37
- minLength: 1,
38
- maxLength: 100
39
- },
40
- last: {
41
- type: 'string',
42
- isNullable: false,
43
- isRequired: true,
44
- minLength: 1,
45
- maxLength: 100
46
- }
47
- }
48
- },
49
- incomePerMonth: {
50
- type: 'number',
51
- min: 0
52
- }
53
- }
54
- });
55
-
56
- test('Can add schema', () => {
57
- const validator = new SchemaValidator().addSchemaType(
58
- 'something',
59
- getUserSchema()
60
- );
61
- expect(validator.schemas.something).toBeDefined();
62
- });
63
-
64
- test('Error thrown on adding a schema with duplicate name', () => {
65
- expect(() =>
66
- new SchemaValidator()
67
- .addSchemaType('smth', {})
68
- .addSchemaType('smth', {})
69
- ).toThrow();
70
- });
71
-
72
- test('Receiving the same schema after add', () => {
73
- const schema: ObjectSchemaDefinitionParam<{ name: string }> = {
74
- properties: {
75
- name: 'string'
76
- }
77
- };
78
- const validator = new SchemaValidator().addSchemaType('something', schema);
79
-
80
- expect(
81
- deepEqual(
82
- { ...schema, type: 'object' },
83
- validator.schemas.something.schema
84
- )
85
- ).toEqual(true);
86
- });
87
-
88
- test('Schemas property is cached when reading', () => {
89
- const validator = new SchemaValidator().addSchemaType('something', {});
90
- expect(validator.schemas).toEqual(validator.schemas);
91
- });
92
-
93
- test('Schemas property is updated after adding a new schema', () => {
94
- let validator = new SchemaValidator().addSchemaType('something', {});
95
- const s = validator.schemas;
96
- validator = validator.addSchemaType('another', {});
97
- expect(s).not.toEqual(validator.schemas);
98
- });
99
-
100
- test('Trows when trying to add a schema with name = "number"', () => {
101
- const validator = new SchemaValidator();
102
- expect(() => validator.addSchemaType('number', {})).toThrow();
103
- });
104
-
105
- test('Trows when trying to add a schema with name = "array"', () => {
106
- const validator = new SchemaValidator();
107
- expect(() => validator.addSchemaType('array', {})).toThrow();
108
- });
109
-
110
- test('Trows when trying to add a schema with name = "date"', () => {
111
- const validator = new SchemaValidator();
112
- expect(() => validator.addSchemaType('date', {})).toThrow();
113
- });
114
-
115
- test('Trows when trying to add a schema with name = "string"', () => {
116
- const validator = new SchemaValidator();
117
- expect(() => validator.addSchemaType('string', {})).toThrow();
118
- });
119
-
120
- test('Throws if schema name is empty', () => {
121
- const validator = new SchemaValidator();
122
- expect(() => validator.addSchemaType('', {})).toThrow();
123
- });
124
-
125
- test('Throws if schema name is not a string', () => {
126
- const validator = new SchemaValidator();
127
- expect(() =>
128
- validator.addSchemaType(new Date() as any as string, {})
129
- ).toThrow();
130
- });
131
-
132
- test('Throws if schema is not an object', () => {
133
- const validator = new SchemaValidator();
134
- expect(() =>
135
- validator.addSchemaType(
136
- 'string',
137
- 'string' as any as ObjectSchemaDefinitionParam<any>
138
- )
139
- ).toThrow();
140
- });
141
-
142
- test('Array as schema type', async () => {
143
- const validator = new SchemaValidator()
144
- .addSchemaType('name', {
145
- properties: {
146
- name: 'string'
147
- }
148
- })
149
- .addSchemaType('number_or_string', ['number', 'string', 'name']);
150
-
151
- let result = await validator.schemas.number_or_string.validate(123);
152
-
153
- expect(result).toHaveProperty('valid', true);
154
-
155
- result = await validator.schemas.number_or_string.validate('some string');
156
-
157
- expect(result).toHaveProperty('valid', true);
158
-
159
- result = await validator.schemas.number_or_string.validate({});
160
-
161
- expect(result).toHaveProperty('valid', false);
162
-
163
- result = await validator.schemas.number_or_string.validate({
164
- name: 'some name'
165
- });
166
- expect(result).toHaveProperty('valid', true);
167
- });
168
-
169
- test('Validate - no schema', async () => {
170
- const validator = new SchemaValidator();
171
- const cth = jest.fn();
172
- validator
173
- .validate(null as any, 10)
174
- .catch(cth)
175
- .then(() => {
176
- expect(cth).toBeCalled();
177
- });
178
- });
179
-
180
- test('Validate - no schema type', async () => {
181
- const validator = new SchemaValidator();
182
- const cth = jest.fn();
183
- validator
184
- .validate(
185
- {
186
- isRequired: true
187
- } as Schema<any>,
188
- 10
189
- )
190
- .catch(cth)
191
- .then(() => {
192
- expect(cth).toBeCalled();
193
- });
194
- });
195
-
196
- test('Validate - number by value', async () => {
197
- const validator = new SchemaValidator();
198
- const result = await validator.validate(10, 0);
199
- expect(result).toHaveProperty('valid', false);
200
- });
201
-
202
- test('Validate - number by value - 2', async () => {
203
- const validator = new SchemaValidator();
204
- const result = await validator.validate(10, 10);
205
- expect(result).toHaveProperty('valid', true);
206
- });
207
-
208
- test('Validate - number by value - 3', async () => {
209
- const validator = new SchemaValidator();
210
- const result = await validator.validate(10, {});
211
- expect(result).toHaveProperty('valid', false);
212
- });
213
-
214
- test('Validate - number by value - 4', async () => {
215
- const validator = new SchemaValidator();
216
- const result = await validator.validate(10, 15);
217
- expect(result).toHaveProperty('valid', false);
218
- });
219
-
220
- test('Validate - number by name: object', async () => {
221
- const validator = new SchemaValidator();
222
- const result = await validator.validate('number', {});
223
- expect(result).toHaveProperty('valid', false);
224
- });
225
-
226
- test('Validate - number by name: string', async () => {
227
- const validator = new SchemaValidator();
228
- const result = await validator.validate('number', '10');
229
- expect(result).toHaveProperty('valid', false);
230
- });
231
-
232
- test('Validate - number by name - correct', async () => {
233
- const validator = new SchemaValidator();
234
- const result = await validator.validate('number', 10);
235
- expect(result).toHaveProperty('valid', true);
236
- });
237
-
238
- test('Validate - number by schema', async () => {
239
- const validator = new SchemaValidator();
240
- const result = await validator.validate(
241
- {
242
- type: 'number'
243
- },
244
- 10
245
- );
246
- expect(result).toHaveProperty('valid', true);
247
- });
248
-
249
- test('Validate - number by schema - not number passed', async () => {
250
- const validator = new SchemaValidator();
251
- const result = await validator.validate(
252
- {
253
- type: 'number'
254
- },
255
- 'str'
256
- );
257
- expect(result).toHaveProperty('valid', false);
258
- });
259
-
260
- test('Validate - number by schema - min', async () => {
261
- const validator = new SchemaValidator();
262
- const result = await validator.validate(
263
- {
264
- type: 'number',
265
- min: 1000
266
- },
267
- 10
268
- );
269
- expect(result).toHaveProperty('valid', false);
270
- });
271
-
272
- test('Validate - number by schema - min 2', async () => {
273
- const validator = new SchemaValidator();
274
- const result = await validator.validate(
275
- {
276
- type: 'number',
277
- min: 1000
278
- },
279
- 10000
280
- );
281
- expect(result).toEqual({
282
- valid: true
283
- });
284
- });
285
-
286
- test('Validate - number by schema - min 3', async () => {
287
- const validator = new SchemaValidator();
288
- const result = await validator.validate(
289
- {
290
- type: 'number',
291
- min: 1000
292
- },
293
- 1000
294
- );
295
- expect(result).toHaveProperty('valid', true);
296
- });
297
-
298
- test('Validate - number by schema - min 4', async () => {
299
- const validator = new SchemaValidator();
300
- const mk = jest.fn();
301
- validator
302
- .validate(
303
- {
304
- type: 'number',
305
- min: 'string' as any as number
306
- },
307
- 10
308
- )
309
- .catch(mk)
310
- .then(() => {
311
- expect(mk).toBeCalled();
312
- });
313
- });
314
-
315
- test('Validate - number by schema - max', async () => {
316
- const validator = new SchemaValidator();
317
- const result = await validator.validate(
318
- {
319
- type: 'number',
320
- max: 1000
321
- },
322
- 20000
323
- );
324
- expect(result).toHaveProperty('valid', false);
325
- });
326
-
327
- test('Validate - number by schema - max 2', async () => {
328
- const validator = new SchemaValidator();
329
- const result = await validator.validate(
330
- {
331
- type: 'number',
332
- max: 40000
333
- },
334
- 10000
335
- );
336
- expect(result).toHaveProperty('valid', true);
337
- });
338
-
339
- test('Validate - number by schema - max 3', async () => {
340
- const validator = new SchemaValidator();
341
- const result = await validator.validate(
342
- {
343
- type: 'number',
344
- max: 1000
345
- },
346
- 1000
347
- );
348
- expect(result).toHaveProperty('valid', true);
349
- });
350
-
351
- test('Validate - number by schema - max 4', async () => {
352
- const validator = new SchemaValidator();
353
- const mk = jest.fn();
354
- validator
355
- .validate(
356
- {
357
- type: 'number',
358
- max: 'string' as any as number
359
- },
360
- 10
361
- )
362
- .catch(mk)
363
- .then(() => {
364
- expect(mk).toBeCalled();
365
- });
366
- });
367
-
368
- test('Validate - number by schema - range', async () => {
369
- const validator = new SchemaValidator();
370
- const result = await validator.validate(
371
- {
372
- type: 'number',
373
- min: 1,
374
- max: 100
375
- },
376
- 10
377
- );
378
-
379
- expect(result).toHaveProperty('valid', true);
380
- });
381
-
382
- test('Validate - number by schema - range - 2', async () => {
383
- const validator = new SchemaValidator();
384
- const result = await validator.validate(
385
- {
386
- type: 'number',
387
- min: -100,
388
- max: 100
389
- },
390
- -210
391
- );
392
-
393
- expect(result).toHaveProperty('valid', false);
394
- });
395
-
396
- test('Validate - number by schema - range - 3', async () => {
397
- const validator = new SchemaValidator();
398
- const result = await validator.validate(
399
- {
400
- type: 'number',
401
- min: -100,
402
- max: 100
403
- },
404
- -100
405
- );
406
-
407
- expect(result).toHaveProperty('valid', true);
408
- });
409
-
410
- test('Validate - number by schema - range - 4', async () => {
411
- const validator = new SchemaValidator();
412
- const result = await validator.validate(
413
- {
414
- type: 'number',
415
- min: -100,
416
- max: 100
417
- },
418
- 100
419
- );
420
-
421
- expect(result).toHaveProperty('valid', true);
422
- });
423
-
424
- test('Validate - number by schema - range - 5', async () => {
425
- const validator = new SchemaValidator();
426
- const result = await validator.validate(
427
- {
428
- type: 'number',
429
- min: -100,
430
- max: 100
431
- },
432
- 200
433
- );
434
-
435
- expect(result).toHaveProperty('valid', false);
436
- });
437
-
438
- test('Validate - number by schema - range - 6', async () => {
439
- const validator = new SchemaValidator();
440
- const result = await validator.validate(
441
- {
442
- type: 'number',
443
- min: -100,
444
- max: 100
445
- },
446
- 200
447
- );
448
-
449
- expect(result).toHaveProperty('valid', false);
450
- });
451
-
452
- test('Validate - number by schema - NaN', async () => {
453
- const validator = new SchemaValidator();
454
- const result = await validator.validate(
455
- {
456
- type: 'number',
457
- min: -100,
458
- max: 100
459
- },
460
- 0 / 0
461
- );
462
- expect(result).toHaveProperty('valid', false);
463
- });
464
-
465
- test('Validate - number by schema - NaN - 2', async () => {
466
- const validator = new SchemaValidator();
467
- const result = await validator.validate(
468
- {
469
- type: 'number',
470
- ensureNotNaN: false
471
- },
472
- 0 / 0
473
- );
474
-
475
- expect(result).toHaveProperty('valid', true);
476
- });
477
-
478
- test('Validate - number by schema - Infinity', async () => {
479
- const validator = new SchemaValidator();
480
- const result = await validator.validate(
481
- {
482
- type: 'number'
483
- },
484
- 100 / 0
485
- );
486
-
487
- expect(result).toHaveProperty('valid', false);
488
- });
489
-
490
- test('Validate - number by schema - Infinity - 2', async () => {
491
- const validator = new SchemaValidator();
492
- const result = await validator.validate(
493
- {
494
- type: 'number',
495
- ensureIsFinite: false
496
- },
497
- 100 / 0
498
- );
499
-
500
- expect(result).toHaveProperty('valid', true);
501
- });
502
-
503
- test('Validate - number by schema - custom validators - 1', async () => {
504
- const validator = new SchemaValidator();
505
- const schema: NumberSchemaDefinition<any> = {
506
- type: 'number',
507
- validators: [
508
- async (value) => {
509
- if ((value & 0xb01) === 0)
510
- return {
511
- valid: false,
512
- errors: ['value should be odd!']
513
- };
514
- return {
515
- valid: true
516
- };
517
- }
518
- ]
519
- };
520
- let result = await validator.validate(schema, 101);
521
-
522
- expect(result).toHaveProperty('valid', true);
523
-
524
- result = await validator.validate(schema, 100);
525
- expect(result).toHaveProperty('valid', false);
526
- });
527
-
528
- test('Validate - number by schema - custom validators - 2', async () => {
529
- const validator = new SchemaValidator();
530
- const schema: NumberSchemaDefinition<any> = {
531
- type: 'number',
532
- validators: [
533
- (value) => {
534
- if ((value & 0xb01) === 0)
535
- return {
536
- valid: false,
537
- errors: ['value should be odd!']
538
- };
539
- return {
540
- valid: true
541
- };
542
- },
543
- (value) => ({ valid: value > 100 })
544
- ]
545
- };
546
- let result = await validator.validate(schema, 101);
547
-
548
- expect(result).toHaveProperty('valid', true);
549
-
550
- result = await validator.validate(schema, 99);
551
- expect(result).toHaveProperty('valid', false);
552
-
553
- result = await validator.validate(schema, 100);
554
- expect(result).toHaveProperty('valid', false);
555
- });
556
-
557
- test('Validate - boolean - 1', async () => {
558
- const validator = new SchemaValidator();
559
- const result = await validator.validate(
560
- {
561
- type: 'boolean'
562
- },
563
- 300
564
- );
565
-
566
- expect(result).toHaveProperty('valid', false);
567
- });
568
-
569
- test('Validate - boolean - 2', async () => {
570
- const validator = new SchemaValidator();
571
- const result = await validator.validate(
572
- {
573
- type: 'boolean'
574
- },
575
- true
576
- );
577
-
578
- expect(result).toHaveProperty('valid', true);
579
- });
580
-
581
- test('Validate - boolean - 3', async () => {
582
- const validator = new SchemaValidator();
583
- const result = await validator.validate(
584
- {
585
- type: 'boolean'
586
- },
587
- false
588
- );
589
-
590
- expect(result).toHaveProperty('valid', true);
591
- });
592
-
593
- test('Validate - boolean - 4', async () => {
594
- const validator = new SchemaValidator();
595
- const result = await validator.validate(
596
- {
597
- type: 'boolean',
598
- equals: true
599
- },
600
- false
601
- );
602
-
603
- expect(result).toHaveProperty('valid', false);
604
- });
605
-
606
- test('Validate - boolean - 5', async () => {
607
- const validator = new SchemaValidator();
608
- const result = await validator.validate(
609
- {
610
- type: 'boolean',
611
- equals: false
612
- },
613
- false
614
- );
615
-
616
- expect(result).toHaveProperty('valid', true);
617
- });
618
-
619
- test('Validate - boolean - 6', async () => {
620
- const validator = new SchemaValidator();
621
- const result = await validator.validate('boolean', false);
622
-
623
- expect(result).toHaveProperty('valid', true);
624
- });
625
-
626
- test('Validate - boolean - 7', async () => {
627
- const validator = new SchemaValidator();
628
- const result = await validator.validate('boolean', '123');
629
-
630
- expect(result).toHaveProperty('valid', false);
631
- });
632
-
633
- test('Validate - string - 1', async () => {
634
- const validator = new SchemaValidator();
635
- const result = await validator.validate('string', '12345');
636
- expect(result).toHaveProperty('valid', true);
637
- });
638
-
639
- test('Validate - string - 2', async () => {
640
- const validator = new SchemaValidator();
641
- const result = await validator.validate('string', 12345);
642
- expect(result).toHaveProperty('valid', false);
643
- });
644
-
645
- test('Validate - string - 3', async () => {
646
- const validator = new SchemaValidator();
647
- const result = await validator.validate('12345', '12345');
648
- expect(result).toHaveProperty('valid', true);
649
- });
650
-
651
- test('Validate - string - 4', async () => {
652
- const validator = new SchemaValidator();
653
- const result = await validator.validate('12345', '123456');
654
- expect(result).toHaveProperty('valid', false);
655
- });
656
-
657
- test('Validate - string - 5', async () => {
658
- const validator = new SchemaValidator();
659
- const result = await validator.validate('12345', 123456);
660
- expect(result).toHaveProperty('valid', false);
661
- });
662
-
663
- test('Validate - string - schema object - 1', async () => {
664
- const validator = new SchemaValidator();
665
- const result = await validator.validate(
666
- {
667
- type: 'string',
668
- equals: '123456'
669
- },
670
- '123456'
671
- );
672
- expect(result).toHaveProperty('valid', true);
673
- });
674
-
675
- test('Validate - string - schema object - 2', async () => {
676
- const validator = new SchemaValidator();
677
- const result = await validator.validate(
678
- {
679
- type: 'string',
680
- equals: '123456'
681
- },
682
- '12345'
683
- );
684
- expect(result).toHaveProperty('valid', false);
685
- });
686
-
687
- test('Validate - string - schema object - 3', async () => {
688
- const validator = new SchemaValidator();
689
- const result = await validator.validate(
690
- {
691
- type: 'string',
692
- equals: '123456'
693
- },
694
- 1234
695
- );
696
- expect(result).toHaveProperty('valid', false);
697
- });
698
-
699
- test('Validate - string - length control - 1', async () => {
700
- const validator = new SchemaValidator();
701
- let result = await validator.validate(
702
- {
703
- type: 'string',
704
- minLength: 2,
705
- maxLength: 3
706
- },
707
- 'U'
708
- );
709
- expect(result).toHaveProperty('valid', false);
710
-
711
- result = await validator.validate(
712
- {
713
- type: 'string',
714
- minLength: 2,
715
- maxLength: 3
716
- },
717
- 'US'
718
- );
719
- expect(result).toHaveProperty('valid', true);
720
-
721
- result = await validator.validate(
722
- {
723
- type: 'string',
724
- minLength: 2,
725
- maxLength: 3
726
- },
727
- 'USA'
728
- );
729
- expect(result).toHaveProperty('valid', true);
730
-
731
- result = await validator.validate(
732
- {
733
- type: 'string',
734
- minLength: 2,
735
- maxLength: 3
736
- },
737
- 'USA'
738
- );
739
- expect(result).toHaveProperty('valid', true);
740
-
741
- result = await validator.validate(
742
- {
743
- type: 'string',
744
- minLength: 2,
745
- maxLength: 3
746
- },
747
- 'United States of America'
748
- );
749
- expect(result).toHaveProperty('valid', false);
750
- });
751
-
752
- test('Validate - array - 1', async () => {
753
- const validator = new SchemaValidator();
754
- let result = await validator.validate('array', []);
755
- expect(result).toHaveProperty('valid', true);
756
-
757
- result = await validator.validate('array', 123);
758
- expect(result).toHaveProperty('valid', false);
759
- });
760
-
761
- test('Validate - array - size control - 1', async () => {
762
- const validator = new SchemaValidator();
763
- let result = await validator.validate(
764
- {
765
- type: 'array',
766
- minLength: 1,
767
- maxLength: 3
768
- },
769
- []
770
- );
771
- expect(result).toHaveProperty('valid', false);
772
-
773
- result = await validator.validate(
774
- {
775
- type: 'array',
776
- minLength: 1,
777
- maxLength: 3
778
- },
779
- [1]
780
- );
781
- expect(result).toHaveProperty('valid', true);
782
-
783
- result = await validator.validate(
784
- {
785
- type: 'array',
786
- minLength: 1,
787
- maxLength: 3
788
- },
789
- [1, 2]
790
- );
791
- expect(result).toHaveProperty('valid', true);
792
-
793
- result = await validator.validate(
794
- {
795
- type: 'array',
796
- minLength: 1,
797
- maxLength: 3
798
- },
799
- [1, 2, 3]
800
- );
801
- expect(result).toHaveProperty('valid', true);
802
-
803
- result = await validator.validate(
804
- {
805
- type: 'array',
806
- minLength: 1,
807
- maxLength: 3
808
- },
809
- [1, 2, 3, 4]
810
- );
811
- expect(result).toHaveProperty('valid', false);
812
- });
813
-
814
- test('Validate - array - ofType - 1', async () => {
815
- const validator = new SchemaValidator();
816
- let result = await validator.validate(
817
- {
818
- type: 'array',
819
- ofType: 'number'
820
- },
821
- ['1', 2, 3]
822
- );
823
- expect(result).toHaveProperty('valid', false);
824
-
825
- result = await validator.validate(
826
- {
827
- type: 'array',
828
- ofType: 'number'
829
- },
830
- [1, 2, 3]
831
- );
832
- expect(result).toHaveProperty('valid', true);
833
-
834
- result = await validator.validate(
835
- {
836
- type: 'array',
837
- ofType: {
838
- type: 'number',
839
- min: 10
840
- }
841
- },
842
- [-1, 12, 13]
843
- );
844
- expect(result).toHaveProperty('valid', false);
845
- });
846
-
847
- test('Validate - object - 1', async () => {
848
- const validator = new SchemaValidator().addSchemaType(
849
- 'user',
850
- getUserSchema()
851
- );
852
- const user: User = {
853
- id: 1,
854
- name: {
855
- first: 'Andrew',
856
- last: 'Zolotukhin'
857
- },
858
- bornAt: new Date(1986, 4, 30),
859
- incomePerMonth: 134234,
860
- aliases: []
861
- };
862
-
863
- let result = await validator.validate('user', user);
864
-
865
- expect(result).toHaveProperty('valid', true);
866
-
867
- result = await validator.validate('user', 10);
868
-
869
- expect(result).toHaveProperty('valid', false);
870
-
871
- result = await validator.validate(
872
- {
873
- type: 'object',
874
- properties: {
875
- name: {
876
- type: 'string',
877
- maxLength: 5
878
- },
879
- address: {
880
- type: 'object',
881
- properties: {
882
- street: 'string',
883
- house: {
884
- type: 'number',
885
- isRequired: false
886
- }
887
- }
888
- }
889
- }
890
- },
891
- {
892
- name: 'Andr',
893
- address: {
894
- street: 'something'
895
- }
896
- }
897
- );
898
-
899
- expect(result).toHaveProperty('valid', true);
900
-
901
- result = await validator.validate(
902
- {
903
- type: 'object',
904
- properties: {
905
- a: 'number',
906
- b: 'number'
907
- },
908
- validators: [
909
- (value: { a: number; b: number }) => {
910
- if (value.a + value.b === 5) {
911
- return {
912
- valid: true
913
- };
914
- }
915
- return {
916
- valid: false,
917
- error: ['some error']
918
- };
919
- }
920
- ]
921
- },
922
- {
923
- a: 1,
924
- b: 3
925
- }
926
- );
927
- expect(result).toHaveProperty('valid', false);
928
- });
929
-
930
- test('Validate - object - 2', async () => {
931
- const validator = new SchemaValidator().addSchemaType(
932
- 'user',
933
- deepExtend(getUserSchema(), {
934
- validators: [
935
- (value): ValidationResult => {
936
- if (value.bornAt < new Date(1990, 0, 1)) {
937
- return {
938
- valid: true
939
- };
940
- }
941
- return {
942
- valid: false,
943
- errors: [`bornAt should be before Jan 1 1990`]
944
- };
945
- }
946
- ]
947
- }) as any as ObjectSchemaDefinition<any>
948
- );
949
- const user: User = {
950
- id: 1,
951
- name: {
952
- first: 'Andrew',
953
- last: 'Zolotukhin'
954
- },
955
- bornAt: new Date(1996, 4, 30),
956
- incomePerMonth: 134234,
957
- aliases: []
958
- };
959
-
960
- const result = await validator.validate('user', user);
961
- expect(result).toHaveProperty('valid', false);
962
- });
963
-
964
- test('Validate - one of - 1', async () => {
965
- const validator = new SchemaValidator();
966
-
967
- let result = await validator.validate(['number', 'object'], 'something');
968
- expect(result).toHaveProperty('valid', false);
969
-
970
- result = await validator.validate(['number', 'string'], 'something');
971
- expect(result).toHaveProperty('valid', true);
972
-
973
- result = await validator.validate(
974
- [
975
- 'number',
976
- 'string',
977
- {
978
- type: 'object',
979
- properties: {
980
- first: 'string',
981
- last: 'string'
982
- }
983
- }
984
- ],
985
- {
986
- first: 'something',
987
- last: 'another'
988
- }
989
- );
990
- expect(result).toHaveProperty('valid', true);
991
- });
992
-
993
- test('Validate schema - 1', async () => {
994
- const authorsReportSpecificationSchema = {
995
- properties: {
996
- type: {
997
- type: 'string',
998
- equals: 'author'
999
- },
1000
- start: 'Date',
1001
- end: 'Date',
1002
- selectionStart: 'Date',
1003
- selectionEnd: 'Date',
1004
- granularity: ['day', 'week', 'month'],
1005
- metrics: {
1006
- type: 'array',
1007
- ofType: [
1008
- 'articlesPublished',
1009
- 'searchReferrers',
1010
- 'socialReferrers',
1011
- 'views',
1012
- 'visitors',
1013
- 'newVisitors'
1014
- ]
1015
- },
1016
- filters: {
1017
- type: 'object',
1018
- properties: {
1019
- author: 'AuthorFilter'
1020
- // publication: 'PublicationFilter',
1021
- // article: 'ArticleFilter'
1022
- }
1023
- }
1024
- },
1025
- validators: [
1026
- (value) =>
1027
- value.start <= value.end &&
1028
- value.selectionStart <= value.selectionEnd &&
1029
- value.selectionStart >= value.start &&
1030
- value.selectionStart <= value.end &&
1031
- value.selectionEnd >= value.start &&
1032
- value.selectionEnd <= value.end
1033
- ? {
1034
- valid: true
1035
- }
1036
- : {
1037
- valid: false,
1038
- errors: [
1039
- 'selectionStart <=> selectionEnd should be inside the start <=> end interval'
1040
- ]
1041
- }
1042
- ]
1043
- };
1044
-
1045
- const validator = new SchemaValidator()
1046
- .addSchemaType('Date', {
1047
- validators: [
1048
- (value) =>
1049
- value instanceof Date && !Number.isNaN(value)
1050
- ? {
1051
- valid: true
1052
- }
1053
- : {
1054
- valid: false,
1055
- errors: ['should be a valid Date object']
1056
- }
1057
- ]
1058
- })
1059
- .addSchemaType('EqualsFilterCondition', {
1060
- properties: {
1061
- operation: {
1062
- type: 'string',
1063
- equals: 'equals'
1064
- },
1065
- value: ['object', 'string', 'number']
1066
- }
1067
- })
1068
- .addSchemaType('GreaterThanFilterCondition', {
1069
- properties: {
1070
- operation: {
1071
- type: 'string',
1072
- equals: 'greater_than'
1073
- },
1074
- value: 'number'
1075
- }
1076
- })
1077
- .addSchemaType('LessThanFilterCondition', {
1078
- properties: {
1079
- operation: {
1080
- type: 'string',
1081
- equals: 'less_than'
1082
- },
1083
- value: 'number'
1084
- }
1085
- })
1086
- .addSchemaType('ContainsFilterCondition', {
1087
- properties: {
1088
- operation: {
1089
- type: 'string',
1090
- equals: 'contains'
1091
- },
1092
- value: [
1093
- 'string',
1094
- 'number',
1095
- {
1096
- type: 'array',
1097
- ofType: ['string', 'number']
1098
- }
1099
- ]
1100
- }
1101
- })
1102
- .addSchemaType('LikeFilterCondition', {
1103
- properties: {
1104
- operation: 'like',
1105
- value: 'string'
1106
- }
1107
- })
1108
- .addSchemaType('BetweenFilterCondition', {
1109
- properties: {
1110
- operation: 'between',
1111
- from: 'number',
1112
- to: 'number'
1113
- },
1114
- validators: [
1115
- (value) =>
1116
- value.from <= value.to
1117
- ? { valid: true }
1118
- : { valid: false, error: ['from must be <= to'] }
1119
- ]
1120
- })
1121
- .addSchemaType('StringFilterCondition', [
1122
- 'EqualsFilterCondition',
1123
- 'LikeFilterCondition'
1124
- ])
1125
- .addSchemaType('AuthorFilter', {
1126
- properties: {
1127
- fullName: 'StringFilterCondition'
1128
- }
1129
- })
1130
- .addSchemaType(
1131
- 'AuthorsReportSpecification',
1132
- authorsReportSpecificationSchema as ObjectSchemaDefinitionParam<any>
1133
- );
1134
-
1135
- /**
1136
- * @type {import('smg-iq/editorial-analytics.reports').AuthorsReportSpecification}
1137
- */
1138
- let reportSpec = {
1139
- type: 'author',
1140
- start: new Date(2021, 0, 1),
1141
- end: new Date(),
1142
- selectionStart: new Date(2022, 0, 1),
1143
- selectionEnd: new Date(2022, 2, 1),
1144
- granularity: 'day',
1145
- metrics: [
1146
- 'articlesPublished',
1147
- 'searchReferrers',
1148
- 'socialReferrers',
1149
- 'views',
1150
- 'visitors',
1151
- 'newVisitors'
1152
- ],
1153
- filters: {
1154
- author: {
1155
- fullName: {
1156
- operation: 'between',
1157
- value: 'some name'
1158
- }
1159
- }
1160
- }
1161
- };
1162
-
1163
- let result = await validator.schemas.AuthorsReportSpecification.validate(
1164
- reportSpec
1165
- );
1166
-
1167
- expect(result).toHaveProperty('valid', false);
1168
-
1169
- reportSpec = {
1170
- type: 'author',
1171
- start: new Date(2021, 0, 1),
1172
- end: new Date(),
1173
- selectionStart: new Date(2022, 0, 1),
1174
- selectionEnd: new Date(2022, 2, 1),
1175
- granularity: 'day',
1176
- metrics: [
1177
- 'articlesPublished',
1178
- 'searchReferrers',
1179
- 'socialReferrers',
1180
- 'views',
1181
- 'visitors',
1182
- 'newVisitors'
1183
- ],
1184
- filters: {
1185
- author: {
1186
- fullName: {
1187
- operation: 'equals',
1188
- value: 'some name'
1189
- }
1190
- }
1191
- }
1192
- };
1193
-
1194
- result = await validator.schemas.AuthorsReportSpecification.validate(
1195
- reportSpec
1196
- );
1197
-
1198
- expect(result).toHaveProperty('valid', true);
1199
- });
1200
-
1201
- test('Validate schema - 2', async () => {
1202
- const validator = new SchemaValidator()
1203
- .addSchemaType('Date', {
1204
- validators: [
1205
- (value) =>
1206
- value instanceof Date && !Number.isNaN(value)
1207
- ? {
1208
- valid: true
1209
- }
1210
- : {
1211
- valid: false,
1212
- errors: ['should be a valid Date object']
1213
- }
1214
- ]
1215
- })
1216
- .addSchemaType('Module.Schema1', {
1217
- properties: {
1218
- a: 'string'
1219
- }
1220
- })
1221
- .addSchemaType('Module.Schema2', {
1222
- properties: {
1223
- b: 'number'
1224
- }
1225
- });
1226
-
1227
- const result = await validator.validate(
1228
- {
1229
- type: 'object',
1230
- properties: {
1231
- date: {
1232
- type: 'alias',
1233
- schemaName: 'Date',
1234
- isRequired: false
1235
- }
1236
- }
1237
- },
1238
- {}
1239
- );
1240
-
1241
- expect(result).toHaveProperty('valid', true);
1242
- });
1243
-
1244
- test('Not required alternative schema alias', async () => {
1245
- const validator = new SchemaValidator()
1246
- .addSchemaType('Alternate1', {
1247
- properties: {
1248
- a1: 'string'
1249
- }
1250
- })
1251
- .addSchemaType('Alternate2', {
1252
- properties: {
1253
- a2: 'string'
1254
- }
1255
- })
1256
- .addSchemaType('Alternate', ['Alternate1', 'Alternate2']);
1257
-
1258
- let result = await validator.validate(
1259
- {
1260
- type: 'alias',
1261
- isRequired: false,
1262
- schemaName: 'Alternate'
1263
- },
1264
- undefined
1265
- );
1266
-
1267
- expect(result).toHaveProperty('valid', true);
1268
-
1269
- result = await validator.validate(
1270
- {
1271
- type: 'alias',
1272
- isRequired: false,
1273
- schemaName: 'Alternate'
1274
- },
1275
- {
1276
- a2: 'something'
1277
- }
1278
- );
1279
-
1280
- expect(result).toHaveProperty('valid', true);
1281
-
1282
- result = await validator.validate(
1283
- {
1284
- type: 'alias',
1285
- isRequired: false,
1286
- schemaName: 'Alternate'
1287
- },
1288
- 'invalid'
1289
- );
1290
-
1291
- expect(result).toHaveProperty('valid', false);
1292
- });
1293
-
1294
- test('Preprocessors - 1', async () => {
1295
- const validator = new SchemaValidator().addSchemaType('Date', {
1296
- validators: [
1297
- (value) =>
1298
- value instanceof Date && !Number.isNaN(value)
1299
- ? {
1300
- valid: true
1301
- }
1302
- : {
1303
- valid: false,
1304
- errors: ['should be a valid Date object']
1305
- }
1306
- ]
1307
- });
1308
-
1309
- const schema: Schema<{ bornAt: Date }> = {
1310
- type: 'object',
1311
- properties: {
1312
- bornAt: 'Date'
1313
- },
1314
- preprocessors: {
1315
- bornAt: (value: unknown): Date | undefined => {
1316
- const time = Date.parse(
1317
- (value as Record<string, unknown>).toString()
1318
- );
1319
- if (Number.isNaN(time)) return undefined;
1320
- return new Date(time);
1321
- }
1322
- }
1323
- };
1324
-
1325
- const result = await validator.validate(schema, {
1326
- bornAt: new Date().toJSON()
1327
- });
1328
- expect(result).toHaveProperty('valid', true);
1329
- });
1330
-
1331
- test('Preprocessors - 2', async () => {
1332
- const validator = new SchemaValidator().addSchemaType('Date', {
1333
- validators: [
1334
- (value) =>
1335
- value instanceof Date && !Number.isNaN(value)
1336
- ? {
1337
- valid: true
1338
- }
1339
- : {
1340
- valid: false,
1341
- errors: ['should be a valid Date object']
1342
- }
1343
- ]
1344
- });
1345
-
1346
- let schema: Schema<{ bornAt: Date; diedAt?: Date }> = {
1347
- type: 'object',
1348
- properties: {
1349
- bornAt: 'Date'
1350
- },
1351
- preprocessors: {
1352
- bornAt: 'StringToDate'
1353
- }
1354
- };
1355
-
1356
- validator.addPreprocessor(
1357
- 'StringToDate',
1358
- (value: unknown): Date | undefined => {
1359
- const time = Date.parse(
1360
- (value as Record<string, unknown>).toString()
1361
- );
1362
- if (Number.isNaN(time)) return undefined;
1363
- return new Date(time);
1364
- }
1365
- );
1366
-
1367
- expect(() =>
1368
- validator.addPreprocessor(
1369
- 'StringToDate',
1370
- (value: unknown): Date | undefined => {
1371
- const time = Date.parse(
1372
- (value as Record<string, unknown>).toString()
1373
- );
1374
- if (Number.isNaN(time)) return undefined;
1375
- return new Date(time);
1376
- }
1377
- )
1378
- ).toThrow();
1379
-
1380
- const result = await validator.validate(schema, {
1381
- bornAt: new Date().toJSON()
1382
- });
1383
- expect(result).toHaveProperty('valid', true);
1384
-
1385
- schema = {
1386
- type: 'object',
1387
- properties: {
1388
- bornAt: 'Date',
1389
- diedAt: 'Date'
1390
- },
1391
- preprocessors: {
1392
- bornAt: 'StringToDate',
1393
- diedAt: 'Unregistered'
1394
- }
1395
- };
1396
- expect(async () => {
1397
- await validator.validate(schema, {
1398
- bornAt: new Date().toJSON()
1399
- });
1400
- }).rejects.toBeInstanceOf(Error);
1401
- });
1402
-
1403
- test('Preprocessors - 3', async () => {
1404
- const validator = new SchemaValidator().addSchemaType('Date', {
1405
- validators: [
1406
- (value) =>
1407
- value instanceof Date && !Number.isNaN(value)
1408
- ? {
1409
- valid: true
1410
- }
1411
- : {
1412
- valid: false,
1413
- errors: ['should be a valid Date object']
1414
- }
1415
- ]
1416
- });
1417
-
1418
- validator.addPreprocessor(
1419
- 'StringToDate',
1420
- (value: unknown): Date | undefined => {
1421
- const time = Date.parse(
1422
- (value as Record<string, unknown>).toString()
1423
- );
1424
- if (Number.isNaN(time)) return undefined;
1425
- return new Date(time);
1426
- }
1427
- );
1428
-
1429
- let obj = [new Date().toJSON()];
1430
-
1431
- let result = await validator.validate(
1432
- {
1433
- preprocessor: 'StringToDate',
1434
- type: 'array',
1435
- ofType: 'Date'
1436
- },
1437
- obj
1438
- );
1439
- expect(result).toHaveProperty('valid', true);
1440
-
1441
- obj = [new Date().toJSON()];
1442
- result = await validator.validate(
1443
- {
1444
- preprocessor: (value: unknown): Date | undefined => {
1445
- const time = Date.parse(
1446
- (value as Record<string, unknown>).toString()
1447
- );
1448
- if (Number.isNaN(time)) return undefined;
1449
- return new Date(time);
1450
- },
1451
- type: 'array',
1452
- ofType: 'Date'
1453
- },
1454
- obj
1455
- );
1456
- expect(result).toHaveProperty('valid', true);
1457
-
1458
- obj = ['sdfsdf12', new Date().toJSON()];
1459
- result = await validator.validate(
1460
- {
1461
- preprocessor: (value: unknown): Date | undefined => {
1462
- const time = Date.parse(
1463
- (value as Record<string, unknown>).toString()
1464
- );
1465
- if (Number.isNaN(time)) return undefined;
1466
- return new Date(time);
1467
- },
1468
- type: 'array',
1469
- ofType: 'Date'
1470
- },
1471
- obj
1472
- );
1473
- expect(result).toHaveProperty('valid', false);
1474
- });
1475
-
1476
- test('Preprocessors - 3', async () => {
1477
- const validator = new SchemaValidator();
1478
-
1479
- type SomeType = { age: number; marriedAt: number };
1480
-
1481
- const schema: ObjectSchemaDefinition<SomeType> = {
1482
- type: 'object',
1483
- properties: {
1484
- age: 'number',
1485
- marriedAt: 'number'
1486
- },
1487
- preprocessors: {
1488
- age: (value): number => 40,
1489
- '*': (value: SomeType): void => {
1490
- if (value.marriedAt > value.age) {
1491
- value.marriedAt = value.age;
1492
- }
1493
- }
1494
- }
1495
- };
1496
-
1497
- const obj = {
1498
- age: 50,
1499
- marriedAt: 80
1500
- };
1501
- await validator.validate(schema, obj);
1502
- expect(obj).toHaveProperty('marriedAt', 40);
1503
- });
1504
-
1505
- test('Preprocessors - 4', async () => {
1506
- const validator = new SchemaValidator().addSchemaType('Date', {
1507
- validators: [
1508
- (value) =>
1509
- value instanceof Date && !Number.isNaN(value)
1510
- ? {
1511
- valid: true
1512
- }
1513
- : {
1514
- valid: false,
1515
- errors: ['should be a valid Date object']
1516
- }
1517
- ]
1518
- });
1519
-
1520
- validator.addPreprocessor(
1521
- 'StringToDate',
1522
- (value: unknown): Date | undefined => {
1523
- const time = Date.parse(
1524
- (value as Record<string, unknown>).toString()
1525
- );
1526
- if (Number.isNaN(time)) return undefined;
1527
- return new Date(time);
1528
- }
1529
- );
1530
-
1531
- let obj = [new Date().toJSON()];
1532
-
1533
- let result = await validator.validate(
1534
- {
1535
- preprocessor: 'StringToDate',
1536
- type: 'array',
1537
- ofType: 'Date'
1538
- },
1539
- obj
1540
- );
1541
- expect(result).toHaveProperty('valid', true);
1542
-
1543
- obj = [new Date().toJSON()];
1544
- result = await validator.validate(
1545
- {
1546
- preprocessor: (value: unknown): Date | undefined => {
1547
- const time = Date.parse(
1548
- (value as Record<string, unknown>).toString()
1549
- );
1550
- if (Number.isNaN(time)) return undefined;
1551
- return new Date(time);
1552
- },
1553
- type: 'array',
1554
- ofType: 'Date'
1555
- },
1556
- obj
1557
- );
1558
- expect(result).toHaveProperty('valid', true);
1559
-
1560
- obj = ['sdfsdf12', new Date().toJSON()];
1561
- result = await validator.validate(
1562
- {
1563
- preprocessor: (value: unknown): Date | undefined => {
1564
- const time = Date.parse(
1565
- (value as Record<string, unknown>).toString()
1566
- );
1567
- if (Number.isNaN(time)) return undefined;
1568
- return new Date(time);
1569
- },
1570
- type: 'array',
1571
- ofType: 'Date'
1572
- },
1573
- obj
1574
- );
1575
- expect(result).toHaveProperty('valid', false);
1576
- });
1577
-
1578
- test('Submodules - 1', async () => {
1579
- const validator = new SchemaValidator().addSchemaType(
1580
- 'Module1.Schema1',
1581
- {}
1582
- );
1583
-
1584
- const result = validator.schemas;
1585
-
1586
- expect(result).toHaveProperty('Module1');
1587
- expect(result).toHaveProperty('Module1.Schema1');
1588
- });
1589
-
1590
- test('Submodules - 2', async () => {
1591
- const validator = new SchemaValidator()
1592
- .addSchemaType('Module1.Schema1', {})
1593
- .addSchemaType('Module1.Schema2', {
1594
- properties: {
1595
- a: 'number'
1596
- }
1597
- });
1598
-
1599
- const result = validator.schemas;
1600
-
1601
- expect(result).toHaveProperty('Module1');
1602
- expect(result).toHaveProperty('Module1.Schema1');
1603
- expect(result).toHaveProperty('Module1.Schema2');
1604
-
1605
- const result2 = await validator.schemas.Module1.Schema2.validate({
1606
- a: 234
1607
- });
1608
- expect(result2).toHaveProperty('valid', true);
1609
- });
1610
-
1611
- test('Submodules - 3', async () => {
1612
- const validator = new SchemaValidator()
1613
- .addSchemaType('Module1.Schema1', {
1614
- properties: {
1615
- b: 'number'
1616
- }
1617
- })
1618
- .addSchemaType('Module1.Schema2', {
1619
- properties: {
1620
- a: {
1621
- type: 'alias',
1622
- schemaName: 'Module1.Schema1'
1623
- }
1624
- }
1625
- });
1626
-
1627
- const result2 = await validator.schemas.Module1.Schema2.validate({
1628
- a: {
1629
- b: 20
1630
- }
1631
- });
1632
- expect(result2).toHaveProperty('valid', true);
1633
- });
1634
-
1635
- test('Submodules - 4', async () => {
1636
- const validator = new SchemaValidator()
1637
- .addSchemaType('Module1.Schema1', {
1638
- properties: {
1639
- b: 'number'
1640
- }
1641
- })
1642
- .addSchemaType('Module1.Schema2', {
1643
- properties: {
1644
- a: {
1645
- type: 'alias',
1646
- schemaName: 'Module1.Schema3'
1647
- }
1648
- }
1649
- });
1650
-
1651
- await validator.schemas.Module1.Schema2.validate({
1652
- a: {
1653
- b: 20
1654
- }
1655
- }).catch((e) => expect(e).toBeInstanceOf(Error));
1656
- });