@cleverbrush/schema 0.0.11 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import SchemaValidator from './schemaValidator';
2
- export declare type DefaultSchemaType = 'object' | 'function' | 'number' | 'string' | 'array' | 'alias';
2
+ export declare type DefaultSchemaType = 'object' | 'boolean' | 'function' | 'number' | 'string' | 'array' | 'alias';
3
3
  export declare type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
4
4
  export declare type DefaultPropertyDefinition = {
5
5
  isRequired: boolean;
@@ -24,7 +24,7 @@ export declare type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'>
24
24
  [S in keyof T]: Schema<PropType<T, S>>;
25
25
  }>;
26
26
  preprocessors?: Partial<{
27
- [S in keyof T]: ((value: unknown) => PropType<T, S> | Promise<PropType<T, S>>) | string;
27
+ [S in keyof T | '*']: S extends keyof T ? ((value: unknown) => PropType<T, S> | Promise<PropType<T, S>>) | string : (value: T) => void | Promise<void>;
28
28
  }>;
29
29
  };
30
30
  export declare type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
@@ -39,6 +39,10 @@ export declare type FunctionSchemaDefinition<T extends (...args: any) => any> =
39
39
  type: 'function';
40
40
  params?: ParamsValidators<T>;
41
41
  };
42
+ export declare type BooleanSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
43
+ type: 'boolean';
44
+ equals?: boolean;
45
+ };
42
46
  export declare type NumberSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
43
47
  type: 'number';
44
48
  min?: number;
@@ -61,7 +65,7 @@ export declare type ArraySchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 't
61
65
  minLength?: number;
62
66
  maxLength?: number;
63
67
  };
64
- export declare type CompositeSchema<TObj> = TObj extends (...args: any) => any ? FunctionSchemaDefinition<TObj> : TObj extends number ? NumberSchemaDefinition<TObj> : TObj extends string ? StringSchemaDefinition<TObj> | 'string' : NumberSchemaDefinition<TObj> | StringSchemaDefinition<TObj> | ArraySchemaDefinition<TObj> | ObjectSchemaDefinition<TObj> | AliasSchemaDefinition<TObj>;
68
+ export declare type CompositeSchema<TObj> = TObj extends (...args: any) => any ? FunctionSchemaDefinition<TObj> : TObj extends number ? NumberSchemaDefinition<TObj> : TObj extends string ? StringSchemaDefinition<TObj> | 'string' : BooleanSchemaDefinition<TObj> | NumberSchemaDefinition<TObj> | StringSchemaDefinition<TObj> | ArraySchemaDefinition<TObj> | ObjectSchemaDefinition<TObj> | AliasSchemaDefinition<TObj>;
65
69
  export declare type SingleSchema<TObj = Record<string, never>> = number | string | DefaultSchemaType | CompositeSchema<TObj>;
66
70
  export declare type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
67
71
  export interface ISchemaActions<K, T extends keyof K> {
@@ -13,5 +13,5 @@ export default class SchemaValidator<T = Record<string, never>> implements ISche
13
13
  };
14
14
  private validateDefaultType;
15
15
  private checkValidators;
16
- validate(schema: keyof T | DefaultSchemaType | Schema<any>, obj: any): Promise<ValidationResult>;
16
+ validate<K>(schema: keyof T | DefaultSchemaType | Schema<K>, obj: any): Promise<ValidationResult>;
17
17
  }
@@ -2,10 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const deep_1 = require("@cleverbrush/deep");
4
4
  const validateNumber_1 = require("./validators/validateNumber");
5
+ const validateBoolean_1 = require("./validators/validateBoolean");
5
6
  const validateString_1 = require("./validators/validateString");
6
7
  const validateArray_1 = require("./validators/validateArray");
7
8
  const validateObject_1 = require("./validators/validateObject");
