@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
@@ -25,19 +25,13 @@ type PlainSchema = {
25
25
  * };
26
26
  * ```
27
27
  */
28
- type Schema = SchemaIndex;
28
+ type Schema = PlainSchema;
29
29
  /**
30
30
  * A union of all valid types for a single schema entry
31
31
  *
32
32
  * Can be a {@link Constructor}, {@link PlainSchema}, {@link SchemaProperty}, {@link Schematic}, {@link ValueName} string, or a custom validator function
33
33
  */
34
34
  type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
35
- /**
36
- * Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link PlainSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
37
- */
38
- interface SchemaIndex {
39
- [key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
40
- }
41
35
  /**
42
36
  * A property definition with explicit type(s), an optional requirement flag, and optional validators
43
37
  *
@@ -89,4 +83,4 @@ type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | Value
89
83
  */
90
84
  type PropertyValidators<Value> = { [Key in ExtractValueNames<Value>]?: ((value: Values[Key]) => boolean) | Array<(value: Values[Key]) => boolean> };
91
85
  //#endregion
92
- export { PlainSchema, PropertyValidators, Schema, SchemaEntry, SchemaIndex, SchemaProperty, SchemaPropertyType };
86
+ export { PlainSchema, PropertyValidators, Schema, SchemaEntry, SchemaProperty, SchemaPropertyType };
@@ -3,19 +3,18 @@ import { ValueName } from "./misc.model.mjs";
3
3
  import { GenericCallback, PlainObject } from "@oscarpalmer/atoms/models";
4
4
 
5
5
  //#region src/models/validation.model.d.ts
6
- /**
7
- * Maps each {@link ReportingType} to a boolean flag
8
- */
6
+ type NamedValidatorHandlers = { [Key in ValueName]?: Array<(value: unknown) => boolean> };
7
+ type NamedValidators = Record<ValueName, (value: unknown) => boolean>;
9
8
  type ReportingInformation = Record<ReportingType, boolean> & {
10
9
  type: ReportingType;
11
10
  };
12
11
  /**
13
12
  * Controls how validation failures are reported
14
13
  *
15
- * - `'none'` returns a boolean _(default)_
16
- * - `'first'` returns the first failure as a `Result`
17
- * - `'all'` returns all failures as a `Result` _(from same level)_
18
- * - `'throw'` throws a {@link ValidationError} on failure
14
+ * - `'none'`, returns a boolean _(default)_
15
+ * - `'first'`, returns the first failure as a `Result`
16
+ * - `'all'`, returns all failures as a `Result` _(from same level)_
17
+ * - `'throw'`, throws a {@link ValidationError} on failure
19
18
  */
20
19
  type ReportingType = 'all' | 'first' | 'none' | 'throw';
21
20
  /**
@@ -24,49 +23,6 @@ type ReportingType = 'all' | 'first' | 'none' | 'throw';
24
23
  declare class SchematicError extends Error {
25
24
  constructor(message: string);
26
25
  }
27
- /**
28
- * The runtime representation of a parsed schema property, used internally during validation
29
- *
30
- * @example
31
- * ```ts
32
- * const parsed: ValidatedProperty = {
33
- * key: 'age',
34
- * required: true,
35
- * types: ['number'],
36
- * validators: { number: [(v) => v > 0] },
37
- * };
38
- * ```
39
- */
40
- type ValidatedProperty = {
41
- /**
42
- * The property name in the schema
43
- */
44
- key: string;
45
- /**
46
- * Whether the property is required
47
- */
48
- required: boolean;
49
- /**
50
- * The allowed types for this property
51
- */
52
- types: ValidatedPropertyType[];
53
- /**
54
- * Custom validators grouped by {@link ValueName}
55
- */
56
- validators: ValidatedPropertyValidators;
57
- };
58
- /**
59
- * A union of valid types for a {@link ValidatedProperty}'s `types` array
60
- *
61
- * Can be a callback _(custom validator)_, a {@link Schematic}, a nested {@link ValidatedProperty}, or a {@link ValueName} string
62
- */
63
- type ValidatedPropertyType = GenericCallback | ValidatedProperty[] | Schematic<unknown> | ValueName;
64
- /**
65
- * A map of validator functions keyed by {@link ValueName}, used at runtime in {@link ValidatedProperty}
66
- *
67
- * Each key holds an array of validator functions that receive an `unknown` value and return a `boolean`
68
- */
69
- type ValidatedPropertyValidators = { [Key in ValueName]?: Array<(value: unknown) => boolean> };
70
26
  /**
71
27
  * Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
72
28
  */
@@ -90,26 +46,37 @@ type ValidationInformationKey = {
90
46
  full: string;
91
47
  short: string;
92
48
  };
93
- /**
94
- * Options for validation
95
- */
96
- type ValidationOptions<Errors extends ReportingType> = {
49
+ type BaseOptions<Errors extends ReportingType> = {
97
50
  /**
98
51
  * How should validation failures be reported; see {@link ReportingType} _(defaults to `'none'`)_
99
52
  */
100
- errors?: Errors;
53
+ errors: Errors;
101
54
  /**
102
55
  * Validate if unknown keys are present in the object? _(defaults to `false`)_
103
56
  */
104
57
  strict?: boolean;
105
58
  };
106
- type ValidationParameters = {
59
+ /**
60
+ * Options for validating and getting a value from an input
61
+ */
62
+ type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
63
+ /**
64
+ * Get a deeply cloned version of the input? _(defaults to `true`)_
65
+ */
66
+ clone?: boolean;
67
+ };
68
+ /**
69
+ * Options for validation an input value
70
+ */
71
+ type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
72
+ type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => true | ValidationInformation[];
73
+ type ValidatorParameters = {
74
+ clone: boolean;
107
75
  information?: ValidationInformation[];
108
- origin?: ValidatedProperty;
109
76
  output: PlainObject;
110
- prefix?: string;
111
77
  reporting: ReportingInformation;
112
78
  strict: boolean;
113
79
  };
80
+ type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
114
81
  //#endregion
115
- export { ReportingInformation, ReportingType, SchematicError, ValidatedProperty, ValidatedPropertyType, ValidatedPropertyValidators, ValidationError, ValidationInformation, ValidationInformationKey, ValidationOptions, ValidationParameters };
82
+ export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorParameters, ValidatorType };
@@ -1,6 +1,6 @@
1
1
  import { Infer } from "./models/infer.model.mjs";
2
2
  import { TypedSchema } from "./models/schema.typed.model.mjs";
3
- import { ValidatedProperty, ValidationInformation, ValidationOptions } from "./models/validation.model.mjs";
3
+ import { GetOptions, IsOptions, ValidationInformation, Validator } from "./models/validation.model.mjs";
4
4
  import { Schema } from "./models/schema.plain.model.mjs";
5
5
  import { PlainObject } from "@oscarpalmer/atoms/models";
6
6
  import { Result } from "@oscarpalmer/atoms/result/models";
@@ -12,7 +12,7 @@ import { Result } from "@oscarpalmer/atoms/result/models";
12
12
  declare class Schematic<Model> {
13
13
  #private;
14
14
  private readonly $schematic;
15
- constructor(properties: ValidatedProperty[]);
15
+ constructor(validator: Validator);
16
16
  /**
17
17
  * Parse a value according to the schema
18
18
  *
@@ -21,7 +21,7 @@ declare class Schematic<Model> {
21
21
  * @param options Validation options
22
22
  * @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
23
23
  */
24
- get(value: unknown, options: ValidationOptions<'throw'>): Model;
24
+ get(value: unknown, options: GetOptions<'throw'>): Model;
25
25
  /**
26
26
  * Parse a value according to the schema
27
27
  *
@@ -39,7 +39,7 @@ declare class Schematic<Model> {
39
39
  * @param options Validation options
40
40
  * @returns Result holding deeply cloned value or all validation information
41
41
  */
42
- get(value: unknown, options: ValidationOptions<'all'>): Result<Model, ValidationInformation[]>;
42
+ get(value: unknown, options: GetOptions<'all'>): Result<Model, ValidationInformation[]>;
43
43
  /**
44
44
  * Parse a value according to the schema
45
45
  *
@@ -57,7 +57,7 @@ declare class Schematic<Model> {
57
57
  * @param options Validation options
58
58
  * @returns Result holding deeply cloned value or all validation information
59
59
  */
60
- get(value: unknown, options: ValidationOptions<'first'>): Result<Model, ValidationInformation>;
60
+ get(value: unknown, options: GetOptions<'first'>): Result<Model, ValidationInformation>;
61
61
  /**
62
62
  * Parse a value according to the schema
63
63
  *
@@ -67,6 +67,15 @@ declare class Schematic<Model> {
67
67
  * @returns Result holding deeply cloned value or all validation information
68
68
  */
69
69
  get(value: unknown, errors: 'first'): Result<Model, ValidationInformation>;
70
+ /**
71
+ * Parse a value according to the schema
72
+ *
73
+ * Returns a deeply cloned version of the value or `undefined` if the value does not match the schema
74
+ * @param value Value to parse
75
+ * @param options Validation options
76
+ * @returns Deeply cloned value, or `undefined` if it's invalid
77
+ */
78
+ get(value: unknown, options: GetOptions<'none'>): Model | undefined;
70
79
  /**
71
80
  * Parse a value according to the schema
72
81
  *
@@ -84,7 +93,7 @@ declare class Schematic<Model> {
84
93
  * @param options Validation options
85
94
  * @returns `true` if the value matches the schema, otherwise throws an error
86
95
  */
87
- is(value: unknown, options: ValidationOptions<'throw'>): asserts value is Model;
96
+ is(value: unknown, options: IsOptions<'throw'>): asserts value is Model;
88
97
  /**
89
98
  * Does the value match the schema?
90
99
  *
@@ -102,7 +111,7 @@ declare class Schematic<Model> {
102
111
  * @param options Validation options
103
112
  * @returns Result holding `true` or all validation information
104
113
  */
105
- is(value: unknown, options: ValidationOptions<'all'>): Result<true, ValidationInformation[]>;
114
+ is(value: unknown, options: IsOptions<'all'>): Result<true, ValidationInformation[]>;
106
115
  /**
107
116
  * Does the value match the schema?
108
117
  *
@@ -120,7 +129,7 @@ declare class Schematic<Model> {
120
129
  * @param options Validation options
121
130
  * @returns `true` if the value matches the schema, otherwise `false`
122
131
  */
123
- is(value: unknown, options: ValidationOptions<'first'>): Result<true, ValidationInformation>;
132
+ is(value: unknown, options: IsOptions<'first'>): Result<true, ValidationInformation>;
124
133
  /**
125
134
  * Does the value match the schema?
126
135
  *
@@ -130,6 +139,15 @@ declare class Schematic<Model> {
130
139
  * @returns `true` if the value matches the schema, otherwise `false`
131
140
  */
132
141
  is(value: unknown, errors: 'first'): Result<true, ValidationInformation>;
142
+ /**
143
+ * Does the value match the schema?
144
+ *
145
+ * Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
146
+ * @param value Value to validate
147
+ * @param options Validation options
148
+ * @returns `true` if the value matches the schema, otherwise `false`
149
+ */
150
+ is(value: unknown, options: IsOptions<'none'>): value is Model;
133
151
  /**
134
152
  * Does the value match the schema?
135
153
  *
@@ -156,6 +174,6 @@ declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer
156
174
  * @returns A schematic for the given typed schema
157
175
  */
158
176
  declare function schematic<Model extends PlainObject>(schema: TypedSchema<Model>): Schematic<Model>;
159
- declare const schematicProperties: WeakMap<Schematic<unknown>, ValidatedProperty[]>;
177
+ declare const schematicValidator: WeakMap<Schematic<unknown>, Validator>;
160
178
  //#endregion
161
- export { Schematic, schematic, schematicProperties };
179
+ export { Schematic, schematic, schematicValidator };
@@ -1,8 +1,7 @@
1
1
  import { PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
2
- import { getParameters, isSchematic } from "./helpers.mjs";
2
+ import { getParameters, isSchematic } from "./helpers/misc.helper.mjs";
3
3
  import { SchematicError } from "./models/validation.model.mjs";
4
- import { getProperties } from "./validation/property.validation.mjs";
5
- import { validateObject } from "./validation/value.validation.mjs";
4
+ import { getObjectValidator } from "./validator/object.validator.mjs";
6
5
  import { isPlainObject } from "@oscarpalmer/atoms/is";
7
6
  import { error, ok } from "@oscarpalmer/atoms/result/misc";
8
7
  //#region src/schematic.ts
@@ -10,32 +9,32 @@ import { error, ok } from "@oscarpalmer/atoms/result/misc";
10
9
  * A schematic for validating objects
11
10
  */
12
11
  var Schematic = class {
13
- #properties;
14
- constructor(properties) {
12
+ #validator;
13
+ constructor(validator) {
15
14
  Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
16
- this.#properties = properties;
17
- schematicProperties.set(this, properties);
15
+ this.#validator = validator;
16
+ schematicValidator.set(this, validator);
18
17
  }
19
18
  get(value, options) {
20
19
  const parameters = getParameters(options);
21
- const result = validateObject(value, this.#properties, parameters, true);
22
- if (result == null) return;
23
- if (!Array.isArray(result)) return parameters.reporting.none ? result : ok(result);
20
+ const result = this.#validator(value, parameters, true);
21
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
22
+ if (parameters.reporting.none) return;
24
23
  return error(parameters.reporting.all ? result : result[0]);
25
24
  }
26
25
  is(value, options) {
27
26
  const parameters = getParameters(options);
28
- const result = validateObject(value, this.#properties, parameters, false);
29
- if (result == null) return false;
30
- if (!Array.isArray(result)) return parameters.reporting.none ? true : ok(true);
27
+ const result = this.#validator(value, parameters, false);
28
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
29
+ if (parameters.reporting.none) return false;
31
30
  return error(parameters.reporting.all ? result : result[0]);
32
31
  }
33
32
  };
34
33
  function schematic(schema) {
35
34
  if (isSchematic(schema)) return schema;
36
35
  if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
37
- return new Schematic(getProperties(schema));
36
+ return new Schematic(getObjectValidator(schema));
38
37
  }
39
- const schematicProperties = /* @__PURE__ */ new WeakMap();
38
+ const schematicValidator = /* @__PURE__ */ new WeakMap();
40
39
  //#endregion
41
- export { Schematic, schematic, schematicProperties };
40
+ export { Schematic, schematic, schematicValidator };
@@ -0,0 +1,6 @@
1
+ import { Validator } from "../models/validation.model.mjs";
2
+
3
+ //#region src/validator/base.validator.d.ts
4
+ declare function getBaseValidator(validators: Validator[]): Validator;
5
+ //#endregion
6
+ export { getBaseValidator };
@@ -0,0 +1,19 @@
1
+ //#region src/validator/base.validator.ts
2
+ function getBaseValidator(validators) {
3
+ const { length } = validators;
4
+ return (input, parameters, get) => {
5
+ const allInformation = [];
6
+ for (let index = 0; index < length; index += 1) {
7
+ const previousInformation = parameters.information;
8
+ parameters.information = [];
9
+ const result = validators[index](input, parameters, get);
10
+ parameters.information = previousInformation;
11
+ if (result === true) return true;
12
+ parameters.information?.push(...result);
13
+ allInformation.push(...result);
14
+ }
15
+ return allInformation;
16
+ };
17
+ }
18
+ //#endregion
19
+ export { getBaseValidator };
@@ -0,0 +1,6 @@
1
+ import { Validator } from "../models/validation.model.mjs";
2
+
3
+ //#region src/validator/function.validator.d.ts
4
+ declare function getFunctionValidator(fn: Function): Validator;
5
+ //#endregion
6
+ export { getFunctionValidator };
@@ -0,0 +1,9 @@
1
+ import { instanceOf } from "../helpers/misc.helper.mjs";
2
+ import { isConstructor } from "@oscarpalmer/atoms/is";
3
+ //#region src/validator/function.validator.ts
4
+ function getFunctionValidator(fn) {
5
+ const validator = isConstructor(fn) ? instanceOf(fn) : fn;
6
+ return (input) => validator(input) ? true : [];
7
+ }
8
+ //#endregion
9
+ export { getFunctionValidator };
@@ -0,0 +1,6 @@
1
+ import { NamedValidatorHandlers } from "../models/validation.model.mjs";
2
+
3
+ //#region src/validator/named.handler.d.ts
4
+ declare function getNamedHandlers(original: unknown, prefix: string): NamedValidatorHandlers;
5
+ //#endregion
6
+ export { getNamedHandlers };
@@ -0,0 +1,22 @@
1
+ import { SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
2
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
3
+ //#region src/validator/named.handler.ts
4
+ function getNamedHandlers(original, prefix) {
5
+ const handlers = {};
6
+ if (original == null) return handlers;
7
+ if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
8
+ const keys = Object.keys(original);
9
+ const { length } = keys;
10
+ for (let index = 0; index < length; index += 1) {
11
+ const key = keys[index];
12
+ if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
13
+ const value = original[key];
14
+ handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
15
+ if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
16
+ return item;
17
+ });
18
+ }
19
+ return handlers;
20
+ }
21
+ //#endregion
22
+ export { getNamedHandlers };
@@ -0,0 +1,7 @@
1
+ import { NamedValidatorHandlers, ValidationInformationKey, Validator } from "../models/validation.model.mjs";
2
+ import { ValueName } from "../models/misc.model.mjs";
3
+
4
+ //#region src/validator/named.validator.d.ts
5
+ declare function getNamedValidator(key: ValidationInformationKey, name: ValueName, handlers: NamedValidatorHandlers): Validator;
6
+ //#endregion
7
+ export { getNamedValidator };
@@ -0,0 +1,39 @@
1
+ import "../constants.mjs";
2
+ import { getInvalidValidatorMessage } from "../helpers/message.helper.mjs";
3
+ //#region src/validator/named.validator.ts
4
+ function getNamedValidator(key, name, handlers) {
5
+ const validator = namedValidators[name];
6
+ const named = handlers[name] ?? [];
7
+ const { length } = named;
8
+ return (input, parameters) => {
9
+ if (!validator(input)) return [];
10
+ for (let index = 0; index < length; index += 1) {
11
+ const handler = named[index];
12
+ if (handler(input) === true) continue;
13
+ const information = {
14
+ key,
15
+ validator,
16
+ message: getInvalidValidatorMessage(key.full, name, index, length),
17
+ value: input
18
+ };
19
+ parameters.information?.push(information);
20
+ return parameters.reporting.none ? [] : [information];
21
+ }
22
+ return true;
23
+ };
24
+ }
25
+ const namedValidators = {
26
+ array: Array.isArray,
27
+ bigint: (value) => typeof value === "bigint",
28
+ boolean: (value) => typeof value === "boolean",
29
+ date: (value) => value instanceof Date,
30
+ function: (value) => typeof value === "function",
31
+ null: (value) => value === null,
32
+ number: (value) => typeof value === "number",
33
+ object: (value) => typeof value === "object" && value !== null,
34
+ string: (value) => typeof value === "string",
35
+ symbol: (value) => typeof value === "symbol",
36
+ undefined: (value) => value === void 0
37
+ };
38
+ //#endregion
39
+ export { getNamedValidator };
@@ -0,0 +1,7 @@
1
+ import { ValidationInformationKey, Validator } from "../models/validation.model.mjs";
2
+ import { PlainObject } from "@oscarpalmer/atoms/models";
3
+
4
+ //#region src/validator/object.validator.d.ts
5
+ declare function getObjectValidator(original: PlainObject, origin?: ValidationInformationKey, fromType?: boolean): Validator;
6
+ //#endregion
7
+ export { getObjectValidator };
@@ -0,0 +1,167 @@
1
+ import { PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, TYPE_ALL } from "../constants.mjs";
2
+ import { isSchematic } from "../helpers/misc.helper.mjs";
3
+ import { SchematicError, ValidationError } from "../models/validation.model.mjs";
4
+ import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getUnknownKeysMessage } from "../helpers/message.helper.mjs";
5
+ import { getBaseValidator } from "./base.validator.mjs";
6
+ import { getFunctionValidator } from "./function.validator.mjs";
7
+ import { getNamedHandlers } from "./named.handler.mjs";
8
+ import { getNamedValidator } from "./named.validator.mjs";
9
+ import { getSchematicValidator } from "./schematic.validator.mjs";
10
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
11
+ import { join } from "@oscarpalmer/atoms/string";
12
+ import { clone } from "@oscarpalmer/atoms/value/clone";
13
+ //#region src/validator/object.validator.ts
14
+ function getDisallowedProperty(obj) {
15
+ if ("$required" in obj) return PROPERTY_REQUIRED;
16
+ if ("$type" in obj) return PROPERTY_TYPE;
17
+ if ("$validators" in obj) return PROPERTY_VALIDATORS;
18
+ }
19
+ function getObjectValidator(original, origin, fromType) {
20
+ const keys = Object.keys(original);
21
+ const keysLength = keys.length;
22
+ if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
23
+ if (fromType ?? false) {
24
+ const property = getDisallowedProperty(original);
25
+ if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
26
+ }
27
+ const set = /* @__PURE__ */ new Set();
28
+ const items = [];
29
+ for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
30
+ const key = keys[keyIndex];
31
+ const value = original[key];
32
+ if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
33
+ const prefixedKey = origin == null ? key : join([origin.full, key], ".");
34
+ const fullKey = {
35
+ full: prefixedKey,
36
+ short: key
37
+ };
38
+ let handlers = {};
39
+ let required = true;
40
+ let typed = false;
41
+ let types;
42
+ const validators = [];
43
+ if (isPlainObject(value)) {
44
+ typed = PROPERTY_TYPE in value;
45
+ const type = typed ? value[PROPERTY_TYPE] : value;
46
+ handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
47
+ required = getRequired(key, value) ?? required;
48
+ types = Array.isArray(type) ? type : [type];
49
+ } else types = Array.isArray(value) ? value : [value];
50
+ if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
51
+ const typesLength = types.length;
52
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
53
+ const type = types[typeIndex];
54
+ let validator;
55
+ switch (true) {
56
+ case typeof type === "function":
57
+ validator = getFunctionValidator(type);
58
+ break;
59
+ case isPlainObject(type):
60
+ validator = getObjectValidator(type, fullKey, typed);
61
+ break;
62
+ case isSchematic(type):
63
+ validator = getSchematicValidator(type);
64
+ break;
65
+ case TYPE_ALL.has(type):
66
+ validator = getNamedValidator(fullKey, type, handlers);
67
+ break;
68
+ default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
69
+ }
70
+ validators.push(validator);
71
+ }
72
+ set.add(key);
73
+ items.push({
74
+ types,
75
+ key: fullKey,
76
+ required: required && !types.includes("undefined"),
77
+ validator: getBaseValidator(validators)
78
+ });
79
+ }
80
+ const validatorsLength = items.length;
81
+ return (input, parameters, get) => {
82
+ if (!isPlainObject(input)) {
83
+ if (origin != null) return [];
84
+ const information = {
85
+ key: {
86
+ full: "",
87
+ short: ""
88
+ },
89
+ value: input,
90
+ message: getInvalidInputMessage(input)
91
+ };
92
+ if (parameters.reporting.throw) throw new ValidationError([information]);
93
+ parameters.information?.push(information);
94
+ return [information];
95
+ }
96
+ if (parameters.strict) {
97
+ const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
98
+ if (unknownKeys.length > 0) {
99
+ const information = {
100
+ key: origin ?? {
101
+ full: "",
102
+ short: ""
103
+ },
104
+ message: getUnknownKeysMessage(unknownKeys),
105
+ value: input
106
+ };
107
+ if (parameters.reporting.throw) throw new ValidationError([information]);
108
+ parameters.information?.push(information);
109
+ return [information];
110
+ }
111
+ }
112
+ const allInformation = [];
113
+ const output = {};
114
+ for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
115
+ const { key, required, types, validator } = items[validatorIndex];
116
+ const value = input[key.short];
117
+ if (value === void 0) {
118
+ if (required) {
119
+ if (parameters.reporting.none) return [];
120
+ const information = {
121
+ key,
122
+ value,
123
+ message: getInvalidMissingMessage(key.full, types)
124
+ };
125
+ if (parameters.reporting.throw) throw new ValidationError([information]);
126
+ parameters.information?.push(information);
127
+ if (parameters.reporting.all) {
128
+ allInformation.push(information);
129
+ continue;
130
+ }
131
+ return [information];
132
+ }
133
+ continue;
134
+ }
135
+ const previousOutput = parameters.output;
136
+ parameters.output = output;
137
+ const result = validator(value, parameters, get);
138
+ parameters.output = previousOutput;
139
+ if (result === true) {
140
+ if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
141
+ continue;
142
+ }
143
+ if (parameters.reporting.none) return [];
144
+ const information = typeof result !== "boolean" && result.length > 0 ? result : [{
145
+ key,
146
+ value,
147
+ message: getInvalidTypeMessage(key.full, types, value)
148
+ }];
149
+ if (parameters.reporting.throw) throw new ValidationError(information);
150
+ if (parameters.reporting.all) {
151
+ allInformation.push(...information);
152
+ continue;
153
+ }
154
+ return information;
155
+ }
156
+ if (get) if (origin == null) parameters.output = output;
157
+ else parameters.output[origin.short] = output;
158
+ return allInformation.length === 0 ? true : allInformation;
159
+ };
160
+ }
161
+ function getRequired(key, obj) {
162
+ if (!("$required" in obj)) return;
163
+ if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
164
+ return obj[PROPERTY_REQUIRED];
165
+ }
166
+ //#endregion
167
+ export { getObjectValidator };
@@ -0,0 +1,7 @@
1
+ import { Validator } from "../models/validation.model.mjs";
2
+ import { Schematic } from "../schematic.mjs";
3
+
4
+ //#region src/validator/schematic.validator.d.ts
5
+ declare function getSchematicValidator(schematic: Schematic<unknown>): Validator;
6
+ //#endregion
7
+ export { getSchematicValidator };
@@ -0,0 +1,16 @@
1
+ import { schematicValidator } from "../schematic.mjs";
2
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
3
+ //#region src/validator/schematic.validator.ts
4
+ function getSchematicValidator(schematic) {
5
+ const validator = schematicValidator.get(schematic);
6
+ return (input, parameters, get) => {
7
+ let result;
8
+ if (isPlainObject(input)) result = validator(input, parameters, get);
9
+ else result = [];
10
+ if (result === true) return result;
11
+ parameters.information?.push(...result);
12
+ return result;
13
+ };
14
+ }
15
+ //#endregion
16
+ export { getSchematicValidator };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/jhunal",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Flies free beneath the glistening moons…",
5
5
  "keywords": [
6
6
  "schema",