@oscarpalmer/jhunal 0.24.0 → 0.26.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 +4 -4
- package/dist/constants.mjs +4 -4
- package/dist/helpers/misc.helper.d.mts +3 -3
- package/dist/helpers/misc.helper.mjs +3 -3
- package/dist/index.d.mts +64 -64
- package/dist/index.mjs +78 -56
- 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} +18 -18
- package/dist/models/{schema.typed.model.d.mts → schematic.typed.model.d.mts} +8 -8
- package/dist/models/transform.model.d.mts +6 -6
- package/dist/models/validation.model.d.mts +2 -2
- package/dist/{schematic.d.mts → schema.d.mts} +20 -20
- package/dist/{schematic.mjs → schema.mjs} +13 -13
- package/dist/validator/object.validator.mjs +63 -41
- package/dist/validator/schema.validator.d.mts +7 -0
- package/dist/validator/{schematic.validator.mjs → schema.validator.mjs} +5 -5
- package/package.json +1 -1
- package/src/constants.ts +3 -3
- package/src/helpers/misc.helper.ts +5 -5
- 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} +20 -20
- package/src/models/{schema.typed.model.ts → schematic.typed.model.ts} +8 -8
- package/src/models/transform.model.ts +6 -6
- package/src/models/validation.model.ts +2 -2
- package/src/{schematic.ts → schema.ts} +29 -27
- package/src/validator/object.validator.ts +123 -63
- package/src/validator/{schematic.validator.ts → schema.validator.ts} +3 -3
- package/dist/validator/schematic.validator.d.mts +0 -7
- /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,35 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Schema } from "../schema.mjs";
|
|
2
|
+
import { PlainSchematic, Schematic, SchematicProperty } from "./schematic.plain.model.mjs";
|
|
3
3
|
import { IsOptionalProperty, ValueName, Values } from "./misc.model.mjs";
|
|
4
4
|
import { Constructor, Simplify } from "@oscarpalmer/atoms/models";
|
|
5
5
|
|
|
6
6
|
//#region src/models/infer.model.d.ts
|
|
7
7
|
/**
|
|
8
|
-
* Infers the TypeScript type from a {@link
|
|
8
|
+
* Infers the TypeScript type from a {@link Schematic} definition
|
|
9
9
|
*
|
|
10
|
-
* @template Model
|
|
10
|
+
* @template Model Schematic to infer types from
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
|
-
* const
|
|
14
|
+
* const userSchematic = {
|
|
15
15
|
* name: 'string',
|
|
16
16
|
* age: 'number',
|
|
17
17
|
* address: { $required: false, $type: 'string' },
|
|
18
|
-
* } satisfies
|
|
18
|
+
* } satisfies Schematic;
|
|
19
19
|
*
|
|
20
|
-
* type User = Infer<typeof
|
|
20
|
+
* type User = Infer<typeof userSchematic>;
|
|
21
21
|
* // { name: string; age: number; address?: string }
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
type Infer<Model extends
|
|
24
|
+
type Infer<Model extends Schematic> = Simplify<{ [Key in InferRequiredKeys<Model>]: InferSchemaEntry<Model[Key]> } & { [Key in InferOptionalKeys<Model>]?: InferSchemaEntry<Model[Key]> }>;
|
|
25
25
|
/**
|
|
26
|
-
* Extracts keys from a {@link
|
|
26
|
+
* Extracts keys from a {@link Schematic} whose entries are optional _(i.e., `$required` is `false`)_
|
|
27
27
|
*
|
|
28
|
-
* @template Model - {@link
|
|
28
|
+
* @template Model - {@link Schematic} to extract optional keys from
|
|
29
29
|
*/
|
|
30
|
-
type InferOptionalKeys<Model extends
|
|
30
|
+
type InferOptionalKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? Key : never]: never };
|
|
31
31
|
/**
|
|
32
|
-
* Infers the TypeScript type from a {@link
|
|
32
|
+
* Infers the TypeScript type from a {@link SchematicProperty}'s `$type` field
|
|
33
33
|
*
|
|
34
34
|
* @template Value `$type` value _(single or array)_
|
|
35
35
|
*/
|
|
@@ -37,30 +37,30 @@ type InferPropertyType<Value> = Value extends (infer Item)[] ? InferPropertyValu
|
|
|
37
37
|
/**
|
|
38
38
|
* Maps a single `$type` definition to its TypeScript equivalent
|
|
39
39
|
*
|
|
40
|
-
* Resolves, in order: {@link Constructor}
|
|
40
|
+
* Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link ValueName} values, and nested {@link PlainSchematic} objects
|
|
41
41
|
*
|
|
42
42
|
* @template Value single type definition
|
|
43
43
|
*/
|
|
44
|
-
type InferPropertyValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends
|
|
44
|
+
type InferPropertyValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schema<infer Model> ? Model : Value extends ValueName ? Values[Value & ValueName] : Value extends PlainSchematic ? Infer<Value> : never;
|
|
45
45
|
/**
|
|
46
|
-
* Extracts keys from a {@link
|
|
46
|
+
* Extracts keys from a {@link Schematic} whose entries are required _(i.e., `$required` is not `false`)_
|
|
47
47
|
*
|
|
48
|
-
* @template Model
|
|
48
|
+
* @template Model Schematic to extract required keys from
|
|
49
49
|
*/
|
|
50
|
-
type InferRequiredKeys<Model extends
|
|
50
|
+
type InferRequiredKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never };
|
|
51
51
|
/**
|
|
52
|
-
* Infers the TypeScript type from a top-level {@link
|
|
52
|
+
* Infers the TypeScript type from a top-level {@link Schematic} entry
|
|
53
53
|
*
|
|
54
|
-
* @template Value
|
|
54
|
+
* @template Value Schematic entry value _(single or array)_
|
|
55
55
|
*/
|
|
56
56
|
type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryValue<Item> : InferSchemaEntryValue<Value>;
|
|
57
57
|
/**
|
|
58
58
|
* Maps a single top-level schema entry to its TypeScript type
|
|
59
59
|
*
|
|
60
|
-
* Resolves, in order: {@link Constructor}
|
|
60
|
+
* Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link SchemaProperty} objects, {@link PlainSchematic} objects, and {@link ValueName} values
|
|
61
61
|
*
|
|
62
62
|
* @template Value single schema entry
|
|
63
63
|
*/
|
|
64
|
-
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends
|
|
64
|
+
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schema<infer Model> ? Model : Value extends SchematicProperty ? InferPropertyType<Value['$type']> : Value extends PlainSchematic ? Infer<Value & Schematic> : Value extends ValueName ? Values[Value & ValueName] : never;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { Infer, InferOptionalKeys, InferPropertyType, InferPropertyValue, InferRequiredKeys, InferSchemaEntry, InferSchemaEntryValue };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SchematicProperty } from "./schematic.plain.model.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/models/misc.model.d.ts
|
|
4
4
|
/**
|
|
@@ -29,11 +29,11 @@ type ExtractValueNames<Value> = Value extends ValueName ? Value : Value extends
|
|
|
29
29
|
/**
|
|
30
30
|
* Determines whether a schema entry is optional
|
|
31
31
|
*
|
|
32
|
-
* Returns `true` if the entry is a {@link
|
|
32
|
+
* Returns `true` if the entry is a {@link SchematicProperty} with `$required` set to `false`; otherwise returns `false`
|
|
33
33
|
*
|
|
34
34
|
* @template Value Schema entry to check
|
|
35
35
|
*/
|
|
36
|
-
type IsOptionalProperty<Value> = Value extends
|
|
36
|
+
type IsOptionalProperty<Value> = Value extends SchematicProperty ? Value['$required'] extends false ? true : false : false;
|
|
37
37
|
/**
|
|
38
38
|
* Extracts the last member from a union type by leveraging contravariance of function parameter types
|
|
39
39
|
*
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Schema } from "../schema.mjs";
|
|
2
2
|
import { ExtractValueNames, ValueName, Values } from "./misc.model.mjs";
|
|
3
3
|
import { Constructor } from "@oscarpalmer/atoms/models";
|
|
4
4
|
|
|
5
|
-
//#region src/models/
|
|
5
|
+
//#region src/models/schematic.plain.model.d.ts
|
|
6
6
|
/**
|
|
7
|
-
* A generic
|
|
7
|
+
* A generic schematic allowing nested schematics, {@link SchematicEntry} values, or arrays of {@link SchematicEntry} as values
|
|
8
8
|
*/
|
|
9
|
-
type
|
|
10
|
-
[key: string]:
|
|
9
|
+
type PlainSchematic = {
|
|
10
|
+
[key: string]: PlainSchematic | SchematicEntry | SchematicEntry[] | undefined;
|
|
11
11
|
} & {
|
|
12
12
|
$default?: never;
|
|
13
13
|
$required?: never;
|
|
@@ -15,30 +15,30 @@ type PlainSchema = {
|
|
|
15
15
|
$validators?: never;
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
|
-
* A
|
|
18
|
+
* A schematic for validating objects
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* ```ts
|
|
22
|
-
* const
|
|
22
|
+
* const schematic = {
|
|
23
23
|
* name: 'string',
|
|
24
24
|
* age: 'number',
|
|
25
25
|
* tags: ['string', 'number'],
|
|
26
|
-
* };
|
|
26
|
+
* } satisfies Schematic;
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
type
|
|
29
|
+
type Schematic = PlainSchematic;
|
|
30
30
|
/**
|
|
31
|
-
* A union of all valid types for a single
|
|
31
|
+
* A union of all valid types for a single schematic entry
|
|
32
32
|
*
|
|
33
|
-
* Can be a {@link Constructor}, {@link
|
|
33
|
+
* Can be a {@link Constructor}, {@link PlainSchematic}, {@link SchematicProperty}, {@link Schema}, {@link ValueName}, or a custom validator function
|
|
34
34
|
*/
|
|
35
|
-
type
|
|
35
|
+
type SchematicEntry = Constructor | PlainSchematic | Schema<unknown> | SchematicProperty | ValueName | ((value: unknown) => boolean);
|
|
36
36
|
/**
|
|
37
37
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
38
38
|
*
|
|
39
39
|
* @example
|
|
40
40
|
* ```ts
|
|
41
|
-
* const prop:
|
|
41
|
+
* const prop: SchematicProperty = {
|
|
42
42
|
* $required: false,
|
|
43
43
|
* $type: ['string', 'number'],
|
|
44
44
|
* $validators: {
|
|
@@ -48,7 +48,7 @@ type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknow
|
|
|
48
48
|
* };
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
|
-
type
|
|
51
|
+
type SchematicProperty = {
|
|
52
52
|
$default?: unknown;
|
|
53
53
|
/**
|
|
54
54
|
* Whether the property is required _(defaults to `true`)_
|
|
@@ -64,11 +64,11 @@ type SchemaProperty = {
|
|
|
64
64
|
$validators?: PropertyValidators<SchemaPropertyType | SchemaPropertyType[]>;
|
|
65
65
|
};
|
|
66
66
|
/**
|
|
67
|
-
* A union of valid types for a {@link
|
|
67
|
+
* A union of valid types for a {@link SchematicProperty}'s `$type` field
|
|
68
68
|
*
|
|
69
|
-
* Can be a {@link Constructor}, {@link
|
|
69
|
+
* Can be a {@link Constructor}, {@link PlainSchematic}, {@link Schema}, {@link ValueName} string, or a custom validator function
|
|
70
70
|
*/
|
|
71
|
-
type SchemaPropertyType = Constructor |
|
|
71
|
+
type SchemaPropertyType = Constructor | PlainSchematic | Schema<unknown> | ValueName | ((value: unknown) => boolean);
|
|
72
72
|
/**
|
|
73
73
|
* A map of optional validator functions keyed by {@link ValueName}, used to add custom validation to {@link SchemaProperty} definitions
|
|
74
74
|
*
|
|
@@ -85,4 +85,4 @@ type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | Value
|
|
|
85
85
|
*/
|
|
86
86
|
type PropertyValidators<Value> = { [Key in ExtractValueNames<Value>]?: ((value: Values[Key]) => boolean) | Array<(value: Values[Key]) => boolean> };
|
|
87
87
|
//#endregion
|
|
88
|
-
export {
|
|
88
|
+
export { PlainSchematic, PropertyValidators, SchemaPropertyType, Schematic, SchematicEntry, SchematicProperty };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ToSchemaPropertyType, ToSchemaType } from "./transform.model.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { PropertyValidators } from "./
|
|
2
|
+
import { Schema } from "../schema.mjs";
|
|
3
|
+
import { PropertyValidators } from "./schematic.plain.model.mjs";
|
|
4
4
|
import { OptionalKeys, RequiredKeys } from "./misc.model.mjs";
|
|
5
5
|
import { PlainObject, Simplify } from "@oscarpalmer/atoms/models";
|
|
6
6
|
|
|
7
|
-
//#region src/models/
|
|
7
|
+
//#region src/models/schematic.typed.model.d.ts
|
|
8
8
|
/**
|
|
9
|
-
* A typed optional property definition generated by {@link
|
|
9
|
+
* A typed optional property definition generated by {@link TypedSchematic} for optional keys, with `$required` set to `false` and excludes `undefined` from the type
|
|
10
10
|
*
|
|
11
11
|
* @template Value Property's type _(including `undefined`)_
|
|
12
12
|
*
|
|
@@ -24,7 +24,7 @@ type TypedPropertyOptional<Value> = {
|
|
|
24
24
|
$validators?: PropertyValidators<ToSchemaPropertyType<Exclude<Value, undefined>>>;
|
|
25
25
|
};
|
|
26
26
|
/**
|
|
27
|
-
* A typed required property definition generated by {@link
|
|
27
|
+
* A typed required property definition generated by {@link TypedSchematic} for required keys, with `$required` defaulting to `true`
|
|
28
28
|
*
|
|
29
29
|
* @template Value Property's type
|
|
30
30
|
*
|
|
@@ -44,7 +44,7 @@ type TypedPropertyRequired<Value> = {
|
|
|
44
44
|
/**
|
|
45
45
|
* Creates a schema type constrained to match a TypeScript type
|
|
46
46
|
*
|
|
47
|
-
* Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link
|
|
47
|
+
* Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link Schema}
|
|
48
48
|
*
|
|
49
49
|
* @template Model Object type to generate a schema for
|
|
50
50
|
*
|
|
@@ -59,6 +59,6 @@ type TypedPropertyRequired<Value> = {
|
|
|
59
59
|
* };
|
|
60
60
|
* ```
|
|
61
61
|
*/
|
|
62
|
-
type
|
|
62
|
+
type TypedSchematic<Model extends PlainObject> = Simplify<{ [Key in RequiredKeys<Model>]: Model[Key] extends PlainObject ? Schema<Model[Key]> : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]> } & { [Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject ? Schema<Exclude<Model[Key], undefined>> : TypedPropertyOptional<Model[Key]> }>;
|
|
63
63
|
//#endregion
|
|
64
|
-
export { TypedPropertyOptional, TypedPropertyRequired,
|
|
64
|
+
export { TypedPropertyOptional, TypedPropertyRequired, TypedSchematic };
|
|
@@ -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
|
|
|
@@ -87,6 +87,6 @@ type ValidatorParameters = {
|
|
|
87
87
|
reporting: ReportingInformation;
|
|
88
88
|
strict: boolean;
|
|
89
89
|
};
|
|
90
|
-
type ValidatorType = Function | PlainObject |
|
|
90
|
+
type ValidatorType = Function | PlainObject | Schema<unknown> | ValueName;
|
|
91
91
|
//#endregion
|
|
92
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
|
|
@@ -75,7 +75,7 @@ declare class Schematic<Model> {
|
|
|
75
75
|
* @param options Validation options
|
|
76
76
|
* @returns Deeply cloned value, or `undefined` if it's invalid
|
|
77
77
|
*/
|
|
78
|
-
get(value: unknown, options: GetOptions<'none'
|
|
78
|
+
get(value: unknown, options: Partial<GetOptions<'none'>>): Model | undefined;
|
|
79
79
|
/**
|
|
80
80
|
* Parse a value according to the schema
|
|
81
81
|
*
|
|
@@ -147,7 +147,7 @@ declare class Schematic<Model> {
|
|
|
147
147
|
* @param options Validation options
|
|
148
148
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
149
149
|
*/
|
|
150
|
-
is(value: unknown, options: IsOptions<'none'
|
|
150
|
+
is(value: unknown, options: Partial<IsOptions<'none'>>): value is Model;
|
|
151
151
|
/**
|
|
152
152
|
* Does the value match the schema?
|
|
153
153
|
*
|
|
@@ -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,24 +1,24 @@
|
|
|
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);
|
|
20
20
|
const result = this.#validator(value, parameters, true);
|
|
21
|
-
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
|
|
21
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.clone ? parameters.output : value : ok(parameters.clone ? parameters.output : value);
|
|
22
22
|
if (parameters.reporting.none) return;
|
|
23
23
|
return error(parameters.reporting.all ? result : result[0]);
|
|
24
24
|
}
|
|
@@ -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,12 +1,12 @@
|
|
|
1
1
|
import { PROPERTY_DEFAULT, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY, TYPE_ALL } from "../constants.mjs";
|
|
2
|
-
import { getParameters,
|
|
2
|
+
import { getParameters, isSchema } from "../helpers/misc.helper.mjs";
|
|
3
3
|
import { SchematicError, ValidationError } from "../models/validation.model.mjs";
|
|
4
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 "./schema.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";
|
|
@@ -35,8 +35,8 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
35
35
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
36
36
|
const key = keys[keyIndex];
|
|
37
37
|
const value = original[key];
|
|
38
|
-
if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
|
|
39
38
|
const prefixedKey = origin == null ? key : join([origin.full, key], ".");
|
|
39
|
+
if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
|
|
40
40
|
const fullKey = {
|
|
41
41
|
full: prefixedKey,
|
|
42
42
|
short: key
|
|
@@ -67,8 +67,8 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
67
67
|
case isPlainObject(type):
|
|
68
68
|
validator = getObjectValidator(type, fullKey, typed);
|
|
69
69
|
break;
|
|
70
|
-
case
|
|
71
|
-
validator =
|
|
70
|
+
case isSchema(type):
|
|
71
|
+
validator = getSchemaValidator(type);
|
|
72
72
|
break;
|
|
73
73
|
case TYPE_ALL.has(type):
|
|
74
74
|
validator = getNamedValidator(fullKey, type, handlers);
|
|
@@ -92,20 +92,18 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
92
92
|
}
|
|
93
93
|
const validatorsLength = items.length;
|
|
94
94
|
return (input, parameters, get) => {
|
|
95
|
-
if (!isPlainObject(input)) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return [information];
|
|
108
|
-
}
|
|
95
|
+
if (!isPlainObject(input)) return origin == null ? report({
|
|
96
|
+
key: {
|
|
97
|
+
full: "",
|
|
98
|
+
short: ""
|
|
99
|
+
},
|
|
100
|
+
message: {
|
|
101
|
+
arguments: [input],
|
|
102
|
+
callback: getInputTypeMessage
|
|
103
|
+
},
|
|
104
|
+
original: parameters,
|
|
105
|
+
value: input
|
|
106
|
+
}, true) : [];
|
|
109
107
|
if (parameters.strict) {
|
|
110
108
|
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
111
109
|
if (unknownKeys.length > 0) {
|
|
@@ -122,6 +120,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
122
120
|
return [information];
|
|
123
121
|
}
|
|
124
122
|
}
|
|
123
|
+
const getAndClone = get && parameters.clone;
|
|
125
124
|
const allInformation = [];
|
|
126
125
|
const output = {};
|
|
127
126
|
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
@@ -130,22 +129,24 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
130
129
|
if (value === void 0) {
|
|
131
130
|
if (required) {
|
|
132
131
|
if (get && defaults != null) {
|
|
133
|
-
|
|
132
|
+
const defaultValue = clone(defaults.value);
|
|
133
|
+
if (parameters.clone) output[key.short] = defaultValue;
|
|
134
|
+
else input[key.short] = defaultValue;
|
|
134
135
|
continue;
|
|
135
136
|
}
|
|
136
137
|
if (parameters.reporting.none) return [];
|
|
137
|
-
const
|
|
138
|
+
const reported = report({
|
|
138
139
|
key,
|
|
139
140
|
value,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return
|
|
141
|
+
information: { all: allInformation },
|
|
142
|
+
message: {
|
|
143
|
+
arguments: [key.full, types],
|
|
144
|
+
callback: getInputPropertyMissingMessage
|
|
145
|
+
},
|
|
146
|
+
original: parameters
|
|
147
|
+
});
|
|
148
|
+
if (reported == null) continue;
|
|
149
|
+
return reported;
|
|
149
150
|
}
|
|
150
151
|
continue;
|
|
151
152
|
}
|
|
@@ -154,23 +155,32 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
154
155
|
const result = validator(value, parameters, get);
|
|
155
156
|
parameters.output = previousOutput;
|
|
156
157
|
if (result === true) {
|
|
157
|
-
if (
|
|
158
|
+
if (getAndClone && !isPlainObject(value)) output[key.short] = clone(value);
|
|
158
159
|
continue;
|
|
159
160
|
}
|
|
160
161
|
if (parameters.reporting.none) return [];
|
|
161
|
-
const
|
|
162
|
+
const reported = report({
|
|
162
163
|
key,
|
|
163
164
|
value,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
extract: false,
|
|
166
|
+
information: {
|
|
167
|
+
all: allInformation,
|
|
168
|
+
existing: typeof result !== "boolean" && result.length > 0 ? result : void 0
|
|
169
|
+
},
|
|
170
|
+
message: {
|
|
171
|
+
arguments: [
|
|
172
|
+
key.full,
|
|
173
|
+
types,
|
|
174
|
+
value
|
|
175
|
+
],
|
|
176
|
+
callback: getInputPropertyTypeMessage
|
|
177
|
+
},
|
|
178
|
+
original: parameters
|
|
179
|
+
});
|
|
180
|
+
if (reported == null) continue;
|
|
181
|
+
return reported;
|
|
172
182
|
}
|
|
173
|
-
if (
|
|
183
|
+
if (getAndClone) if (origin == null) parameters.output = output;
|
|
174
184
|
else parameters.output[origin.short] = output;
|
|
175
185
|
return allInformation.length === 0 ? true : allInformation;
|
|
176
186
|
};
|
|
@@ -181,5 +191,17 @@ function getRequired(obj, key, allowed) {
|
|
|
181
191
|
if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
|
|
182
192
|
return obj[PROPERTY_REQUIRED];
|
|
183
193
|
}
|
|
194
|
+
function report(parameters, getReports) {
|
|
195
|
+
const { information, message, original } = parameters;
|
|
196
|
+
const reported = information?.existing ?? [{
|
|
197
|
+
key: parameters.key,
|
|
198
|
+
value: parameters.value,
|
|
199
|
+
message: message.callback(...message.arguments)
|
|
200
|
+
}];
|
|
201
|
+
if (original.reporting.throw) throw new ValidationError(reported);
|
|
202
|
+
information?.all.push(...reported);
|
|
203
|
+
if (parameters.extract ?? true) original.information?.push(...reported);
|
|
204
|
+
if ((getReports ?? false) || !original.reporting.all) return reported;
|
|
205
|
+
}
|
|
184
206
|
//#endregion
|
|
185
207
|
export { getObjectValidator };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Validator } from "../models/validation.model.mjs";
|
|
2
|
+
import { Schema } from "../schema.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/validator/schema.validator.d.ts
|
|
5
|
+
declare function getSchemaValidator(schematic: Schema<unknown>): Validator;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getSchemaValidator };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { schemaValidators } from "../schema.mjs";
|
|
2
2
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
|
-
//#region src/validator/
|
|
4
|
-
function
|
|
5
|
-
const validator =
|
|
3
|
+
//#region src/validator/schema.validator.ts
|
|
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 };
|