@oscarpalmer/jhunal 0.25.0 → 0.27.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 (75) hide show
  1. package/dist/constants.d.mts +15 -7
  2. package/dist/constants.mjs +15 -6
  3. package/dist/handler/base.handler.d.mts +6 -0
  4. package/dist/{validator/base.validator.mjs → handler/base.handler.mjs} +5 -5
  5. package/dist/handler/function.handler.d.mts +6 -0
  6. package/dist/handler/function.handler.mjs +9 -0
  7. package/dist/handler/object.handler.d.mts +7 -0
  8. package/dist/handler/object.handler.mjs +130 -0
  9. package/dist/handler/schema.handler.d.mts +7 -0
  10. package/dist/handler/schema.handler.mjs +16 -0
  11. package/dist/handler/type.handler.d.mts +9 -0
  12. package/dist/handler/type.handler.mjs +71 -0
  13. package/dist/handler/validator.handler.d.mts +10 -0
  14. package/dist/handler/validator.handler.mjs +34 -0
  15. package/dist/handler/value.handler.d.mts +14 -0
  16. package/dist/handler/value.handler.mjs +98 -0
  17. package/dist/helpers/message.helper.d.mts +9 -7
  18. package/dist/helpers/message.helper.mjs +34 -16
  19. package/dist/helpers/misc.helper.d.mts +13 -6
  20. package/dist/helpers/misc.helper.mjs +12 -4
  21. package/dist/helpers/report.helper.d.mts +23 -0
  22. package/dist/helpers/report.helper.mjs +19 -0
  23. package/dist/helpers/result.helper.d.mts +7 -0
  24. package/dist/helpers/result.helper.mjs +17 -0
  25. package/dist/index.d.mts +172 -73
  26. package/dist/index.mjs +396 -235
  27. package/dist/models/infer.model.d.mts +11 -8
  28. package/dist/models/misc.model.d.mts +8 -8
  29. package/dist/models/schematic.plain.model.d.mts +10 -9
  30. package/dist/models/schematic.typed.model.d.mts +1 -1
  31. package/dist/models/transform.model.d.mts +2 -2
  32. package/dist/models/validation.model.d.mts +56 -25
  33. package/dist/models/validation.model.mjs +11 -2
  34. package/dist/schema.d.mts +34 -34
  35. package/dist/schema.mjs +11 -19
  36. package/dist/validator.d.mts +83 -0
  37. package/dist/validator.mjs +25 -0
  38. package/package.json +2 -2
  39. package/src/constants.ts +30 -8
  40. package/src/{validator/base.validator.ts → handler/base.handler.ts} +6 -6
  41. package/src/handler/function.handler.ts +9 -0
  42. package/src/handler/object.handler.ts +245 -0
  43. package/src/handler/schema.handler.ts +25 -0
  44. package/src/handler/type.handler.ts +160 -0
  45. package/src/handler/validator.handler.ts +49 -0
  46. package/src/handler/value.handler.ts +202 -0
  47. package/src/helpers/message.helper.ts +72 -30
  48. package/src/helpers/misc.helper.ts +23 -6
  49. package/src/helpers/report.helper.ts +72 -0
  50. package/src/helpers/result.helper.ts +33 -0
  51. package/src/index.ts +1 -0
  52. package/src/models/infer.model.ts +31 -13
  53. package/src/models/misc.model.ts +9 -9
  54. package/src/models/schematic.plain.model.ts +12 -9
  55. package/src/models/schematic.typed.model.ts +3 -3
  56. package/src/models/transform.model.ts +2 -2
  57. package/src/models/validation.model.ts +75 -37
  58. package/src/schema.ts +44 -70
  59. package/src/validator.ts +135 -0
  60. package/dist/validator/base.validator.d.mts +0 -6
  61. package/dist/validator/function.validator.d.mts +0 -6
  62. package/dist/validator/function.validator.mjs +0 -9
  63. package/dist/validator/named.handler.d.mts +0 -6
  64. package/dist/validator/named.handler.mjs +0 -23
  65. package/dist/validator/named.validator.d.mts +0 -7
  66. package/dist/validator/named.validator.mjs +0 -38
  67. package/dist/validator/object.validator.d.mts +0 -7
  68. package/dist/validator/object.validator.mjs +0 -185
  69. package/dist/validator/schematic.validator.d.mts +0 -7
  70. package/dist/validator/schematic.validator.mjs +0 -16
  71. package/src/validator/function.validator.ts +0 -9
  72. package/src/validator/named.handler.ts +0 -65
  73. package/src/validator/named.validator.ts +0 -61
  74. package/src/validator/object.validator.ts +0 -366
  75. package/src/validator/schematic.validator.ts +0 -25
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
2
2
  import { join } from "@oscarpalmer/atoms/string";
3
- import { error, ok } from "@oscarpalmer/atoms/result/misc";
4
3
  import { clone } from "@oscarpalmer/atoms/value/clone";
