@oscarpalmer/jhunal 0.21.0 → 0.23.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 (47) hide show
  1. package/dist/constants.d.mts +7 -3
  2. package/dist/constants.mjs +34 -12
  3. package/dist/helpers/message.helper.d.mts +11 -0
  4. package/dist/helpers/message.helper.mjs +70 -0
  5. package/dist/helpers/misc.helper.d.mts +22 -0
  6. package/dist/helpers/misc.helper.mjs +56 -0
  7. package/dist/index.d.mts +318 -328
  8. package/dist/index.mjs +324 -295
  9. package/dist/models/schema.plain.model.d.mts +2 -8
  10. package/dist/models/validation.model.d.mts +26 -59
  11. package/dist/schematic.d.mts +28 -10
  12. package/dist/schematic.mjs +15 -16
  13. package/dist/validator/base.validator.d.mts +6 -0
  14. package/dist/validator/base.validator.mjs +19 -0
  15. package/dist/validator/function.validator.d.mts +6 -0
  16. package/dist/validator/function.validator.mjs +9 -0
  17. package/dist/validator/named.handler.d.mts +6 -0
  18. package/dist/validator/named.handler.mjs +22 -0
  19. package/dist/validator/named.validator.d.mts +7 -0
  20. package/dist/validator/named.validator.mjs +39 -0
  21. package/dist/validator/object.validator.d.mts +7 -0
  22. package/dist/validator/object.validator.mjs +167 -0
  23. package/dist/validator/schematic.validator.d.mts +7 -0
  24. package/dist/validator/schematic.validator.mjs +16 -0
  25. package/package.json +1 -1
  26. package/src/constants.ts +42 -10
  27. package/src/helpers/message.helper.ts +152 -0
  28. package/src/helpers/misc.helper.ts +93 -0
  29. package/src/index.ts +7 -2
  30. package/src/models/schema.plain.model.ts +1 -8
  31. package/src/models/validation.model.ts +55 -77
  32. package/src/schematic.ts +49 -27
  33. package/src/validator/base.validator.ts +31 -0
  34. package/src/validator/function.validator.ts +9 -0
  35. package/src/validator/named.handler.ts +50 -0
  36. package/src/validator/named.validator.ts +62 -0
  37. package/src/validator/object.validator.ts +340 -0
  38. package/src/validator/schematic.validator.ts +25 -0
  39. package/dist/helpers.d.mts +0 -28
  40. package/dist/helpers.mjs +0 -119
  41. package/dist/validation/property.validation.d.mts +0 -7
  42. package/dist/validation/property.validation.mjs +0 -92
  43. package/dist/validation/value.validation.d.mts +0 -7
  44. package/dist/validation/value.validation.mjs +0 -162
  45. package/src/helpers.ts +0 -246
  46. package/src/validation/property.validation.ts +0 -217
  47. package/src/validation/value.validation.ts +0 -293
package/src/schematic.ts CHANGED
@@ -3,18 +3,18 @@ import type {PlainObject} from '@oscarpalmer/atoms/models';
3
3
  import {error, ok} from '@oscarpalmer/atoms/result/misc';
4
4
  import type {Result} from '@oscarpalmer/atoms/result/models';
5
5
  import {PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE} from './constants';
6
- import {getParameters, isSchematic} from './helpers';
6
+ import {getParameters, isSchematic} from './helpers/misc.helper';
7
7
  import type {Infer} from './models/infer.model';
8
8
  import type {Schema} from './models/schema.plain.model';
9
9
  import type {TypedSchema} from './models/schema.typed.model';
10
10
  import {
11
11
  SchematicError,
12
- type ValidatedProperty,
12
+ type GetOptions,
13
+ type IsOptions,
13
14
  type ValidationInformation,
14
- type ValidationOptions,
15
+ type Validator,
15
16
  } from './models/validation.model';
16
- import {getProperties} from './validation/property.validation';
17
- import {validateObject} from './validation/value.validation';
17
+ import {getObjectValidator} from './validator/object.validator';
18
18
 
