@oscarpalmer/jhunal 0.19.0 → 0.21.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/constants.d.mts +7 -1
- package/dist/constants.mjs +7 -1
- package/dist/helpers.d.mts +7 -5
- package/dist/helpers.mjs +47 -18
- package/dist/index.d.mts +190 -109
- package/dist/index.mjs +161 -62
- package/dist/models/infer.model.d.mts +12 -12
- package/dist/models/misc.model.d.mts +20 -29
- package/dist/models/schema.plain.model.d.mts +4 -4
- package/dist/models/schema.typed.model.d.mts +5 -23
- package/dist/models/transform.model.d.mts +9 -13
- package/dist/models/validation.model.d.mts +55 -22
- package/dist/models/validation.model.mjs +4 -1
- package/dist/schematic.d.mts +103 -11
- package/dist/schematic.mjs +18 -8
- package/dist/validation/property.validation.mjs +2 -6
- package/dist/validation/value.validation.d.mts +3 -2
- package/dist/validation/value.validation.mjs +92 -34
- package/package.json +52 -52
- package/src/constants.ts +16 -0
- package/src/helpers.ts +81 -29
- package/src/models/infer.model.ts +12 -12
- package/src/models/misc.model.ts +20 -29
- package/src/models/schema.plain.model.ts +4 -4
- package/src/models/schema.typed.model.ts +5 -23
- package/src/models/transform.model.ts +9 -13
- package/src/models/validation.model.ts +57 -19
- package/src/schematic.ts +143 -17
- package/src/validation/property.validation.ts +8 -11
- package/src/validation/value.validation.ts +148 -44
|
@@ -7,37 +7,33 @@ import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
|
7
7
|
/**
|
|
8
8
|
* Maps each element of a tuple through {@link ToValueType}
|
|
9
9
|
*
|
|
10
|
-
* @template Value
|
|
10
|
+
* @template Value Tuple of types to map
|
|
11
11
|
*/
|
|
12
12
|
type MapToValueTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToValueType<Head>, ...MapToValueTypes<Tail>] : [];
|
|
13
13
|
/**
|
|
14
14
|
* Maps each element of a tuple through {@link ToSchemaPropertyTypeEach}
|
|
15
15
|
*
|
|
16
|
-
* @template Value
|
|
16
|
+
* @template Value Tuple of types to map
|
|
17
17
|
*/
|
|
18
18
|
type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToSchemaPropertyTypeEach<Head>, ...MapToSchemaPropertyTypes<Tail>] : [];
|
|
19
19
|
/**
|
|
20
|
-
* Converts a type
|
|
20
|
+
* Converts a TypeScript type to its {@link SchemaPropertyType} representation, suitable for use in a typed schema
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* @template Value - type to convert
|
|
22
|
+
* @template Value Type to convert
|
|
25
23
|
*/
|
|
26
24
|
type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaPropertyTypes<UnionToTuple<Value>>>>;
|
|
27
25
|
/**
|
|
28
26
|
* Converts a single type to its schema property equivalent
|
|
29
27
|
*
|
|
30
|
-
*
|
|
28
|
+
* Plain objects become {@link TypedSchema}; primitives go through {@link ToValueType}
|
|
31
29
|
*
|
|
32
|
-
* @template Value
|
|
30
|
+
* @template Value Type to convert
|
|
33
31
|
*/
|
|
34
32
|
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
|
|
35
33
|
/**
|
|
36
|
-
* Converts a type
|
|
37
|
-
*
|
|
38
|
-
* Deduplicates and unwraps single-element tuples via {@link UnwrapSingle}
|
|
34
|
+
* Converts a TypeScript type to its {@link ValueName} representation, suitable for use as a top-level schema entry
|
|
39
35
|
*
|
|
40
|
-
* @template Value
|
|
36
|
+
* @template Value Type to convert
|
|
41
37
|
*/
|
|
42
38
|
type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionToTuple<Value>>>>;
|
|
43
39
|
/**
|
|
@@ -45,7 +41,7 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
|
|
|
45
41
|
*
|
|
46
42
|
* Resolves {@link Schematic} types as-is, then performs a reverse-lookup against {@link Values} _(excluding `'object'`)_ to find a matching key. If no match is found, `object` types resolve to `'object'` or a type-guard function, and all other unrecognised types resolve to a type-guard function
|
|
47
43
|
*
|
|
48
|
-
* @template Value
|
|
44
|
+
* @template Value Type to map
|
|
49
45
|
*
|
|
50
46
|
* @example
|
|
51
47
|
* ```ts
|
|
@@ -1,12 +1,25 @@
|
|
|
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
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Maps each {@link ReportingType} to a boolean flag
|
|
8
|
+
*/
|
|
9
|
+
type ReportingInformation = Record<ReportingType, boolean> & {
|
|
10
|
+
type: ReportingType;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Controls how validation failures are reported
|
|
14
|
+
*
|
|
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
|
|
19
|
+
*/
|
|
7
20
|
type ReportingType = 'all' | 'first' | 'none' | 'throw';
|
|
8
21
|
/**
|
|
9
|
-
*
|
|
22
|
+
* Thrown when a schema definition is invalid
|
|
10
23
|
*/
|
|
11
24
|
declare class SchematicError extends Error {
|
|
12
25
|
constructor(message: string);
|
|
@@ -28,7 +41,7 @@ type ValidatedProperty = {
|
|
|
28
41
|
/**
|
|
29
42
|
* The property name in the schema
|
|
30
43
|
*/
|
|
31
|
-
key:
|
|
44
|
+
key: string;
|
|
32
45
|
/**
|
|
33
46
|
* Whether the property is required
|
|
34
47
|
*/
|
|
@@ -42,19 +55,6 @@ type ValidatedProperty = {
|
|
|
42
55
|
*/
|
|
43
56
|
validators: ValidatedPropertyValidators;
|
|
44
57
|
};
|
|
45
|
-
/**
|
|
46
|
-
* Property name in schema
|
|
47
|
-
*/
|
|
48
|
-
type ValidatedPropertyKey = {
|
|
49
|
-
/**
|
|
50
|
-
* Full property key, including parent keys for nested properties _(e.g., `address.street`)_
|
|
51
|
-
*/
|
|
52
|
-
full: string;
|
|
53
|
-
/**
|
|
54
|
-
* The last segment of the property key _(e.g., `street` for `address.street`)_
|
|
55
|
-
*/
|
|
56
|
-
short: string;
|
|
57
|
-
};
|
|
58
58
|
/**
|
|
59
59
|
* A union of valid types for a {@link ValidatedProperty}'s `types` array
|
|
60
60
|
*
|
|
@@ -67,16 +67,49 @@ type ValidatedPropertyType = GenericCallback | ValidatedProperty[] | Schematic<u
|
|
|
67
67
|
* Each key holds an array of validator functions that receive an `unknown` value and return a `boolean`
|
|
68
68
|
*/
|
|
69
69
|
type ValidatedPropertyValidators = { [Key in ValueName]?: Array<(value: unknown) => boolean> };
|
|
70
|
+
/**
|
|
71
|
+
* Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
|
|
72
|
+
*/
|
|
70
73
|
declare class ValidationError extends Error {
|
|
71
74
|
readonly information: ValidationInformation[];
|
|
72
75
|
constructor(information: ValidationInformation[]);
|
|
73
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Describes a single validation failure
|
|
79
|
+
*/
|
|
74
80
|
type ValidationInformation = {
|
|
75
|
-
key: ValidationInformationKey;
|
|
76
|
-
message: string;
|
|
77
|
-
validator?: GenericCallback;
|
|
81
|
+
/** The key path of the property that failed */key: ValidationInformationKey; /** Human-readable description of the failure */
|
|
82
|
+
message: string; /** The validator function that failed, if the failure was from a `$validators` entry */
|
|
83
|
+
validator?: GenericCallback; /** The value that was provided */
|
|
78
84
|
value: unknown;
|
|
79
85
|
};
|
|
80
|
-
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
*/
|
|
89
|
+
type ValidationInformationKey = {
|
|
90
|
+
full: string;
|
|
91
|
+
short: string;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Options for validation
|
|
95
|
+
*/
|
|
96
|
+
type ValidationOptions<Errors extends ReportingType> = {
|
|
97
|
+
/**
|
|
98
|
+
* How should validation failures be reported; see {@link ReportingType} _(defaults to `'none'`)_
|
|
99
|
+
*/
|
|
100
|
+
errors?: Errors;
|
|
101
|
+
/**
|
|
102
|
+
* Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
103
|
+
*/
|
|
104
|
+
strict?: boolean;
|
|
105
|
+
};
|
|
106
|
+
type ValidationParameters = {
|
|
107
|
+
information?: ValidationInformation[];
|
|
108
|
+
origin?: ValidatedProperty;
|
|
109
|
+
output: PlainObject;
|
|
110
|
+
prefix?: string;
|
|
111
|
+
reporting: ReportingInformation;
|
|
112
|
+
strict: boolean;
|
|
113
|
+
};
|
|
81
114
|
//#endregion
|
|
82
|
-
export { ReportingInformation, ReportingType, SchematicError, ValidatedProperty,
|
|
115
|
+
export { ReportingInformation, ReportingType, SchematicError, ValidatedProperty, ValidatedPropertyType, ValidatedPropertyValidators, ValidationError, ValidationInformation, ValidationInformationKey, ValidationOptions, ValidationParameters };
|
|
@@ -2,7 +2,7 @@ import { NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION } from "../constants.mjs";
|
|
|
2
2
|
import { join } from "@oscarpalmer/atoms/string";
|
|
3
3
|
//#region src/models/validation.model.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Thrown when a schema definition is invalid
|
|
6
6
|
*/
|
|
7
7
|
var SchematicError = class extends Error {
|
|
8
8
|
constructor(message) {
|
|
@@ -10,6 +10,9 @@ var SchematicError = class extends Error {
|
|
|
10
10
|
this.name = NAME_ERROR_SCHEMATIC;
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
|
|
15
|
+
*/
|
|
13
16
|
var ValidationError = class extends Error {
|
|
14
17
|
constructor(information) {
|
|
15
18
|
super(join(information.map((item) => item.message), "; "));
|
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 { ValidatedProperty, ValidationInformation } from "./models/validation.model.mjs";
|
|
3
|
+
import { ValidatedProperty, ValidationInformation, ValidationOptions } 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";
|
|
@@ -13,41 +13,132 @@ declare class Schematic<Model> {
|
|
|
13
13
|
#private;
|
|
14
14
|
private readonly $schematic;
|
|
15
15
|
constructor(properties: ValidatedProperty[]);
|
|
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;
|
|
79
|
+
/**
|
|
80
|
+
* Does the value match the schema?
|
|
81
|
+
*
|
|
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
|
|
83
|
+
* @param value Value to validate
|
|
84
|
+
* @param options Validation options
|
|
85
|
+
* @returns `true` if the value matches the schema, otherwise throws an error
|
|
86
|
+
*/
|
|
87
|
+
is(value: unknown, options: ValidationOptions<'throw'>): asserts value is Model;
|
|
16
88
|
/**
|
|
17
89
|
* Does the value match the schema?
|
|
18
90
|
*
|
|
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
|
|
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
|
|
20
92
|
* @param value Value to validate
|
|
21
|
-
* @param errors
|
|
93
|
+
* @param errors Reporting type
|
|
22
94
|
* @returns `true` if the value matches the schema, otherwise throws an error
|
|
23
95
|
*/
|
|
24
96
|
is(value: unknown, errors: 'throw'): asserts value is Model;
|
|
25
97
|
/**
|
|
26
98
|
* Does the value match the schema?
|
|
27
99
|
*
|
|
28
|
-
* 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
|
|
29
101
|
* @param value Value to validate
|
|
30
|
-
* @param
|
|
31
|
-
* @returns `true`
|
|
102
|
+
* @param options Validation options
|
|
103
|
+
* @returns Result holding `true` or all validation information
|
|
104
|
+
*/
|
|
105
|
+
is(value: unknown, options: ValidationOptions<'all'>): Result<true, ValidationInformation[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Does the value match the schema?
|
|
108
|
+
*
|
|
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
|
|
110
|
+
* @param value Value to validate
|
|
111
|
+
* @param errors Reporting type
|
|
112
|
+
* @returns Result holding `true` or all validation information
|
|
32
113
|
*/
|
|
33
114
|
is(value: unknown, errors: 'all'): Result<true, ValidationInformation[]>;
|
|
34
115
|
/**
|
|
35
116
|
* Does the value match the schema?
|
|
36
117
|
*
|
|
37
|
-
* 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
|
|
119
|
+
* @param value Value to validate
|
|
120
|
+
* @param options Validation options
|
|
121
|
+
* @returns `true` if the value matches the schema, otherwise `false`
|
|
122
|
+
*/
|
|
123
|
+
is(value: unknown, options: ValidationOptions<'first'>): Result<true, ValidationInformation>;
|
|
124
|
+
/**
|
|
125
|
+
* Does the value match the schema?
|
|
126
|
+
*
|
|
127
|
+
* Will validate that the value matches the schema and return a result of `true` or all validation information for the first failing property
|
|
38
128
|
* @param value Value to validate
|
|
39
|
-
* @param errors
|
|
129
|
+
* @param errors Reporting type
|
|
40
130
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
41
131
|
*/
|
|
42
132
|
is(value: unknown, errors: 'first'): Result<true, ValidationInformation>;
|
|
43
133
|
/**
|
|
44
134
|
* Does the value match the schema?
|
|
45
135
|
*
|
|
46
|
-
* 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
|
|
47
137
|
* @param value Value to validate
|
|
138
|
+
* @param strict Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
48
139
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
49
140
|
*/
|
|
50
|
-
is(value: unknown): value is Model;
|
|
141
|
+
is(value: unknown, strict?: true): value is Model;
|
|
51
142
|
}
|
|
52
143
|
/**
|
|
53
144
|
* Create a schematic from a schema
|
|
@@ -65,5 +156,6 @@ declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer
|
|
|
65
156
|
* @returns A schematic for the given typed schema
|
|
66
157
|
*/
|
|
67
158
|
declare function schematic<Model extends PlainObject>(schema: TypedSchema<Model>): Schematic<Model>;
|
|
159
|
+
declare const schematicProperties: WeakMap<Schematic<unknown>, ValidatedProperty[]>;
|
|
68
160
|
//#endregion
|
|
69
|
-
export { Schematic, schematic };
|
|
161
|
+
export { Schematic, schematic, schematicProperties };
|
package/dist/schematic.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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
4
|
import { getProperties } from "./validation/property.validation.mjs";
|
|
5
5
|
import { validateObject } from "./validation/value.validation.mjs";
|
|
6
6
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
7
|
-
import { error } from "@oscarpalmer/atoms/result/misc";
|
|
7
|
+
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
8
8
|
//#region src/schematic.ts
|
|
9
9
|
/**
|
|
10
10
|
* A schematic for validating objects
|
|
@@ -14,12 +14,21 @@ var Schematic = class {
|
|
|
14
14
|
constructor(properties) {
|
|
15
15
|
Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
|
|
16
16
|
this.#properties = properties;
|
|
17
|
+
schematicProperties.set(this, properties);
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const result = validateObject(value, this.#properties,
|
|
21
|
-
if (
|
|
22
|
-
return
|
|
19
|
+
get(value, options) {
|
|
20
|
+
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);
|
|
24
|
+
return error(parameters.reporting.all ? result : result[0]);
|
|
25
|
+
}
|
|
26
|
+
is(value, options) {
|
|
27
|
+
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);
|
|
31
|
+
return error(parameters.reporting.all ? result : result[0]);
|
|
23
32
|
}
|
|
24
33
|
};
|
|
25
34
|
function schematic(schema) {
|
|
@@ -27,5 +36,6 @@ function schematic(schema) {
|
|
|
27
36
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
28
37
|
return new Schematic(getProperties(schema));
|
|
29
38
|
}
|
|
39
|
+
const schematicProperties = /* @__PURE__ */ new WeakMap();
|
|
30
40
|
//#endregion
|
|
31
|
-
export { Schematic, schematic };
|
|
41
|
+
export { Schematic, schematic, schematicProperties };
|
|
@@ -20,9 +20,8 @@ function getProperties(original, prefix, fromType) {
|
|
|
20
20
|
const properties = [];
|
|
21
21
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
22
22
|
const key = keys[keyIndex];
|
|
23
|
-
const prefixed = join([prefix, key], ".");
|
|
24
23
|
const value = original[key];
|
|
25
|
-
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>",
|
|
24
|
+
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([prefix, key], ".")));
|
|
26
25
|
const types = [];
|
|
27
26
|
let required = true;
|
|
28
27
|
let validators = {};
|
|
@@ -34,12 +33,9 @@ function getProperties(original, prefix, fromType) {
|
|
|
34
33
|
} else types.push(...getTypes(key, value, prefix));
|
|
35
34
|
if (!required && !types.includes("undefined")) types.push(TYPE_UNDEFINED);
|
|
36
35
|
properties.push({
|
|
36
|
+
key,
|
|
37
37
|
types,
|
|
38
38
|
validators,
|
|
39
|
-
key: {
|
|
40
|
-
full: prefixed,
|
|
41
|
-
short: key
|
|
42
|
-
},
|
|
43
39
|
required: required && !types.includes("undefined")
|
|
44
40
|
});
|
|
45
41
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ValidatedProperty, ValidationInformation, ValidationParameters } from "../models/validation.model.mjs";
|
|
2
|
+
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
2
3
|
|
|
3
4
|
//#region src/validation/value.validation.d.ts
|
|
4
|
-
declare function validateObject(obj: unknown, properties: ValidatedProperty[],
|
|
5
|
+
declare function validateObject(obj: unknown, properties: ValidatedProperty[], parameters: ValidationParameters, get: boolean): PlainObject | ValidationInformation[] | undefined;
|
|
5
6
|
//#endregion
|
|
6
7
|
export { validateObject };
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import "../constants.mjs";
|
|
2
|
-
import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, isSchematic } from "../helpers.mjs";
|
|
2
|
+
import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, getUnknownKeysMessage, isSchematic } from "../helpers.mjs";
|
|
3
3
|
import { ValidationError } from "../models/validation.model.mjs";
|
|
4
|
+
import { schematicProperties } from "../schematic.mjs";
|
|
4
5
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
|
+
import { join } from "@oscarpalmer/atoms/string";
|
|
7
|
+
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
5
8
|
//#region src/validation/value.validation.ts
|
|
6
|
-
function validateNamed(
|
|
9
|
+
function validateNamed(name, value, parameters) {
|
|
7
10
|
if (!validators[name](value)) return false;
|
|
8
|
-
const propertyValidators =
|
|
11
|
+
const propertyValidators = parameters.origin.validators[name];
|
|
9
12
|
if (propertyValidators == null || propertyValidators.length === 0) return true;
|
|
10
13
|
const { length } = propertyValidators;
|
|
11
14
|
for (let index = 0; index < length; index += 1) {
|
|
12
15
|
const validator = propertyValidators[index];
|
|
13
16
|
if (!validator(value)) {
|
|
14
|
-
|
|
17
|
+
parameters.information.push({
|
|
15
18
|
value,
|
|
16
|
-
key: {
|
|
17
|
-
|
|
19
|
+
key: {
|
|
20
|
+
full: parameters.prefix,
|
|
21
|
+
short: parameters.origin.key
|
|
22
|
+
},
|
|
23
|
+
message: getInvalidValidatorMessage(parameters.prefix, name, index, length),
|
|
18
24
|
validator
|
|
19
25
|
});
|
|
20
26
|
return false;
|
|
@@ -22,69 +28,121 @@ function validateNamed(property, name, value, validation) {
|
|
|
22
28
|
}
|
|
23
29
|
return true;
|
|
24
30
|
}
|
|
25
|
-
function validateObject(obj, properties,
|
|
31
|
+
function validateObject(obj, properties, parameters, get) {
|
|
26
32
|
if (!isPlainObject(obj)) {
|
|
33
|
+
const key = parameters?.origin == null ? {
|
|
34
|
+
full: "",
|
|
35
|
+
short: ""
|
|
36
|
+
} : {
|
|
37
|
+
full: parameters.prefix,
|
|
38
|
+
short: parameters.origin.key
|
|
39
|
+
};
|
|
27
40
|
const information = {
|
|
28
|
-
key
|
|
29
|
-
|
|
30
|
-
short: ""
|
|
31
|
-
},
|
|
32
|
-
message: property == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(property, obj),
|
|
41
|
+
key,
|
|
42
|
+
message: parameters?.origin == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(key.full, parameters.origin.types, obj),
|
|
33
43
|
value: obj
|
|
34
44
|
};
|
|
35
|
-
if (reporting.throw) throw new ValidationError([information]);
|
|
36
|
-
|
|
45
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
46
|
+
parameters?.information?.push(information);
|
|
47
|
+
return parameters.reporting.none ? void 0 : [information];
|
|
48
|
+
}
|
|
49
|
+
if (parameters.strict) {
|
|
50
|
+
const objKeys = Object.keys(obj);
|
|
51
|
+
const propertiesKeys = new Set(properties.map((property) => property.key));
|
|
52
|
+
const unknownKeys = objKeys.filter((key) => !propertiesKeys.has(key));
|
|
53
|
+
if (unknownKeys.length > 0) {
|
|
54
|
+
const information = {
|
|
55
|
+
key: parameters?.origin == null ? {
|
|
56
|
+
full: "",
|
|
57
|
+
short: ""
|
|
58
|
+
} : {
|
|
59
|
+
full: join([parameters.prefix, parameters.origin?.key], "."),
|
|
60
|
+
short: parameters.origin.key
|
|
61
|
+
},
|
|
62
|
+
message: getUnknownKeysMessage(unknownKeys.map((key) => join([parameters?.prefix, key], "."))),
|
|
63
|
+
value: obj
|
|
64
|
+
};
|
|
65
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
66
|
+
parameters?.information?.push(information);
|
|
67
|
+
return parameters.reporting.none ? void 0 : [information];
|
|
68
|
+
}
|
|
37
69
|
}
|
|
38
70
|
const allInformation = [];
|
|
71
|
+
const output = {};
|
|
39
72
|
const propertiesLength = properties.length;
|
|
40
73
|
outer: for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
|
|
41
74
|
const property = properties[propertyIndex];
|
|
42
75
|
const { key, required, types } = property;
|
|
43
|
-
const value = obj[key
|
|
76
|
+
const value = obj[key];
|
|
77
|
+
if (get && value === void 0 && !required) continue;
|
|
44
78
|
if (value === void 0 && required) {
|
|
79
|
+
const prefixedKey = join([parameters.prefix, key], ".");
|
|
45
80
|
const information = {
|
|
46
81
|
value,
|
|
47
|
-
key: {
|
|
48
|
-
|
|
82
|
+
key: {
|
|
83
|
+
full: prefixedKey,
|
|
84
|
+
short: key
|
|
85
|
+
},
|
|
86
|
+
message: getInvalidMissingMessage(prefixedKey, property.types)
|
|
49
87
|
};
|
|
50
|
-
if (reporting.throw
|
|
51
|
-
|
|
52
|
-
if (reporting.all) {
|
|
88
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
89
|
+
parameters?.information?.push(information);
|
|
90
|
+
if (parameters.reporting.all) {
|
|
53
91
|
allInformation.push(information);
|
|
54
92
|
continue;
|
|
55
93
|
}
|
|
56
|
-
return reporting.none ?
|
|
94
|
+
return parameters.reporting.none ? void 0 : [information];
|
|
57
95
|
}
|
|
96
|
+
const prefixedKey = join([parameters.prefix, key], ".");
|
|
58
97
|
const typesLength = types.length;
|
|
59
98
|
const information = [];
|
|
60
99
|
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
61
100
|
const type = types[typeIndex];
|
|
62
|
-
if (validateValue(type,
|
|
101
|
+
if (validateValue(type, value, {
|
|
102
|
+
information,
|
|
103
|
+
output,
|
|
104
|
+
origin: property,
|
|
105
|
+
prefix: prefixedKey,
|
|
106
|
+
reporting: parameters.reporting,
|
|
107
|
+
strict: parameters.strict
|
|
108
|
+
}, get)) {
|
|
109
|
+
if (get) output[key] = clone(value);
|
|
110
|
+
continue outer;
|
|
111
|
+
}
|
|
63
112
|
}
|
|
64
113
|
if (information.length === 0) information.push({
|
|
65
114
|
value,
|
|
66
|
-
key: {
|
|
67
|
-
|
|
115
|
+
key: {
|
|
116
|
+
full: prefixedKey,
|
|
117
|
+
short: key
|
|
118
|
+
},
|
|
119
|
+
message: getInvalidTypeMessage(prefixedKey, property.types, value)
|
|
68
120
|
});
|
|
69
|
-
if (reporting.throw
|
|
70
|
-
|
|
71
|
-
if (reporting.all) {
|
|
121
|
+
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
122
|
+
parameters?.information?.push(...information);
|
|
123
|
+
if (parameters.reporting.all) {
|
|
72
124
|
allInformation.push(...information);
|
|
73
125
|
continue;
|
|
74
126
|
}
|
|
75
|
-
return reporting.none ?
|
|
127
|
+
return parameters.reporting.none ? void 0 : information;
|
|
76
128
|
}
|
|
77
|
-
|
|
129
|
+
if (get) if (parameters.origin == null) parameters.output = output;
|
|
130
|
+
else parameters.output[parameters.origin.key] = output;
|
|
131
|
+
return parameters.reporting.none || allInformation.length === 0 ? parameters.output : allInformation;
|
|
132
|
+
}
|
|
133
|
+
function validateSchematic(schematic, value, parameters, get) {
|
|
134
|
+
const result = validateObject(value, schematicProperties.get(schematic), parameters, get);
|
|
135
|
+
return result == null || Array.isArray(result) ? false : true;
|
|
78
136
|
}
|
|
79
|
-
function validateValue(type,
|
|
137
|
+
function validateValue(type, value, parameters, get) {
|
|
80
138
|
switch (true) {
|
|
81
139
|
case typeof type === "function": return type(value);
|
|
82
140
|
case Array.isArray(type): {
|
|
83
|
-
const
|
|
84
|
-
return
|
|
141
|
+
const result = validateObject(value, type, parameters, get);
|
|
142
|
+
return result == null || Array.isArray(result) ? false : true;
|
|
85
143
|
}
|
|
86
|
-
case isSchematic(type): return type
|
|
87
|
-
default: return validateNamed(
|
|
144
|
+
case isSchematic(type): return validateSchematic(type, value, parameters, get);
|
|
145
|
+
default: return validateNamed(type, value, parameters);
|
|
88
146
|
}
|
|
89
147
|
}
|
|
90
148
|
const validators = {
|