knight-validation 4.0.0 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,8 @@
1
1
  import { Misfit } from 'knight-misfit';
2
2
  import { Constraint } from './Constraint';
3
+ export interface ValidatorMap {
4
+ [validatorId: string]: Validator;
5
+ }
3
6
  export interface ValidatorOptions {
4
7
  checkOnlyWhatIsThere?: boolean;
5
8
  exclude?: string[];
@@ -10,13 +13,18 @@ export interface ValidatorEntry<T = any> {
10
13
  validator?: Validator;
11
14
  condition?: (object: T) => Promise<boolean>;
12
15
  }
13
- declare abstract class ValidatorFactory<T = any> {
14
- abstract create(): Validator<T>;
16
+ export declare class ValidatorFactory<T = any> {
17
+ validatorId: string;
18
+ createFn: (validators: ValidatorMap) => Validator<T>;
19
+ constructor(validatorId: string | (new (...args: any[]) => any), createFn: (validators: ValidatorMap) => Validator<T>);
20
+ createOrGetExisting(validators: ValidatorMap): Validator<T>;
15
21
  }
16
22
  export declare class Validator<T = any> {
23
+ validatorId: string;
17
24
  options?: ValidatorOptions;
25
+ validators: ValidatorMap;
18
26
  entries: ValidatorEntry<T>[];
19
- constructor(options?: ValidatorOptions);
27
+ constructor(validators?: ValidatorMap, options?: ValidatorOptions, validatorId?: string | (new (...args: any[]) => any));
20
28
  add(constraint: Constraint, condition?: (object: T) => Promise<boolean>): void;
21
29
  add(constraintName: string, validate: (value: any) => Promise<Misfit | null>, condition?: (object: T) => Promise<boolean>): void;
22
30
  add(validatorFactory: ValidatorFactory): void;
@@ -26,6 +34,5 @@ export declare class Validator<T = any> {
26
34
  add(properties: string[], constraint: Constraint, condition?: (object: T) => Promise<boolean>): void;
27
35
  add(properties: string[], constraintName: string, validate: (object: T, properties: string[]) => Promise<Misfit | null>, condition?: (object: T) => Promise<boolean>): void;
28
36
  add(validatorEntry: ValidatorEntry): void;
29
- validate(object: T, options?: ValidatorOptions): Promise<Misfit[]>;
37
+ validate(object: T, options?: ValidatorOptions, validated?: WeakSet<any>): Promise<Misfit[]>;
30
38
  }
31
- export {};
@@ -9,18 +9,45 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.Validator = void 0;
12
+ exports.Validator = exports.ValidatorFactory = void 0;
13
13
  const knight_log_1 = require("knight-log");
14
14
  const Constraint_1 = require("./Constraint");
15
15
  const DotNotation_1 = require("./DotNotation");
16
16
  const QuickConstraint_1 = require("./constraints/QuickConstraint");
17
17
  let log = new knight_log_1.Log('knight-validation/Validator.ts');
18
18
  class ValidatorFactory {
19
+ constructor(validatorId, createFn) {
20
+ this.validatorId = typeof validatorId == 'string' ? validatorId : validatorId.name;
21
+ this.createFn = createFn;
22
+ }
23
+ createOrGetExisting(validators) {
24
+ let l = log.cls('ValidatorFactory', 'createOrGetExisting');
25
+ l.param('validators', validators);
26
+ l.creator('this.validatorId', this.validatorId);
27
+ if (this.validatorId in validators) {
28
+ l.returning('existing validator', validators[this.validatorId]);
29
+ return validators[this.validatorId];
30
+ }
31
+ l.returning('created validator');
32
+ return this.createFn(validators);
33
+ }
19
34
  }
35
+ exports.ValidatorFactory = ValidatorFactory;
20
36
  class Validator {
21
- constructor(options) {
37
+ constructor(validators, options, validatorId) {
22
38
  this.entries = [];
23
39
  this.options = options;
40
+ this.validators = validators || {};
41
+ if (typeof validatorId == 'string') {
42
+ this.validatorId = validatorId;
43
+ }
44
+ else if (typeof validatorId == 'function') {
45
+ this.validatorId = validatorId.name;
46
+ }
47
+ else {
48
+ this.validatorId = this.constructor.name;
49
+ }
50
+ this.validators[this.validatorId] = this;
24
51
  }
25
52
  add(...args) {
26
53
  var _a, _b, _c;
@@ -30,20 +57,35 @@ class Validator {
30
57
  let constraint;
31
58
  let validatorFactory;
32
59
  let condition;
33
- if (typeof args[0] == 'object' && args[0] !== null && 'create' in args[0] && typeof args[0].create == 'function') {
34
- let validator = args[0].create();
35
- if (typeof validator == 'object' && validator !== null && 'entries' in validator && Array.isArray(validator.entries)) {
60
+ if (args[0] instanceof ValidatorFactory) {
61
+ if (this.options == undefined) {
62
+ this.options = {};
63
+ }
64
+ let validator = args[0].createOrGetExisting(this.validators);
65
+ if (validator == this) {
66
+ throw new Error('Cannot add add another validator that is itself which would result in an endless loop of adding itself!');
67
+ }
68
+ if (typeof validator == 'object' &&
69
+ validator !== null &&
70
+ 'entries' in validator &&
71
+ Array.isArray(validator.entries) &&
72
+ validator.entries.length > 0) {
73
+ l.dev('Adding entries from validator', validator);
36
74
  for (let entry of validator.entries) {
37
75
  this.add(entry);
38
76
  }
39
77
  }
78
+ else {
79
+ l.warn('Given validator to add does not have any entries!', validator);
80
+ }
40
81
  }
41
82
  else if (typeof args[0] == 'object' && args[0] !== null && 'properties' in args[0] && Array.isArray(args[0].properties)) {
42
83
  properties = args[0].properties;
43
84
  constraint = args[0].constraint;
44
- validatorFactory = args[0].validator ?
45
- { create: () => args[0].validator } : undefined;
46
85
  condition = args[0].condition;
86
+ if (args[0].validator) {
87
+ validatorFactory = new ValidatorFactory(args[0].validator.constructor.name, () => args[0].validator);
88
+ }
47
89
  if (constraint != undefined && validatorFactory != undefined) {
48
90
  throw new Error('The provided parameter is a ValidatorEntry with both a constraint and a validator defined. This is invalid! Only one may be specified at a time!');
49
91
  }
@@ -73,7 +115,7 @@ class Validator {
73
115
  constraint = args[1];
74
116
  condition = args.length > 2 ? args[2] : undefined;
75
117
  }
76
- else if (typeof args[1] == 'object' && args[1] !== null && 'create' in args[1] && typeof args[1].create == 'function') {
118
+ else if (args[1] instanceof ValidatorFactory) {
77
119
  validatorFactory = args[1];
78
120
  condition = args.length > 2 ? args[2] : undefined;
79
121
  }
@@ -98,10 +140,20 @@ class Validator {
98
140
  }
99
141
  }
100
142
  if (!propertyExcluded) {
143
+ let validator;
144
+ if (validatorFactory) {
145
+ if (this.options == undefined) {
146
+ this.options = {};
147
+ }
148
+ validator = validatorFactory.createOrGetExisting(this.validators);
149
+ if (validator == undefined) {
150
+ throw new Error('Validator factory did not create a validator!');
151
+ }
152
+ }
101
153
  let entry = {
102
154
  properties: properties,
103
155
  constraint: constraint,
104
- validator: validatorFactory ? validatorFactory.create() : undefined,
156
+ validator: validator,
105
157
  condition: condition
106
158
  };
107
159
  this.entries.push(entry);
@@ -109,17 +161,22 @@ class Validator {
109
161
  }
110
162
  l.returning();
111
163
  }
112
- validate(object, options) {
164
+ validate(object, options, validated) {
113
165
  return __awaiter(this, void 0, void 0, function* () {
114
166
  var _a;
115
167
  let l = log.mt('validate');
116
168
  l.param('object', object);
117
169
  l.param('options', options);
170
+ if (validated == undefined) {
171
+ validated = new WeakSet;
172
+ }
173
+ validated.add(object);
118
174
  options = options || this.options;
119
175
  let misfits = [];
120
176
  let misfittingProperties = [];
121
177
  for (let entry of this.entries) {
122
178
  let constraintOrValidatorName = entry.constraint ? (_a = entry.constraint) === null || _a === void 0 ? void 0 : _a.name : entry.validator ? entry.validator.constructor.name : '';
179
+ l.dev('Checking constraint', JSON.stringify(entry.properties), constraintOrValidatorName);
123
180
  l.location = ['' + JSON.stringify(entry.properties) + ' > ' + constraintOrValidatorName];
124
181
  let propertyAlreadyHasAMisfit = false;
125
182
  for (let property of entry.properties) {
@@ -205,6 +262,10 @@ class Validator {
205
262
  l.dev('Value of the property is not of type object or null. Skipping...', value);
206
263
  continue;
207
264
  }
265
+ if (validated.has(value)) {
266
+ l.dev('Object is or was already being validated. Skipping...', value);
267
+ continue;
268
+ }
208
269
  if (value instanceof Array) {
209
270
  l.dev('Value of the property is an array. Iterating its elements...');
210
271
  for (let i = 0; i < value.length; i++) {
@@ -213,7 +274,7 @@ class Validator {
213
274
  continue;
214
275
  }
215
276
  l.calling('entry.validator.validate', value[i], options);
216
- let subMisfits = yield entry.validator.validate(value[i], options);
277
+ let subMisfits = yield entry.validator.validate(value[i], options, validated);
217
278
  l.called('entry.validator.validate');
218
279
  if (subMisfits.length > 0) {
219
280
  l.dev('Validator returned misfits', subMisfits);
@@ -234,7 +295,7 @@ class Validator {
234
295
  else {
235
296
  l.dev('Value of the property is not an array');
236
297
  l.calling('entry.validator.validate', value, options);
237
- let subMisfits = yield entry.validator.validate(value, options);
298
+ let subMisfits = yield entry.validator.validate(value, options, validated);
238
299
  l.called('entry.validator.validate');
239
300
  if (subMisfits.length > 0) {
240
301
  l.dev('Validator returned misfits', subMisfits);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knight-validation",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "A validation lib",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",