19
19
  /**
20
20
  * A schematic for validating objects
@@ -22,16 +22,16 @@ import {validateObject} from './validation/value.validation';
22
22
  export class Schematic<Model> {
23
23
  declare private readonly $schematic: true;
24
24
 
25
- #properties: ValidatedProperty[];
25
+ #validator: Validator;
26
26
 
27
- constructor(properties: ValidatedProperty[]) {
27
+ constructor(validator: Validator) {
28
28
  Object.defineProperty(this, PROPERTY_SCHEMATIC, {
29
29
  value: true,
30
30
  });
31
31
 
32
- this.#properties = properties;
32
+ this.#validator = validator;
33
33
 
34
- schematicProperties.set(this, properties);
34
+ schematicValidator.set(this, validator);
35
35
  }
36
36
 
37
37
  /**
@@ -42,7 +42,7 @@ export class Schematic<Model> {
42
42
  * @param options Validation options
43
43
  * @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
44
44
  */
45
- get(value: unknown, options: ValidationOptions<'throw'>): Model;
45
+ get(value: unknown, options: GetOptions<'throw'>): Model;
46
46
 
47
47
  /**
48
48
  * Parse a value according to the schema
@@ -62,7 +62,7 @@ export class Schematic<Model> {
62
62
  * @param options Validation options
63
63
  * @returns Result holding deeply cloned value or all validation information
64
64
  */
65
- get(value: unknown, options: ValidationOptions<'all'>): Result<Model, ValidationInformation[]>;
65
+ get(value: unknown, options: GetOptions<'all'>): Result<Model, ValidationInformation[]>;
66
66
 
67
67
  /**
68
68
  * Parse a value according to the schema
@@ -82,7 +82,7 @@ export class Schematic<Model> {
82
82
  * @param options Validation options
83
83
  * @returns Result holding deeply cloned value or all validation information
84
84
  */
85
- get(value: unknown, options: ValidationOptions<'first'>): Result<Model, ValidationInformation>;
85
+ get(value: unknown, options: GetOptions<'first'>): Result<Model, ValidationInformation>;
86
86
 
87
87
  /**
88
88
  * Parse a value according to the schema
@@ -94,6 +94,16 @@ export class Schematic<Model> {
94
94
  */
95
95
  get(value: unknown, errors: 'first'): Result<Model, ValidationInformation>;
96
96
 
97
+ /**
98
+ * Parse a value according to the schema
99
+ *
100
+ * Returns a deeply cloned version of the value or `undefined` if the value does not match the schema
101
+ * @param value Value to parse
102
+ * @param options Validation options
103
+ * @returns Deeply cloned value, or `undefined` if it's invalid
104
+ */
105
+ get(value: unknown, options: GetOptions<'none'>): Model | undefined;
106
+
97
107
  /**
98
108
  * Parse a value according to the schema
99
109
  *
@@ -107,14 +117,16 @@ export class Schematic<Model> {
107
117
  get(value: unknown, options?: unknown): unknown {
108
118
  const parameters = getParameters(options);
109
119
 
110
- const result = validateObject(value, this.#properties, parameters, true);
120
+ const result = this.#validator(value, parameters, true);
111
121
 
112
- if (result == null) {
113
- return;
122
+ if (result === true) {
123
+ return parameters.reporting.none || parameters.reporting.throw
124
+ ? parameters.output
125
+ : ok(parameters.output);
114
126
  }
115
127
 
116
- if (!Array.isArray(result)) {
117
- return parameters.reporting.none ? result : ok(result);
128
+ if (parameters.reporting.none) {
129
+ return;
118
130
  }
119
131
 
120
132
  return error(parameters.reporting.all ? result : result[0]);
@@ -128,7 +140,7 @@ export class Schematic<Model> {
128
140
  * @param options Validation options
129
141
  * @returns `true` if the value matches the schema, otherwise throws an error
130
142
  */
131
- is(value: unknown, options: ValidationOptions<'throw'>): asserts value is Model;
143
+ is(value: unknown, options: IsOptions<'throw'>): asserts value is Model;
132
144
 
133
145
  /**
134
146
  * Does the value match the schema?
@@ -148,7 +160,7 @@ export class Schematic<Model> {
148
160
  * @param options Validation options
149
161
  * @returns Result holding `true` or all validation information
150
162
  */
151
- is(value: unknown, options: ValidationOptions<'all'>): Result<true, ValidationInformation[]>;
163
+ is(value: unknown, options: IsOptions<'all'>): Result<true, ValidationInformation[]>;
152
164
 
153
165
  /**
154
166
  * Does the value match the schema?
@@ -168,7 +180,7 @@ export class Schematic<Model> {
168
180
  * @param options Validation options
169
181
  * @returns `true` if the value matches the schema, otherwise `false`
170
182
  */
171
- is(value: unknown, options: ValidationOptions<'first'>): Result<true, ValidationInformation>;
183
+ is(value: unknown, options: IsOptions<'first'>): Result<true, ValidationInformation>;
172
184
 