4
+ import { error, ok } from "@oscarpalmer/atoms/result/misc";
5
5
  //#region src/constants.ts
6
6
  const CONJUNCTION_OR = " or ";
7
7
  const CONJUNCTION_OR_COMMA = ", or ";
@@ -10,24 +10,30 @@ const CONJUNCTION_AND_COMMA = ", and ";
10
10
  const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
11
11
  const NAME_ERROR_SCHEMATIC = "SchematicError";
12
12
  const NAME_ERROR_VALIDATION = "ValidationError";
13
+ const NAME_ERROR_VALIDATOR = "ValidatorError";
13
14
  const PROPERTY_DEFAULT = "$default";
14
15
  const PROPERTY_REQUIRED = "$required";
15
16
  const PROPERTY_SCHEMA = "$schema";
16
17
  const PROPERTY_TYPE = "$type";
18
+ const PROPERTY_VALIDATOR = "$validator";
17
19
  const PROPERTY_VALIDATORS = "$validators";
18
20
  const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
19
21
  const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
20
- const VALIDATION_MESSAGE_INVALID_TYPE = "Expected <> for '<>' but received <>";
21
- const VALIDATION_MESSAGE_INVALID_VALUE = "Value does not satisfy validator for '<>' and type '<>'";
22
- const VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX = " at index <>";
22
+ const VALIDATION_MESSAGE_INVALID_PROPERTY_TYPE = "Expected <> for '<>' but received <>";
23
+ const VALIDATION_MESSAGE_INVALID_PROPERTY_VALIDATOR = "Value does not satisfy validator for '<>' and type '<>'";
24
+ const VALIDATION_MESSAGE_INVALID_VALIDATOR_SUFFIX = " at index <>";
25
+ const VALIDATION_MESSAGE_INVALID_VALUE_TYPE = "Expected <> but received <>";
26
+ const VALIDATION_MESSAGE_INVALID_VALUE_VALIDATOR = "Value does not satisfy validator for type '<>'";
23
27
  const VALIDATION_MESSAGE_UNKNOWN_KEYS = "Found keys that are not defined in the schema: <>";
24
28
  const REPORTING_FIRST = "first";
25
29
  const REPORTING_NONE = "none";
30
+ const REPORTING_RESULT = "result";
26
31
  const REPORTING_THROW = "throw";
27
32
  const REPORTING_TYPES = new Set([
28
33
  "all",
29
34
  REPORTING_FIRST,
30
35
  REPORTING_NONE,
36
+ REPORTING_RESULT,
31
37
  REPORTING_THROW
32
38
  ]);
33
39
  const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED = "'<>' has a default value but is not required";
@@ -47,7 +53,7 @@ const TYPE_FUNCTION_RESULT = "a validated value";
47
53
  const TYPE_NULL = "null";
48
54
  const TYPE_OBJECT = "object";
49
55
  const TYPE_UNDEFINED = "undefined";
