@oscarpalmer/jhunal 0.23.0 → 0.25.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 +8 -5
- package/dist/constants.mjs +20 -23
- package/dist/helpers/message.helper.d.mts +11 -5
- package/dist/helpers/message.helper.mjs +31 -9
- package/dist/helpers/misc.helper.d.mts +4 -4
- package/dist/helpers/misc.helper.mjs +4 -4
- package/dist/index.d.mts +66 -78
- package/dist/index.mjs +100 -62
- package/dist/models/infer.model.d.mts +21 -21
- package/dist/models/misc.model.d.mts +3 -3
- package/dist/models/{schema.plain.model.d.mts → schematic.plain.model.d.mts} +20 -18
- package/dist/models/{schema.typed.model.d.mts → schematic.typed.model.d.mts} +10 -24
- package/dist/models/transform.model.d.mts +6 -6
- package/dist/models/validation.model.d.mts +13 -3
- package/dist/{schematic.d.mts → schema.d.mts} +18 -18
- package/dist/{schematic.mjs → schema.mjs} +12 -12
- package/dist/validator/named.handler.d.mts +1 -1
- package/dist/validator/named.handler.mjs +3 -2
- package/dist/validator/named.validator.mjs +2 -3
- package/dist/validator/object.validator.mjs +40 -22
- package/dist/validator/schematic.validator.d.mts +3 -3
- package/dist/validator/schematic.validator.mjs +4 -4
- package/package.json +1 -1
- package/src/constants.ts +24 -28
- package/src/helpers/message.helper.ts +74 -9
- package/src/helpers/misc.helper.ts +9 -10
- package/src/index.ts +4 -4
- package/src/models/infer.model.ts +26 -28
- package/src/models/misc.model.ts +3 -3
- package/src/models/{schema.plain.model.ts → schematic.plain.model.ts} +22 -20
- package/src/models/{schema.typed.model.ts → schematic.typed.model.ts} +10 -28
- package/src/models/transform.model.ts +6 -6
- package/src/models/validation.model.ts +14 -2
- package/src/{schematic.ts → schema.ts} +23 -23
- package/src/validator/named.handler.ts +16 -1
- package/src/validator/named.validator.ts +3 -4
- package/src/validator/object.validator.ts +81 -55
- package/src/validator/schematic.validator.ts +3 -3
- /package/dist/models/{schema.plain.model.mjs → schematic.plain.model.mjs} +0 -0
- /package/dist/models/{schema.typed.model.mjs → schematic.typed.model.mjs} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TypedSchematic } from "./schematic.typed.model.mjs";
|
|
2
|
+
import { Schema } from "../schema.mjs";
|
|
3
3
|
import { DeduplicateTuple, UnionToTuple, UnwrapSingle, Values } from "./misc.model.mjs";
|
|
4
4
|
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
5
5
|
|
|
@@ -25,11 +25,11 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaProp
|
|
|
25
25
|
/**
|
|
26
26
|
* Converts a single type to its schema property equivalent
|
|
27
27
|
*
|
|
28
|
-
* Plain objects become {@link
|
|
28
|
+
* Plain objects become {@link TypedSchematic}; primitives go through {@link ToValueType}
|
|
29
29
|
*
|
|
30
30
|
* @template Value Type to convert
|
|
31
31
|
*/
|
|
32
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ?
|
|
32
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchematic<Value> : ToValueType<Value>;
|
|
33
33
|
/**
|
|
34
34
|
* Converts a TypeScript type to its {@link ValueName} representation, suitable for use as a top-level schema entry
|
|
35
35
|
*
|
|
@@ -39,7 +39,7 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
|
|
|
39
39
|
/**
|
|
40
40
|
* Maps a type to its {@link ValueName} string equivalent
|
|
41
41
|
*
|
|
42
|
-
* Resolves {@link
|
|
42
|
+
* Resolves {@link Schema} 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
|
|
43
43
|
*
|
|
44
44
|
* @template Value Type to map
|
|
45
45
|
*
|
|
@@ -50,6 +50,6 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
|
|
|
50
50
|
* // ToValueType<Date> => 'date'
|
|
51
51
|
* ```
|
|
52
52
|
*/
|
|
53
|
-
type ToValueType<Value> = Value extends
|
|
53
|
+
type ToValueType<Value> = Value extends Schema<any> ? Value : { [Key in keyof Omit<Values, 'object'>]: Value extends Values[Key] ? Key : never }[keyof Omit<Values, 'object'>] extends infer Match ? [Match] extends [never] ? Value extends object ? 'object' | ((value: unknown) => value is Value) : (value: unknown) => value is Value : Match : never;
|
|
54
54
|
//#endregion
|
|
55
55
|
export { MapToSchemaPropertyTypes, MapToValueTypes, ToSchemaPropertyType, ToSchemaPropertyTypeEach, ToSchemaType, ToValueType };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Schema } from "../schema.mjs";
|
|
2
2
|
import { ValueName } from "./misc.model.mjs";
|
|
3
3
|
import { GenericCallback, PlainObject } from "@oscarpalmer/atoms/models";
|
|
4
4
|
|
|
@@ -70,6 +70,16 @@ type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
|
|
|
70
70
|
*/
|
|
71
71
|
type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
|
|
72
72
|
type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => true | ValidationInformation[];
|
|
73
|
+
type ValidatorDefaults = {
|
|
74
|
+
value: unknown;
|
|
75
|
+
};
|
|
76
|
+
type ValidatorItem = {
|
|
77
|
+
defaults: ValidatorDefaults | undefined;
|
|
78
|
+
key: ValidationInformationKey;
|
|
79
|
+
required: boolean;
|
|
80
|
+
types: ValidatorType[];
|
|
81
|
+
validator: Validator;
|
|
82
|
+
};
|
|
73
83
|
type ValidatorParameters = {
|
|
74
84
|
clone: boolean;
|
|
75
85
|
information?: ValidationInformation[];
|
|
@@ -77,6 +87,6 @@ type ValidatorParameters = {
|
|
|
77
87
|
reporting: ReportingInformation;
|
|
78
88
|
strict: boolean;
|
|
79
89
|
};
|
|
80
|
-
type ValidatorType = Function | PlainObject |
|
|
90
|
+
type ValidatorType = Function | PlainObject | Schema<unknown> | ValueName;
|
|
81
91
|
//#endregion
|
|
82
|
-
export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorParameters, ValidatorType };
|
|
92
|
+
export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorDefaults, ValidatorItem, ValidatorParameters, ValidatorType };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Infer } from "./models/infer.model.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { TypedSchematic } from "./models/schematic.typed.model.mjs";
|
|
3
3
|
import { GetOptions, IsOptions, ValidationInformation, Validator } from "./models/validation.model.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Schematic } from "./models/schematic.plain.model.mjs";
|
|
5
5
|
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
6
6
|
import { Result } from "@oscarpalmer/atoms/result/models";
|
|
7
7
|
|
|
8
|
-
//#region src/
|
|
8
|
+
//#region src/schema.d.ts
|
|
9
9
|
/**
|
|
10
|
-
* A
|
|
10
|
+
* A schema for validating objects
|
|
11
11
|
*/
|
|
12
|
-
declare class
|
|
12
|
+
declare class Schema<Model> {
|
|
13
13
|
#private;
|
|
14
|
-
private readonly $
|
|
14
|
+
private readonly $schema;
|
|
15
15
|
constructor(validator: Validator);
|
|
16
16
|
/**
|
|
17
17
|
* Parse a value according to the schema
|
|
@@ -159,21 +159,21 @@ declare class Schematic<Model> {
|
|
|
159
159
|
is(value: unknown, strict?: true): value is Model;
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
162
|
-
* Create a
|
|
162
|
+
* Create a schema from a schematic
|
|
163
163
|
* @template Model Schema type
|
|
164
|
-
* @param schema
|
|
165
|
-
* @throws Throws {@link SchematicError} if the
|
|
166
|
-
* @returns A
|
|
164
|
+
* @param schema Schematic to create the schema from
|
|
165
|
+
* @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
|
|
166
|
+
* @returns A schema for the given schematic
|
|
167
167
|
*/
|
|
168
|
-
declare function
|
|
168
|
+
declare function schema<Model extends Schematic>(schema: Model): Schema<Infer<Model>>;
|
|
169
169
|
/**
|
|
170
|
-
* Create a
|
|
170
|
+
* Create a schema from a typed schematic
|
|
171
171
|
* @template Model Existing type
|
|
172
|
-
* @param schema Typed
|
|
173
|
-
* @throws Throws {@link SchematicError} if the
|
|
174
|
-
* @returns A
|
|
172
|
+
* @param schema Typed schematic to create the schema from
|
|
173
|
+
* @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
|
|
174
|
+
* @returns A schema for the given typed schematic
|
|
175
175
|
*/
|
|
176
|
-
declare function
|
|
177
|
-
declare const
|
|
176
|
+
declare function schema<Model extends PlainObject>(schema: TypedSchematic<Model>): Schema<Model>;
|
|
177
|
+
declare const schemaValidators: WeakMap<Schema<unknown>, Validator>;
|
|
178
178
|
//#endregion
|
|
179
|
-
export {
|
|
179
|
+
export { Schema, schema, schemaValidators };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getParameters,
|
|
1
|
+
import { PROPERTY_SCHEMA, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
|
|
2
|
+
import { getParameters, isSchema } from "./helpers/misc.helper.mjs";
|
|
3
3
|
import { SchematicError } from "./models/validation.model.mjs";
|
|
4
4
|
import { getObjectValidator } from "./validator/object.validator.mjs";
|
|
5
5
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
6
|
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
7
|
-
//#region src/
|
|
7
|
+
//#region src/schema.ts
|
|
8
8
|
/**
|
|
9
|
-
* A
|
|
9
|
+
* A schema for validating objects
|
|
10
10
|
*/
|
|
11
|
-
var
|
|
11
|
+
var Schema = class {
|
|
12
12
|
#validator;
|
|
13
13
|
constructor(validator) {
|
|
14
|
-
Object.defineProperty(this,
|
|
14
|
+
Object.defineProperty(this, PROPERTY_SCHEMA, { value: true });
|
|
15
15
|
this.#validator = validator;
|
|
16
|
-
|
|
16
|
+
schemaValidators.set(this, validator);
|
|
17
17
|
}
|
|
18
18
|
get(value, options) {
|
|
19
19
|
const parameters = getParameters(options);
|
|
@@ -30,11 +30,11 @@ var Schematic = class {
|
|
|
30
30
|
return error(parameters.reporting.all ? result : result[0]);
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
|
-
function
|
|
34
|
-
if (
|
|
33
|
+
function schema(schema) {
|
|
34
|
+
if (isSchema(schema)) return schema;
|
|
35
35
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
36
|
-
return new
|
|
36
|
+
return new Schema(getObjectValidator(schema));
|
|
37
37
|
}
|
|
38
|
-
const
|
|
38
|
+
const schemaValidators = /* @__PURE__ */ new WeakMap();
|
|
39
39
|
//#endregion
|
|
40
|
-
export {
|
|
40
|
+
export { Schema, schema, schemaValidators };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NamedValidatorHandlers } from "../models/validation.model.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/validator/named.handler.d.ts
|
|
4
|
-
declare function getNamedHandlers(original: unknown, prefix: string): NamedValidatorHandlers;
|
|
4
|
+
declare function getNamedHandlers(original: unknown, prefix: string, allowed: boolean): NamedValidatorHandlers;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { getNamedHandlers };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
|
|
1
|
+
import { PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
|
|
2
2
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
3
|
//#region src/validator/named.handler.ts
|
|
4
|
-
function getNamedHandlers(original, prefix) {
|
|
4
|
+
function getNamedHandlers(original, prefix, allowed) {
|
|
5
5
|
const handlers = {};
|
|
6
6
|
if (original == null) return handlers;
|
|
7
|
+
if (!allowed) throw new TypeError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", PROPERTY_VALIDATORS));
|
|
7
8
|
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
8
9
|
const keys = Object.keys(original);
|
|
9
10
|
const { length } = keys;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import { getInvalidValidatorMessage } from "../helpers/message.helper.mjs";
|
|
1
|
+
import { getInputPropertyValidatorMessage } from "../helpers/message.helper.mjs";
|
|
3
2
|
//#region src/validator/named.validator.ts
|
|
4
3
|
function getNamedValidator(key, name, handlers) {
|
|
5
4
|
const validator = namedValidators[name];
|
|
@@ -13,7 +12,7 @@ function getNamedValidator(key, name, handlers) {
|
|
|
13
12
|
const information = {
|
|
14
13
|
key,
|
|
15
14
|
validator,
|
|
16
|
-
message:
|
|
15
|
+
message: getInputPropertyValidatorMessage(key.full, name, index, length),
|
|
17
16
|
value: input
|
|
18
17
|
};
|
|
19
18
|
parameters.information?.push(information);
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY,
|
|
2
|
-
import {
|
|
1
|
+
import { PROPERTY_DEFAULT, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY, TYPE_ALL } from "../constants.mjs";
|
|
2
|
+
import { getParameters, isSchema } from "../helpers/misc.helper.mjs";
|
|
3
3
|
import { SchematicError, ValidationError } from "../models/validation.model.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { getDefaultRequiredMessage, getDefaultTypeMessage, getDisallowedMessage, getInputPropertyMissingMessage, getInputPropertyTypeMessage, getInputTypeMessage, getRequiredMessage, getSchematicPropertyNullableMessage, getSchematicPropertyTypeMessage, getUnknownKeysMessage } from "../helpers/message.helper.mjs";
|
|
5
5
|
import { getBaseValidator } from "./base.validator.mjs";
|
|
6
6
|
import { getFunctionValidator } from "./function.validator.mjs";
|
|
7
7
|
import { getNamedHandlers } from "./named.handler.mjs";
|
|
8
8
|
import { getNamedValidator } from "./named.validator.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import { getSchemaValidator } from "./schematic.validator.mjs";
|
|
10
10
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
11
11
|
import { join } from "@oscarpalmer/atoms/string";
|
|
12
12
|
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
13
13
|
//#region src/validator/object.validator.ts
|
|
14
|
+
function getDefaults(obj, key, allowed) {
|
|
15
|
+
if (!("$default" in obj)) return;
|
|
16
|
+
if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_DEFAULT));
|
|
17
|
+
return { value: obj[PROPERTY_DEFAULT] };
|
|
18
|
+
}
|
|
14
19
|
function getDisallowedProperty(obj) {
|
|
20
|
+
if ("$default" in obj) return PROPERTY_DEFAULT;
|
|
15
21
|
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
16
22
|
if ("$type" in obj) return PROPERTY_TYPE;
|
|
17
23
|
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
@@ -22,14 +28,14 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
22
28
|
if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
23
29
|
if (fromType ?? false) {
|
|
24
30
|
const property = getDisallowedProperty(original);
|
|
25
|
-
if (property != null) throw new SchematicError(
|
|
31
|
+
if (property != null) throw new SchematicError(getDisallowedMessage(origin.full, property));
|
|
26
32
|
}
|
|
27
33
|
const set = /* @__PURE__ */ new Set();
|
|
28
34
|
const items = [];
|
|
29
35
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
30
36
|
const key = keys[keyIndex];
|
|
31
37
|
const value = original[key];
|
|
32
|
-
if (value == null) throw new SchematicError(
|
|
38
|
+
if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
|
|
33
39
|
const prefixedKey = origin == null ? key : join([origin.full, key], ".");
|
|
34
40
|
const fullKey = {
|
|
35
41
|
full: prefixedKey,
|
|
@@ -38,16 +44,18 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
38
44
|
let handlers = {};
|
|
39
45
|
let required = true;
|
|
40
46
|
let typed = false;
|
|
47
|
+
let defaults;
|
|
41
48
|
let types;
|
|
42
49
|
const validators = [];
|
|
43
50
|
if (isPlainObject(value)) {
|
|
44
51
|
typed = PROPERTY_TYPE in value;
|
|
45
52
|
const type = typed ? value[PROPERTY_TYPE] : value;
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
defaults = getDefaults(value, prefixedKey, typed);
|
|
54
|
+
handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey, typed);
|
|
55
|
+
required = getRequired(value, prefixedKey, typed) ?? required;
|
|
48
56
|
types = Array.isArray(type) ? type : [type];
|
|
49
57
|
} else types = Array.isArray(value) ? value : [value];
|
|
50
|
-
if (types.length === 0) throw new SchematicError(
|
|
58
|
+
if (types.length === 0) throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
|
|
51
59
|
const typesLength = types.length;
|
|
52
60
|
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
53
61
|
const type = types[typeIndex];
|
|
@@ -59,23 +67,28 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
59
67
|
case isPlainObject(type):
|
|
60
68
|
validator = getObjectValidator(type, fullKey, typed);
|
|
61
69
|
break;
|
|
62
|
-
case
|
|
63
|
-
validator =
|
|
70
|
+
case isSchema(type):
|
|
71
|
+
validator = getSchemaValidator(type);
|
|
64
72
|
break;
|
|
65
73
|
case TYPE_ALL.has(type):
|
|
66
74
|
validator = getNamedValidator(fullKey, type, handlers);
|
|
67
75
|
break;
|
|
68
|
-
default: throw new SchematicError(
|
|
76
|
+
default: throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
|
|
69
77
|
}
|
|
70
78
|
validators.push(validator);
|
|
71
79
|
}
|
|
72
|
-
|
|
80
|
+
required = required && !types.includes("undefined");
|
|
81
|
+
if (defaults != null && !required) throw new SchematicError(getDefaultRequiredMessage(prefixedKey));
|
|
82
|
+
const validator = getBaseValidator(validators);
|
|
83
|
+
if (defaults != null && Array.isArray(validator(defaults.value, getParameters(), false))) throw new SchematicError(getDefaultTypeMessage(prefixedKey, types));
|
|
73
84
|
items.push({
|
|
85
|
+
defaults,
|
|
86
|
+
required,
|
|
74
87
|
types,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
validator: getBaseValidator(validators)
|
|
88
|
+
validator,
|
|
89
|
+
key: fullKey
|
|
78
90
|
});
|
|
91
|
+
set.add(key);
|
|
79
92
|
}
|
|
80
93
|
const validatorsLength = items.length;
|
|
81
94
|
return (input, parameters, get) => {
|
|
@@ -87,7 +100,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
87
100
|
short: ""
|
|
88
101
|
},
|
|
89
102
|
value: input,
|
|
90
|
-
message:
|
|
103
|
+
message: getInputTypeMessage(input)
|
|
91
104
|
};
|
|
92
105
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
93
106
|
parameters.information?.push(information);
|
|
@@ -112,15 +125,19 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
112
125
|
const allInformation = [];
|
|
113
126
|
const output = {};
|
|
114
127
|
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
115
|
-
const { key, required, types, validator } = items[validatorIndex];
|
|
128
|
+
const { defaults, key, required, types, validator } = items[validatorIndex];
|
|
116
129
|
const value = input[key.short];
|
|
117
130
|
if (value === void 0) {
|
|
118
131
|
if (required) {
|
|
132
|
+
if (get && defaults != null) {
|
|
133
|
+
output[key.short] = clone(defaults.value);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
119
136
|
if (parameters.reporting.none) return [];
|
|
120
137
|
const information = {
|
|
121
138
|
key,
|
|
122
139
|
value,
|
|
123
|
-
message:
|
|
140
|
+
message: getInputPropertyMissingMessage(key.full, types)
|
|
124
141
|
};
|
|
125
142
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
126
143
|
parameters.information?.push(information);
|
|
@@ -144,7 +161,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
144
161
|
const information = typeof result !== "boolean" && result.length > 0 ? result : [{
|
|
145
162
|
key,
|
|
146
163
|
value,
|
|
147
|
-
message:
|
|
164
|
+
message: getInputPropertyTypeMessage(key.full, types, value)
|
|
148
165
|
}];
|
|
149
166
|
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
150
167
|
if (parameters.reporting.all) {
|
|
@@ -158,9 +175,10 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
158
175
|
return allInformation.length === 0 ? true : allInformation;
|
|
159
176
|
};
|
|
160
177
|
}
|
|
161
|
-
function getRequired(key,
|
|
178
|
+
function getRequired(obj, key, allowed) {
|
|
162
179
|
if (!("$required" in obj)) return;
|
|
163
|
-
if (
|
|
180
|
+
if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_REQUIRED));
|
|
181
|
+
if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
|
|
164
182
|
return obj[PROPERTY_REQUIRED];
|
|
165
183
|
}
|
|
166
184
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Validator } from "../models/validation.model.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Schema } from "../schema.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/validator/schematic.validator.d.ts
|
|
5
|
-
declare function
|
|
5
|
+
declare function getSchemaValidator(schematic: Schema<unknown>): Validator;
|
|
6
6
|
//#endregion
|
|
7
|
-
export {
|
|
7
|
+
export { getSchemaValidator };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { schemaValidators } from "../schema.mjs";
|
|
2
2
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
3
|
//#region src/validator/schematic.validator.ts
|
|
4
|
-
function
|
|
5
|
-
const validator =
|
|
4
|
+
function getSchemaValidator(schematic) {
|
|
5
|
+
const validator = schemaValidators.get(schematic);
|
|
6
6
|
return (input, parameters, get) => {
|
|
7
7
|
let result;
|
|
8
8
|
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
@@ -13,4 +13,4 @@ function getSchematicValidator(schematic) {
|
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
//#endregion
|
|
16
|
-
export {
|
|
16
|
+
export { getSchemaValidator };
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -23,9 +23,9 @@ export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
|
|
|
23
23
|
|
|
24
24
|
// #region Names
|
|
25
25
|
|
|
26
|
-
export const
|
|
26
|
+
export const NAME_SCHEMA = 'Schema';
|
|
27
27
|
|
|
28
|
-
export const
|
|
28
|
+
export const NAME_SCHEMA_PREFIXED = 'a Schema';
|
|
29
29
|
|
|
30
30
|
export const NAME_ERROR_SCHEMATIC = 'SchematicError';
|
|
31
31
|
|
|
@@ -35,9 +35,11 @@ export const NAME_ERROR_VALIDATION = 'ValidationError';
|
|
|
35
35
|
|
|
36
36
|
// #region Properties
|
|
37
37
|
|
|
38
|
+
export const PROPERTY_DEFAULT = '$default';
|
|
39
|
+
|
|
38
40
|
export const PROPERTY_REQUIRED = '$required';
|
|
39
41
|
|
|
40
|
-
export const
|
|
42
|
+
export const PROPERTY_SCHEMA = '$schema';
|
|
41
43
|
|
|
42
44
|
export const PROPERTY_TYPE = '$type';
|
|
43
45
|
|
|
@@ -83,10 +85,16 @@ export const REPORTING_TYPES = new Set<ReportingType>([
|
|
|
83
85
|
|
|
84
86
|
// #region Schematic validation
|
|
85
87
|
|
|
88
|
+
export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED =
|
|
89
|
+
"'<>' has a default value but is not required";
|
|
90
|
+
|
|
91
|
+
export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE =
|
|
92
|
+
"Expected default value for property '<>' to be <>";
|
|
93
|
+
|
|
86
94
|
export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
|
|
87
95
|
|
|
88
96
|
export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
|
|
89
|
-
"'<>.<>' property is not allowed for schemas
|
|
97
|
+
"'<>.<>' property is not allowed for plain schemas";
|
|
90
98
|
|
|
91
99
|
export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE =
|
|
92
100
|
"'<>' property must not be 'null' or 'undefined'";
|
|
@@ -118,52 +126,40 @@ export const TEMPLATE_PATTERN = '<>';
|
|
|
118
126
|
|
|
119
127
|
export const TYPE_ARRAY = 'array';
|
|
120
128
|
|
|
121
|
-
const TYPE_BIGINT = 'bigint';
|
|
122
|
-
|
|
123
|
-
const TYPE_BOOLEAN = 'boolean';
|
|
124
|
-
|
|
125
|
-
const TYPE_DATE = 'date';
|
|
126
|
-
|
|
127
129
|
export const TYPE_FUNCTION = 'function';
|
|
128
130
|
|
|
129
131
|
export const TYPE_FUNCTION_RESULT = 'a validated value';
|
|
130
132
|
|
|
131
133
|
export const TYPE_NULL = 'null';
|
|
132
134
|
|
|
133
|
-
const TYPE_NUMBER = 'number';
|
|
134
|
-
|
|
135
135
|
export const TYPE_OBJECT = 'object';
|
|
136
136
|
|
|
137
|
-
const TYPE_STRING = 'string';
|
|
138
|
-
|
|
139
|
-
const TYPE_SYMBOL = 'symbol';
|
|
140
|
-
|
|
141
137
|
export const TYPE_UNDEFINED = 'undefined';
|
|
142
138
|
|
|
143
139
|
export const VALIDATABLE_TYPES = new Set<ValueName>([
|
|
144
140
|
TYPE_ARRAY,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
'bigint',
|
|
142
|
+
'boolean',
|
|
143
|
+
'date',
|
|
148
144
|
TYPE_FUNCTION,
|
|
149
|
-
|
|
145
|
+
'number',
|
|
150
146
|
TYPE_OBJECT,
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
'string',
|
|
148
|
+
'symbol',
|
|
153
149
|
]);
|
|
154
150
|
|
|
155
151
|
export const TYPE_ALL = new Set<ValueName>([...VALIDATABLE_TYPES, TYPE_NULL, TYPE_UNDEFINED]);
|
|
156
152
|
|
|
157
153
|
export const PREFIXED_TYPES: Record<ValueName, string> = {
|
|
158
154
|
[TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
155
|
+
bigint: `a bigint`,
|
|
156
|
+
boolean: `a boolean`,
|
|
157
|
+
date: `a date`,
|
|
162
158
|
[TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
|
|
163
159
|
[TYPE_NULL]: TYPE_NULL,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
number: `a number`,
|
|
161
|
+
string: `a string`,
|
|
162
|
+
symbol: `a symbol`,
|
|
167
163
|
[TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
|
|
168
164
|
[TYPE_UNDEFINED]: TYPE_UNDEFINED,
|
|
169
165
|
};
|
|
@@ -6,10 +6,15 @@ import {
|
|
|
6
6
|
CONJUNCTION_OR,
|
|
7
7
|
CONJUNCTION_OR_COMMA,
|
|
8
8
|
PREFIXED_TYPES,
|
|
9
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED,
|
|
10
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE,
|
|
11
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
|
|
12
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE,
|
|
13
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED,
|
|
14
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE,
|
|
9
15
|
TEMPLATE_PATTERN,
|
|
10
16
|
TYPE_ALL,
|
|
11
17
|
TYPE_ARRAY,
|
|
12
|
-
TYPE_FUNCTION,
|
|
13
18
|
TYPE_FUNCTION_RESULT,
|
|
14
19
|
TYPE_NULL,
|
|
15
20
|
TYPE_OBJECT,
|
|
@@ -23,11 +28,41 @@ import {
|
|
|
23
28
|
import type {ValueName} from '../models/misc.model';
|
|
24
29
|
import type {ValidatorType} from '../models/validation.model';
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
// #region Defaults
|
|
32
|
+
|
|
33
|
+
export function getDefaultRequiredMessage(key: string): string {
|
|
34
|
+
return SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED.replace(TEMPLATE_PATTERN, key);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getDefaultTypeMessage(key: string, types: ValidatorType[]): string {
|
|
38
|
+
let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE.replace(TEMPLATE_PATTERN, key);
|
|
39
|
+
|
|
40
|
+
message = message.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
41
|
+
|
|
42
|
+
return message;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// #endregion
|
|
46
|
+
|
|
47
|
+
// #region Disallowed
|
|
48
|
+
|
|
49
|
+
export function getDisallowedMessage(key: string, property: string): string {
|
|
50
|
+
let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(TEMPLATE_PATTERN, key);
|
|
51
|
+
|
|
52
|
+
message = message.replace(TEMPLATE_PATTERN, property);
|
|
53
|
+
|
|
54
|
+
return message;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// #endregion
|
|
58
|
+
|
|
59
|
+
// #region Input
|
|
60
|
+
|
|
61
|
+
export function getInputTypeMessage(actual: unknown): string {
|
|
27
62
|
return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
28
63
|
}
|
|
29
64
|
|
|
30
|
-
export function
|
|
65
|
+
export function getInputPropertyMissingMessage(key: string, types: ValidatorType[]): string {
|
|
31
66
|
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
32
67
|
|
|
33
68
|
message = message.replace(TEMPLATE_PATTERN, key);
|
|
@@ -35,7 +70,7 @@ export function getInvalidMissingMessage(key: string, types: ValidatorType[]): s
|
|
|
35
70
|
return message;
|
|
36
71
|
}
|
|
37
72
|
|
|
38
|
-
export function
|
|
73
|
+
export function getInputPropertyTypeMessage(
|
|
39
74
|
key: string,
|
|
40
75
|
types: ValidatorType[],
|
|
41
76
|
actual: unknown,
|
|
@@ -48,7 +83,7 @@ export function getInvalidTypeMessage(
|
|
|
48
83
|
return message;
|
|
49
84
|
}
|
|
50
85
|
|
|
51
|
-
export function
|
|
86
|
+
export function getInputPropertyValidatorMessage(
|
|
52
87
|
key: string,
|
|
53
88
|
type: ValueName,
|
|
54
89
|
index: number,
|
|
@@ -65,6 +100,22 @@ export function getInvalidValidatorMessage(
|
|
|
65
100
|
return message;
|
|
66
101
|
}
|
|
67
102
|
|
|
103
|
+
// #endregion
|
|
104
|
+
|
|
105
|
+
// #region Schematic
|
|
106
|
+
|
|
107
|
+
export function getSchematicPropertyNullableMessage(key: string): string {
|
|
108
|
+
return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace(TEMPLATE_PATTERN, key);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getSchematicPropertyTypeMessage(key: string): string {
|
|
112
|
+
return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace(TEMPLATE_PATTERN, key);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// #endregion
|
|
116
|
+
|
|
117
|
+
// #region Misc.
|
|
118
|
+
|
|
68
119
|
function getPropertyType(type: ValidatorType): string {
|
|
69
120
|
switch (true) {
|
|
70
121
|
case typeof type === 'function':
|
|
@@ -78,10 +129,6 @@ function getPropertyType(type: ValidatorType): string {
|
|
|
78
129
|
}
|
|
79
130
|
}
|
|
80
131
|
|
|
81
|
-
export function getUnknownKeysMessage(keys: string[]): string {
|
|
82
|
-
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
132
|
function getValueType(value: unknown): string {
|
|
86
133
|
const valueType = typeof value;
|
|
87
134
|
|
|
@@ -150,3 +197,21 @@ function renderTypes(types: ValidatorType[]): string {
|
|
|
150
197
|
|
|
151
198
|
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
152
199
|
}
|
|
200
|
+
|
|
201
|
+
// #endregion
|
|
202
|
+
|
|
203
|
+
// #region Required
|
|
204
|
+
|
|
205
|
+
export function getRequiredMessage(key: string): string {
|
|
206
|
+
return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace(TEMPLATE_PATTERN, key);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// #endregion
|
|
210
|
+
|
|
211
|
+
// #region Strictness
|
|
212
|
+
|
|
213
|
+
export function getUnknownKeysMessage(keys: string[]): string {
|
|
214
|
+
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// #endregion
|