@cleverbrush/schema 1.0.0-beta.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +118 -320
  2. package/dist/builders/AnySchemaBuilder.d.ts +76 -0
  3. package/dist/builders/AnySchemaBuilder.js +112 -0
  4. package/dist/builders/ArraySchemaBuilder.d.ts +112 -14
  5. package/dist/builders/ArraySchemaBuilder.js +254 -111
  6. package/dist/builders/BooleanSchemaBuilder.d.ts +69 -29
  7. package/dist/builders/BooleanSchemaBuilder.js +134 -74
  8. package/dist/builders/DateSchemaBuilder.d.ts +177 -0
  9. package/dist/builders/DateSchemaBuilder.js +433 -0
  10. package/dist/builders/FunctionSchemaBuilder.d.ts +59 -23
  11. package/dist/builders/FunctionSchemaBuilder.js +103 -56
  12. package/dist/builders/NumberSchemaBuilder.d.ts +159 -59
  13. package/dist/builders/NumberSchemaBuilder.js +345 -165
  14. package/dist/builders/ObjectSchemaBuilder.d.ts +357 -81
  15. package/dist/builders/ObjectSchemaBuilder.js +519 -283
  16. package/dist/builders/SchemaBuilder.d.ts +158 -34
  17. package/dist/builders/SchemaBuilder.js +258 -71
  18. package/dist/builders/StringSchemaBuilder.d.ts +138 -13
  19. package/dist/builders/StringSchemaBuilder.js +261 -115
  20. package/dist/builders/UnionSchemaBuilder.d.ts +129 -9
  21. package/dist/builders/UnionSchemaBuilder.js +196 -75
  22. package/dist/index.d.ts +20 -40
  23. package/dist/index.js +19 -32
  24. package/dist/utils/transaction.d.ts +46 -0
  25. package/dist/utils/transaction.js +178 -0
  26. package/package.json +27 -14
  27. package/dist/defaultSchemas.d.ts +0 -4
  28. package/dist/defaultSchemas.js +0 -45
  29. package/dist/schema.d.ts +0 -230
  30. package/dist/schema.js +0 -2
  31. package/dist/schemaRegistry.d.ts +0 -49
  32. package/dist/schemaRegistry.js +0 -278
  33. package/dist/validators/validateArray.d.ts +0 -3
  34. package/dist/validators/validateArray.js +0 -60
  35. package/dist/validators/validateBoolean.d.ts +0 -2
  36. package/dist/validators/validateBoolean.js +0 -30
  37. package/dist/validators/validateFunction.d.ts +0 -2
  38. package/dist/validators/validateFunction.js +0 -21
  39. package/dist/validators/validateNumber.d.ts +0 -2
  40. package/dist/validators/validateNumber.js +0 -69
  41. package/dist/validators/validateObject.d.ts +0 -3
  42. package/dist/validators/validateObject.js +0 -95
  43. package/dist/validators/validateString.d.ts +0 -2
  44. package/dist/validators/validateString.js +0 -50
  45. package/dist/validators/validateUnion.d.ts +0 -3
  46. package/dist/validators/validateUnion.js +0 -30
  47. package/src/builders/ArraySchemaBuilder.test.ts +0 -270
  48. package/src/builders/ArraySchemaBuilder.ts +0 -381
  49. package/src/builders/BooleanSchemaBuilder.test.ts +0 -196
  50. package/src/builders/BooleanSchemaBuilder.ts +0 -155
  51. package/src/builders/FunctionSchemaBuilder.test.ts +0 -134
  52. package/src/builders/FunctionSchemaBuilder.ts +0 -109
  53. package/src/builders/NumberSchemaBuilder.test.ts +0 -493
  54. package/src/builders/NumberSchemaBuilder.ts +0 -789
  55. package/src/builders/ObjectSchemaBuilder.test.ts +0 -657
  56. package/src/builders/ObjectSchemaBuilder.ts +0 -794
  57. package/src/builders/SchemaBuilder.test.ts +0 -73
  58. package/src/builders/SchemaBuilder.ts +0 -135
  59. package/src/builders/StringSchemaBuilder.test.ts +0 -318
  60. package/src/builders/StringSchemaBuilder.ts +0 -392
  61. package/src/builders/UnionSchemaBuilder.test.ts +0 -162
  62. package/src/builders/UnionSchemaBuilder.ts +0 -154
  63. package/src/defaultSchemas.ts +0 -44
  64. package/src/index.ts +0 -66
  65. package/src/schema.ts +0 -827
  66. package/src/schemaRegistry.builders.test.ts +0 -1393
  67. package/src/schemaRegistry.test.ts +0 -118
  68. package/src/schemaRegistry.ts +0 -461
  69. package/src/validators/validateArray.ts +0 -76
  70. package/src/validators/validateBoolean.ts +0 -36
  71. package/src/validators/validateFunction.ts +0 -25
  72. package/src/validators/validateNumber.ts +0 -82
  73. package/src/validators/validateObject.ts +0 -119
  74. package/src/validators/validateString.ts +0 -59
  75. package/src/validators/validateUnion.ts +0 -36
  76. package/tsconfig.json +0 -16