50
- const TYPE_ALL = new Set([
56
+ const TYPES_ALL = new Set([
51
57
  ...new Set([
52
58
  TYPE_ARRAY,
53
59
  "bigint",
@@ -62,7 +68,7 @@ const TYPE_ALL = new Set([
62
68
  TYPE_NULL,
63
69
  TYPE_UNDEFINED
64
70
  ]);
65
- const PREFIXED_TYPES = {
71
+ const TYPES_PREFIXED = {
66
72
  [TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
67
73
  bigint: `a bigint`,
68
74
  boolean: `a boolean`,
@@ -75,6 +81,9 @@ const PREFIXED_TYPES = {
75
81
  [TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
76
82
  [TYPE_UNDEFINED]: TYPE_UNDEFINED
77
83
  };
84
+ const VALIDATOR_MESSAGE_INVALID_PROPERTY_NULLABLE = "Validator must not be 'null' or 'undefined'";
85
+ const VALIDATOR_MESSAGE_INVALID_PROPERTY_TYPE = "Validator must be of a valid type";
86
+ const VALIDATOR_MESSAGE_INVALID_VALIDATOR = "Validator must be a function or an array of functions";
78
87
  //#endregion
79
88
  //#region src/helpers/misc.helper.ts
80
89
  function getParameters(input) {
@@ -103,7 +112,7 @@ function getReporting(value) {
103
112
  return {
104
113
  type,
105
114
  ["all"]: type === "all",
106
- [REPORTING_FIRST]: type === REPORTING_FIRST,
115
+ [REPORTING_FIRST]: type === "first" || type === "result",
107
116
  [REPORTING_NONE]: type === REPORTING_NONE,
108
117
  [REPORTING_THROW]: type === REPORTING_THROW
109
118
  };
@@ -121,13 +130,21 @@ function instanceOf(constructor) {
121
130
  };
122
131
  }
123
132
  /**
124
- * Is the value a schematic?
133
+ * Is the value a schema?
125
134
  * @param value Value to check
126
- * @returns `true` if the value is a schematic, `false` otherwise
135
+ * @returns `true` if the value is a schema, `false` otherwise
127
136
  */
128
137
  function isSchema(value) {
129
138
  return typeof value === "object" && value !== null && "$schema" in value && value["$schema"] === true;
130
139
  }
140
+ /**
141
+ * Is the value a validator?
142
+ * @param value Value to check
143
+ * @returns `true` if the value is a validator, `false` otherwise
144
+ */
145
+ function isValidator(value) {
146
+ return typeof value === "object" && value !== null && "$validator" in value && value["$validator"] === true;
147
+ }
131
148
  //#endregion
132
149
  //#region src/models/validation.model.ts
133
150
  /**
@@ -149,6 +166,285 @@ var ValidationError = class extends Error {
149
166
  this.name = NAME_ERROR_VALIDATION;
150
167
  }
151
168
  };
169
+ /**
170
+ * Thrown when a validator definition is invalid
171
+ */
172
+ var ValidatorError = class extends Error {
173
+ constructor(message) {
174
+ super(message);
175
+ this.name = NAME_ERROR_VALIDATOR;
176
+ }
177
+ };
178
+ //#endregion
179
+ //#region src/helpers/report.helper.ts
180
+ function report(parameters, getReports) {
181
+ const { information, message, original } = parameters;
182
+ let reported;
183
+ if (information?.existing == null) {
184
+ reported = [{
185
+ value: parameters.value,
186
+ message: message.callback(...message.arguments)
187
+ }];
188
+ if (parameters.key != null) reported[0].key = parameters.key;
189
+ } else reported = information.existing;
190
+ if (original.reporting.throw) throw new ValidationError(reported);
191
+ information?.all.push(...reported);
192
+ if (parameters.extract ?? true) original.information?.push(...reported);
193
+ if ((getReports ?? false) || !original.reporting.all) return reported;
194
+ }
195
+ //#endregion
196
+ //#region src/handler/base.handler.ts
197
+ function getBaseHandler(handlers) {
198
+ const { length } = handlers;
199
+ return (input, parameters, get) => {
200
+ const allInformation = [];
201
+ for (let index = 0; index < length; index += 1) {
202
+ const previousInformation = parameters.information;
203
+ parameters.information = [];
204
+ const result = handlers[index](input, parameters, get);
205
+ parameters.information = previousInformation;
206
+ if (result === true) return true;
207
+ parameters.information?.push(...result);
208
+ allInformation.push(...result);
209
+ }
210
+ return allInformation;
211
+ };
212
+ }
213
+ //#endregion
214
+ //#region src/handler/function.handler.ts
215
+ function getFunctionHandler(fn) {
216
+ const handler = isConstructor(fn) ? instanceOf(fn) : fn;
217
+ return (input) => handler(input) ? true : [];
218
+ }
219
+ //#endregion
220
+ //#region src/handler/schema.handler.ts
221
+ function getSchemaHandler(schematic) {
222
+ const handler = schemaHandlers.get(schematic);
223
+ return (input, parameters, get) => {
224
+ let result;
225
+ if (isPlainObject(input)) result = handler(input, parameters, get);
226
+ else result = [];
227
+ if (result === true) return result;
228
+ parameters.information?.push(...result);
229
+ return result;
230
+ };
231
+ }
232
+ //#endregion
233
+ //#region src/handler/type.handler.ts
234
+ function getTypeHandler(type, validators, key) {
235
+ const validator = typeValidators[type];
236
+ const typedValidators = validators[type] ?? [];
237
+ const { length } = typedValidators;
238
+ return (input, parameters) => {
239
+ if (!validator(input)) return [];
240
+ for (let index = 0; index < length; index += 1) {
241
+ const validator = typedValidators[index];
242
+ if (validator(input) === true) continue;
243
+ const information = {
244
+ validator,
245
+ message: key == null ? getInputValueValidatorMessage(type, index, length) : getInputPropertyValidatorMessage(key.full, type, index, length),
246
+ value: input
247
+ };
248
+ if (key != null) information.key = key;
249
+ parameters.information?.push(information);
250
+ return parameters.reporting.none ? [] : [information];
251
+ }
252
+ return true;
253
+ };
254
+ }
255
+ function getTypeValidators(types, original) {
256
+ const values = types.filter((type) => TYPES_ALL.has(type));
257
+ const { length } = values;
258
+ const validators = {};
259
+ if (original == null || length === 0) return validators;
260
+ if (typeof original === "function" || Array.isArray(original)) {
261
+ if (length > 1) throw new ValidatorError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
262
+ return getValidators({ [values[0]]: original }, true);
263
+ }
264
+ return getValidators(original, true);
265
+ }
266
+ function getValidators(original, allowed, prefix) {
267
+ const validators = {};
268
+ if (original == null) return validators;
269
+ if (!allowed) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", PROPERTY_VALIDATORS));
270
+ if (!isPlainObject(original)) throw new SchematicError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
271
+ const keys = Object.keys(original);
272
+ const { length } = keys;
273
+ for (let index = 0; index < length; index += 1) {
274
+ const key = keys[index];
275
+ if (!TYPES_ALL.has(key)) throw new SchematicError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
276
+ const value = original[key];
277
+ validators[key] = (Array.isArray(value) ? value : [value]).map((item) => {
278
+ if (typeof item !== "function") if (prefix == null) throw new ValidatorError(VALIDATOR_MESSAGE_INVALID_VALIDATOR);
279
+ else throw new SchematicError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
280
+ return item;
281
+ });
282
+ }
283
+ return validators;
284
+ }
285
+ const typeValidators = {
286
+ array: Array.isArray,
287
+ bigint: (value) => typeof value === "bigint",
288
+ boolean: (value) => typeof value === "boolean",
289
+ date: (value) => value instanceof Date,
290
+ function: (value) => typeof value === "function",
291
+ null: (value) => value === null,
292
+ number: (value) => typeof value === "number",
293
+ object: (value) => typeof value === "object" && value !== null,
294
+ string: (value) => typeof value === "string",
295
+ symbol: (value) => typeof value === "symbol",
296
+ undefined: (value) => value === void 0
297
+ };
298
+ //#endregion
299
+ //#region src/handler/value.handler.ts
300
+ function getDefaults(obj, key, allowed) {
301
+ if (!("$default" in obj)) return;
302
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_DEFAULT));
303
+ return { value: obj[PROPERTY_DEFAULT] };
304
+ }
305
+ function getRequired(obj, key, allowed) {
306
+ if (!("$required" in obj)) return;
307
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_REQUIRED));
308
+ if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
309
+ return obj[PROPERTY_REQUIRED];
310
+ }
311
+ function getValueHandler(input, property) {
312
+ const isProperty = property != null;
313
+ const prefixedKey = isProperty ? property.origin == null ? property.key : join([property.origin.full, property.key], ".") : "";
314
+ const { value } = input;
315
+ if (value == null) {
316
+ if (isProperty) throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
317
+ throw new ValidatorError(VALIDATOR_MESSAGE_INVALID_PROPERTY_NULLABLE);
318
+ }
319
+ const fullKey = {
320
+ full: prefixedKey,
321
+ short: property?.key ?? ""
322
+ };
323
+ let required = true;
324
+ let typed = false;
325
+ let validators = {};
326
+ let defaults;
327
+ let types;
328
+ const handlers = [];
329
+ if (isProperty && isPlainObject(value)) {
330
+ typed = PROPERTY_TYPE in value;
331
+ const type = typed ? value[PROPERTY_TYPE] : value;
332
+ defaults = getDefaults(value, prefixedKey, typed);
333
+ required = getRequired(value, prefixedKey, typed) ?? required;
334
+ validators = getValidators(value[PROPERTY_VALIDATORS], typed, prefixedKey);
335
+ types = Array.isArray(type) ? type : [type];
336
+ } else {
337
+ types = Array.isArray(value) ? value : [value];
338
+ if (input.validators != null) validators = getTypeValidators(types, input.validators);
339
+ }
340
+ const typesLength = types.length;
341
+ let invalid = false;
342
+ typeLoop: for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
343
+ const type = types[typeIndex];
344
+ let handler;
345
+ switch (true) {
346
+ case typeof type === "function":
347
+ handler = getFunctionHandler(type);
348
+ break;
349
+ case isProperty && isPlainObject(type):
350
+ handler = getObjectHandler(type, fullKey, typed);
351
+ break;
352
+ case isProperty && isSchema(type):
353
+ handler = getSchemaHandler(type);
354
+ break;
355
+ case isProperty && isValidator(type):
356
+ handler = validatorHandlers.get(type);
357
+ break;
358
+ case TYPES_ALL.has(type):
359
+ handler = getTypeHandler(type, validators, isProperty ? fullKey : void 0);
360
+ break;
361
+ default:
362
+ invalid = true;
363
+ break typeLoop;
364
+ }
365
+ handlers.push(handler);
366
+ }
367
+ if (invalid || handlers.length === 0) {
368
+ if (isProperty) throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
369
+ throw new ValidatorError(VALIDATOR_MESSAGE_INVALID_PROPERTY_TYPE);
370
+ }
371
+ required = required && !types.includes("undefined");
372
+ if (defaults != null && !required) throw new SchematicError(getDefaultRequiredMessage(prefixedKey));
373
+ const handler = getBaseHandler(handlers);
374
+ if (defaults != null && Array.isArray(handler(defaults.value, getParameters(isProperty), false))) throw new SchematicError(getDefaultTypeMessage(prefixedKey, types));
375
+ return {
376
+ defaults,
377
+ handler,
378
+ required,
379
+ types,
380
+ key: fullKey
381
+ };
382
+ }
383
+ //#endregion
384
+ //#region src/handler/validator.handler.ts
385
+ function getValidatorHandler(value, validators) {
386
+ const { handler, types } = getValueHandler({
387
+ validators,
388
+ value
389
+ });
390
+ const validator = (input, parameters, get) => {
391
+ const result = handler(input, parameters, get);
392
+ if (result === true) return true;
393
+ if (parameters.key != null) return [];
394
+ return report({
395
+ value: input,
396
+ extract: false,
397
+ information: {
398
+ all: parameters.information ?? [],
399
+ existing: result.length > 0 ? result : void 0
400
+ },
401
+ message: {
402
+ arguments: [types, input],
403
+ callback: getInputValueTypeMessage
404
+ },
405
+ original: parameters
406
+ });
407
+ };
408
+ return {
409
+ types,
410
+ handler: validator
411
+ };
412
+ }
413
+ //#endregion
414
+ //#region src/helpers/result.helper.ts
415
+ function getResult(handler, value, options) {
416
+ const parameters = getParameters(options);
417
+ const result = handler(value, parameters, true);
418
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.clone ? parameters.output : value : ok(parameters.clone ? parameters.output : value);
419
+ if (!parameters.reporting.none) return error(parameters.reporting.all ? result : result[0]);
420
+ }
421
+ function isResult(handler, value, options) {
422
+ const parameters = getParameters(options);
423
+ const result = handler(value, parameters, false);
424
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
425
+ return parameters.reporting.none ? false : error(parameters.reporting.all ? result : result[0]);
426
+ }
427
+ //#endregion
428
+ //#region src/validator.ts
429
+ var Validator = class {
430
+ #handler;
431
+ constructor(handler, types) {
432
+ Object.defineProperty(this, PROPERTY_VALIDATOR, { value: true });
433
+ this.#handler = handler;
434
+ validatorHandlers.set(this, handler);
435
+ validatorTypes.set(this, types);
436
+ }
437
+ is(value, options) {
438
+ return isResult(this.#handler, value, options);
439
+ }
440
+ };
441
+ function validator(value, validators) {
442
+ if (value instanceof Validator) return value;
443
+ const { handler, types } = getValidatorHandler(value, validators);
444
+ return new Validator(handler, types);
445
+ }
446
+ const validatorHandlers = /* @__PURE__ */ new WeakMap();
447
+ const validatorTypes = /* @__PURE__ */ new WeakMap();
152
448
  //#endregion
153
449
  //#region src/helpers/message.helper.ts
154
450
  function getDefaultRequiredMessage(key) {
@@ -173,15 +469,25 @@ function getInputPropertyMissingMessage(key, types) {
173
469
  return message;
174
470
  }
175
471
  function getInputPropertyTypeMessage(key, types, actual) {
176
- let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
472
+ let message = VALIDATION_MESSAGE_INVALID_PROPERTY_TYPE.replace("<>", renderTypes(types));
177
473
  message = message.replace("<>", key);
178
474
  message = message.replace("<>", getValueType(actual));
179
475
  return message;
180
476
  }
181
477
  function getInputPropertyValidatorMessage(key, type, index, length) {
182
- let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
478
+ let message = VALIDATION_MESSAGE_INVALID_PROPERTY_VALIDATOR.replace("<>", key);
183
479
  message = message.replace("<>", type);
184
- if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
480
+ if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALIDATOR_SUFFIX.replace("<>", String(index));
481
+ return message;
482
+ }
483
+ function getInputValueTypeMessage(types, actual) {
484
+ let message = VALIDATION_MESSAGE_INVALID_VALUE_TYPE.replace("<>", renderTypes(types));
485
+ message = message.replace("<>", getValueType(actual));
486
+ return message;
487
+ }
488
+ function getInputValueValidatorMessage(type, index, length) {
489
+ let message = VALIDATION_MESSAGE_INVALID_VALUE_VALIDATOR.replace("<>", type);
490
+ if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALIDATOR_SUFFIX.replace("<>", String(index));
185
491
  return message;
186
492
  }
187
493
  function getSchematicPropertyNullableMessage(key) {
@@ -192,18 +498,19 @@ function getSchematicPropertyTypeMessage(key) {
192
498
  }
193
499
  function getPropertyType(type) {
194
500
  switch (true) {
195
- case typeof type === "function": return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
196
- case TYPE_ALL.has(type): return PREFIXED_TYPES[type];
197
- default: return PREFIXED_TYPES[TYPE_OBJECT];
501
+ case typeof type === "function": return [isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT];
502
+ case isValidator(type): return validatorTypes.get(type).flatMap(getPropertyType);
503
+ case TYPES_ALL.has(type): return [TYPES_PREFIXED[type]];
504
+ default: return [TYPES_PREFIXED[TYPE_OBJECT]];
198
505
  }
199
506
  }
200
507
  function getValueType(value) {
201
508
  const valueType = typeof value;
202
509
  switch (true) {
203
510
  case value === null: return TYPE_NULL;
204
- case Array.isArray(value): return PREFIXED_TYPES[TYPE_ARRAY];
205
- case isPlainObject(value): return PREFIXED_TYPES[TYPE_OBJECT];
206
- case valueType !== TYPE_OBJECT: return PREFIXED_TYPES[valueType];
511
+ case Array.isArray(value): return TYPES_PREFIXED[TYPE_ARRAY];
512
+ case isPlainObject(value): return TYPES_PREFIXED[TYPE_OBJECT];
513
+ case valueType !== TYPE_OBJECT: return TYPES_PREFIXED[valueType];
207
514
  default: return value.constructor.name;
208
515
  }
209
516
  }
@@ -224,11 +531,16 @@ function renderParts(parts, delimiterShort, delimiterLong) {
224
531
  function renderTypes(types) {
225
532
  const unique = /* @__PURE__ */ new Set();
226
533
  const parts = [];
227
- for (let index = 0; index < types.length; index += 1) {
228
- const rendered = getPropertyType(types[index]);
229
- if (unique.has(rendered)) continue;
230
- unique.add(rendered);
231
- parts.push(rendered);
534
+ const typesLength = types.length;
535
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
536
+ const properties = getPropertyType(types[typeIndex]);
537
+ const propertiesLength = properties.length;
538
+ for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
539
+ const property = properties[propertyIndex];
540
+ if (unique.has(property)) continue;
541
+ unique.add(property);
542
+ parts.push(property);
543
+ }
232
544
  }
233
545
  return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
234
546
  }
@@ -239,112 +551,14 @@ function getUnknownKeysMessage(keys) {
239
551
  return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
240
552
  }
241
553
  //#endregion
242
- //#region src/validator/base.validator.ts
243
- function getBaseValidator(validators) {
244
- const { length } = validators;
245
- return (input, parameters, get) => {
246
- const allInformation = [];
247
- for (let index = 0; index < length; index += 1) {
248
- const previousInformation = parameters.information;
249
- parameters.information = [];
250
- const result = validators[index](input, parameters, get);
251
- parameters.information = previousInformation;
252
- if (result === true) return true;
253
- parameters.information?.push(...result);
254
- allInformation.push(...result);
255
- }
256
- return allInformation;
257
- };
258
- }
259
- //#endregion
260
- //#region src/validator/function.validator.ts
261
- function getFunctionValidator(fn) {
262
- const validator = isConstructor(fn) ? instanceOf(fn) : fn;
263
- return (input) => validator(input) ? true : [];
264
- }
265
- //#endregion
266
- //#region src/validator/named.handler.ts
267
- function getNamedHandlers(original, prefix, allowed) {
268
- const handlers = {};
269
- if (original == null) return handlers;
270
- if (!allowed) throw new TypeError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", PROPERTY_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 (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
277
- const value = original[key];
278
- handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
279
- if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
280
- return item;
281
- });
282
- }
283
- return handlers;
284
- }
285
- //#endregion
286
- //#region src/validator/named.validator.ts
287
- function getNamedValidator(key, name, handlers) {
288
- const validator = namedValidators[name];
289
- const named = handlers[name] ?? [];
290
- const { length } = named;
291
- return (input, parameters) => {
292
- if (!validator(input)) return [];
293
- for (let index = 0; index < length; index += 1) {
294
- const handler = named[index];
295
- if (handler(input) === true) continue;
296
- const information = {
297
- key,
298
- validator,
299
- message: getInputPropertyValidatorMessage(key.full, name, index, length),
300
- value: input
301
- };
302
- parameters.information?.push(information);
303
- return parameters.reporting.none ? [] : [information];
304
- }
305
- return true;
306
- };
307
- }
308
- const namedValidators = {
309
- array: Array.isArray,
310
- bigint: (value) => typeof value === "bigint",
311
- boolean: (value) => typeof value === "boolean",
312
- date: (value) => value instanceof Date,
313
- function: (value) => typeof value === "function",
314
- null: (value) => value === null,
315
- number: (value) => typeof value === "number",
316
- object: (value) => typeof value === "object" && value !== null,
317
- string: (value) => typeof value === "string",
318
- symbol: (value) => typeof value === "symbol",
319
- undefined: (value) => value === void 0
320
- };
321
- //#endregion
322
- //#region src/validator/schematic.validator.ts
323
- function getSchemaValidator(schematic) {
324
- const validator = schemaValidators.get(schematic);
325
- return (input, parameters, get) => {
326
- let result;
327
- if (isPlainObject(input)) result = validator(input, parameters, get);
328
- else result = [];
329
- if (result === true) return result;
330
- parameters.information?.push(...result);
331
- return result;
332
- };
333
- }
334
- //#endregion
335
- //#region src/validator/object.validator.ts
336
- function getDefaults(obj, key, allowed) {
337
- if (!("$default" in obj)) return;
338
- if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_DEFAULT));
339
- return { value: obj[PROPERTY_DEFAULT] };
340
- }
554
+ //#region src/handler/object.handler.ts
341
555
  function getDisallowedProperty(obj) {
342
556
  if ("$default" in obj) return PROPERTY_DEFAULT;
343
557
  if ("$required" in obj) return PROPERTY_REQUIRED;
344
558
  if ("$type" in obj) return PROPERTY_TYPE;
345
559
  if ("$validators" in obj) return PROPERTY_VALIDATORS;
346
560
  }
347
- function getObjectValidator(original, origin, fromType) {
561
+ function getObjectHandler(original, origin, fromType) {
348
562
  const keys = Object.keys(original);
349
563
  const keysLength = keys.length;
350
564
  if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
@@ -356,86 +570,34 @@ function getObjectValidator(original, origin, fromType) {
356
570
  const items = [];
357
571
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
358
572
  const key = keys[keyIndex];
359
- const value = original[key];
360
- if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
361
- const prefixedKey = origin == null ? key : join([origin.full, key], ".");
362
- const fullKey = {
363
- full: prefixedKey,
364
- short: key
365
- };
366
- let handlers = {};
367
- let required = true;
368
- let typed = false;
369
- let defaults;
370
- let types;
371
- const validators = [];
372
- if (isPlainObject(value)) {
373
- typed = PROPERTY_TYPE in value;
374
- const type = typed ? value[PROPERTY_TYPE] : value;
375
- defaults = getDefaults(value, prefixedKey, typed);
376
- handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey, typed);
377
- required = getRequired(value, prefixedKey, typed) ?? required;
378
- types = Array.isArray(type) ? type : [type];
379
- } else types = Array.isArray(value) ? value : [value];
380
- if (types.length === 0) throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
381
- const typesLength = types.length;
382
- for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
383
- const type = types[typeIndex];
384
- let validator;
385
- switch (true) {
386
- case typeof type === "function":
387
- validator = getFunctionValidator(type);
388
- break;
389
- case isPlainObject(type):
390
- validator = getObjectValidator(type, fullKey, typed);
391
- break;
392
- case isSchema(type):
393
- validator = getSchemaValidator(type);
394
- break;
395
- case TYPE_ALL.has(type):
396
- validator = getNamedValidator(fullKey, type, handlers);
397
- break;
398
- default: throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
399
- }
400
- validators.push(validator);
401
- }
402
- required = required && !types.includes("undefined");
403
- if (defaults != null && !required) throw new SchematicError(getDefaultRequiredMessage(prefixedKey));
404
- const validator = getBaseValidator(validators);
405
- if (defaults != null && Array.isArray(validator(defaults.value, getParameters(), false))) throw new SchematicError(getDefaultTypeMessage(prefixedKey, types));
573
+ const { defaults, handler, key: fullKey, required, types } = getValueHandler({ value: original[key] }, {
574
+ key,
575
+ origin
576
+ });
406
577
  items.push({
407
578
  defaults,
579
+ handler,
408
580
  required,
409
581
  types,
410
- validator,
411
582
  key: fullKey
412
583
  });
413
584
  set.add(key);
414
585
  }
415
586
  const validatorsLength = items.length;
416
587
  return (input, parameters, get) => {
417
- if (!isPlainObject(input)) {
418
- if (origin != null) return [];
419
- const information = {
420
- key: {
421
- full: "",
422
- short: ""
423
- },
424
- value: input,
425
- message: getInputTypeMessage(input)
426
- };
427
- if (parameters.reporting.throw) throw new ValidationError([information]);
428
- parameters.information?.push(information);
429
- return [information];
430
- }
588
+ if (!isPlainObject(input)) return origin == null ? report({
589
+ message: {
590
+ arguments: [input],
591
+ callback: getInputTypeMessage
592
+ },
593
+ original: parameters,
594
+ value: input
595
+ }, true) : [];
431
596
  if (parameters.strict) {
432
597
  const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
433
598
  if (unknownKeys.length > 0) {
434
599
  const information = {
435
- key: origin ?? {
436
- full: "",
437
- short: ""
438
- },
600
+ key: origin,
439
601
  message: getUnknownKeysMessage(unknownKeys),
440
602
  value: input
441
603
  };
@@ -444,97 +606,96 @@ function getObjectValidator(original, origin, fromType) {
444
606
  return [information];
445
607
  }
446
608
  }
609
+ const getAndClone = get && parameters.clone;
447
610
  const allInformation = [];
448
611
  const output = {};
449
612
  for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
450
- const { defaults, key, required, types, validator } = items[validatorIndex];
613
+ const { defaults, handler, key, required, types } = items[validatorIndex];
451
614
  const value = input[key.short];
452
615
  if (value === void 0) {
453
616
  if (required) {
454
617
  if (get && defaults != null) {
455
- output[key.short] = clone(defaults.value);
618
+ const defaultValue = clone(defaults.value);
619
+ if (parameters.clone) output[key.short] = defaultValue;
620
+ else input[key.short] = defaultValue;
456
621
  continue;
457
622
  }
458
623
  if (parameters.reporting.none) return [];
459
- const information = {
624
+ const reported = report({
460
625
  key,
461
626
  value,
462
- message: getInputPropertyMissingMessage(key.full, types)
463
- };
464
- if (parameters.reporting.throw) throw new ValidationError([information]);
465
- parameters.information?.push(information);
466
- if (parameters.reporting.all) {
467
- allInformation.push(information);
468
- continue;
469
- }
470
- return [information];
627
+ information: { all: allInformation },
628
+ message: {
629
+ arguments: [key.full, types],
630
+ callback: getInputPropertyMissingMessage
631
+ },
632
+ original: parameters
633
+ });
634
+ if (reported == null) continue;
635
+ return reported;
471
636
  }
472
637
  continue;
473
638
  }
474
639
  const previousOutput = parameters.output;
640
+ parameters.key = key.full;
475
641
  parameters.output = output;
476
- const result = validator(value, parameters, get);
642
+ const result = handler(value, parameters, get);
477
643
  parameters.output = previousOutput;
478
644
  if (result === true) {
479
- if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
645
+ if (getAndClone && !isPlainObject(value)) output[key.short] = clone(value);
480
646
  continue;
481
647
  }
482
648
  if (parameters.reporting.none) return [];
483
- const information = typeof result !== "boolean" && result.length > 0 ? result : [{
649
+ const reported = report({
484
650
  key,
485
651
  value,
486
- message: getInputPropertyTypeMessage(key.full, types, value)
487
- }];
488
- if (parameters.reporting.throw) throw new ValidationError(information);
489
- if (parameters.reporting.all) {
490
- allInformation.push(...information);
491
- continue;
492
- }
493
- return information;
652
+ extract: false,
653
+ information: {
654
+ all: allInformation,
655
+ existing: typeof result !== "boolean" && result.length > 0 ? result : void 0
656
+ },
657
+ message: {
658
+ arguments: [
659
+ key.full,
660
+ types,
661
+ value
662
+ ],
663
+ callback: getInputPropertyTypeMessage
664
+ },
665
+ original: parameters
666
+ });
667
+ if (reported == null) continue;
668
+ return reported;
494
669
  }
495
- if (get) if (origin == null) parameters.output = output;
670
+ if (getAndClone) if (origin == null) parameters.output = output;
496
671
  else parameters.output[origin.short] = output;
497
672
  return allInformation.length === 0 ? true : allInformation;
498
673
  };
499
674
  }
500
- function getRequired(obj, key, allowed) {
501
- if (!("$required" in obj)) return;
502
- if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_REQUIRED));
503
- if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
504
- return obj[PROPERTY_REQUIRED];
505
- }
506
675
  //#endregion
507
676
  //#region src/schema.ts
508
677
  /**
509
678
  * A schema for validating objects
510
679
  */
511
680
  var Schema = class {
512
- #validator;
681
+ #handler;
513
682
  constructor(validator) {
514
683
  Object.defineProperty(this, PROPERTY_SCHEMA, { value: true });
515
- this.#validator = validator;
516
- schemaValidators.set(this, validator);
684
+ this.#handler = validator;
685
+ schemaHandlers.set(this, validator);
517
686
  }
518
687
  get(value, options) {
519
- const parameters = getParameters(options);
520
- const result = this.#validator(value, parameters, true);
521
- if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
522
- if (parameters.reporting.none) return;
523
- return error(parameters.reporting.all ? result : result[0]);
688
+ return getResult(this.#handler, value, options);
524
689
  }
525
690
  is(value, options) {
526
- const parameters = getParameters(options);
527
- const result = this.#validator(value, parameters, false);
528
- if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
529
- if (parameters.reporting.none) return false;
530
- return error(parameters.reporting.all ? result : result[0]);
691
+ return isResult(this.#handler, value, options);
531
692
  }
532
693
  };
533
694
  function schema(schema) {
534
695
  if (isSchema(schema)) return schema;
535
696
  if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
536
- return new Schema(getObjectValidator(schema));
697
+ return new Schema(getObjectHandler(schema));
537
698
  }
538
- const schemaValidators = /* @__PURE__ */ new WeakMap();
699
+ const schemaHandlers = /* @__PURE__ */ new WeakMap();
539
700
  //#endregion
540
- export { SchematicError, ValidationError, instanceOf, isSchema, schema };
701
+ export { SchematicError, ValidationError, instanceOf, isSchema, schema, validator };