@oscarpalmer/jhunal 0.20.0 → 0.22.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.
- package/dist/helpers.d.mts +6 -9
- package/dist/helpers.mjs +15 -11
- package/dist/index.d.mts +94 -76
- package/dist/index.mjs +233 -211
- package/dist/models/schema.plain.model.d.mts +2 -8
- package/dist/models/validation.model.d.mts +18 -64
- package/dist/schematic.d.mts +76 -13
- package/dist/schematic.mjs +20 -18
- package/dist/validation.d.mts +7 -0
- package/dist/validation.mjs +245 -0
- package/package.json +52 -52
- package/src/helpers.ts +29 -20
- package/src/index.ts +6 -1
- package/src/models/schema.plain.model.ts +1 -8
- package/src/models/validation.model.ts +44 -82
- package/src/schematic.ts +109 -24
- package/src/validation.ts +498 -0
- package/dist/validation/property.validation.d.mts +0 -7
- package/dist/validation/property.validation.mjs +0 -96
- package/dist/validation/value.validation.d.mts +0 -6
- package/dist/validation/value.validation.mjs +0 -140
- package/src/validation/property.validation.ts +0 -219
- package/src/validation/value.validation.ts +0 -253
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { Schematic } from "../schematic.mjs";
|
|
2
2
|
import { ValueName } from "./misc.model.mjs";
|
|
3
|
-
import { GenericCallback } from "@oscarpalmer/atoms/models";
|
|
3
|
+
import { GenericCallback, PlainObject } from "@oscarpalmer/atoms/models";
|
|
4
4
|
|
|
5
5
|
//#region src/models/validation.model.d.ts
|
|
6
|
-
|
|
7
|
-
|
|
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'
|
|
16
|
-
* - `'first'
|
|
17
|
-
* - `'all'
|
|
18
|
-
* - `'throw'
|
|
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,58 +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: ValidatedPropertyKey;
|
|
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
|
-
* The full and short forms of a property's key path
|
|
60
|
-
*
|
|
61
|
-
* For a nested property `address.street`: `full` is `'address.street'`, `short` is `'street'`
|
|
62
|
-
*/
|
|
63
|
-
type ValidatedPropertyKey = {
|
|
64
|
-
full: string;
|
|
65
|
-
short: string;
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* A union of valid types for a {@link ValidatedProperty}'s `types` array
|
|
69
|
-
*
|
|
70
|
-
* Can be a callback _(custom validator)_, a {@link Schematic}, a nested {@link ValidatedProperty}, or a {@link ValueName} string
|
|
71
|
-
*/
|
|
72
|
-
type ValidatedPropertyType = GenericCallback | ValidatedProperty[] | Schematic<unknown> | ValueName;
|
|
73
|
-
/**
|
|
74
|
-
* A map of validator functions keyed by {@link ValueName}, used at runtime in {@link ValidatedProperty}
|
|
75
|
-
*
|
|
76
|
-
* Each key holds an array of validator functions that receive an `unknown` value and return a `boolean`
|
|
77
|
-
*/
|
|
78
|
-
type ValidatedPropertyValidators = { [Key in ValueName]?: Array<(value: unknown) => boolean> };
|
|
79
26
|
/**
|
|
80
27
|
* Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
|
|
81
28
|
*/
|
|
@@ -93,9 +40,12 @@ type ValidationInformation = {
|
|
|
93
40
|
value: unknown;
|
|
94
41
|
};
|
|
95
42
|
/**
|
|
96
|
-
*
|
|
43
|
+
*
|
|
97
44
|
*/
|
|
98
|
-
type ValidationInformationKey =
|
|
45
|
+
type ValidationInformationKey = {
|
|
46
|
+
full: string;
|
|
47
|
+
short: string;
|
|
48
|
+
};
|
|
99
49
|
/**
|
|
100
50
|
* Options for validation
|
|
101
51
|
*/
|
|
@@ -109,9 +59,13 @@ type ValidationOptions<Errors extends ReportingType> = {
|
|
|
109
59
|
*/
|
|
110
60
|
strict?: boolean;
|
|
111
61
|
};
|
|
112
|
-
type
|
|
62
|
+
type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => boolean | ValidationInformation[];
|
|
63
|
+
type ValidatorParameters = {
|
|
64
|
+
information?: ValidationInformation[];
|
|
65
|
+
output: PlainObject;
|
|
113
66
|
reporting: ReportingInformation;
|
|
114
67
|
strict: boolean;
|
|
115
68
|
};
|
|
69
|
+
type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
|
|
116
70
|
//#endregion
|
|
117
|
-
export {
|
|
71
|
+
export { NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, ValidationOptions, Validator, ValidatorParameters, ValidatorType };
|
package/dist/schematic.d.mts
CHANGED
|
@@ -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 {
|
|
3
|
+
import { ValidationInformation, ValidationOptions, 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,11 +12,74 @@ import { Result } from "@oscarpalmer/atoms/result/models";
|
|
|
12
12
|
declare class Schematic<Model> {
|
|
13
13
|
#private;
|
|
14
14
|
private readonly $schematic;
|
|
15
|
-
constructor(
|
|
15
|
+
constructor(validator: Validator);
|
|
16
|
+
/**
|
|
17
|
+
* Parse a value according to the schema
|
|
18
|
+
*
|
|
19
|
+
* Returns a deeply cloned version of the value or throws an error for the first property that fails validation
|
|
20
|
+
* @param value Value to parse
|
|
21
|
+
* @param options Validation options
|
|
22
|
+
* @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
|
|
23
|
+
*/
|
|
24
|
+
get(value: unknown, options: ValidationOptions<'throw'>): Model;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a value according to the schema
|
|
27
|
+
*
|
|
28
|
+
* Returns a deeply cloned version of the value or throws an error for the first property that fails validation
|
|
29
|
+
* @param value Value to parse
|
|
30
|
+
* @param errors Reporting type
|
|
31
|
+
* @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
|
|
32
|
+
*/
|
|
33
|
+
get(value: unknown, errors: 'throw'): Model;
|
|
34
|
+
/**
|
|
35
|
+
* Parse a value according to the schema
|
|
36
|
+
*
|
|
37
|
+
* Returns a result of a deeply cloned version of the value or all validation information for validation failures from the same depth in the value
|
|
38
|
+
* @param value Value to parse
|
|
39
|
+
* @param options Validation options
|
|
40
|
+
* @returns Result holding deeply cloned value or all validation information
|
|
41
|
+
*/
|
|
42
|
+
get(value: unknown, options: ValidationOptions<'all'>): Result<Model, ValidationInformation[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Parse a value according to the schema
|
|
45
|
+
*
|
|
46
|
+
* Returns a result of a deeply cloned version of the value or all validation information for validation failures from the same depth in the value
|
|
47
|
+
* @param value Value to parse
|
|
48
|
+
* @param errors Reporting type
|
|
49
|
+
* @returns Result holding deeply cloned value or all validation information
|
|
50
|
+
*/
|
|
51
|
+
get(value: unknown, errors: 'all'): Result<Model, ValidationInformation[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Parse a value according to the schema
|
|
54
|
+
*
|
|
55
|
+
* Returns a deeply cloned version of the value or all validation information for the first failing property
|
|
56
|
+
* @param value Value to parse
|
|
57
|
+
* @param options Validation options
|
|
58
|
+
* @returns Result holding deeply cloned value or all validation information
|
|
59
|
+
*/
|
|
60
|
+
get(value: unknown, options: ValidationOptions<'first'>): Result<Model, ValidationInformation>;
|
|
61
|
+
/**
|
|
62
|
+
* Parse a value according to the schema
|
|
63
|
+
*
|
|
64
|
+
* Returns a deeply cloned version of the value or all validation information for the first failing property
|
|
65
|
+
* @param value Value to parse
|
|
66
|
+
* @param errors Reporting type
|
|
67
|
+
* @returns Result holding deeply cloned value or all validation information
|
|
68
|
+
*/
|
|
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 strict Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
76
|
+
* @returns Deeply cloned value, or `undefined` if it's invalid
|
|
77
|
+
*/
|
|
78
|
+
get(value: unknown, strict?: true): Model | undefined;
|
|
16
79
|
/**
|
|
17
80
|
* Does the value match the schema?
|
|
18
81
|
*
|
|
19
|
-
* Will assert that the values matches the schema and throw an error if it does not. The error will contain all validation information for the first property that fails validation
|
|
82
|
+
* Will assert that the values matches the schema and throw an error if it does not. The error will contain all validation information for the first property that fails validation
|
|
20
83
|
* @param value Value to validate
|
|
21
84
|
* @param options Validation options
|
|
22
85
|
* @returns `true` if the value matches the schema, otherwise throws an error
|
|
@@ -25,7 +88,7 @@ declare class Schematic<Model> {
|
|
|
25
88
|
/**
|
|
26
89
|
* Does the value match the schema?
|
|
27
90
|
*
|
|
28
|
-
* Will assert that the values matches the schema and throw an error if it does not. The error will contain all validation information for the first property that fails validation
|
|
91
|
+
* Will assert that the values matches the schema and throw an error if it does not. The error will contain all validation information for the first property that fails validation
|
|
29
92
|
* @param value Value to validate
|
|
30
93
|
* @param errors Reporting type
|
|
31
94
|
* @returns `true` if the value matches the schema, otherwise throws an error
|
|
@@ -34,25 +97,25 @@ declare class Schematic<Model> {
|
|
|
34
97
|
/**
|
|
35
98
|
* Does the value match the schema?
|
|
36
99
|
*
|
|
37
|
-
* Will validate that the value matches the schema and return a result of `true` or all validation information for validation failures from the same depth in the
|
|
100
|
+
* Will validate that the value matches the schema and return a result of `true` or all validation information for validation failures from the same depth in the value
|
|
38
101
|
* @param value Value to validate
|
|
39
102
|
* @param options Validation options
|
|
40
|
-
* @returns `true`
|
|
103
|
+
* @returns Result holding `true` or all validation information
|
|
41
104
|
*/
|
|
42
105
|
is(value: unknown, options: ValidationOptions<'all'>): Result<true, ValidationInformation[]>;
|
|
43
106
|
/**
|
|
44
107
|
* Does the value match the schema?
|
|
45
108
|
*
|
|
46
|
-
* Will validate that the value matches the schema and return a result of `true` or all validation information for validation failures from the same depth in the
|
|
109
|
+
* Will validate that the value matches the schema and return a result of `true` or all validation information for validation failures from the same depth in the value
|
|
47
110
|
* @param value Value to validate
|
|
48
111
|
* @param errors Reporting type
|
|
49
|
-
* @returns `true`
|
|
112
|
+
* @returns Result holding `true` or all validation information
|
|
50
113
|
*/
|
|
51
114
|
is(value: unknown, errors: 'all'): Result<true, ValidationInformation[]>;
|
|
52
115
|
/**
|
|
53
116
|
* Does the value match the schema?
|
|
54
117
|
*
|
|
55
|
-
* Will validate that the value matches the schema and return a result of `true` or all validation information for the failing property
|
|
118
|
+
* Will validate that the value matches the schema and return a result of `true` or all validation information for the first failing property
|
|
56
119
|
* @param value Value to validate
|
|
57
120
|
* @param options Validation options
|
|
58
121
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
@@ -61,7 +124,7 @@ declare class Schematic<Model> {
|
|
|
61
124
|
/**
|
|
62
125
|
* Does the value match the schema?
|
|
63
126
|
*
|
|
64
|
-
* Will validate that the value matches the schema and return a result of `true` or all validation information for the failing property
|
|
127
|
+
* Will validate that the value matches the schema and return a result of `true` or all validation information for the first failing property
|
|
65
128
|
* @param value Value to validate
|
|
66
129
|
* @param errors Reporting type
|
|
67
130
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
@@ -70,7 +133,7 @@ declare class Schematic<Model> {
|
|
|
70
133
|
/**
|
|
71
134
|
* Does the value match the schema?
|
|
72
135
|
*
|
|
73
|
-
* Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
|
|
136
|
+
* Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
|
|
74
137
|
* @param value Value to validate
|
|
75
138
|
* @param strict Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
76
139
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
@@ -93,6 +156,6 @@ declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer
|
|
|
93
156
|
* @returns A schematic for the given typed schema
|
|
94
157
|
*/
|
|
95
158
|
declare function schematic<Model extends PlainObject>(schema: TypedSchema<Model>): Schematic<Model>;
|
|
96
|
-
declare const
|
|
159
|
+
declare const schematicValidator: WeakMap<Schematic<unknown>, Validator>;
|
|
97
160
|
//#endregion
|
|
98
|
-
export { Schematic, schematic,
|
|
161
|
+
export { Schematic, schematic, schematicValidator };
|
package/dist/schematic.mjs
CHANGED
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
import { PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { getParameters, isSchematic } from "./helpers.mjs";
|
|
3
3
|
import { SchematicError } from "./models/validation.model.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { validateObject } from "./validation/value.validation.mjs";
|
|
4
|
+
import { getObjectValidator } from "./validation.mjs";
|
|
6
5
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
7
|
-
import { error } from "@oscarpalmer/atoms/result/misc";
|
|
6
|
+
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
8
7
|
//#region src/schematic.ts
|
|
9
8
|
/**
|
|
10
9
|
* A schematic for validating objects
|
|
11
10
|
*/
|
|
12
11
|
var Schematic = class {
|
|
13
|
-
#
|
|
14
|
-
constructor(
|
|
12
|
+
#validator;
|
|
13
|
+
constructor(validator) {
|
|
15
14
|
Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
|
|
16
|
-
this.#
|
|
17
|
-
|
|
15
|
+
this.#validator = validator;
|
|
16
|
+
schematicValidator.set(this, validator);
|
|
17
|
+
}
|
|
18
|
+
get(value, options) {
|
|
19
|
+
const parameters = getParameters(options);
|
|
20
|
+
const result = this.#validator(value, parameters, true);
|
|
21
|
+
if (typeof result === "boolean") return parameters.reporting.none ? result ? parameters.output : void 0 : ok(parameters.output);
|
|
22
|
+
return error(parameters.reporting.all ? result : result[0]);
|
|
18
23
|
}
|
|
19
24
|
is(value, options) {
|
|
20
|
-
const
|
|
21
|
-
const result =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
if (typeof result === "boolean") return result;
|
|
26
|
-
return error(reporting.all ? result : result[0]);
|
|
25
|
+
const parameters = getParameters(options);
|
|
26
|
+
const result = this.#validator(value, parameters, false);
|
|
27
|
+
if (typeof result === "boolean") return parameters.reporting.none ? result : ok(result);
|
|
28
|
+
return error(parameters.reporting.all ? result : result[0]);
|
|
27
29
|
}
|
|
28
30
|
};
|
|
29
31
|
function schematic(schema) {
|
|
30
32
|
if (isSchematic(schema)) return schema;
|
|
31
33
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
32
|
-
return new Schematic(
|
|
34
|
+
return new Schematic(getObjectValidator(schema));
|
|
33
35
|
}
|
|
34
|
-
const
|
|
36
|
+
const schematicValidator = /* @__PURE__ */ new WeakMap();
|
|
35
37
|
//#endregion
|
|
36
|
-
export { Schematic, schematic,
|
|
38
|
+
export { Schematic, schematic, schematicValidator };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationInformationKey, Validator } from "./models/validation.model.mjs";
|
|
2
|
+
import { PlainObject } from "@oscarpalmer/atoms";
|
|
3
|
+
|
|
4
|
+
//#region src/validation.d.ts
|
|
5
|
+
declare function getObjectValidator(original: PlainObject, origin?: ValidationInformationKey, fromType?: boolean): Validator;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getObjectValidator };
|
|
@@ -0,0 +1,245 @@
|
|
|
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, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "./constants.mjs";
|
|
2
|
+
import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, getUnknownKeysMessage, instanceOf, isSchematic } from "./helpers.mjs";
|
|
3
|
+
import { SchematicError, ValidationError } from "./models/validation.model.mjs";
|
|
4
|
+
import { schematicValidator } from "./schematic.mjs";
|
|
5
|
+
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
|
+
import { join } from "@oscarpalmer/atoms";
|
|
7
|
+
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
8
|
+
//#region src/validation.ts
|
|
9
|
+
function getDisallowedProperty(obj) {
|
|
10
|
+
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
11
|
+
if ("$type" in obj) return PROPERTY_TYPE;
|
|
12
|
+
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
13
|
+
}
|
|
14
|
+
function getFunctionValidator(fn) {
|
|
15
|
+
const validator = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
16
|
+
return (input) => validator(input) === true;
|
|
17
|
+
}
|
|
18
|
+
function getNamedValidator(key, name, handlers) {
|
|
19
|
+
const validator = namedValidators[name];
|
|
20
|
+
const named = handlers[name] ?? [];
|
|
21
|
+
const { length } = named;
|
|
22
|
+
return (input, parameters) => {
|
|
23
|
+
if (!validator(input)) return false;
|
|
24
|
+
for (let index = 0; index < length; index += 1) {
|
|
25
|
+
const handler = named[index];
|
|
26
|
+
if (handler(input) === true) continue;
|
|
27
|
+
const information = {
|
|
28
|
+
key,
|
|
29
|
+
validator,
|
|
30
|
+
message: getInvalidValidatorMessage(key.full, name, index, length),
|
|
31
|
+
value: input
|
|
32
|
+
};
|
|
33
|
+
parameters.information?.push(information);
|
|
34
|
+
return parameters.reporting.none ? false : [information];
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function getNamedHandlers(original, prefix) {
|
|
40
|
+
const handlers = {};
|
|
41
|
+
if (original == null) return handlers;
|
|
42
|
+
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
43
|
+
const keys = Object.keys(original);
|
|
44
|
+
const { length } = keys;
|
|
45
|
+
for (let index = 0; index < length; index += 1) {
|
|
46
|
+
const key = keys[index];
|
|
47
|
+
if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
48
|
+
const value = original[key];
|
|
49
|
+
handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
50
|
+
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
|
|
51
|
+
return item;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return handlers;
|
|
55
|
+
}
|
|
56
|
+
function getObjectValidator(original, origin, fromType) {
|
|
57
|
+
const keys = Object.keys(original);
|
|
58
|
+
const keysLength = keys.length;
|
|
59
|
+
if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
60
|
+
if (fromType ?? false) {
|
|
61
|
+
const property = getDisallowedProperty(original);
|
|
62
|
+
if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
|
|
63
|
+
}
|
|
64
|
+
const set = /* @__PURE__ */ new Set();
|
|
65
|
+
const items = [];
|
|
66
|
+
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
67
|
+
const key = keys[keyIndex];
|
|
68
|
+
const value = original[key];
|
|
69
|
+
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
|
|
70
|
+
const prefixedKey = origin == null ? key : join([origin.full, key], ".");
|
|
71
|
+
const fullKey = {
|
|
72
|
+
full: prefixedKey,
|
|
73
|
+
short: key
|
|
74
|
+
};
|
|
75
|
+
let handlers = {};
|
|
76
|
+
let required = true;
|
|
77
|
+
let typed = false;
|
|
78
|
+
let types;
|
|
79
|
+
const validators = [];
|
|
80
|
+
if (isPlainObject(value)) {
|
|
81
|
+
typed = PROPERTY_TYPE in value;
|
|
82
|
+
const type = typed ? value[PROPERTY_TYPE] : value;
|
|
83
|
+
handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
|
|
84
|
+
required = getRequired(key, value) ?? required;
|
|
85
|
+
types = Array.isArray(type) ? type : [type];
|
|
86
|
+
} else types = Array.isArray(value) ? value : [value];
|
|
87
|
+
if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
|
|
88
|
+
const typesLength = types.length;
|
|
89
|
+
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
90
|
+
const type = types[typeIndex];
|
|
91
|
+
let validator;
|
|
92
|
+
switch (true) {
|
|
93
|
+
case typeof type === "function":
|
|
94
|
+
validator = getFunctionValidator(type);
|
|
95
|
+
break;
|
|
96
|
+
case isPlainObject(type):
|
|
97
|
+
validator = getObjectValidator(type, fullKey, typed);
|
|
98
|
+
break;
|
|
99
|
+
case isSchematic(type):
|
|
100
|
+
validator = getSchematicValidator(type);
|
|
101
|
+
break;
|
|
102
|
+
case TYPE_ALL.has(type):
|
|
103
|
+
validator = getNamedValidator(fullKey, type, handlers);
|
|
104
|
+
break;
|
|
105
|
+
default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
|
|
106
|
+
}
|
|
107
|
+
validators.push(validator);
|
|
108
|
+
}
|
|
109
|
+
set.add(key);
|
|
110
|
+
items.push({
|
|
111
|
+
types,
|
|
112
|
+
key: fullKey,
|
|
113
|
+
required: required && !types.includes("undefined"),
|
|
114
|
+
validator: getValidator(validators)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const validatorsLength = items.length;
|
|
118
|
+
return (input, parameters, get) => {
|
|
119
|
+
if (!isPlainObject(input)) {
|
|
120
|
+
if (origin != null) return false;
|
|
121
|
+
const information = {
|
|
122
|
+
key: {
|
|
123
|
+
full: "",
|
|
124
|
+
short: ""
|
|
125
|
+
},
|
|
126
|
+
value: input,
|
|
127
|
+
message: getInvalidInputMessage(input)
|
|
128
|
+
};
|
|
129
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
130
|
+
parameters.information?.push(information);
|
|
131
|
+
return parameters.reporting.none ? false : [information];
|
|
132
|
+
}
|
|
133
|
+
if (parameters.strict) {
|
|
134
|
+
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
135
|
+
if (unknownKeys.length > 0) {
|
|
136
|
+
const information = {
|
|
137
|
+
key: origin ?? {
|
|
138
|
+
full: "",
|
|
139
|
+
short: ""
|
|
140
|
+
},
|
|
141
|
+
message: getUnknownKeysMessage(unknownKeys),
|
|
142
|
+
value: input
|
|
143
|
+
};
|
|
144
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
145
|
+
parameters.information?.push(information);
|
|
146
|
+
return parameters.reporting.none ? false : [information];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const allInformation = [];
|
|
150
|
+
const output = {};
|
|
151
|
+
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
152
|
+
const { key, required, types, validator } = items[validatorIndex];
|
|
153
|
+
const value = input[key.short];
|
|
154
|
+
if (value === void 0) {
|
|
155
|
+
if (required) {
|
|
156
|
+
if (parameters.reporting.none) return false;
|
|
157
|
+
const information = {
|
|
158
|
+
key,
|
|
159
|
+
value,
|
|
160
|
+
message: getInvalidMissingMessage(key.full, types)
|
|
161
|
+
};
|
|
162
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
163
|
+
parameters.information?.push(information);
|
|
164
|
+
if (parameters.reporting.all) {
|
|
165
|
+
allInformation.push(information);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
return [information];
|
|
169
|
+
}
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const previousOutput = parameters.output;
|
|
173
|
+
parameters.output = output;
|
|
174
|
+
const result = validator(value, parameters, get);
|
|
175
|
+
parameters.output = previousOutput;
|
|
176
|
+
if (result === false) continue;
|
|
177
|
+
if (result === true) {
|
|
178
|
+
if (get) output[key.short] = clone(value);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (parameters.reporting.none) return false;
|
|
182
|
+
const information = typeof result !== "boolean" && result.length > 0 ? result : [{
|
|
183
|
+
key,
|
|
184
|
+
value,
|
|
185
|
+
message: getInvalidTypeMessage(key.full, types, value)
|
|
186
|
+
}];
|
|
187
|
+
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
188
|
+
if (parameters.reporting.all) {
|
|
189
|
+
allInformation.push(...information);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
return information;
|
|
193
|
+
}
|
|
194
|
+
if (get) if (origin == null) parameters.output = output;
|
|
195
|
+
else parameters.output[origin.short] = output;
|
|
196
|
+
return parameters.reporting.none || allInformation.length === 0 ? true : allInformation;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function getRequired(key, obj) {
|
|
200
|
+
if (!("$required" in obj)) return;
|
|
201
|
+
if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
202
|
+
return obj[PROPERTY_REQUIRED];
|
|
203
|
+
}
|
|
204
|
+
function getSchematicValidator(schematic) {
|
|
205
|
+
const validator = schematicValidator.get(schematic);
|
|
206
|
+
return (input, parameters, get) => {
|
|
207
|
+
let result = false;
|
|
208
|
+
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
209
|
+
if (typeof result === "boolean") return result;
|
|
210
|
+
parameters.information?.push(...result);
|
|
211
|
+
return result.length === 0 ? true : result;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function getValidator(validators) {
|
|
215
|
+
const { length } = validators;
|
|
216
|
+
return (input, parameters, get) => {
|
|
217
|
+
const allInformation = [];
|
|
218
|
+
for (let index = 0; index < length; index += 1) {
|
|
219
|
+
const previousInformation = parameters.information;
|
|
220
|
+
parameters.information = [];
|
|
221
|
+
const result = validators[index](input, parameters, get);
|
|
222
|
+
parameters.information = previousInformation;
|
|
223
|
+
if (result === false) continue;
|
|
224
|
+
if (result === true) return true;
|
|
225
|
+
parameters.information?.push(...result);
|
|
226
|
+
allInformation.push(...result);
|
|
227
|
+
}
|
|
228
|
+
return allInformation;
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const namedValidators = {
|
|
232
|
+
array: Array.isArray,
|
|
233
|
+
bigint: (value) => typeof value === "bigint",
|
|
234
|
+
boolean: (value) => typeof value === "boolean",
|
|
235
|
+
date: (value) => value instanceof Date,
|
|
236
|
+
function: (value) => typeof value === "function",
|
|
237
|
+
null: (value) => value === null,
|
|
238
|
+
number: (value) => typeof value === "number",
|
|
239
|
+
object: (value) => typeof value === "object" && value !== null,
|
|
240
|
+
string: (value) => typeof value === "string",
|
|
241
|
+
symbol: (value) => typeof value === "symbol",
|
|
242
|
+
undefined: (value) => value === void 0
|
|
243
|
+
};
|
|
244
|
+
//#endregion
|
|
245
|
+
export { getObjectValidator };
|