8
- const defaultSchemaNames = ['string', 'number', 'date', 'array'];
9
+ const defaultSchemaNames = ['string', 'boolean', 'number', 'date', 'array'];
9
10
  const defaultSchemas = {
10
11
  number: {
11
12
  type: 'number',
@@ -14,6 +15,11 @@ const defaultSchemas = {
14
15
  ensureNotNaN: true,
15
16
  ensureIsFinite: true
16
17
  },
18
+ boolean: {
19
+ type: 'boolean',
20
+ isRequired: true,
21
+ isNullable: false
22
+ },
17
23
  string: {
18
24
  type: 'string',
19
25
  isNullable: false,
@@ -30,6 +36,7 @@ const defaultSchemas = {
30
36
  };
31
37
  const defaultSchemasValidationStrategies = {
32
38
  number: (obj, schema, validator) => (0, validateNumber_1.validateNumber)(obj, schema, validator),
39
+ boolean: (obj, schema, validator) => (0, validateBoolean_1.validateBoolean)(obj, schema, validator),
33
40
  string: (obj, schema, validator) => (0, validateString_1.validateString)(obj, schema, validator),
34
41
  array: (obj, schema, validator) => (0, validateArray_1.validateArray)(obj, schema, validator)
35
42
  };
@@ -0,0 +1,2 @@
1
+ import { ValidationResult, BooleanSchemaDefinition, ISchemaValidator } from '../index';
2
+ export declare const validateBoolean: (obj: any, schema: BooleanSchemaDefinition<any>, validator: ISchemaValidator<any>) => Promise<ValidationResult>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateBoolean = void 0;
4
+ const validateBoolean = async (obj, schema, validator) => {
5
+ if (typeof obj === 'undefined' &&
6
+ typeof schema === 'object' &&
7
+ schema.isRequired === false) {
8
+ return {
9
+ valid: true
10
+ };
11
+ }
12
+ if (typeof obj !== 'boolean')
13
+ return {
14
+ valid: false,
15
+ errors: [`expected type boolean, but saw ${typeof obj}`]
16
+ };
17
+ if (typeof schema === 'boolean') {
18
+ return { valid: true };
19
+ }
20
+ const bool = obj;
21
+ if (typeof schema.equals === 'boolean') {
22
+ return schema.equals === bool
23
+ ? { valid: true }
24
+ : {
25
+ valid: false,
26
+ errors: [`must be equal to ${schema.equals}`]
27
+ };
28
+ }
29
+ return {
30
+ valid: true
31
+ };
32
+ };
33
+ exports.validateBoolean = validateBoolean;
@@ -19,6 +19,8 @@ const validateObject = async (obj, schema, validator) => {
19
19
  }
20
20
  if (typeof schema.preprocessors === 'object' && schema.preprocessors) {
21
21
  await Promise.all(Object.keys(schema.preprocessors).map(async (key) => {
22
+ if (key === '*')
23
+ return;
22
24
  if (typeof schema.preprocessors[key] === 'function') {
23
25
  obj[key] = await Promise.resolve(schema.preprocessors[key](obj[key]));
24
26
  }
@@ -30,6 +32,19 @@ const validateObject = async (obj, schema, validator) => {
30
32
  obj[key] = await Promise.resolve(preprocessor(obj[key]));
31
33
  }
32
34
  }));
35
+ if ('*' in schema.preprocessors) {
36
+ const objectPreprocessor = schema.preprocessors['*'];
37
+ if (typeof objectPreprocessor === 'function') {
38
+ await Promise.resolve(objectPreprocessor(obj));
39
+ }
40
+ else {
41
+ const preprocessor = validator.preprocessors.get(objectPreprocessor);
42
+ if (typeof preprocessor !== 'function') {
43
+ throw new Error(`preprocessor '${objectPreprocessor}' is unknown`);
44
+ }
45
+ await Promise.resolve(preprocessor(obj));
46
+ }
47
+ }
33
48
  }
34
49
  if (typeof schema.properties === 'object' && schema.properties) {
35
50
  const errors = (await Promise.all(Object.entries(schema.properties).map(async ([name, schema]) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleverbrush/schema",
3
- "version": "0.0.11",
3
+ "version": "0.0.14",
4
4
  "keywords": [
5
5
  "object schema validator",
6
6
  "schema",
@@ -19,7 +19,7 @@
19
19
  "build": "tsc"
20
20
  },
21
21
  "dependencies": {
22
- "@cleverbrush/deep": "0.0.11"
22
+ "@cleverbrush/deep": "0.0.14"
23
23
  },
24
24
  "types": "./dist/index.d.ts"
25
25
  }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import SchemaValidator from './schemaValidator';
2
2
 
3
3
  export type DefaultSchemaType =
4
4
  | 'object'
5
+ | 'boolean'
5
6
  | 'function'
6
7
  | 'number'
7
8
  | 'string'
@@ -40,9 +41,13 @@ export type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
40
41
  [S in keyof T]: Schema<PropType<T, S>>;
41
42
  }>;
42
43
  preprocessors?: Partial<{
43
- [S in keyof T]:
44
- | ((value: unknown) => PropType<T, S> | Promise<PropType<T, S>>)
45
- | string;
44
+ [S in keyof T | '*']: S extends keyof T
45
+ ?
46
+ | ((
47
+ value: unknown
48
+ ) => PropType<T, S> | Promise<PropType<T, S>>)
49
+ | string
50
+ : (value: T) => void | Promise<void>;
46
51
  }>;
47
52
  };
48
53
 
@@ -68,6 +73,14 @@ export type FunctionSchemaDefinition<T extends (...args: any) => any> = Omit<
68
73
  params?: ParamsValidators<T>;
69
74
  };
70
75
 
76
+ export type BooleanSchemaDefinition<TObj> = Omit<
77
+ SchemaDefintion<TObj>,
78
+ 'type'
79
+ > & {
80
+ type: 'boolean';
81
+ equals?: boolean;
82
+ };
83
+
71
84
  export type NumberSchemaDefinition<TObj> = Omit<
72
85
  SchemaDefintion<TObj>,
73
86
  'type'
@@ -109,6 +122,7 @@ export type CompositeSchema<TObj> = TObj extends (...args: any) => any
109
122
  : TObj extends string
110
123
  ? StringSchemaDefinition<TObj> | 'string'
111
124
  :
125
+ | BooleanSchemaDefinition<TObj>
112
126
  | NumberSchemaDefinition<TObj>
113
127
  | StringSchemaDefinition<TObj>
114
128
  | ArraySchemaDefinition<TObj>
@@ -4,6 +4,7 @@ import { ValidationResult } from '../dist/index.js';
4
4
  import {
5
5
  NumberSchemaDefinition,
6
6
  ObjectSchemaDefinitionParam,
7
+ ObjectSchemaDefinition,
7
8
  Schema
8
9
  } from './index';
9
10
  import SchemaValidator from './schemaValidator';
@@ -553,6 +554,82 @@ test('Validate - number by schema - custom validators - 2', async () => {
553
554
  expect(result).toHaveProperty('valid', false);
554
555
  });
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
+
556
633
  test('Validate - string - 1', async () => {
557
634
  const validator = new SchemaValidator();
558
635
  const result = await validator.validate('string', '12345');
@@ -829,7 +906,7 @@ test('Validate - object - 1', async () => {
829
906
  b: 'number'
830
907
  },
831
908
  validators: [
832
- (value) => {
909
+ (value: { a: number; b: number }) => {
833
910
  if (value.a + value.b === 5) {
834
911
  return {
835
912
  valid: true
@@ -1363,3 +1440,96 @@ test('Preprocessors - 3', async () => {
1363
1440
  );
1364
1441
  expect(result).toHaveProperty('valid', false);
1365
1442
  });
1443
+
1444
+ test('Preprocessors - 3', async () => {
1445
+ const validator = new SchemaValidator();
1446
+
1447
+ type SomeType = { age: number; marriedAt: number };
1448
+
1449
+ const schema: ObjectSchemaDefinition<SomeType> = {
1450
+ type: 'object',
1451
+ properties: {
1452
+ age: 'number',
1453
+ marriedAt: 'number'
1454
+ },
1455
+ preprocessors: {
1456
+ age: (value): number => 40,
1457
+ '*': (value: SomeType): void => {
1458
+ if (value.marriedAt > value.age) {
1459
+ value.marriedAt = value.age;
1460
+ }
1461
+ }
1462
+ }
1463
+ };
1464
+
1465
+ const obj = {
1466
+ age: 50,
1467
+ marriedAt: 80
1468
+ };
1469
+ await validator.validate(schema, obj);
1470
+ expect(obj).toHaveProperty('marriedAt', 40);
1471
+ });
1472
+
1473
+ test('Preprocessors - 4', async () => {
1474
+ const validator = new SchemaValidator().addSchemaType('Date', {
1475
+ validators: [
1476
+ (value) =>
1477
+ value instanceof Date && !Number.isNaN(value)
1478
+ ? {
1479
+ valid: true
1480
+ }
1481
+ : {
1482
+ valid: false,
1483
+ errors: ['should be a valid Date object']
1484
+ }
1485
+ ]
1486
+ });
1487
+
1488
+ validator.addPreprocessor('StringToDate', (value: unknown): Date => {
1489
+ const time = Date.parse(value.toString());
1490
+ if (Number.isNaN(time)) return undefined;
1491
+ return new Date(time);
1492
+ });
1493
+
1494
+ let obj = [new Date().toJSON()];
1495
+
1496
+ let result = await validator.validate(
1497
+ {
1498
+ preprocessor: 'StringToDate',
1499
+ type: 'array',
1500
+ ofType: 'Date'
1501
+ },
1502
+ obj
1503
+ );
1504
+ expect(result).toHaveProperty('valid', true);
1505
+
1506
+ obj = [new Date().toJSON()];
1507
+ result = await validator.validate(
1508
+ {
1509
+ preprocessor: (value: unknown): Date => {
1510
+ const time = Date.parse(value.toString());
1511
+ if (Number.isNaN(time)) return undefined;
1512
+ return new Date(time);
1513
+ },
1514
+ type: 'array',
1515
+ ofType: 'Date'
1516
+ },
1517
+ obj
1518
+ );
1519
+ expect(result).toHaveProperty('valid', true);
1520
+
1521
+ obj = ['sdfsdf12', new Date().toJSON()];
1522
+ result = await validator.validate(
1523
+ {
1524
+ preprocessor: (value: unknown): Date => {
1525
+ const time = Date.parse(value.toString());
1526
+ if (Number.isNaN(time)) return undefined;
1527
+ return new Date(time);
1528
+ },
1529
+ type: 'array',
1530
+ ofType: 'Date'
1531
+ },
1532
+ obj
1533
+ );
1534
+ expect(result).toHaveProperty('valid', false);
1535
+ });
@@ -12,14 +12,16 @@ import {
12
12
  ArraySchemaDefinition,
13
13
  ISchemaValidator,
14
14
  DefaultSchemaType,
15
- ObjectSchemaDefinition
15
+ ObjectSchemaDefinition,
16
+ BooleanSchemaDefinition
16
17
  } from './index';
17
18
  import { validateNumber } from './validators/validateNumber';
19
+ import { validateBoolean } from './validators/validateBoolean';
18
20
  import { validateString } from './validators/validateString';
19
21
  import { validateArray } from './validators/validateArray';
20
22
  import { validateObject } from './validators/validateObject';
21
23
 
22
- const defaultSchemaNames = ['string', 'number', 'date', 'array'];
24
+ const defaultSchemaNames = ['string', 'boolean', 'number', 'date', 'array'];
23
25
 
24
26
  const defaultSchemas: { [key in DefaultSchemaType]?: Schema<any> } = {
25
27
  number: {
@@ -29,6 +31,11 @@ const defaultSchemas: { [key in DefaultSchemaType]?: Schema<any> } = {
29
31
  ensureNotNaN: true,
30
32
  ensureIsFinite: true
31
33
  },
34
+ boolean: {
35
+ type: 'boolean',
36
+ isRequired: true,
37
+ isNullable: false
38
+ },
32
39
  string: {
33
40
  type: 'string',
34
41
  isNullable: false,
@@ -50,6 +57,11 @@ const defaultSchemasValidationStrategies = {
50
57
  schema: NumberSchemaDefinition<any>,
51
58
  validator: ISchemaValidator<any>
52
59
  ): Promise<ValidationResult> => validateNumber(obj, schema, validator),
60
+ boolean: (
61
+ obj: any,
62
+ schema: BooleanSchemaDefinition<any>,
63
+ validator: ISchemaValidator<any>
64
+ ): Promise<ValidationResult> => validateBoolean(obj, schema, validator),
53
65
  string: (
54
66
  obj: any,
55
67
  schema: StringSchemaDefinition<any>,
@@ -213,8 +225,8 @@ export default class SchemaValidator<T = Record<string, never>>
213
225
  };
214
226
  }
215
227
 
216
- public async validate(
217
- schema: keyof T | DefaultSchemaType | Schema<any>,
228
+ public async validate<K>(
229
+ schema: keyof T | DefaultSchemaType | Schema<K>,
218
230
  obj: any
219
231
  ): Promise<ValidationResult> {
220
232
  if (!schema) throw new Error('schemaName is required');
@@ -293,7 +305,7 @@ export default class SchemaValidator<T = Record<string, never>>
293
305
  'it is only possible to use a full schema schema definition as alias'
294
306
  );
295
307
 
296
- const schemaToMerge = { ...schema };
308
+ const schemaToMerge = { ...(schema as any) };
297
309
  delete schemaToMerge.type;
298
310
  delete schemaToMerge.schemaName;
299
311
  const finalSchema: Schema<any> = deepExtend(
@@ -0,0 +1,45 @@
1
+ import {
2
+ ValidationResult,
3
+ BooleanSchemaDefinition,
4
+ ISchemaValidator
5
+ } from '../index';
6
+
7
+ export const validateBoolean = async (
8
+ obj: any,
9
+ schema: BooleanSchemaDefinition<any>,
10
+ validator: ISchemaValidator<any>
11
+ ): Promise<ValidationResult> => {
12
+ if (
13
+ typeof obj === 'undefined' &&
14
+ typeof schema === 'object' &&
15
+ schema.isRequired === false
16
+ ) {
17
+ return {
18
+ valid: true
19
+ };
20
+ }
21
+ if (typeof obj !== 'boolean')
22
+ return {
23
+ valid: false,
24
+ errors: [`expected type boolean, but saw ${typeof obj}`]
25
+ };
26
+
27
+ if (typeof schema === 'boolean') {
28
+ return { valid: true };
29
+ }
30
+
31
+ const bool = obj as boolean;
32
+
33
+ if (typeof schema.equals === 'boolean') {
34
+ return schema.equals === bool
35
+ ? { valid: true }
36
+ : {
37
+ valid: false,
38
+ errors: [`must be equal to ${schema.equals}`]
39
+ };
40
+ }
41
+
42
+ return {
43
+ valid: true
44
+ };
45
+ };
@@ -31,6 +31,7 @@ export const validateObject = async (
31
31
  if (typeof schema.preprocessors === 'object' && schema.preprocessors) {
32
32
  await Promise.all(
33
33
  Object.keys(schema.preprocessors).map(async (key: string) => {
34
+ if (key === '*') return;
34
35
  if (typeof schema.preprocessors[key] === 'function') {
35
36
  obj[key] = await Promise.resolve(
36
37
  (schema.preprocessors[key] as (unknown) => unknown)(
@@ -50,6 +51,24 @@ export const validateObject = async (
50
51
  }
51
52
  })
52
53
  );
54
+ if ('*' in schema.preprocessors) {
55
+ const objectPreprocessor = schema.preprocessors['*'];
56
+ if (typeof objectPreprocessor === 'function') {
57
+ await Promise.resolve(
58
+ (objectPreprocessor as (unknown) => unknown)(obj)
59
+ );
60
+ } else {
61
+ const preprocessor = validator.preprocessors.get(
62
+ objectPreprocessor as string
63
+ );
64
+ if (typeof preprocessor !== 'function') {
65
+ throw new Error(
66
+ `preprocessor '${objectPreprocessor}' is unknown`
67
+ );
68
+ }
69
+ await Promise.resolve(preprocessor(obj));
70
+ }
71
+ }
53
72
  }
54
73
 
55
74
  if (typeof schema.properties === 'object' && schema.properties) {