@oscarpalmer/jhunal 0.19.0 → 0.20.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.
@@ -1,21 +1,24 @@
1
1
  import {isPlainObject} from '@oscarpalmer/atoms/is';
2
2
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
3
+ import {join} from '@oscarpalmer/atoms/string';
3
4
  import {TYPE_OBJECT} from '../constants';
4
5
  import {
5
6
  getInvalidInputMessage,
6
7
  getInvalidMissingMessage,
7
8
  getInvalidTypeMessage,
8
9
  getInvalidValidatorMessage,
10
+ getUnknownKeysMessage,
9
11
  isSchematic,
10
12
  } from '../helpers';
11
13
  import type {ValueName} from '../models/misc.model';
12
14
  import {
13
15
  ValidationError,
14
- type ReportingInformation,
15
16
  type ValidatedProperty,
16
17
  type ValidatedPropertyType,
17
18
  type ValidationInformation,
19
+ type ValidationOptionsExtended,
18
20
  } from '../models/validation.model';
21
+ import {schematicProperties, type Schematic} from '../schematic';
19
22
 
20
23
  function validateNamed(
21
24
  property: ValidatedProperty,
@@ -56,23 +59,61 @@ function validateNamed(
56
59
  export function validateObject(
57
60
  obj: unknown,
58
61
  properties: ValidatedProperty[],
59
- reporting: ReportingInformation,
60
- property?: ValidatedProperty,
62
+ options: ValidationOptionsExtended,
63
+ origin?: ValidatedProperty,
61
64
  validation?: ValidationInformation[],
62
65
  ): boolean | ValidationInformation[] {
63
66
  if (!isPlainObject(obj)) {
67
+ const key = origin == null ? {full: '', short: ''} : {...origin.key};
68
+
64
69
  const information = {
65
- key: {full: '', short: ''},
70
+ key,
66
71
  message:
67
- property == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(property, obj),
72
+ origin == null
73
+ ? getInvalidInputMessage(obj)
74
+ : getInvalidTypeMessage(
75
+ {
76
+ ...origin,
77
+ key,
78
+ },
79
+ obj,
80
+ ),
68
81
  value: obj,
69
82
  };
70
83
 
71
- if (reporting.throw) {
84
+ if (options.reporting.throw) {
72
85
  throw new ValidationError([information]);
73
86
  }
74
87
 
75
- return reporting.none ? false : [information];
88
+ validation?.push(information);
89
+
90
+ return options.reporting.none ? false : [information];
91
+ }
92
+
93
+ if (options.strict) {
94
+ const objKeys = Object.keys(obj);
95
+
96
+ const propertiesKeys = new Set(properties.map(property => property.key.short));
97
+
98
+ const unknownKeys = objKeys.filter(key => !propertiesKeys.has(key));
99
+
100
+ if (unknownKeys.length > 0) {
101
+ const key = origin == null ? {full: '', short: ''} : {...origin.key};
102
+
103
+ const information: ValidationInformation = {
104
+ key,
105
+ message: getUnknownKeysMessage(unknownKeys.map(key => join([origin?.key.full, key], '.'))),
106
+ value: obj,
107
+ };
108
+
109
+ if (options.reporting.throw) {
110
+ throw new ValidationError([information]);
111
+ }
112
+
113
+ validation?.push(information);
114
+
115
+ return options.reporting.none ? false : [information];
116
+ }
76
117
  }
77
118
 
78
119
  const allInformation: ValidationInformation[] = [];
@@ -80,7 +121,15 @@ export function validateObject(
80
121
  const propertiesLength = properties.length;
81
122
 
82
123
  outer: for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
83
- const property = properties[propertyIndex];
124
+ let property = properties[propertyIndex];
125
+
126
+ property = {
127
+ ...property,
128
+ key: {
129
+ full: join([origin?.key.full, property.key.short], '.'),
130
+ short: property.key.short,
131
+ },
132
+ };
84
133
 
85
134
  const {key, required, types} = property;
86
135
 
@@ -93,7 +142,7 @@ export function validateObject(
93
142
  message: getInvalidMissingMessage(property),
94
143
  };
95
144
 
96
- if (reporting.throw && validation == null) {
145
+ if (options.reporting.throw && validation == null) {
97
146
  throw new ValidationError([information]);
98
147
  }
99
148
 
@@ -101,13 +150,13 @@ export function validateObject(
101
150
  validation.push(information);
102
151
  }
103
152
 
104
- if (reporting.all) {
153
+ if (options.reporting.all) {
105
154
  allInformation.push(information);
106
155
 
107
156
  continue;
108
157
  }
109
158
 
110
- return reporting.none ? false : [information];
159
+ return options.reporting.none ? false : [information];
111
160
  }
112
161
 
113
162
  const typesLength = types.length;
@@ -117,7 +166,7 @@ export function validateObject(
117
166
  for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
118
167
  const type = types[typeIndex];
119
168
 
120
- if (validateValue(type, property, value, reporting, information)) {
169
+ if (validateValue(type, property, value, options, information)) {
121
170
  continue outer;
122
171
  }
123
172
  }
@@ -130,29 +179,43 @@ export function validateObject(
130
179
  });
131
180
  }
132
181
 
133
- if (reporting.throw && validation == null) {
182
+ if (options.reporting.throw && validation == null) {
134
183
  throw new ValidationError(information);
135
184
  }
136
185
 
137
186
  validation?.push(...information);
138
187
 
139
- if (reporting.all) {
188
+ if (options.reporting.all) {
140
189
  allInformation.push(...information);
141
190
 
142
191
  continue;
143
192
  }
144
193
 
145
- return reporting.none ? false : information;
194
+ return options.reporting.none ? false : information;
146
195
  }
147
196
 
148
- return reporting.none ? true : allInformation.length === 0 ? true : allInformation;
197
+ return options.reporting.none || allInformation.length === 0 ? true : allInformation;
198
+ }
199
+
200
+ function validateSchematic(
201
+ property: ValidatedProperty,
202
+ schematic: Schematic<unknown>,
203
+ value: unknown,
204
+ options: ValidationOptionsExtended,
205
+ validation: ValidationInformation[],
206
+ ): boolean {
207
+ const properties = schematicProperties.get(schematic)!;
208
+
209
+ const result = validateObject(value, properties, options, property, validation);
210
+
211
+ return typeof result === 'boolean' ? result : result.length === 0;
149
212
  }
150
213
 
151
214
  function validateValue(
152
215
  type: ValidatedPropertyType,
153
216
  property: ValidatedProperty,
154
217
  value: unknown,
155
- reporting: ReportingInformation,
218
+ options: ValidationOptionsExtended,
156
219
  validation: ValidationInformation[],
157
220
  ): boolean {
158
221
  switch (true) {
@@ -160,12 +223,13 @@ function validateValue(
160
223
  return (type as GenericCallback)(value);
161
224
 
162
225
  case Array.isArray(type): {
163
- const nested = validateObject(value, type, reporting, property, validation);
164
- return typeof nested !== 'boolean' ? false : nested;
226
+ const validated = validateObject(value, type, options, property, validation);
227
+
228
+ return typeof validated === 'boolean' ? validated : false;
165
229
  }
166
230
 
167
231
  case isSchematic(type):
168
- return type.is(value, reporting as never) as unknown as boolean;
232
+ return validateSchematic(property, type, value, options, validation);
169
233
 
170
234
  default:
171
235
  return validateNamed(property, type as ValueName, value, validation);