173
185
  /**
174
186
  * Does the value match the schema?
@@ -180,6 +192,16 @@ export class Schematic<Model> {
180
192
  */
181
193
  is(value: unknown, errors: 'first'): Result<true, ValidationInformation>;
182
194
 
195
+ /**
196
+ * Does the value match the schema?
197
+ *
198
+ * Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
199
+ * @param value Value to validate
200
+ * @param options Validation options
201
+ * @returns `true` if the value matches the schema, otherwise `false`
202
+ */
203
+ is(value: unknown, options: IsOptions<'none'>): value is Model;
204
+
183
205
  /**
184
206
  * Does the value match the schema?
185
207
  *
@@ -193,14 +215,14 @@ export class Schematic<Model> {
193
215
  is(value: unknown, options?: unknown): unknown {
194
216
  const parameters = getParameters(options);
195
217
 
196
- const result = validateObject(value, this.#properties, parameters, false);
218
+ const result = this.#validator(value, parameters, false);
197
219
 
198
- if (result == null) {
199
- return false;
220
+ if (result === true) {
221
+ return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
200
222
  }
201
223
 
202
- if (!Array.isArray(result)) {
203
- return parameters.reporting.none ? true : ok(true);
224
+ if (parameters.reporting.none) {
225
+ return false;
204
226
  }
205
227
 
206
228
  return error(parameters.reporting.all ? result : result[0]);
@@ -234,7 +256,7 @@ export function schematic<Model extends Schema>(schema: Model): Schematic<Model>
234
256
  throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
235
257
  }
236
258
 
237
- return new Schematic<Model>(getProperties(schema));
259
+ return new Schematic<Model>(getObjectValidator(schema));
238
260
  }
239
261
 
240
- export const schematicProperties = new WeakMap<Schematic<unknown>, ValidatedProperty[]>();
262
+ export const schematicValidator = new WeakMap<Schematic<unknown>, Validator>();
@@ -0,0 +1,31 @@
1
+ import type {ValidationInformation, Validator} from '../models/validation.model';
2
+
3
+ export function getBaseValidator(validators: Validator[]): Validator {
4
+ const {length} = validators;
5
+
6
+ return (input, parameters, get) => {
7
+ const allInformation: ValidationInformation[] = [];
8
+
9
+ for (let index = 0; index < length; index += 1) {
10
+ const previousInformation = parameters.information;
11
+
12
+ const nextInformation: ValidationInformation[] = [];
13
+
14
+ parameters.information = nextInformation;
15
+
16
+ const result = validators[index](input, parameters, get);
17
+
18
+ parameters.information = previousInformation;
19
+
20
+ if (result === true) {
21
+ return true;
22
+ }
23
+
24
+ parameters.information?.push(...result);
25
+
26
+ allInformation.push(...result);
27
+ }
28
+
29
+ return allInformation;
30
+ };
31
+ }
@@ -0,0 +1,9 @@
1
+ import {isConstructor} from '@oscarpalmer/atoms/is';
2
+ import {instanceOf} from '../helpers/misc.helper';
3
+ import type {Validator} from '../models/validation.model';
4
+
5
+ export function getFunctionValidator(fn: Function): Validator {
6
+ const validator = isConstructor(fn) ? instanceOf(fn) : fn;
7
+
8
+ return input => (validator(input) ? true : []);
9
+ }
@@ -0,0 +1,50 @@
1
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import {
3
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY,
4
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE,
5
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE,
6
+ TEMPLATE_PATTERN,
7
+ TYPE_ALL,
8
+ } from '../constants';
9
+ import type {ValueName} from '../models/misc.model';
10
+ import type {NamedValidatorHandlers} from '../models/validation.model';
11
+
12
+ export function getNamedHandlers(original: unknown, prefix: string): NamedValidatorHandlers {
13
+ const handlers: NamedValidatorHandlers = {};
14
+
15
+ if (original == null) {
16
+ return handlers;
17
+ }
18
+
19
+ if (!isPlainObject(original)) {
20
+ throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
21
+ }
22
+
23
+ const keys = Object.keys(original);
24
+ const {length} = keys;
25
+
26
+ for (let index = 0; index < length; index += 1) {
27
+ const key = keys[index];
28
+
29
+ if (!TYPE_ALL.has(key as never)) {
30
+ throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace(TEMPLATE_PATTERN, key));
31
+ }
32
+
33
+ const value = original[key];
34
+
35
+ handlers[key as ValueName] = (Array.isArray(value) ? value : [value]).map(item => {
36
+ if (typeof item !== 'function') {
37
+ throw new TypeError(
38
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace(TEMPLATE_PATTERN, key).replace(
39
+ TEMPLATE_PATTERN,
40
+ prefix,
41
+ ),
42
+ );
43
+ }
44
+
45
+ return item;
46
+ });
47
+ }
48
+
49
+ return handlers;
50
+ }
@@ -0,0 +1,62 @@
1
+ import {TYPE_OBJECT} from '../constants';
2
+ import {getInvalidValidatorMessage} from '../helpers/message.helper';
3
+ import type {ValueName} from '../models/misc.model';
4
+ import type {
5
+ NamedValidatorHandlers,
6
+ NamedValidators,
7
+ ValidationInformation,
8
+ ValidationInformationKey,
9
+ Validator,
10
+ } from '../models/validation.model';
11
+
12
+ export function getNamedValidator(
13
+ key: ValidationInformationKey,
14
+ name: ValueName,
15
+ handlers: NamedValidatorHandlers,
16
+ ): Validator {
17
+ const validator = namedValidators[name];
18
+
19
+ const named = handlers[name] ?? [];
20
+ const {length} = named;
21
+
22
+ return (input, parameters) => {
23
+ if (!validator(input)) {
24
+ return [];
25
+ }
26
+
27
+ for (let index = 0; index < length; index += 1) {
28
+ const handler = named[index];
29
+
30
+ if (handler(input) === true) {
31
+ continue;
32
+ }
33
+
34
+ const information: ValidationInformation = {
35
+ key,
36
+ validator,
37
+ message: getInvalidValidatorMessage(key.full, name, index, length),
38
+ value: input,
39
+ };
40
+
41
+ parameters.information?.push(information);
42
+
43
+ return parameters.reporting.none ? [] : [information];
44
+ }
45
+
46
+ return true;
47
+ };
48
+ }
49
+
50
+ const namedValidators: NamedValidators = {
51
+ array: Array.isArray,
52
+ bigint: value => typeof value === 'bigint',
53
+ boolean: value => typeof value === 'boolean',
54
+ date: value => value instanceof Date,
55
+ function: value => typeof value === 'function',
56
+ null: value => value === null,
57
+ number: value => typeof value === 'number',
58
+ object: value => typeof value === TYPE_OBJECT && value !== null,
59
+ string: value => typeof value === 'string',
60
+ symbol: value => typeof value === 'symbol',
61
+ undefined: value => value === undefined,
62
+ };
@@ -0,0 +1,340 @@
1
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import type {PlainObject} from '@oscarpalmer/atoms/models';
3
+ import {join} from '@oscarpalmer/atoms/string';
4
+ import {clone} from '@oscarpalmer/atoms/value/clone';
5
+ import {
6
+ PROPERTY_REQUIRED,
7
+ PROPERTY_TYPE,
8
+ PROPERTY_VALIDATORS,
9
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY,
10
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
11
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE,
12
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED,
13
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE,
14
+ TEMPLATE_PATTERN,
15
+ TYPE_ALL,
16
+ TYPE_UNDEFINED,
17
+ } from '../constants';
18
+ import {
19
+ getInvalidInputMessage,
20
+ getInvalidMissingMessage,
21
+ getInvalidTypeMessage,
22
+ getUnknownKeysMessage,
23
+ } from '../helpers/message.helper';
24
+ import {isSchematic} from '../helpers/misc.helper';
25
+ import type {ValueName} from '../models/misc.model';
26
+ import {
27
+ type NamedValidatorHandlers,
28
+ SchematicError,
29
+ ValidationError,
30
+ type ValidationInformation,
31
+ type ValidationInformationKey,
32
+ type Validator,
33
+ type ValidatorType,
34
+ } from '../models/validation.model';
35
+ import {getBaseValidator} from './base.validator';
36
+ import {getFunctionValidator} from './function.validator';
37
+ import {getNamedHandlers} from './named.handler';
38
+ import {getNamedValidator} from './named.validator';
39
+ import {getSchematicValidator} from './schematic.validator';
40
+
41
+ function getDisallowedProperty(obj: PlainObject): string | undefined {
42
+ if (PROPERTY_REQUIRED in obj) {
43
+ return PROPERTY_REQUIRED;
44
+ }
45
+
46
+ if (PROPERTY_TYPE in obj) {
47
+ return PROPERTY_TYPE;
48
+ }
49
+
50
+ if (PROPERTY_VALIDATORS in obj) {
51
+ return PROPERTY_VALIDATORS;
52
+ }
53
+ }
54
+
55
+ export function getObjectValidator(
56
+ original: PlainObject,
57
+ origin?: ValidationInformationKey,
58
+ fromType?: boolean,
59
+ ): Validator {
60
+ const keys = Object.keys(original);
61
+ const keysLength = keys.length;
62
+
63
+ if (keysLength === 0) {
64
+ throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
65
+ }
66
+
67
+ if (fromType ?? false) {
68
+ const property = getDisallowedProperty(original);
69
+
70
+ if (property != null) {
71
+ throw new SchematicError(
72
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(
73
+ TEMPLATE_PATTERN,
74
+ origin!.full,
75
+ ).replace(TEMPLATE_PATTERN, property),
76
+ );
77
+ }
78
+ }
79
+
80
+ const set = new Set<string>();
81
+
82
+ const items: {
83
+ key: ValidationInformationKey;
84
+ required: boolean;
85
+ types: ValidatorType[];
86
+ validator: Validator;
87
+ }[] = [];
88
+
89
+ for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
90
+ const key = keys[keyIndex];
91
+ const value = original[key];
92
+
93
+ if (value == null) {
94
+ throw new SchematicError(
95
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace(
96
+ TEMPLATE_PATTERN,
97
+ join([origin?.full, key], '.'),
98
+ ),
99
+ );
100
+ }
101
+
102
+ const prefixedKey = origin == null ? key : join([origin.full, key], '.');
103
+
104
+ const fullKey: ValidationInformationKey = {
105
+ full: prefixedKey,
106
+ short: key,
107
+ };
108
+
109
+ let handlers: NamedValidatorHandlers = {};
110
+ let required = true;
111
+ let typed = false;
112
+ let types: ValidatorType[];
113
+
114
+ const validators: Validator[] = [];
115
+
116
+ if (isPlainObject(value)) {
117
+ typed = PROPERTY_TYPE in value;
118
+
119
+ const type = typed ? value[PROPERTY_TYPE] : value;
120
+
121
+ handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
122
+ required = getRequired(key, value) ?? required;
123
+
124
+ types = Array.isArray(type) ? type : [type];
125
+ } else {
126
+ types = Array.isArray(value) ? value : [value];
127
+ }
128
+
129
+ if (types.length === 0) {
130
+ throw new SchematicError(
131
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace(
132
+ TEMPLATE_PATTERN,
133
+ prefixedKey,
134
+ ).replace(TEMPLATE_PATTERN, String(value)),
135
+ );
136
+ }
137
+
138
+ const typesLength = types.length;
139
+
140
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
141
+ const type = types[typeIndex];
142
+
143
+ let validator: Validator;
144
+
145
+ switch (true) {
146
+ case typeof type === 'function':
147
+ validator = getFunctionValidator(type);
148
+ break;
149
+
150
+ case isPlainObject(type):
151
+ validator = getObjectValidator(type, fullKey, typed);
152
+ break;
153
+
154
+ case isSchematic(type):
155
+ validator = getSchematicValidator(type);
156
+ break;
157
+
158
+ case TYPE_ALL.has(type as ValueName):
159
+ validator = getNamedValidator(fullKey, type as ValueName, handlers);
160
+ break;
161
+
162
+ default:
163
+ throw new SchematicError(
164
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace(
165
+ TEMPLATE_PATTERN,
166
+ prefixedKey,
167
+ ).replace(TEMPLATE_PATTERN, String(type)),
168
+ );
169
+ }
170
+
171
+ validators.push(validator);
172
+ }
173
+
174
+ set.add(key);
175
+
176
+ items.push({
177
+ types,
178
+ key: fullKey,
179
+ required: required && !types.includes(TYPE_UNDEFINED),
180
+ validator: getBaseValidator(validators),
181
+ });
182
+ }
183
+
184
+ const validatorsLength = items.length;
185
+
186
+ return (input, parameters, get) => {
187
+ if (!isPlainObject(input)) {
188
+ if (origin != null) {
189
+ return [];
190
+ }
191
+
192
+ const information: ValidationInformation = {
193
+ key: {
194
+ full: '',
195
+ short: '',
196
+ },
197
+ value: input,
198
+ message: getInvalidInputMessage(input),
199
+ };
200
+
201
+ if (parameters.reporting.throw) {
202
+ throw new ValidationError([information]);
203
+ }
204
+
205
+ parameters.information?.push(information);
206
+
207
+ return [information];
208
+ }
209
+
210
+ if (parameters.strict) {
211
+ const inputKeys = Object.keys(input);
212
+ const unknownKeys = inputKeys.filter(key => !set.has(key));
213
+
214
+ if (unknownKeys.length > 0) {
215
+ const information: ValidationInformation = {
216
+ key: origin ?? {
217
+ full: '',
218
+ short: '',
219
+ },
220
+ message: getUnknownKeysMessage(unknownKeys),
221
+ value: input,
222
+ };
223
+
224
+ if (parameters.reporting.throw) {
225
+ throw new ValidationError([information]);
226
+ }
227
+
228
+ parameters.information?.push(information);
229
+
230
+ return [information];
231
+ }
232
+ }
233
+
234
+ const allInformation: ValidationInformation[] = [];
235
+ const output: PlainObject = {};
236
+
237
+ for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
238
+ const {key, required, types, validator} = items[validatorIndex];
239
+
240
+ const value = (input as PlainObject)[key.short];
241
+
242
+ if (value === undefined) {
243
+ if (required) {
244
+ if (parameters.reporting.none) {
245
+ return [];
246
+ }
247
+
248
+ const information: ValidationInformation = {
249
+ key,
250
+ value,
251
+ message: getInvalidMissingMessage(key.full, types),
252
+ };
253
+
254
+ if (parameters.reporting.throw) {
255
+ throw new ValidationError([information]);
256
+ }
257
+
258
+ parameters.information?.push(information);
259
+
260
+ if (parameters.reporting.all) {
261
+ allInformation.push(information);
262
+
263
+ continue;
264
+ }
265
+
266
+ return [information];
267
+ }
268
+
269
+ continue;
270
+ }
271
+
272
+ const previousOutput = parameters.output;
273
+
274
+ parameters.output = output;
275
+
276
+ const result = validator(value, parameters, get);
277
+
278
+ parameters.output = previousOutput;
279
+
280
+ if (result === true) {
281
+ if (get && !isPlainObject(value)) {
282
+ output[key.short] = parameters.clone ? clone(value) : value;
283
+ }
284
+
285
+ continue;
286
+ }
287
+
288
+ if (parameters.reporting.none) {
289
+ return [];
290
+ }
291
+
292
+ const information: ValidationInformation[] =
293
+ typeof result !== 'boolean' && result.length > 0
294
+ ? result
295
+ : [
296
+ {
297
+ key,
298
+ value,
299
+ message: getInvalidTypeMessage(key.full, types, value),
300
+ },
301
+ ];
302
+
303
+ if (parameters.reporting.throw) {
304
+ throw new ValidationError(information);
305
+ }
306
+
307
+ if (parameters.reporting.all) {
308
+ allInformation.push(...information);
309
+
310
+ continue;
311
+ }
312
+
313
+ return information;
314
+ }
315
+
316
+ if (get) {
317
+ if (origin == null) {
318
+ parameters.output = output;
319
+ } else {
320
+ parameters.output[origin.short] = output;
321
+ }
322
+ }
323
+
324
+ return allInformation.length === 0 ? true : allInformation;
325
+ };
326
+ }
327
+
328
+ function getRequired(key: string, obj: PlainObject): boolean | undefined {
329
+ if (!(PROPERTY_REQUIRED in obj)) {
330
+ return;
331
+ }
332
+
333
+ if (typeof obj[PROPERTY_REQUIRED] !== 'boolean') {
334
+ throw new SchematicError(
335
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace(TEMPLATE_PATTERN, key),
336
+ );
337
+ }
338
+
339
+ return obj[PROPERTY_REQUIRED];
340
+ }
@@ -0,0 +1,25 @@
1
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import type {Validator} from '../models/validation.model';
3
+ import {Schematic, schematicValidator} from '../schematic';
4
+
5
+ export function getSchematicValidator(schematic: Schematic<unknown>): Validator {
6
+ const validator = schematicValidator.get(schematic)!;
7
+
8
+ return (input, parameters, get) => {
9
+ let result: ReturnType<Validator>;
10
+
11
+ if (isPlainObject(input)) {
12
+ result = validator(input, parameters, get);
13
+ } else {
14
+ result = [];
15
+ }
16
+
17
+ if (result === true) {
18
+ return result;
19
+ }
20
+
21
+ parameters.information?.push(...result);
22
+
23
+ return result;
24
+ };
25
+ }