@@ -1,1393 +0,0 @@
1
- import { InferType, Schema } from './schema.js';
2
- import { object } from './builders/ObjectSchemaBuilder.js';
3
- import { number } from './builders/NumberSchemaBuilder.js';
4
- import { string } from './builders/StringSchemaBuilder.js';
5
- import { array } from './builders/ArraySchemaBuilder.js';
6
- import { union } from './builders/UnionSchemaBuilder.js';
7
- import { boolean } from './builders/BooleanSchemaBuilder.js';
8
-
9
- import SchemaRegistry from './schemaRegistry.js';
10
-
11
- const getUserSchema = () =>
12
- object({
13
- id: number(),
14
- name: object().addProps({
15
- first: string().minLength(1).maxLength(100),
16
- last: string().minLength(1).maxLength(100)
17
- }),
18
- incomePerMonth: number().min(0),
19
- bornAt: object(),
20
- aliases: array()
21
- });
22
-
23
- test('Can add schema', () => {
24
- const validator = new SchemaRegistry().addSchema(
25
- 'something',
26
- ({ object, string }) =>
27
- object().addProps({
28
- a: string()
29
- })
30
- );
31
- expect(validator.schemas.something).toBeDefined();
32
- });
33
-
34
- test('Error thrown on adding a schema with duplicate name', () => {
35
- expect(() =>
36
- new SchemaRegistry()
37
- .addSchema('smth', {} as any)
38
- .addSchema('smth', {} as any)
39
- ).toThrow();
40
- });
41
-
42
- test('Union - Array as schema type', async () => {
43
- const validator = new SchemaRegistry()
44
- .addSchema('name', ({ object, string }) =>
45
- object().addProps({
46
- name: string()
47
- })
48
- )
49
- .addSchema('number_or_string', ({ number, string, alias, union }) =>
50
- union(number()).or(string()).or(alias('name'))
51
- );
52
-
53
- let result = await validator.schemas.number_or_string.validate(123);
54
-
55
- expect(result).toHaveProperty('valid', true);
56
-
57
- result = await validator.schemas.number_or_string.validate('some string');
58
-
59
- expect(result).toHaveProperty('valid', true);
60
-
61
- result = await validator.schemas.number_or_string.validate({});
62
-
63
- expect(result).toHaveProperty('valid', false);
64
-
65
- result = await validator.schemas.number_or_string.validate({
66
- name: 'some name'
67
- });
68
- expect(result).toHaveProperty('valid', true);
69
- });
70
-
71
- test('Union - Schema Object - 1', async () => {
72
- const validator = new SchemaRegistry().addSchema(
73
- 'address',
74
- ({ object, union, number, string }) =>
75
- object().addProps({
76
- first: union(number().min(10).max(20)).or(string().minLength(2))
77
- })
78
- );
79
-
80
- let result = await validator.schemas.address.validate({
81
- first: 15
82
- });
83
- expect(result).toHaveProperty('valid', true);
84
- result = await validator.schemas.address.validate({
85
- first: 25
86
- });
87
- expect(result).toHaveProperty('valid', false);
88
- result = await validator.schemas.address.validate({
89
- first: 'some string'
90
- });
91
- expect(result).toHaveProperty('valid', true);
92
- result = await validator.schemas.address.validate({
93
- first: 's'
94
- });
95
- expect(result).toHaveProperty('valid', false);
96
- });
97
-
98
- test('Union - Schema Object - 2', async () => {
99
- const validator = new SchemaRegistry().addSchema(
100
- 'address',
101
- ({ object, number, string, union }) =>
102
- object({
103
- first: union(number().min(10).max(20))
104
- .or(string().minLength(2))
105
- .optional()
106
- .nullable()
107
- })
108
- );
109
- let result = await validator.schemas.address.validate({});
110
- expect(result).toHaveProperty('valid', true);
111
- result = await validator.schemas.address.validate({
112
- first: null
113
- });
114
- expect(result).toHaveProperty('valid', true);
115
- });
116
-
117
- test('Validate - number by schema', async () => {
118
- const validator = new SchemaRegistry();
119
- const result = await validator.validate(number(), 10);
120
- expect(result).toHaveProperty('valid', true);
121
- });
122
-
123
- test('Validate - number by schema - not number passed', async () => {
124
- const validator = new SchemaRegistry();
125
- const result = await validator.validate(number(), 'str');
126
- expect(result).toHaveProperty('valid', false);
127
- });
128
-
129
- test('Validate - number by schema - min', async () => {
130
- const validator = new SchemaRegistry();
131
- const result = await validator.validate(number().min(1000), 10);
132
- expect(result).toHaveProperty('valid', false);
133
- });
134
-
135
- test('Validate - number by schema - min 2', async () => {
136
- const validator = new SchemaRegistry();
137
- const result = await validator.validate(number().min(1000), 10000);
138
- expect(result).toEqual({
139
- valid: true
140
- });
141
- });
142
-
143
- test('Validate - number by schema - min 3', async () => {
144
- const validator = new SchemaRegistry();
145
- const result = await validator.validate(number().min(1000), 1000);
146
- expect(result).toHaveProperty('valid', true);
147
- });
148
-
149
- test('Validate - number by schema - min 4', async () => {
150
- const validator = new SchemaRegistry();
151
- const mk = jest.fn();
152
- validator
153
- .validate(number().min('wdd' as any), 10)
154
- .catch(mk)
155
- .then(() => {
156
- expect(mk).toBeCalled();
157
- });
158
- });
159
-
160
- test('Validate - number by schema - max', async () => {
161
- const validator = new SchemaRegistry();
162
- const result = await validator.validate(number().max(1000), 20000);
163
- expect(result).toHaveProperty('valid', false);
164
- });
165
-
166
- test('Validate - number by schema - max 2', async () => {
167
- const validator = new SchemaRegistry();
168
- const result = await validator.validate(number().max(40000), 10000);
169
- expect(result).toHaveProperty('valid', true);
170
- });
171
-
172
- test('Validate - number by schema - max 3', async () => {
173
- const validator = new SchemaRegistry();
174
- const result = await validator.validate(number().max(1000), 1000);
175
- expect(result).toHaveProperty('valid', true);
176
- });
177
-
178
- test('Validate - number by schema - max 4', async () => {
179
- const validator = new SchemaRegistry();
180
- const mk = jest.fn();
181
- validator
182
- .validate(number().max('string' as any), 10)
183
- .catch(mk)
184
- .then(() => {
185
- expect(mk).toBeCalled();
186
- });
187
- });
188
-
189
- test('Validate - number by schema - range', async () => {
190
- const validator = new SchemaRegistry();
191
- const result = await validator.validate(number().min(1).max(100), 10);
192
-
193
- expect(result).toHaveProperty('valid', true);
194
- });
195
-
196
- test('Validate - number by schema - range - 2', async () => {
197
- const validator = new SchemaRegistry();
198
- const result = await validator.validate(number().min(-1).max(100), -210);
199
-
200
- expect(result).toHaveProperty('valid', false);
201
- });
202
-
203
- test('Validate - number by schema - range - 3', async () => {
204
- const validator = new SchemaRegistry();
205
- const result = await validator.validate(number().min(-100).max(100), -100);
206
-
207
- expect(result).toHaveProperty('valid', true);
208
- });
209
-
210
- test('Validate - number by schema - range - 4', async () => {
211
- const validator = new SchemaRegistry();
212
- const result = await validator.validate(number().min(-100).max(100), 100);
213
-
214
- expect(result).toHaveProperty('valid', true);
215
- });
216
-
217
- test('Validate - number by schema - range - 5', async () => {
218
- const validator = new SchemaRegistry();
219
- const result = await validator.validate(number().min(-100).max(100), 200);
220
-
221
- expect(result).toHaveProperty('valid', false);
222
- });
223
-
224
- test('Validate - number by schema - range - 6', async () => {
225
- const validator = new SchemaRegistry();
226
- const result = await validator.validate(number().min(-100).max(100), 200);
227
-
228
- expect(result).toHaveProperty('valid', false);
229
- });
230
-
231
- test('Validate - number by schema - NaN', async () => {
232
- const validator = new SchemaRegistry();
233
- const result = await validator.validate(number().min(-100).max(100), 0 / 0);
234
- expect(result).toHaveProperty('valid', false);
235
- });
236
-
237
- test('Validate - number by schema - NaN - 2', async () => {
238
- const validator = new SchemaRegistry();
239
- const result = await validator.validate(number().canBeNaN(), 0 / 0);
240
-
241
- expect(result).toHaveProperty('valid', true);
242
- });
243
-
244
- test('Validate - number by schema - Infinity', async () => {
245
- const validator = new SchemaRegistry();
246
- const result = await validator.validate(number(), 100 / 0);
247
-
248
- expect(result).toHaveProperty('valid', false);
249
- });
250
-
251
- test('Validate - number by schema - Infinity - 2', async () => {
252
- const validator = new SchemaRegistry();
253
- const result = await validator.validate(number().canBeInfinite(), 100 / 0);
254
-
255
- expect(result).toHaveProperty('valid', true);
256
- });
257
-
258
- test('Validate - number by schema - custom validators - 1', async () => {
259
- const validator = new SchemaRegistry();
260
- const schema = number().addValidator(async (value) => {
261
- if ((value & 0xb01) === 0)
262
- return {
263
- valid: false,
264
- errors: ['value should be odd!']
265
- };
266
- return {
267
- valid: true
268
- };
269
- });
270
- let result = await validator.validate(schema, 101);
271
-
272
- expect(result).toHaveProperty('valid', true);
273
-
274
- result = await validator.validate(schema, 100);
275
- expect(result).toHaveProperty('valid', false);
276
- });
277
-
278
- test('Validate - number by schema - custom validators - 2', async () => {
279
- const validator = new SchemaRegistry();
280
- const schema = number()
281
- .addValidator((value) => {
282
- if ((value & 0xb01) === 0)
283
- return {
284
- valid: false,
285
- errors: ['value should be odd!']
286
- };
287
- return {
288
- valid: true
289
- };
290
- })
291
- .addValidator((value) => ({ valid: value > 100 }));
292
- let result = await validator.validate(schema, 101);
293
-
294
- expect(result).toHaveProperty('valid', true);
295
-
296
- result = await validator.validate(schema, 99);
297
- expect(result).toHaveProperty('valid', false);
298
-
299
- result = await validator.validate(schema, 100);
300
- expect(result).toHaveProperty('valid', false);
301
- });
302
-
303
- test('Validate - boolean - 1', async () => {
304
- const validator = new SchemaRegistry();
305
- const result = await validator.validate(boolean(), 300);
306
-
307
- expect(result).toHaveProperty('valid', false);
308
- });
309
-
310
- test('Validate - boolean - 2', async () => {
311
- const validator = new SchemaRegistry();
312
- const result = await validator.validate(boolean(), true);
313
-
314
- expect(result).toHaveProperty('valid', true);
315
- });
316
-
317
- test('Validate - boolean - 3', async () => {
318
- const validator = new SchemaRegistry();
319
- const result = await validator.validate(boolean(), false);
320
-
321
- expect(result).toHaveProperty('valid', true);
322
- });
323
-
324
- test('Validate - boolean - 4', async () => {
325
- const validator = new SchemaRegistry();
326
- const result = await validator.validate(boolean().equals(true), false);
327
-
328
- expect(result).toHaveProperty('valid', false);
329
- });
330
-
331
- test('Validate - boolean - 5', async () => {
332
- const validator = new SchemaRegistry();
333
- const result = await validator.validate(boolean().equals(false), false);
334
-
335
- expect(result).toHaveProperty('valid', true);
336
- });
337
-
338
- test('Validate - string - schema object - 1', async () => {
339
- const validator = new SchemaRegistry();
340
- const result = await validator.validate(
341
- string().equals('123456'),
342
- '123456'
343
- );
344
- expect(result).toHaveProperty('valid', true);
345
- });
346
-
347
- test('Validate - string - schema object - 2', async () => {
348
- const validator = new SchemaRegistry();
349
- const result = await validator.validate(string().equals('123456'), '12345');
350
- expect(result).toHaveProperty('valid', false);
351
- });
352
-
353
- test('Validate - string - schema object - 3', async () => {
354
- const validator = new SchemaRegistry();
355
- const result = await validator.validate(string().equals('123456'), 1234);
356
- expect(result).toHaveProperty('valid', false);
357
- });
358
-
359
- test('Validate - string - length control - 1', async () => {
360
- const validator = new SchemaRegistry();
361
- let result = await validator.validate(
362
- string().minLength(2).maxLength(3),
363
- 'U'
364
- );
365
- expect(result).toHaveProperty('valid', false);
366
-
367
- result = await validator.validate(string().minLength(2).maxLength(3), 'US');
368
- expect(result).toHaveProperty('valid', true);
369
-
370
- result = await validator.validate(
371
- string().minLength(2).maxLength(3),
372
- 'USA'
373
- );
374
- expect(result).toHaveProperty('valid', true);
375
-
376
- result = await validator.validate(
377
- string().minLength(2).maxLength(3),
378
- 'USA'
379
- );
380
- expect(result).toHaveProperty('valid', true);
381
-
382
- result = await validator.validate(
383
- string().minLength(2).maxLength(3),
384
- 'United States of America'
385
- );
386
- expect(result).toHaveProperty('valid', false);
387
- });
388
-
389
- test('Validate - array - size control - 1', async () => {
390
- const validator = new SchemaRegistry();
391
- let result = await validator.validate(
392
- array().minLength(1).maxLength(3),
393
- []
394
- );
395
- expect(result).toHaveProperty('valid', false);
396
-
397
- result = await validator.validate(array().minLength(1).maxLength(3), [1]);
398
- expect(result).toHaveProperty('valid', true);
399
-
400
- result = await validator.validate(
401
- array().minLength(1).maxLength(3),
402
- [1, 2]
403
- );
404
- expect(result).toHaveProperty('valid', true);
405
-
406
- result = await validator.validate(
407
- array().minLength(1).maxLength(3),
408
- [1, 2, 3]
409
- );
410
- expect(result).toHaveProperty('valid', true);
411
-
412
- result = await validator.validate(
413
- array().minLength(1).maxLength(3),
414
- [1, 2, 3, 4]
415
- );
416
- expect(result).toHaveProperty('valid', false);
417
- });
418
-
419
- test('Validate - array - ofType - 1', async () => {
420
- const validator = new SchemaRegistry();
421
- let result = await validator.validate(array().ofType(number()), [
422
- '1',
423
- 2,
424
- 3
425
- ]);
426
- expect(result).toHaveProperty('valid', false);
427
-
428
- result = await validator.validate(array().ofType(number()), [1, 2, 3]);
429
- expect(result).toHaveProperty('valid', true);
430
-
431
- result = await validator.validate(
432
- array().ofType(number().min(10)),
433
- [-1, 12, 13]
434
- );
435
- expect(result).toHaveProperty('valid', false);
436
- });
437
-
438
- test('Validate - object - 1', async () => {
439
- const validator = new SchemaRegistry().addSchema('user', getUserSchema());
440
- const schema = getUserSchema();
441
- type User = InferType<typeof schema>;
442
- const user: User = {
443
- id: 1,
444
- name: {
445
- first: 'Andrew',
446
- last: 'Zolotukhin'
447
- },
448
- bornAt: new Date(1986, 4, 30),
449
- incomePerMonth: 134234,
450
- aliases: []
451
- };
452
-
453
- let result = await validator.validate('user', user);
454
-
455
- expect(result).toHaveProperty('valid', true);
456
-
457
- result = await validator.validate('user', 10);
458
-
459
- expect(result).toHaveProperty('valid', false);
460
-
461
- result = await validator.validate(
462
- object({
463
- name: string().maxLength(5),
464
- address: object({
465
- street: string(),
466
- house: number().optional()
467
- })
468
- }),
469
- {
470
- name: 'Andr',
471
- address: {
472
- street: 'something'
473
- }
474
- }
475
- );
476
-
477
- expect(result).toHaveProperty('valid', true);
478
-
479
- result = await validator.validate(
480
- object({
481
- a: number(),
482
- b: number()
483
- }).addValidator((value: { a: number; b: number }) => {
484
- if (value.a + value.b === 5) {
485
- return {
486
- valid: true
487
- };
488
- }
489
- return {
490
- valid: false,
491
- error: ['some error']
492
- };
493
- }),
494
- {
495
- a: 1,
496
- b: 3
497
- }
498
- );
499
- expect(result).toHaveProperty('valid', false);
500
- });
501
-
502
- test('Validate - one of - 1', async () => {
503
- const validator = new SchemaRegistry();
504
-
505
- let result = await validator.validate(
506
- union(number()).or(object()),
507
- 'something'
508
- );
509
- expect(result).toHaveProperty('valid', false);
510
-
511
- result = await validator.validate(
512
- union(number()).or(string()),
513
- 'something'
514
- );
515
- expect(result).toHaveProperty('valid', true);
516
-
517
- result = await validator.validate(
518
- union(number())
519
- .or(string())
520
- .or(
521
- object({
522
- first: string(),
523
- last: string()
524
- })
525
- ),
526
- {
527
- first: 'something',
528
- last: 'another'
529
- }
530
- );
531
- expect(result).toHaveProperty('valid', true);
532
- });
533
-
534
- test('Validate schema - 1', async () => {
535
- const validator = new SchemaRegistry()
536
- .addSchema(
537
- 'EqualsFilterCondition',
538
- ({ object, number, string, union }) =>
539
- object({
540
- operation: string().equals('equals'),
541
- value: union(object()).or(string()).or(number())
542
- })
543
- )
544
- .addSchema('LikeFilterCondition', ({ object, string }) =>
545
- object({
546
- operation: string().equals('like'),
547
- value: string()
548
- })
549
- )
550
- .addSchema('StringFilterCondition', ({ union, alias }) =>
551
- union(alias('EqualsFilterCondition')).or(
552
- alias('LikeFilterCondition')
553
- )
554
- )
555
- .addSchema('AuthorFilter', ({ alias, object }) =>
556
- object({
557
- fullName: alias('StringFilterCondition')
558
- })
559
- )
560
- .addSchema('Date', ({ object }) =>
561
- object().addValidator((value) =>
562
- value instanceof Date && !Number.isNaN(value)
563
- ? {
564
- valid: true
565
- }
566
- : {
567
- valid: false,
568
- errors: ['should be a valid Date object']
569
- }
570
- )
571
- )
572
- .addSchema(
573
- 'AuthorsReportSpecification',
574
- ({ object, string, alias, union }) =>
575
- object({
576
- type: string().equals('author'),
577
- start: alias('Date'),
578
- end: alias('Date'),
579
- selectionStart: alias('Date'),
580
- selectionEnd: alias('Date'),
581
- granularity: union(string().equals('day'))
582
- .or(string().equals('week'))
583
- .or(string().equals('month')),
584
- metrics: array().ofType(
585
- union(string().equals('articlesPublished'))
586
- .or(string().equals('searchReferrers'))
587
- .or(string().equals('socialReferrers'))
588
- .or(string().equals('views'))
589
- .or(string().equals('visitors'))
590
- .or(string().equals('newVisitors'))
591
- ),
592
- filters: object({
593
- author: alias('AuthorFilter')
594
- })
595
- }).addValidator((value) =>
596
- value.start <= value.end &&
597
- value.selectionStart <= value.selectionEnd &&
598
- value.selectionStart >= value.start &&
599
- value.selectionStart <= value.end &&
600
- value.selectionEnd >= value.start &&
601
- value.selectionEnd <= value.end
602
- ? {
603
- valid: true
604
- }
605
- : {
606
- valid: false,
607
- errors: [
608
- 'selectionStart <=> selectionEnd should be inside the start <=> end interval'
609
- ]
610
- }
611
- )
612
- );
613
-
614
- let reportSpec = {
615
- type: 'author',
616
- start: new Date(2021, 0, 1),
617
- end: new Date(),
618
- selectionStart: new Date(2022, 0, 1),
619
- selectionEnd: new Date(2022, 2, 1),
620
- granularity: 'day',
621
- metrics: [
622
- 'articlesPublished',
623
- 'searchReferrers',
624
- 'socialReferrers',
625
- 'views',
626
- 'visitors',
627
- 'newVisitors'
628
- ],
629
- filters: {
630
- author: {
631
- fullName: {
632
- operation: 'between',
633
- value: 'some name'
634
- }
635
- }
636
- }
637
- };
638
-
639
- let result = await validator.schemas.AuthorsReportSpecification.validate(
640
- reportSpec
641
- );
642
-
643
- expect(result).toHaveProperty('valid', false);
644
-
645
- reportSpec = {
646
- type: 'author',
647
- start: new Date(2021, 0, 1),
648
- end: new Date(),
649
- selectionStart: new Date(2022, 0, 1),
650
- selectionEnd: new Date(2022, 2, 1),
651
- granularity: 'day',
652
- metrics: [
653
- 'articlesPublished',
654
- 'searchReferrers',
655
- 'socialReferrers',
656
- 'views',
657
- 'visitors',
658
- 'newVisitors'
659
- ],
660
- filters: {
661
- author: {
662
- fullName: {
663
- operation: 'equals',
664
- value: 'some name'
665
- }
666
- }
667
- }
668
- };
669
-
670
- result = await validator.schemas.AuthorsReportSpecification.validate(
671
- reportSpec
672
- );
673
-
674
- expect(result).toHaveProperty('valid', true);
675
- });
676
-
677
- test('Validate schema - 2', async () => {
678
- const validator = new SchemaRegistry()
679
- .addSchema('Date', ({ object }) =>
680
- object().addValidator((value) =>
681
- value instanceof Date && !Number.isNaN(value)
682
- ? {
683
- valid: true
684
- }
685
- : {
686
- valid: false,
687
- errors: ['should be a valid Date object']
688
- }
689
- )
690
- )
691
- .addSchema('Module.Schema1', ({ object, string }) =>
692
- object({
693
- a: string()
694
- })
695
- )
696
- .addSchema('Module.Schema2', ({ object, number }) =>
697
- object({
698
- b: number()
699
- })
700
- );
701
-
702
- const result = await validator.validate(
703
- object({
704
- date: validator.schemas.Date.schema.optional()
705
- }),
706
- {}
707
- );
708
-
709
- expect(result).toHaveProperty('valid', true);
710
- });
711
-
712
- test('Preprocessors - 1', async () => {
713
- const validator = new SchemaRegistry().addSchema(
714
- 'Date',
715
- object().addValidator((value) =>
716
- value instanceof Date && !Number.isNaN(value)
717
- ? {
718
- valid: true
719
- }
720
- : {
721
- valid: false,
722
- errors: ['should be a valid Date object']
723
- }
724
- )
725
- );
726
-
727
- const schema = object({
728
- bornAt: validator.schemas.Date.schema
729
- }).setPropPreprocessor('bornAt', (value: any): Date | undefined => {
730
- const time = Date.parse((value as Record<string, unknown>).toString());
731
- if (Number.isNaN(time)) return undefined;
732
- return new Date(time);
733
- });
734
- const result = await validator.validate(schema as Schema, {
735
- bornAt: new Date().toJSON()
736
- });
737
- expect(result).toHaveProperty('valid', true);
738
- });
739
-
740
- test('Preprocessors - 2', async () => {
741
- const validator = new SchemaRegistry().addSchema(
742
- 'Date',
743
- object().addValidator((value) =>
744
- value instanceof Date && !Number.isNaN(value)
745
- ? {
746
- valid: true
747
- }
748
- : {
749
- valid: false,
750
- errors: ['should be a valid Date object']
751
- }
752
- )
753
- );
754
-
755
- let schema = object({
756
- bornAt: validator.schemas.Date.schema
757
- }).setPropPreprocessor('bornAt', 'StringToDate');
758
-
759
- validator.addPreprocessor(
760
- 'StringToDate',
761
- (value: unknown): Date | undefined => {
762
- const time = Date.parse(
763
- (value as Record<string, unknown>).toString()
764
- );
765
- if (Number.isNaN(time)) return undefined;
766
- return new Date(time);
767
- }
768
- );
769
-
770
- expect(() =>
771
- validator.addPreprocessor(
772
- 'StringToDate',
773
- (value: unknown): Date | undefined => {
774
- const time = Date.parse(
775
- (value as Record<string, unknown>).toString()
776
- );
777
- if (Number.isNaN(time)) return undefined;
778
- return new Date(time);
779
- }
780
- )
781
- ).toThrow();
782
-
783
- const result = await validator.validate(schema as Schema, {
784
- bornAt: new Date().toJSON()
785
- });
786
- expect(result).toHaveProperty('valid', true);
787
-
788
- schema = object({
789
- bornAt: validator.schemas.Date.schema,
790
- diedAt: validator.schemas.Date.schema
791
- })
792
- .setPropPreprocessor('bornAt', 'StringToDate')
793
- .setPropPreprocessor('diedAt', 'Unregistered') as any;
794
-
795
- expect(async () => {
796
- await validator.validate(schema as Schema, {
797
- bornAt: new Date().toJSON()
798
- });
799
- }).rejects.toBeInstanceOf(Error);
800
- });
801
-
802
- test('Preprocessors - 3', async () => {
803
- const validator = new SchemaRegistry().addSchema('Date', ({ object }) =>
804
- object().addValidator((value: any) =>
805
- value instanceof Date && !Number.isNaN(value)
806
- ? {
807
- valid: true
808
- }
809
- : {
810
- valid: false,
811
- errors: ['should be a valid Date object']
812
- }
813
- )
814
- );
815
- validator.addPreprocessor(
816
- 'StringToDate',
817
- (value: unknown): Date | undefined => {
818
- const time = Date.parse(
819
- (value as Record<string, unknown>).toString()
820
- );
821
- if (Number.isNaN(time)) return undefined;
822
- return new Date(time);
823
- }
824
- );
825
-
826
- let obj = [new Date().toJSON()];
827
-
828
- let result = await validator.validate(
829
- array()
830
- .ofType(validator.schemas.Date.schema)
831
- .addPreprocessor('StringToDate'),
832
- obj
833
- );
834
- expect(result).toHaveProperty('valid', true);
835
-
836
- obj = [new Date().toJSON()];
837
- result = await validator.validate(
838
- array()
839
- .ofType(validator.schemas.Date.schema)
840
- .addPreprocessor((value: unknown): Date | undefined => {
841
- const time = Date.parse(
842
- (value as Record<string, unknown>).toString()
843
- );
844
- if (Number.isNaN(time)) return undefined;
845
- return new Date(time);
846
- }),
847
- obj
848
- );
849
- expect(result).toHaveProperty('valid', true);
850
-
851
- obj = ['sdfsdf12', new Date().toJSON()];
852
- result = await validator.validate(
853
- array()
854
- .ofType(validator.schemas.Date.schema)
855
- .addPreprocessor((value: unknown): Date | undefined => {
856
- const time = Date.parse(
857
- (value as Record<string, unknown>).toString()
858
- );
859
- if (Number.isNaN(time)) return undefined;
860
- return new Date(time);
861
- }),
862
- obj
863
- );
864
- expect(result).toHaveProperty('valid', false);
865
- });
866
-
867
- test('Preprocessors - 3', async () => {
868
- const validator = new SchemaRegistry();
869
-
870
- type SomeType = { age: number; marriedAt: number };
871
-
872
- const schema = object({
873
- age: number(),
874
- marriedAt: number()
875
- })
876
- .setPropPreprocessor('age', (): number => 40)
877
- .setPropPreprocessor('*', (value: SomeType): void => {
878
- if (value.marriedAt > value.age) {
879
- value.marriedAt = value.age;
880
- }
881
- });
882
-
883
- const obj = {
884
- age: 50,
885
- marriedAt: 80
886
- };
887
- await validator.validate(schema as Schema, obj);
888
- expect(obj).toHaveProperty('marriedAt', 40);
889
- });
890
-
891
- test('Preprocessors - 4', async () => {
892
- const validator = new SchemaRegistry().addSchema('Date', ({ object }) =>
893
- object().addValidator((value: any) =>
894
- value instanceof Date && !Number.isNaN(value)
895
- ? {
896
- valid: true
897
- }
898
- : {
899
- valid: false,
900
- errors: ['should be a valid Date object']
901
- }
902
- )
903
- );
904
-
905
- validator.addPreprocessor(
906
- 'StringToDate',
907
- (value: unknown): Date | undefined => {
908
- const time = Date.parse(
909
- (value as Record<string, unknown>).toString()
910
- );
911
- if (Number.isNaN(time)) return undefined;
912
- return new Date(time);
913
- }
914
- );
915
-
916
- let obj = [new Date().toJSON()];
917
-
918
- let result = await validator.validate(
919
- array()
920
- .ofType(validator.schemas.Date.schema)
921
- .addPreprocessor('StringToDate'),
922
- obj
923
- );
924
- expect(result).toHaveProperty('valid', true);
925
-
926
- obj = [new Date().toJSON()];
927
- result = await validator.validate(
928
- array()
929
- .ofType(validator.schemas.Date.schema)
930
- .addPreprocessor((value: unknown): Date | undefined => {
931
- const time = Date.parse(
932
- (value as Record<string, unknown>).toString()
933
- );
934
- if (Number.isNaN(time)) return undefined;
935
- return new Date(time);
936
- }),
937
- obj
938
- );
939
- expect(result).toHaveProperty('valid', true);
940
-
941
- obj = ['sdfsdf12', new Date().toJSON()];
942
- result = await validator.validate(
943
- array()
944
- .ofType(validator.schemas.Date.schema)
945
- .addPreprocessor((value: unknown): Date | undefined => {
946
- const time = Date.parse(
947
- (value as Record<string, unknown>).toString()
948
- );
949
- if (Number.isNaN(time)) return undefined;
950
- return new Date(time);
951
- }),
952
- obj
953
- );
954
- expect(result).toHaveProperty('valid', false);
955
- });
956
- test('Submodules - 2', async () => {
957
- const validator = new SchemaRegistry()
958
- .addSchema('Module1.Schema1', ({ object }) => object())
959
- .addSchema('Module1.Schema2', ({ object, number }) =>
960
- object({
961
- a: number()
962
- })
963
- );
964
-
965
- const result = validator.schemas;
966
-
967
- expect(result).toHaveProperty('Module1');
968
- expect(result).toHaveProperty('Module1.Schema1');
969
- expect(result).toHaveProperty('Module1.Schema2');
970
-
971
- const result2 = await validator.schemas.Module1.Schema2.validate({
972
- a: 234
973
- });
974
- expect(result2).toHaveProperty('valid', true);
975
- });
976
-
977
- test('Submodules - 3', async () => {
978
- const validator = new SchemaRegistry()
979
- .addSchema('Module1.Schema1', ({ object, number }) =>
980
- object({
981
- b: number()
982
- })
983
- )
984
- .addSchema('Module1.Schema2', ({ object, alias }) =>
985
- object({
986
- a: alias('Module1.Schema1')
987
- })
988
- );
989
-
990
- const result2 = await validator.schemas.Module1.Schema2.validate({
991
- a: {
992
- b: 20
993
- }
994
- });
995
- expect(result2).toHaveProperty('valid', true);
996
- });
997
-
998
- test('Submodules - 4', async () => {
999
- try {
1000
- new SchemaRegistry()
1001
- .addSchema('Module1.Schema1', ({ object, number }) =>
1002
- object({
1003
- b: number()
1004
- })
1005
- )
1006
- .addSchema('Module1.Schema2', ({ object, alias }) =>
1007
- object({
1008
- a: alias('Module1.Schema3' as any)
1009
- })
1010
- );
1011
- } catch (e) {
1012
- expect(e).toBeInstanceOf(Error);
1013
- }
1014
- });
1015
-
1016
- test('No unknown fields - 1', async () => {
1017
- const validator = new SchemaRegistry().addSchema(
1018
- 'Schema1',
1019
- ({ object, number }) =>
1020
- object({
1021
- b: number()
1022
- }).noUnknownProps()
1023
- );
1024
-
1025
- const result = await validator.schemas.Schema1.validate({
1026
- b: 20,
1027
- c: 'something'
1028
- });
1029
- expect(result).toHaveProperty('valid', false);
1030
- });
1031
-
1032
- test('No unknown fields - 2', async () => {
1033
- const validator = new SchemaRegistry().addSchema(
1034
- 'Schema1',
1035
- ({ object, number }) =>
1036
- object({
1037
- b: number()
1038
- }).canHaveUnknownProps()
1039
- );
1040
-
1041
- const result = await validator.schemas.Schema1.validate({
1042
- b: 20,
1043
- c: 'something'
1044
- });
1045
- expect(result).toHaveProperty('valid', true);
1046
- });
1047
-
1048
- test('addSchemaFrom - 1', async () => {
1049
- const registry = new SchemaRegistry()
1050
- .addSchema('Person', ({ string, object }) =>
1051
- object({
1052
- first: string(),
1053
- last: string()
1054
- })
1055
- )
1056
- .addSchemaFrom('Person', 'PersonWithEmail', ({ base, string }) =>
1057
- base.addProps({
1058
- email: string()
1059
- })
1060
- );
1061
- expect(
1062
- registry.schemas.Person === registry.schemas.PersonWithEmail
1063
- ).toEqual(false);
1064
- });
1065
-
1066
- test('Object returned - 1', async () => {
1067
- const registry = new SchemaRegistry().addSchema(
1068
- 'Person',
1069
- ({ object, string }) =>
1070
- object({
1071
- first: string(),
1072
- last: string()
1073
- })
1074
- );
1075
- const p = {
1076
- first: 'John',
1077
- last: 'Smith'
1078
- };
1079
- const { valid, object } = await registry.schemas.Person.validate(p);
1080
-
1081
- expect(valid).toEqual(true);
1082
- expect(object === p).toEqual(true);
1083
- });
1084
-
1085
- test('makeAllPropsOptional - 1', async () => {
1086
- const registry = new SchemaRegistry().addSchema(
1087
- 'Schema1',
1088
- ({ object, number }) =>
1089
- object({
1090
- id: number(),
1091
- first: number(),
1092
- second: number()
1093
- })
1094
- .makeAllPropsOptional()
1095
- .makePropRequired('id')
1096
- );
1097
-
1098
- const { valid } = await registry.schemas.Schema1.validate({
1099
- id: 123
1100
- });
1101
-
1102
- const { valid: valid2 } = await registry.schemas.Schema1.validate({});
1103
-
1104
- expect(valid).toEqual(true);
1105
- expect(valid2).toEqual(false);
1106
- });
1107
-
1108
- test('no unknown props allowed by default', async () => {
1109
- const registry = new SchemaRegistry().addSchema(
1110
- 'User',
1111
- ({ object, string }) =>
1112
- object({
1113
- firstName: string(),
1114
- lastName: string()
1115
- })
1116
- );
1117
-
1118
- const { valid } = await registry.schemas.User.validate({
1119
- firstName: 'John',
1120
- lastName: 'Smith',
1121
- age: 20
1122
- });
1123
-
1124
- expect(valid).toEqual(false);
1125
-
1126
- const registry2 = registry.addSchemaFrom('User', 'UserOpen', ({ base }) =>
1127
- base.canHaveUnknownProps()
1128
- );
1129
-
1130
- const { valid: valid2 } = await registry2.schemas.UserOpen.validate({
1131
- firstName: 'John',
1132
- lastName: 'Smith',
1133
- age: 20
1134
- });
1135
-
1136
- expect(valid2).toEqual(true);
1137
- });
1138
-
1139
- test('Func - 1', async () => {
1140
- const validator = new SchemaRegistry().addSchema('something', ({ func }) =>
1141
- func()
1142
- );
1143
- expect(validator.schemas.something).toBeDefined();
1144
- expect(await validator.schemas.something.validate(123)).toHaveProperty(
1145
- 'valid',
1146
- false
1147
- );
1148
- expect(await validator.schemas.something.validate(() => 10)).toHaveProperty(
1149
- 'valid',
1150
- true
1151
- );
1152
- });
1153
-
1154
- test('Func - 2', async () => {
1155
- const validator = new SchemaRegistry().addSchema(
1156
- 'something',
1157
- ({ func, string, object }) =>
1158
- object({
1159
- name: string(),
1160
- f: func()
1161
- })
1162
- );
1163
- expect(
1164
- await validator.schemas.something.validate({
1165
- name: '123',
1166
- f: 324
1167
- })
1168
- ).toHaveProperty('valid', false);
1169
- expect(
1170
- await validator.schemas.something.validate({
1171
- name: '1234',
1172
- f: () => 10
1173
- })
1174
- ).toHaveProperty('valid', true);
1175
- });
1176
-
1177
- test('Func - 3', async () => {
1178
- const validator = new SchemaRegistry().addSchema(
1179
- 'something',
1180
- ({ func, string, object }) =>
1181
- object({
1182
- name: string(),
1183
- f: func().optional()
1184
- })
1185
- );
1186
-
1187
- expect(
1188
- await validator.schemas.something.validate({
1189
- name: '123',
1190
- f: 324
1191
- })
1192
- ).toHaveProperty('valid', false);
1193
- expect(
1194
- await validator.schemas.something.validate({
1195
- name: '1234'
1196
- })
1197
- ).toHaveProperty('valid', true);
1198
- });
1199
-
1200
- test('Func - 3', async () => {
1201
- const validator = new SchemaRegistry().addSchema(
1202
- 'something',
1203
- ({ func, string, object, union }) =>
1204
- object({
1205
- name: string(),
1206
- f: union(func(), object().canHaveUnknownProps()).optional()
1207
- })
1208
- );
1209
-
1210
- expect(
1211
- await validator.schemas.something.validate({
1212
- name: '123',
1213
- f: 324
1214
- })
1215
- ).toHaveProperty('valid', false);
1216
- expect(
1217
- await validator.schemas.something.validate({
1218
- name: '1234'
1219
- })
1220
- ).toHaveProperty('valid', true);
1221
- expect(
1222
- await validator.schemas.something.validate({
1223
- name: '1234',
1224
- f: { a: 34 }
1225
- })
1226
- ).toHaveProperty('valid', true);
1227
- expect(
1228
- await validator.schemas.something.validate({
1229
- name: '1234',
1230
- f: () => 20
1231
- })
1232
- ).toHaveProperty('valid', true);
1233
- expect(
1234
- await validator.schemas.something.validate({
1235
- name: '1234',
1236
- f: '2345'
1237
- })
1238
- ).toHaveProperty('valid', false);
1239
- });
1240
-
1241
- test('External Schema - 1', async () => {
1242
- const validator1 = new SchemaRegistry().addSchema(
1243
- 'person',
1244
- ({ object, number }) =>
1245
- object({
1246
- age: number().min(0),
1247
- marriedAt: number().min(18)
1248
- })
1249
- );
1250
-
1251
- const validator2 = new SchemaRegistry().addSchema(
1252
- 'company',
1253
- ({ object, string }) =>
1254
- object({
1255
- name: string(),
1256
- director: validator1.schemas.person.schema.optional()
1257
- })
1258
- );
1259
-
1260
- const result = await validator2.schemas.company.validate({
1261
- name: 'Some',
1262
- director: {
1263
- age: 40,
1264
- marriedAt: 22
1265
- }
1266
- });
1267
-
1268
- expect(result).toHaveProperty('valid', true);
1269
-
1270
- const result2 = await validator2.schemas.company.validate({
1271
- name: 'Some',
1272
- director: {
1273
- age: -10,
1274
- marriedAt: 22
1275
- }
1276
- });
1277
-
1278
- expect(result2).toHaveProperty('valid', false);
1279
- });
1280
-
1281
- test('External Schema - 2', async () => {
1282
- const validator1 = new SchemaRegistry()
1283
- .addSchema('address', ({ object, string }) =>
1284
- object({
1285
- city: string(),
1286
- street: string().addValidator((v) => ({ valid: v.length > 0 }))
1287
- }).addValidator((val) => ({ valid: val.city.length > 0 }))
1288
- )
1289
- .addSchema('person', ({ object, number, alias }) =>
1290
- object({
1291
- age: number().min(0),
1292
- marriedAt: number()
1293
- .min(18)
1294
- .addValidator((v) => ({ valid: v > 10 })),
1295
- address: alias('address')
1296
- }).addValidator((val) => ({ valid: val.marriedAt < val.age }))
1297
- );
1298
-
1299
- const validator2 = new SchemaRegistry().addSchema(
1300
- 'company',
1301
- ({ object, string, external }) =>
1302
- object({
1303
- name: string().addValidator(() => ({ valid: true })),
1304
- director: external(validator1, 'person')
1305
- }).addValidator(() => ({ valid: true }))
1306
- );
1307
-
1308
- const result = await validator2.schemas.company.validate({
1309
- name: 'Some',
1310
- director: {
1311
- age: 40,
1312
- marriedAt: 22,
1313
- address: {
1314
- city: 'City upon a Hill',
1315
- street: '123 Blossom street'
1316
- }
1317
- }
1318
- });
1319
-
1320
- expect(result).toHaveProperty('valid', true);
1321
-
1322
- const result2 = await validator2.schemas.company.validate({
1323
- name: 'Some',
1324
- director: {
1325
- age: -10,
1326
- marriedAt: 22,
1327
- address: {
1328
- city: 'City upon a Hill',
1329
- street: '123 Blossom street'
1330
- }
1331
- }
1332
- });
1333
-
1334
- expect(result2).toHaveProperty('valid', false);
1335
- });
1336
-
1337
- test('Empty Validators Bug', async () => {
1338
- const isValidEmail = (s) => {
1339
- if (typeof s !== 'string') return false;
1340
- const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,8}$/;
1341
- return regex.test(s);
1342
- };
1343
- const validator = new SchemaRegistry().addSchema(
1344
- 'Report',
1345
- ({ object, array, string }) =>
1346
- object({
1347
- recepients: array()
1348
- .ofType(
1349
- string().addValidator((val) => {
1350
- if (isValidEmail(val)) {
1351
- return { valid: true };
1352
- }
1353
- return {
1354
- valid: false,
1355
- errors: [`${val} is not a valid email`]
1356
- };
1357
- })
1358
- )
1359
- .addValidator((val) => {
1360
- if (!Array.isArray(val)) {
1361
- return {
1362
- valid: false,
1363
- errors: ['not an array']
1364
- };
1365
- }
1366
- const map = {};
1367
- const lowerCased = val.map((v) => v.toLowerCase());
1368
- for (let i = 0; i < lowerCased.length; i++) {
1369
- if (lowerCased[i] in map) {
1370
- return {
1371
- valid: false,
1372
- errors: ['no duplicates allowed']
1373
- };
1374
- }
1375
- map[lowerCased[i]] = true;
1376
- }
1377
- return { valid: true };
1378
- })
1379
- })
1380
- );
1381
-
1382
- const result1 = await validator.schemas.Report.validate({
1383
- recepients: ['user1@domain1.com', 'user2@domain1.com']
1384
- });
1385
-
1386
- expect(result1).toHaveProperty('valid', true);
1387
-
1388
- const result2 = await validator.schemas.Report.validate({
1389
- recepients: ['user1@domain1.com', 'user1@domain1.com']
1390
- });
1391
-
1392
- expect(result2).toHaveProperty('valid', false);
1393
- });