@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/dist/index.mjs CHANGED
@@ -8,14 +8,13 @@ const CONJUNCTION_OR_COMMA = ", or ";
8
8
  const CONJUNCTION_AND = " and ";
9
9
  const CONJUNCTION_AND_COMMA = ", and ";
10
10
  const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
11
- const NAME_SCHEMATIC = "Schematic";
12
11
  const NAME_ERROR_SCHEMATIC = "SchematicError";
13
12
  const NAME_ERROR_VALIDATION = "ValidationError";
14
13
  const PROPERTY_REQUIRED = "$required";
15
14
  const PROPERTY_SCHEMATIC = "$schematic";
16
15
  const PROPERTY_TYPE = "$type";
17
16
  const PROPERTY_VALIDATORS = "$validators";
18
- const VALIDATION_MESSAGE_INVALID_INPUT = "Expected 'object' as input but received <>";
17
+ const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
19
18
  const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
20
19
  const VALIDATION_MESSAGE_INVALID_TYPE = "Expected <> for '<>' but received <>";
21
20
  const VALIDATION_MESSAGE_INVALID_VALUE = "Value does not satisfy validator for '<>' and type '<>'";
@@ -40,71 +39,68 @@ const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
40
39
  const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE = "Validators must be an object";
41
40
  const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE = "Validator '<>' must be a function or an array of functions";
42
41
  const TYPE_ARRAY = "array";
42
+ const TYPE_BIGINT = "bigint";
43
+ const TYPE_BOOLEAN = "boolean";
44
+ const TYPE_DATE = "date";
45
+ const TYPE_FUNCTION = "function";
46
+ const TYPE_FUNCTION_RESULT = "a validated value";
43
47
  const TYPE_NULL = "null";
48
+ const TYPE_NUMBER = "number";
44
49
  const TYPE_OBJECT = "object";
50
+ const TYPE_STRING = "string";
51
+ const TYPE_SYMBOL = "symbol";
45
52
  const TYPE_UNDEFINED = "undefined";
46
- const VALIDATABLE_TYPES = new Set([
47
- "array",
48
- "bigint",
49
- "boolean",
50
- "date",
51
- "function",
52
- "number",
53
- "string",
54
- "symbol",
55
- TYPE_OBJECT
56
- ]);
57
53
  const TYPE_ALL = new Set([
58
- ...VALIDATABLE_TYPES,
59
- "null",
54
+ ...new Set([
55
+ TYPE_ARRAY,
56
+ TYPE_BIGINT,
57
+ TYPE_BOOLEAN,
58
+ TYPE_DATE,
59
+ TYPE_FUNCTION,
60
+ TYPE_NUMBER,
61
+ TYPE_OBJECT,
62
+ TYPE_STRING,
63
+ TYPE_SYMBOL
64
+ ]),
65
+ TYPE_NULL,
60
66
  TYPE_UNDEFINED
61
67
  ]);
