@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.
- package/dist/constants.d.mts +7 -3
- package/dist/constants.mjs +34 -12
- package/dist/helpers/message.helper.d.mts +11 -0
- package/dist/helpers/message.helper.mjs +70 -0
- package/dist/helpers/misc.helper.d.mts +22 -0
- package/dist/helpers/misc.helper.mjs +56 -0
- package/dist/index.d.mts +318 -328
- package/dist/index.mjs +324 -295
- package/dist/models/schema.plain.model.d.mts +2 -8
- package/dist/models/validation.model.d.mts +26 -59
- package/dist/schematic.d.mts +28 -10
- package/dist/schematic.mjs +15 -16
- package/dist/validator/base.validator.d.mts +6 -0
- package/dist/validator/base.validator.mjs +19 -0
- package/dist/validator/function.validator.d.mts +6 -0
- package/dist/validator/function.validator.mjs +9 -0
- package/dist/validator/named.handler.d.mts +6 -0
- package/dist/validator/named.handler.mjs +22 -0
- package/dist/validator/named.validator.d.mts +7 -0
- package/dist/validator/named.validator.mjs +39 -0
- package/dist/validator/object.validator.d.mts +7 -0
- package/dist/validator/object.validator.mjs +167 -0
- package/dist/validator/schematic.validator.d.mts +7 -0
- package/dist/validator/schematic.validator.mjs +16 -0
- package/package.json +1 -1
- package/src/constants.ts +42 -10
- package/src/helpers/message.helper.ts +152 -0
- package/src/helpers/misc.helper.ts +93 -0
- package/src/index.ts +7 -2
- package/src/models/schema.plain.model.ts +1 -8
- package/src/models/validation.model.ts +55 -77
- package/src/schematic.ts +49 -27
- package/src/validator/base.validator.ts +31 -0
- package/src/validator/function.validator.ts +9 -0
- package/src/validator/named.handler.ts +50 -0
- package/src/validator/named.validator.ts +62 -0
- package/src/validator/object.validator.ts +340 -0
- package/src/validator/schematic.validator.ts +25 -0
- package/dist/helpers.d.mts +0 -28
- package/dist/helpers.mjs +0 -119
- package/dist/validation/property.validation.d.mts +0 -7
- package/dist/validation/property.validation.mjs +0 -92
- package/dist/validation/value.validation.d.mts +0 -7
- package/dist/validation/value.validation.mjs +0 -162
- package/src/helpers.ts +0 -246
- package/src/validation/property.validation.ts +0 -217
- package/src/validation/value.validation.ts +0 -293
|
@@ -25,19 +25,13 @@ type PlainSchema = {
|
|
|
25
25
|
* };
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
type Schema =
|
|
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,
|
|
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
|
-
|
|
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,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
|
|
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
|
-
|
|
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 {
|
|
82
|
+
export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, 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 { 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(
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
177
|
+
declare const schematicValidator: WeakMap<Schematic<unknown>, Validator>;
|
|
160
178
|
//#endregion
|
|
161
|
-
export { Schematic, schematic,
|
|
179
|
+
export { Schematic, schematic, schematicValidator };
|
package/dist/schematic.mjs
CHANGED
|
@@ -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 {
|
|
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
|
-
#
|
|
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);
|
|
18
17
|
}
|
|
19
18
|
get(value, options) {
|
|
20
19
|
const parameters = getParameters(options);
|
|
21
|
-
const result =
|
|
22
|
-
if (result
|
|
23
|
-
if (
|
|
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 =
|
|
29
|
-
if (result
|
|
30
|
-
if (
|
|
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(
|
|
36
|
+
return new Schematic(getObjectValidator(schema));
|
|
38
37
|
}
|
|
39
|
-
const
|
|
38
|
+
const schematicValidator = /* @__PURE__ */ new WeakMap();
|
|
40
39
|
//#endregion
|
|
41
|
-
export { Schematic, schematic,
|
|
40
|
+
export { Schematic, schematic, schematicValidator };
|
|
@@ -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,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,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 };
|