@oscarpalmer/jhunal 0.21.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 +4 -4
- package/dist/helpers.mjs +2 -1
- package/dist/index.d.mts +17 -56
- package/dist/index.mjs +211 -215
- package/dist/models/schema.plain.model.d.mts +2 -8
- package/dist/models/validation.model.d.mts +10 -54
- package/dist/schematic.d.mts +4 -4
- package/dist/schematic.mjs +12 -15
- package/dist/validation.d.mts +7 -0
- package/dist/validation.mjs +245 -0
- package/package.json +1 -1
- package/src/helpers.ts +11 -8
- package/src/index.ts +6 -1
- package/src/models/schema.plain.model.ts +1 -8
- package/src/models/validation.model.ts +37 -72
- package/src/schematic.ts +18 -23
- package/src/validation.ts +498 -0
- 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/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
|
*/
|
|
@@ -103,13 +59,13 @@ type ValidationOptions<Errors extends ReportingType> = {
|
|
|
103
59
|
*/
|
|
104
60
|
strict?: boolean;
|
|
105
61
|
};
|
|
106
|
-
type
|
|
62
|
+
type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => boolean | ValidationInformation[];
|
|
63
|
+
type ValidatorParameters = {
|
|
107
64
|
information?: ValidationInformation[];
|
|
108
|
-
origin?: ValidatedProperty;
|
|
109
65
|
output: PlainObject;
|
|
110
|
-
prefix?: string;
|
|
111
66
|
reporting: ReportingInformation;
|
|
112
67
|
strict: boolean;
|
|
113
68
|
};
|
|
69
|
+
type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
|
|
114
70
|
//#endregion
|
|
115
|
-
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,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
|
*
|
|
@@ -156,6 +156,6 @@ declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer
|
|
|
156
156
|
* @returns A schematic for the given typed schema
|
|
157
157
|
*/
|
|
158
158
|
declare function schematic<Model extends PlainObject>(schema: TypedSchema<Model>): Schematic<Model>;
|
|
159
|
-
declare const
|
|
159
|
+
declare const schematicValidator: WeakMap<Schematic<unknown>, Validator>;
|
|
160
160
|
//#endregion
|
|
161
|
-
export { Schematic, schematic,
|
|
161
|
+
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
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
6
|
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
8
7
|
//#region src/schematic.ts
|
|
@@ -10,32 +9,30 @@ 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 (!Array.isArray(result)) return parameters.reporting.none ? result : ok(result);
|
|
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);
|
|
24
22
|
return error(parameters.reporting.all ? result : result[0]);
|
|
25
23
|
}
|
|
26
24
|
is(value, options) {
|
|
27
25
|
const parameters = getParameters(options);
|
|
28
|
-
const result =
|
|
29
|
-
if (result
|
|
30
|
-
if (!Array.isArray(result)) return parameters.reporting.none ? true : ok(true);
|
|
26
|
+
const result = this.#validator(value, parameters, false);
|
|
27
|
+
if (typeof result === "boolean") return parameters.reporting.none ? result : ok(result);
|
|
31
28
|
return error(parameters.reporting.all ? result : result[0]);
|
|
32
29
|
}
|
|
33
30
|
};
|
|
34
31
|
function schematic(schema) {
|
|
35
32
|
if (isSchematic(schema)) return schema;
|
|
36
33
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
37
|
-
return new Schematic(
|
|
34
|
+
return new Schematic(getObjectValidator(schema));
|
|
38
35
|
}
|
|
39
|
-
const
|
|
36
|
+
const schematicValidator = /* @__PURE__ */ new WeakMap();
|
|
40
37
|
//#endregion
|
|
41
|
-
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 };
|
package/package.json
CHANGED
package/src/helpers.ts
CHANGED
|
@@ -30,9 +30,8 @@ import type {ValueName} from './models/misc.model';
|
|
|
30
30
|
import type {
|
|
31
31
|
ReportingInformation,
|
|
32
32
|
ReportingType,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
ValidationParameters,
|
|
33
|
+
ValidatorParameters,
|
|
34
|
+
ValidatorType,
|
|
36
35
|
} from './models/validation.model';
|
|
37
36
|
import type {Schematic} from './schematic';
|
|
38
37
|
|
|
@@ -40,7 +39,7 @@ export function getInvalidInputMessage(actual: unknown): string {
|
|
|
40
39
|
return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
export function getInvalidMissingMessage(key: string, types:
|
|
42
|
+
export function getInvalidMissingMessage(key: string, types: ValidatorType[]): string {
|
|
44
43
|
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
45
44
|
|
|
46
45
|
message = message.replace(TEMPLATE_PATTERN, key);
|
|
@@ -50,7 +49,7 @@ export function getInvalidMissingMessage(key: string, types: ValidatedPropertyTy
|
|
|
50
49
|
|
|
51
50
|
export function getInvalidTypeMessage(
|
|
52
51
|
key: string,
|
|
53
|
-
types:
|
|
52
|
+
types: ValidatorType[],
|
|
54
53
|
actual: unknown,
|
|
55
54
|
): string {
|
|
56
55
|
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
@@ -78,7 +77,7 @@ export function getInvalidValidatorMessage(
|
|
|
78
77
|
return message;
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
export function getParameters(input?: unknown):
|
|
80
|
+
export function getParameters(input?: unknown): ValidatorParameters {
|
|
82
81
|
if (typeof input === 'boolean') {
|
|
83
82
|
return {
|
|
84
83
|
output: {},
|
|
@@ -104,12 +103,16 @@ export function getParameters(input?: unknown): ValidationParameters {
|
|
|
104
103
|
};
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
function getPropertyType(original:
|
|
106
|
+
function getPropertyType(original: ValidatorType): string {
|
|
108
107
|
if (typeof original === 'function') {
|
|
109
108
|
return 'a validated value';
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
if (Array.isArray(original)) {
|
|
112
|
+
return `'array'`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (isPlainObject(original)) {
|
|
113
116
|
return `'${TYPE_OBJECT}'`;
|
|
114
117
|
}
|
|
115
118
|
|
|
@@ -227,7 +230,7 @@ function renderParts(parts: string[], delimiterShort: string, delimiterLong: str
|
|
|
227
230
|
return rendered;
|
|
228
231
|
}
|
|
229
232
|
|
|
230
|
-
function renderTypes(types:
|
|
233
|
+
function renderTypes(types: ValidatorType[]): string {
|
|
231
234
|
const unique = new Set<string>();
|
|
232
235
|
const parts: string[] = [];
|
|
233
236
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export {instanceOf, isSchematic} from './helpers';
|
|
2
2
|
export type {Schema} from './models/schema.plain.model';
|
|
3
3
|
export type {TypedSchema} from './models/schema.typed.model';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
SchematicError,
|
|
6
|
+
ValidationError,
|
|
7
|
+
type ValidationInformation,
|
|
8
|
+
type ValidationOptions,
|
|
9
|
+
} from './models/validation.model';
|
|
5
10
|
export {schematic, type Schematic} from './schematic';
|
|
@@ -25,7 +25,7 @@ export type PlainSchema = {
|
|
|
25
25
|
* };
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export type Schema =
|
|
28
|
+
export type Schema = PlainSchema;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* A union of all valid types for a single schema entry
|
|
@@ -40,13 +40,6 @@ export type SchemaEntry =
|
|
|
40
40
|
| ValueName
|
|
41
41
|
| ((value: unknown) => boolean);
|
|
42
42
|
|
|
43
|
-
/**
|
|
44
|
-
* Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link PlainSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
|
|
45
|
-
*/
|
|
46
|
-
export interface SchemaIndex {
|
|
47
|
-
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
43
|
/**
|
|
51
44
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
52
45
|
*
|