68
+ const PREFIXED_TYPES = {
69
+ [TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
70
+ [TYPE_BIGINT]: `a ${TYPE_BIGINT}`,
71
+ [TYPE_BOOLEAN]: `a ${TYPE_BOOLEAN}`,
72
+ [TYPE_DATE]: `a ${TYPE_DATE}`,
73
+ [TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
74
+ [TYPE_NULL]: TYPE_NULL,
75
+ [TYPE_NUMBER]: `a ${TYPE_NUMBER}`,
76
+ [TYPE_STRING]: `a ${TYPE_STRING}`,
77
+ [TYPE_SYMBOL]: `a ${TYPE_SYMBOL}`,
78
+ [TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
79
+ [TYPE_UNDEFINED]: TYPE_UNDEFINED
80
+ };
62
81
  //#endregion
63
- //#region src/helpers.ts
64
- function getInvalidInputMessage(actual) {
65
- return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
66
- }
67
- function getInvalidMissingMessage(key, types) {
68
- let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
69
- message = message.replace("<>", key);
70
- return message;
71
- }
72
- function getInvalidTypeMessage(key, types, actual) {
73
- let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
74
- message = message.replace("<>", key);
75
- message = message.replace("<>", getValueType(actual));
76
- return message;
77
- }
78
- function getInvalidValidatorMessage(key, type, index, length) {
79
- let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
80
- message = message.replace("<>", type);
81
- if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
82
- return message;
83
- }
82
+ //#region src/helpers/misc.helper.ts
84
83
  function getParameters(input) {
85
84
  if (typeof input === "boolean") return {
85
+ clone: true,
86
86
  output: {},
87
87
  reporting: getReporting(REPORTING_NONE),
88
88
  strict: input
89
89
  };
90
90
  if (REPORTING_TYPES.has(input)) return {
91
+ clone: true,
91
92
  output: {},
92
93
  reporting: getReporting(input),
93
94
  strict: false
94
95
  };
95
96
  const options = isPlainObject(input) ? input : {};
96
97
  return {
98
+ clone: typeof options.clone === "boolean" ? options.clone : true,
97
99
  output: {},
98
100
  reporting: getReporting(options.errors),
99
101
  strict: typeof options.strict === "boolean" ? options.strict : false
100
102
  };
101
103
  }
102
- function getPropertyType(original) {
103
- if (typeof original === "function") return "a validated value";
104
- if (Array.isArray(original)) return `'${TYPE_OBJECT}'`;
105
- if (isSchematic(original)) return `a ${NAME_SCHEMATIC}`;
106
- return `'${String(original)}'`;
107
- }
108
104
  function getReporting(value) {
109
105
  const type = REPORTING_TYPES.has(value) ? value : REPORTING_NONE;
110
106
  return {
@@ -115,21 +111,6 @@ function getReporting(value) {
115
111
  [REPORTING_THROW]: type === REPORTING_THROW
116
112
  };
117
113
  }
118
- function getUnknownKeysMessage(keys) {
119
- return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
120
- }
121
- function getValueType(value) {
122
- const valueType = typeof value;
123
- switch (true) {
124
- case value === null: return `'${TYPE_NULL}'`;
125
- case value === void 0: return `'${TYPE_UNDEFINED}'`;
126
- case valueType !== TYPE_OBJECT: return `'${valueType}'`;
127
- case Array.isArray(value): return `'${TYPE_ARRAY}'`;
128
- case isPlainObject(value): return `'${TYPE_OBJECT}'`;
129
- case isSchematic(value): return `a ${NAME_SCHEMATIC}`;
130
- default: return value.constructor.name;
131
- }
132
- }
133
114
  /**
134
115
  * Creates a validator function for a given constructor
135
116
  * @param constructor - Constructor to check against
@@ -150,6 +131,69 @@ function instanceOf(constructor) {
150
131
  function isSchematic(value) {
151
132
  return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
152
133
  }
134
+ //#endregion
135
+ //#region src/models/validation.model.ts
136
+ /**
137
+ * Thrown when a schema definition is invalid
138
+ */
139
+ var SchematicError = class extends Error {
140
+ constructor(message) {
141
+ super(message);
142
+ this.name = NAME_ERROR_SCHEMATIC;
143
+ }
144
+ };
145
+ /**
146
+ * Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
147
+ */
148
+ var ValidationError = class extends Error {
149
+ constructor(information) {
150
+ super(join(information.map((item) => item.message), "; "));
151
+ this.information = information;
152
+ this.name = NAME_ERROR_VALIDATION;
153
+ }
154
+ };
155
+ //#endregion
156
+ //#region src/helpers/message.helper.ts
157
+ function getInvalidInputMessage(actual) {
158
+ return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
159
+ }
160
+ function getInvalidMissingMessage(key, types) {
161
+ let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
162
+ message = message.replace("<>", key);
163
+ return message;
164
+ }
165
+ function getInvalidTypeMessage(key, types, actual) {
166
+ let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
167
+ message = message.replace("<>", key);
168
+ message = message.replace("<>", getValueType(actual));
169
+ return message;
170
+ }
171
+ function getInvalidValidatorMessage(key, type, index, length) {
172
+ let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
173
+ message = message.replace("<>", type);
174
+ if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
175
+ return message;
176
+ }
177
+ function getPropertyType(type) {
178
+ switch (true) {
179
+ case typeof type === "function": return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
180
+ case TYPE_ALL.has(type): return PREFIXED_TYPES[type];
181
+ default: return PREFIXED_TYPES[TYPE_OBJECT];
182
+ }
183
+ }
184
+ function getUnknownKeysMessage(keys) {
185
+ return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
186
+ }
187
+ function getValueType(value) {
188
+ const valueType = typeof value;
189
+ switch (true) {
190
+ case value === null: return TYPE_NULL;
191
+ case Array.isArray(value): return PREFIXED_TYPES[TYPE_ARRAY];
192
+ case isPlainObject(value): return PREFIXED_TYPES[TYPE_OBJECT];
193
+ case valueType !== TYPE_OBJECT: return PREFIXED_TYPES[valueType];
194
+ default: return value.constructor.name;
195
+ }
196
+ }
153
197
  function renderKeys(keys) {
154
198
  return renderParts(keys.map((key) => `'${key}'`), CONJUNCTION_AND, CONJUNCTION_AND_COMMA);
155
199
  }
@@ -176,298 +220,283 @@ function renderTypes(types) {
176
220
  return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
177
221
  }
178
222
  //#endregion
179
- //#region src/models/validation.model.ts
180
- /**
181
- * Thrown when a schema definition is invalid
182
- */
183
- var SchematicError = class extends Error {
184
- constructor(message) {
185
- super(message);
186
- this.name = NAME_ERROR_SCHEMATIC;
187
- }
188
- };
189
- /**
190
- * Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
191
- */
192
- var ValidationError = class extends Error {
193
- constructor(information) {
194
- super(join(information.map((item) => item.message), "; "));
195
- this.information = information;
196
- this.name = NAME_ERROR_VALIDATION;
223
+ //#region src/validator/base.validator.ts
224
+ function getBaseValidator(validators) {
225
+ const { length } = validators;
226
+ return (input, parameters, get) => {
227
+ const allInformation = [];
228
+ for (let index = 0; index < length; index += 1) {
229
+ const previousInformation = parameters.information;
230
+ parameters.information = [];
231
+ const result = validators[index](input, parameters, get);
232
+ parameters.information = previousInformation;
233
+ if (result === true) return true;
234
+ parameters.information?.push(...result);
235
+ allInformation.push(...result);
236
+ }
237
+ return allInformation;
238
+ };
239
+ }
240
+ //#endregion
241
+ //#region src/validator/function.validator.ts
242
+ function getFunctionValidator(fn) {
243
+ const validator = isConstructor(fn) ? instanceOf(fn) : fn;
244
+ return (input) => validator(input) ? true : [];
245
+ }
246
+ //#endregion
247
+ //#region src/validator/named.handler.ts
248
+ function getNamedHandlers(original, prefix) {
249
+ const handlers = {};
250
+ if (original == null) return handlers;
251
+ if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
252
+ const keys = Object.keys(original);
253
+ const { length } = keys;
254
+ for (let index = 0; index < length; index += 1) {
255
+ const key = keys[index];
256
+ if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
257
+ const value = original[key];
258
+ handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
259
+ if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
260
+ return item;
261
+ });
197
262
  }
263
+ return handlers;
264
+ }
265
+ //#endregion
266
+ //#region src/validator/named.validator.ts
267
+ function getNamedValidator(key, name, handlers) {
268
+ const validator = namedValidators[name];
269
+ const named = handlers[name] ?? [];
270
+ const { length } = named;
271
+ return (input, parameters) => {
272
+ if (!validator(input)) return [];
273
+ for (let index = 0; index < length; index += 1) {
274
+ const handler = named[index];
275
+ if (handler(input) === true) continue;
276
+ const information = {
277
+ key,
278
+ validator,
279
+ message: getInvalidValidatorMessage(key.full, name, index, length),
280
+ value: input
281
+ };
282
+ parameters.information?.push(information);
283
+ return parameters.reporting.none ? [] : [information];
284
+ }
285
+ return true;
286
+ };
287
+ }
288
+ const namedValidators = {
289
+ array: Array.isArray,
290
+ bigint: (value) => typeof value === "bigint",
291
+ boolean: (value) => typeof value === "boolean",
292
+ date: (value) => value instanceof Date,
293
+ function: (value) => typeof value === "function",
294
+ null: (value) => value === null,
295
+ number: (value) => typeof value === "number",
296
+ object: (value) => typeof value === "object" && value !== null,
297
+ string: (value) => typeof value === "string",
298
+ symbol: (value) => typeof value === "symbol",
299
+ undefined: (value) => value === void 0
198
300
  };
199
301
  //#endregion
200
- //#region src/validation/property.validation.ts
302
+ //#region src/validator/schematic.validator.ts
303
+ function getSchematicValidator(schematic) {
304
+ const validator = schematicValidator.get(schematic);
305
+ return (input, parameters, get) => {
306
+ let result;
307
+ if (isPlainObject(input)) result = validator(input, parameters, get);
308
+ else result = [];
309
+ if (result === true) return result;
310
+ parameters.information?.push(...result);
311
+ return result;
312
+ };
313
+ }
314
+ //#endregion
315
+ //#region src/validator/object.validator.ts
201
316
  function getDisallowedProperty(obj) {
202
317
  if ("$required" in obj) return PROPERTY_REQUIRED;
203
318
  if ("$type" in obj) return PROPERTY_TYPE;
204
319
  if ("$validators" in obj) return PROPERTY_VALIDATORS;
205
320
  }
206
- function getProperties(original, prefix, fromType) {
207
- if (Object.keys(original).length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
321
+ function getObjectValidator(original, origin, fromType) {
322
+ const keys = Object.keys(original);
323
+ const keysLength = keys.length;
324
+ if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
208
325
  if (fromType ?? false) {
209
326
  const property = getDisallowedProperty(original);
210
- if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", property));
327
+ if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
211
328
  }
212
- const keys = Object.keys(original);
213
- const keysLength = keys.length;
214
- const properties = [];
329
+ const set = /* @__PURE__ */ new Set();
330
+ const items = [];
215
331
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
216
332
  const key = keys[keyIndex];
217
333
  const value = original[key];
218
- if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([prefix, key], ".")));
219
- const types = [];
334
+ if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
335
+ const prefixedKey = origin == null ? key : join([origin.full, key], ".");
336
+ const fullKey = {
337
+ full: prefixedKey,
338
+ short: key
339
+ };
340
+ let handlers = {};
220
341
  let required = true;
221
- let validators = {};
342
+ let typed = false;
343
+ let types;
344
+ const validators = [];
222
345
  if (isPlainObject(value)) {
346
+ typed = PROPERTY_TYPE in value;
347
+ const type = typed ? value[PROPERTY_TYPE] : value;
348
+ handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
223
349
  required = getRequired(key, value) ?? required;
224
- validators = getValidators(value[PROPERTY_VALIDATORS]);
225
- const hasType = PROPERTY_TYPE in value;
226
- types.push(...getTypes(key, hasType ? value[PROPERTY_TYPE] : value, prefix, hasType));
227
- } else types.push(...getTypes(key, value, prefix));
228
- if (!required && !types.includes("undefined")) types.push(TYPE_UNDEFINED);
229
- properties.push({
230
- key,
231
- types,
232
- validators,
233
- required: required && !types.includes("undefined")
234
- });
235
- }
236
- return properties;
237
- }
238
- function getRequired(key, obj) {
239
- if (!("$required" in obj)) return;
240
- if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
241
- return obj[PROPERTY_REQUIRED];
242
- }
243
- function getTypes(key, original, prefix, fromType) {
244
- const array = Array.isArray(original) ? original : [original];
245
- const { length } = array;
246
- const types = [];
247
- for (let index = 0; index < length; index += 1) {
248
- const value = array[index];
249
- switch (true) {
250
- case typeof value === "function":
251
- types.push(isConstructor(value) ? instanceOf(value) : value);
252
- break;
253
- case isPlainObject(value):
254
- types.push(getProperties(value, join([prefix, key], "."), fromType));
255
- break;
256
- case isSchematic(value):
257
- types.push(value);
258
- break;
259
- case TYPE_ALL.has(value):
260
- types.push(value);
261
- break;
262
- default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", join([prefix, key], ".")));
350
+ types = Array.isArray(type) ? type : [type];
351
+ } else types = Array.isArray(value) ? value : [value];
352
+ if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
353
+ const typesLength = types.length;
354
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
355
+ const type = types[typeIndex];
356
+ let validator;
357
+ switch (true) {
358
+ case typeof type === "function":
359
+ validator = getFunctionValidator(type);
360
+ break;
361
+ case isPlainObject(type):
362
+ validator = getObjectValidator(type, fullKey, typed);
363
+ break;
364
+ case isSchematic(type):
365
+ validator = getSchematicValidator(type);
366
+ break;
367
+ case TYPE_ALL.has(type):
368
+ validator = getNamedValidator(fullKey, type, handlers);
369
+ break;
370
+ default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
371
+ }
372
+ validators.push(validator);
263
373
  }
264
- }
265
- if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", join([prefix, key], ".")));
266
- return types;
267
- }
268
- function getValidators(original) {
269
- const validators = {};
270
- if (original == null) return validators;
271
- if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
272
- const keys = Object.keys(original);
273
- const { length } = keys;
274
- for (let index = 0; index < length; index += 1) {
275
- const key = keys[index];
276
- if (!VALIDATABLE_TYPES.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
277
- const value = original[key];
278
- validators[key] = (Array.isArray(value) ? value : [value]).map((item) => {
279
- if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key));
280
- return item;
374
+ set.add(key);
375
+ items.push({
376
+ types,
377
+ key: fullKey,
378
+ required: required && !types.includes("undefined"),
379
+ validator: getBaseValidator(validators)
281
380
  });
282
381
  }
283
- return validators;
284
- }
285
- //#endregion
286
- //#region src/validation/value.validation.ts
287
- function validateNamed(name, value, parameters) {
288
- if (!validators[name](value)) return false;
289
- const propertyValidators = parameters.origin.validators[name];
290
- if (propertyValidators == null || propertyValidators.length === 0) return true;
291
- const { length } = propertyValidators;
292
- for (let index = 0; index < length; index += 1) {
293
- const validator = propertyValidators[index];
294
- if (!validator(value)) {
295
- parameters.information.push({
296
- value,
297
- key: {
298
- full: parameters.prefix,
299
- short: parameters.origin.key
300
- },
301
- message: getInvalidValidatorMessage(parameters.prefix, name, index, length),
302
- validator
303
- });
304
- return false;
305
- }
306
- }
307
- return true;
308
- }
309
- function validateObject(obj, properties, parameters, get) {
310
- if (!isPlainObject(obj)) {
311
- const key = parameters?.origin == null ? {
312
- full: "",
313
- short: ""
314
- } : {
315
- full: parameters.prefix,
316
- short: parameters.origin.key
317
- };
318
- const information = {
319
- key,
320
- message: parameters?.origin == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(key.full, parameters.origin.types, obj),
321
- value: obj
322
- };
323
- if (parameters.reporting.throw) throw new ValidationError([information]);
324
- parameters?.information?.push(information);
325
- return parameters.reporting.none ? void 0 : [information];
326
- }
327
- if (parameters.strict) {
328
- const objKeys = Object.keys(obj);
329
- const propertiesKeys = new Set(properties.map((property) => property.key));
330
- const unknownKeys = objKeys.filter((key) => !propertiesKeys.has(key));
331
- if (unknownKeys.length > 0) {
382
+ const validatorsLength = items.length;
383
+ return (input, parameters, get) => {
384
+ if (!isPlainObject(input)) {
385
+ if (origin != null) return [];
332
386
  const information = {
333
- key: parameters?.origin == null ? {
387
+ key: {
334
388
  full: "",
335
389
  short: ""
336
- } : {
337
- full: join([parameters.prefix, parameters.origin?.key], "."),
338
- short: parameters.origin.key
339
390
  },
340
- message: getUnknownKeysMessage(unknownKeys.map((key) => join([parameters?.prefix, key], "."))),
341
- value: obj
391
+ value: input,
392
+ message: getInvalidInputMessage(input)
342
393
  };
343
394
  if (parameters.reporting.throw) throw new ValidationError([information]);
344
- parameters?.information?.push(information);
345
- return parameters.reporting.none ? void 0 : [information];
395
+ parameters.information?.push(information);
396
+ return [information];
346
397
  }
347
- }
348
- const allInformation = [];
349
- const output = {};
350
- const propertiesLength = properties.length;
351
- outer: for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
352
- const property = properties[propertyIndex];
353
- const { key, required, types } = property;
354
- const value = obj[key];
355
- if (get && value === void 0 && !required) continue;
356
- if (value === void 0 && required) {
357
- const prefixedKey = join([parameters.prefix, key], ".");
358
- const information = {
398
+ if (parameters.strict) {
399
+ const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
400
+ if (unknownKeys.length > 0) {
401
+ const information = {
402
+ key: origin ?? {
403
+ full: "",
404
+ short: ""
405
+ },
406
+ message: getUnknownKeysMessage(unknownKeys),
407
+ value: input
408
+ };
409
+ if (parameters.reporting.throw) throw new ValidationError([information]);
410
+ parameters.information?.push(information);
411
+ return [information];
412
+ }
413
+ }
414
+ const allInformation = [];
415
+ const output = {};
416
+ for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
417
+ const { key, required, types, validator } = items[validatorIndex];
418
+ const value = input[key.short];
419
+ if (value === void 0) {
420
+ if (required) {
421
+ if (parameters.reporting.none) return [];
422
+ const information = {
423
+ key,
424
+ value,
425
+ message: getInvalidMissingMessage(key.full, types)
426
+ };
427
+ if (parameters.reporting.throw) throw new ValidationError([information]);
428
+ parameters.information?.push(information);
429
+ if (parameters.reporting.all) {
430
+ allInformation.push(information);
431
+ continue;
432
+ }
433
+ return [information];
434
+ }
435
+ continue;
436
+ }
437
+ const previousOutput = parameters.output;
438
+ parameters.output = output;
439
+ const result = validator(value, parameters, get);
440
+ parameters.output = previousOutput;
441
+ if (result === true) {
442
+ if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
443
+ continue;
444
+ }
445
+ if (parameters.reporting.none) return [];
446
+ const information = typeof result !== "boolean" && result.length > 0 ? result : [{
447
+ key,
359
448
  value,
360
- key: {
361
- full: prefixedKey,
362
- short: key
363
- },
364
- message: getInvalidMissingMessage(prefixedKey, property.types)
365
- };
366
- if (parameters.reporting.throw) throw new ValidationError([information]);
367
- parameters?.information?.push(information);
449
+ message: getInvalidTypeMessage(key.full, types, value)
450
+ }];
451
+ if (parameters.reporting.throw) throw new ValidationError(information);
368
452
  if (parameters.reporting.all) {
369
- allInformation.push(information);
453
+ allInformation.push(...information);
370
454
  continue;
371
455
  }
372
- return parameters.reporting.none ? void 0 : [information];
456
+ return information;
373
457
  }
374
- const prefixedKey = join([parameters.prefix, key], ".");
375
- const typesLength = types.length;
376
- const information = [];
377
- for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
378
- const type = types[typeIndex];
379
- if (validateValue(type, value, {
380
- information,
381
- output,
382
- origin: property,
383
- prefix: prefixedKey,
384
- reporting: parameters.reporting,
385
- strict: parameters.strict
386
- }, get)) {
387
- if (get) output[key] = clone(value);
388
- continue outer;
389
- }
390
- }
391
- if (information.length === 0) information.push({
392
- value,
393
- key: {
394
- full: prefixedKey,
395
- short: key
396
- },
397
- message: getInvalidTypeMessage(prefixedKey, property.types, value)
398
- });
399
- if (parameters.reporting.throw) throw new ValidationError(information);
400
- parameters?.information?.push(...information);
401
- if (parameters.reporting.all) {
402
- allInformation.push(...information);
403
- continue;
404
- }
405
- return parameters.reporting.none ? void 0 : information;
406
- }
407
- if (get) if (parameters.origin == null) parameters.output = output;
408
- else parameters.output[parameters.origin.key] = output;
409
- return parameters.reporting.none || allInformation.length === 0 ? parameters.output : allInformation;
410
- }
411
- function validateSchematic(schematic, value, parameters, get) {
412
- const result = validateObject(value, schematicProperties.get(schematic), parameters, get);
413
- return result == null || Array.isArray(result) ? false : true;
458
+ if (get) if (origin == null) parameters.output = output;
459
+ else parameters.output[origin.short] = output;
460
+ return allInformation.length === 0 ? true : allInformation;
461
+ };
414
462
  }
415
- function validateValue(type, value, parameters, get) {
416
- switch (true) {
417
- case typeof type === "function": return type(value);
418
- case Array.isArray(type): {
419
- const result = validateObject(value, type, parameters, get);
420
- return result == null || Array.isArray(result) ? false : true;
421
- }
422
- case isSchematic(type): return validateSchematic(type, value, parameters, get);
423
- default: return validateNamed(type, value, parameters);
424
- }
463
+ function getRequired(key, obj) {
464
+ if (!("$required" in obj)) return;
465
+ if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
466
+ return obj[PROPERTY_REQUIRED];
425
467
  }
426
- const validators = {
427
- array: Array.isArray,
428
- bigint: (value) => typeof value === "bigint",
429
- boolean: (value) => typeof value === "boolean",
430
- date: (value) => value instanceof Date,
431
- function: (value) => typeof value === "function",
432
- null: (value) => value === null,
433
- number: (value) => typeof value === "number",
434
- object: (value) => typeof value === "object" && value !== null,
435
- string: (value) => typeof value === "string",
436
- symbol: (value) => typeof value === "symbol",
437
- undefined: (value) => value === void 0
438
- };
439
468
  //#endregion
440
469
  //#region src/schematic.ts
441
470
  /**
442
471
  * A schematic for validating objects
443
472
  */
444
473
  var Schematic = class {
445
- #properties;
446
- constructor(properties) {
474
+ #validator;
475
+ constructor(validator) {
447
476
  Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
448
- this.#properties = properties;
449
- schematicProperties.set(this, properties);
477
+ this.#validator = validator;
478
+ schematicValidator.set(this, validator);
450
479
  }
451
480
  get(value, options) {
452
481
  const parameters = getParameters(options);
453
- const result = validateObject(value, this.#properties, parameters, true);
454
- if (result == null) return;
455
- if (!Array.isArray(result)) return parameters.reporting.none ? result : ok(result);
482
+ const result = this.#validator(value, parameters, true);
483
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
484
+ if (parameters.reporting.none) return;
456
485
  return error(parameters.reporting.all ? result : result[0]);
457
486
  }
458
487
  is(value, options) {
459
488
  const parameters = getParameters(options);
460
- const result = validateObject(value, this.#properties, parameters, false);
461
- if (result == null) return false;
462
- if (!Array.isArray(result)) return parameters.reporting.none ? true : ok(true);
489
+ const result = this.#validator(value, parameters, false);
490
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
491
+ if (parameters.reporting.none) return false;
463
492
  return error(parameters.reporting.all ? result : result[0]);
464
493
  }
465
494
  };
466
495
  function schematic(schema) {
467
496
  if (isSchematic(schema)) return schema;
468
497
  if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
469
- return new Schematic(getProperties(schema));
498
+ return new Schematic(getObjectValidator(schema));
470
499
  }
471
- const schematicProperties = /* @__PURE__ */ new WeakMap();
500
+ const schematicValidator = /* @__PURE__ */ new WeakMap();
472
501
  //#endregion
473
502
  export { SchematicError, ValidationError, instanceOf, isSchematic, schematic };