@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
package/dist/constants.d.mts
CHANGED
|
@@ -8,13 +8,13 @@ declare const CONJUNCTION_OR_COMMA = ", or ";
|
|
|
8
8
|
declare const CONJUNCTION_AND = " and ";
|
|
9
9
|
declare const CONJUNCTION_AND_COMMA = ", and ";
|
|
10
10
|
declare const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
11
|
-
declare const
|
|
12
|
-
declare const
|
|
11
|
+
declare const NAME_SCHEMA = "Schema";
|
|
12
|
+
declare const NAME_SCHEMA_PREFIXED = "a Schema";
|
|
13
13
|
declare const NAME_ERROR_SCHEMATIC = "SchematicError";
|
|
14
14
|
declare const NAME_ERROR_VALIDATION = "ValidationError";
|
|
15
15
|
declare const PROPERTY_DEFAULT = "$default";
|
|
16
16
|
declare const PROPERTY_REQUIRED = "$required";
|
|
17
|
-
declare const
|
|
17
|
+
declare const PROPERTY_SCHEMA = "$schema";
|
|
18
18
|
declare const PROPERTY_TYPE = "$type";
|
|
19
19
|
declare const PROPERTY_VALIDATORS = "$validators";
|
|
20
20
|
declare const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
|
|
@@ -50,4 +50,4 @@ declare const VALIDATABLE_TYPES: Set<keyof Values>;
|
|
|
50
50
|
declare const TYPE_ALL: Set<keyof Values>;
|
|
51
51
|
declare const PREFIXED_TYPES: Record<ValueName, string>;
|
|
52
52
|
//#endregion
|
|
53
|
-
export { COMMA, CONJUNCTION_AND, CONJUNCTION_AND_COMMA, CONJUNCTION_OR, CONJUNCTION_OR_COMMA, MESSAGE_CONSTRUCTOR, NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION,
|
|
53
|
+
export { COMMA, CONJUNCTION_AND, CONJUNCTION_AND_COMMA, CONJUNCTION_OR, CONJUNCTION_OR_COMMA, MESSAGE_CONSTRUCTOR, NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION, NAME_SCHEMA, NAME_SCHEMA_PREFIXED, PREFIXED_TYPES, PROPERTY_DEFAULT, PROPERTY_REQUIRED, PROPERTY_SCHEMA, PROPERTY_TYPE, PROPERTY_VALIDATORS, REPORTING_ALL, REPORTING_FIRST, REPORTING_NONE, REPORTING_THROW, REPORTING_TYPES, SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE, 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_SCHEMA_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TEMPLATE_PATTERN, TYPE_ALL, TYPE_ARRAY, TYPE_FUNCTION, TYPE_FUNCTION_RESULT, TYPE_NULL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES, VALIDATION_MESSAGE_INVALID_INPUT, VALIDATION_MESSAGE_INVALID_REQUIRED, VALIDATION_MESSAGE_INVALID_TYPE, VALIDATION_MESSAGE_INVALID_VALUE, VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX, VALIDATION_MESSAGE_UNKNOWN_KEYS };
|
package/dist/constants.mjs
CHANGED
|
@@ -5,13 +5,13 @@ const CONJUNCTION_OR_COMMA = ", or ";
|
|
|
5
5
|
const CONJUNCTION_AND = " and ";
|
|
6
6
|
const CONJUNCTION_AND_COMMA = ", and ";
|
|
7
7
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const NAME_SCHEMA = "Schema";
|
|
9
|
+
const NAME_SCHEMA_PREFIXED = "a Schema";
|
|
10
10
|
const NAME_ERROR_SCHEMATIC = "SchematicError";
|
|
11
11
|
const NAME_ERROR_VALIDATION = "ValidationError";
|
|
12
12
|
const PROPERTY_DEFAULT = "$default";
|
|
13
13
|
const PROPERTY_REQUIRED = "$required";
|
|
14
|
-
const
|
|
14
|
+
const PROPERTY_SCHEMA = "$schema";
|
|
15
15
|
const PROPERTY_TYPE = "$type";
|
|
16
16
|
const PROPERTY_VALIDATORS = "$validators";
|
|
17
17
|
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
|
|
@@ -78,4 +78,4 @@ const PREFIXED_TYPES = {
|
|
|
78
78
|
[TYPE_UNDEFINED]: TYPE_UNDEFINED
|
|
79
79
|
};
|
|
80
80
|
//#endregion
|
|
81
|
-
export { COMMA, CONJUNCTION_AND, CONJUNCTION_AND_COMMA, CONJUNCTION_OR, CONJUNCTION_OR_COMMA, MESSAGE_CONSTRUCTOR, NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION,
|
|
81
|
+
export { COMMA, CONJUNCTION_AND, CONJUNCTION_AND_COMMA, CONJUNCTION_OR, CONJUNCTION_OR_COMMA, MESSAGE_CONSTRUCTOR, NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION, NAME_SCHEMA, NAME_SCHEMA_PREFIXED, PREFIXED_TYPES, PROPERTY_DEFAULT, PROPERTY_REQUIRED, PROPERTY_SCHEMA, PROPERTY_TYPE, PROPERTY_VALIDATORS, REPORTING_ALL, REPORTING_FIRST, REPORTING_NONE, REPORTING_THROW, REPORTING_TYPES, SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE, 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_SCHEMA_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TEMPLATE_PATTERN, TYPE_ALL, TYPE_ARRAY, TYPE_FUNCTION, TYPE_FUNCTION_RESULT, TYPE_NULL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES, VALIDATION_MESSAGE_INVALID_INPUT, VALIDATION_MESSAGE_INVALID_REQUIRED, VALIDATION_MESSAGE_INVALID_TYPE, VALIDATION_MESSAGE_INVALID_VALUE, VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX, VALIDATION_MESSAGE_UNKNOWN_KEYS };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReportingInformation, ValidatorParameters } from "../models/validation.model.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Schema } from "../schema.mjs";
|
|
3
3
|
import { Constructor } from "@oscarpalmer/atoms/models";
|
|
4
4
|
|
|
5
5
|
//#region src/helpers/misc.helper.d.ts
|
|
@@ -17,6 +17,6 @@ declare function instanceOf<Instance>(constructor: Constructor<Instance>): (valu
|
|
|
17
17
|
* @param value Value to check
|
|
18
18
|
* @returns `true` if the value is a schematic, `false` otherwise
|
|
19
19
|
*/
|
|
20
|
-
declare function
|
|
20
|
+
declare function isSchema(value: unknown): value is Schema<never>;
|
|
21
21
|
//#endregion
|
|
22
|
-
export { getParameters, getReporting, instanceOf,
|
|
22
|
+
export { getParameters, getReporting, instanceOf, isSchema };
|
|
@@ -49,8 +49,8 @@ function instanceOf(constructor) {
|
|
|
49
49
|
* @param value Value to check
|
|
50
50
|
* @returns `true` if the value is a schematic, `false` otherwise
|
|
51
51
|
*/
|
|
52
|
-
function
|
|
53
|
-
return typeof value === "object" && value !== null && "$
|
|
52
|
+
function isSchema(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && "$schema" in value && value["$schema"] === true;
|
|
54
54
|
}
|
|
55
55
|
//#endregion
|
|
56
|
-
export { getParameters, getReporting, instanceOf,
|
|
56
|
+
export { getParameters, getReporting, instanceOf, isSchema };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Constructor, GenericCallback, PlainObject, Simplify } from "@oscarpalmer/atoms/models";
|
|
2
2
|
import { Result } from "@oscarpalmer/atoms/result/models";
|
|
3
3
|
|
|
4
|
-
//#region src/models/
|
|
4
|
+
//#region src/models/schematic.plain.model.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* A generic
|
|
6
|
+
* A generic schematic allowing nested schematics, {@link SchematicEntry} values, or arrays of {@link SchematicEntry} as values
|
|
7
7
|
*/
|
|
8
|
-
type
|
|
9
|
-
[key: string]:
|
|
8
|
+
type PlainSchematic = {
|
|
9
|
+
[key: string]: PlainSchematic | SchematicEntry | SchematicEntry[] | undefined;
|
|
10
10
|
} & {
|
|
11
11
|
$default?: never;
|
|
12
12
|
$required?: never;
|
|
@@ -14,30 +14,30 @@ type PlainSchema = {
|
|
|
14
14
|
$validators?: never;
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
|
-
* A
|
|
17
|
+
* A schematic for validating objects
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```ts
|
|
21
|
-
* const
|
|
21
|
+
* const schematic = {
|
|
22
22
|
* name: 'string',
|
|
23
23
|
* age: 'number',
|
|
24
24
|
* tags: ['string', 'number'],
|
|
25
|
-
* };
|
|
25
|
+
* } satisfies Schematic;
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
type
|
|
28
|
+
type Schematic = PlainSchematic;
|
|
29
29
|
/**
|
|
30
|
-
* A union of all valid types for a single
|
|
30
|
+
* A union of all valid types for a single schematic entry
|
|
31
31
|
*
|
|
32
|
-
* Can be a {@link Constructor}, {@link
|
|
32
|
+
* Can be a {@link Constructor}, {@link PlainSchematic}, {@link SchematicProperty}, {@link Schema}, {@link ValueName}, or a custom validator function
|
|
33
33
|
*/
|
|
34
|
-
type
|
|
34
|
+
type SchematicEntry = Constructor | PlainSchematic | Schema<unknown> | SchematicProperty | ValueName | ((value: unknown) => boolean);
|
|
35
35
|
/**
|
|
36
36
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
39
39
|
* ```ts
|
|
40
|
-
* const prop:
|
|
40
|
+
* const prop: SchematicProperty = {
|
|
41
41
|
* $required: false,
|
|
42
42
|
* $type: ['string', 'number'],
|
|
43
43
|
* $validators: {
|
|
@@ -47,7 +47,7 @@ type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknow
|
|
|
47
47
|
* };
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
|
-
type
|
|
50
|
+
type SchematicProperty = {
|
|
51
51
|
$default?: unknown;
|
|
52
52
|
/**
|
|
53
53
|
* Whether the property is required _(defaults to `true`)_
|
|
@@ -63,11 +63,11 @@ type SchemaProperty = {
|
|
|
63
63
|
$validators?: PropertyValidators<SchemaPropertyType | SchemaPropertyType[]>;
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
|
-
* A union of valid types for a {@link
|
|
66
|
+
* A union of valid types for a {@link SchematicProperty}'s `$type` field
|
|
67
67
|
*
|
|
68
|
-
* Can be a {@link Constructor}, {@link
|
|
68
|
+
* Can be a {@link Constructor}, {@link PlainSchematic}, {@link Schema}, {@link ValueName} string, or a custom validator function
|
|
69
69
|
*/
|
|
70
|
-
type SchemaPropertyType = Constructor |
|
|
70
|
+
type SchemaPropertyType = Constructor | PlainSchematic | Schema<unknown> | ValueName | ((value: unknown) => boolean);
|
|
71
71
|
/**
|
|
72
72
|
* A map of optional validator functions keyed by {@link ValueName}, used to add custom validation to {@link SchemaProperty} definitions
|
|
73
73
|
*
|
|
@@ -113,11 +113,11 @@ type ExtractValueNames<Value> = Value extends ValueName ? Value : Value extends
|
|
|
113
113
|
/**
|
|
114
114
|
* Determines whether a schema entry is optional
|
|
115
115
|
*
|
|
116
|
-
* Returns `true` if the entry is a {@link
|
|
116
|
+
* Returns `true` if the entry is a {@link SchematicProperty} with `$required` set to `false`; otherwise returns `false`
|
|
117
117
|
*
|
|
118
118
|
* @template Value Schema entry to check
|
|
119
119
|
*/
|
|
120
|
-
type IsOptionalProperty<Value> = Value extends
|
|
120
|
+
type IsOptionalProperty<Value> = Value extends SchematicProperty ? Value['$required'] extends false ? true : false : false;
|
|
121
121
|
/**
|
|
122
122
|
* Extracts the last member from a union type by leveraging contravariance of function parameter types
|
|
123
123
|
*
|
|
@@ -227,31 +227,31 @@ type Values = {
|
|
|
227
227
|
//#endregion
|
|
228
228
|
//#region src/models/infer.model.d.ts
|
|
229
229
|
/**
|
|
230
|
-
* Infers the TypeScript type from a {@link
|
|
230
|
+
* Infers the TypeScript type from a {@link Schematic} definition
|
|
231
231
|
*
|
|
232
|
-
* @template Model
|
|
232
|
+
* @template Model Schematic to infer types from
|
|
233
233
|
*
|
|
234
234
|
* @example
|
|
235
235
|
* ```ts
|
|
236
|
-
* const
|
|
236
|
+
* const userSchematic = {
|
|
237
237
|
* name: 'string',
|
|
238
238
|
* age: 'number',
|
|
239
239
|
* address: { $required: false, $type: 'string' },
|
|
240
|
-
* } satisfies
|
|
240
|
+
* } satisfies Schematic;
|
|
241
241
|
*
|
|
242
|
-
* type User = Infer<typeof
|
|
242
|
+
* type User = Infer<typeof userSchematic>;
|
|
243
243
|
* // { name: string; age: number; address?: string }
|
|
244
244
|
* ```
|
|
245
245
|
*/
|
|
246
|
-
type Infer<Model extends
|
|
246
|
+
type Infer<Model extends Schematic> = Simplify<{ [Key in InferRequiredKeys<Model>]: InferSchemaEntry<Model[Key]> } & { [Key in InferOptionalKeys<Model>]?: InferSchemaEntry<Model[Key]> }>;
|
|
247
247
|
/**
|
|
248
|
-
* Extracts keys from a {@link
|
|
248
|
+
* Extracts keys from a {@link Schematic} whose entries are optional _(i.e., `$required` is `false`)_
|
|
249
249
|
*
|
|
250
|
-
* @template Model - {@link
|
|
250
|
+
* @template Model - {@link Schematic} to extract optional keys from
|
|
251
251
|
*/
|
|
252
|
-
type InferOptionalKeys<Model extends
|
|
252
|
+
type InferOptionalKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? Key : never]: never };
|
|
253
253
|
/**
|
|
254
|
-
* Infers the TypeScript type from a {@link
|
|
254
|
+
* Infers the TypeScript type from a {@link SchematicProperty}'s `$type` field
|
|
255
255
|
*
|
|
256
256
|
* @template Value `$type` value _(single or array)_
|
|
257
257
|
*/
|
|
@@ -259,31 +259,31 @@ type InferPropertyType<Value> = Value extends (infer Item)[] ? InferPropertyValu
|
|
|
259
259
|
/**
|
|
260
260
|
* Maps a single `$type` definition to its TypeScript equivalent
|
|
261
261
|
*
|
|
262
|
-
* Resolves, in order: {@link Constructor}
|
|
262
|
+
* Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link ValueName} values, and nested {@link PlainSchematic} objects
|
|
263
263
|
*
|
|
264
264
|
* @template Value single type definition
|
|
265
265
|
*/
|
|
266
|
-
type InferPropertyValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends
|
|
266
|
+
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;
|
|
267
267
|
/**
|
|
268
|
-
* Extracts keys from a {@link
|
|
268
|
+
* Extracts keys from a {@link Schematic} whose entries are required _(i.e., `$required` is not `false`)_
|
|
269
269
|
*
|
|
270
|
-
* @template Model
|
|
270
|
+
* @template Model Schematic to extract required keys from
|
|
271
271
|
*/
|
|
272
|
-
type InferRequiredKeys<Model extends
|
|
272
|
+
type InferRequiredKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never };
|
|
273
273
|
/**
|
|
274
|
-
* Infers the TypeScript type from a top-level {@link
|
|
274
|
+
* Infers the TypeScript type from a top-level {@link Schematic} entry
|
|
275
275
|
*
|
|
276
|
-
* @template Value
|
|
276
|
+
* @template Value Schematic entry value _(single or array)_
|
|
277
277
|
*/
|
|
278
278
|
type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryValue<Item> : InferSchemaEntryValue<Value>;
|
|
279
279
|
/**
|
|
280
280
|
* Maps a single top-level schema entry to its TypeScript type
|
|
281
281
|
*
|
|
282
|
-
* Resolves, in order: {@link Constructor}
|
|
282
|
+
* Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link SchemaProperty} objects, {@link PlainSchematic} objects, and {@link ValueName} values
|
|
283
283
|
*
|
|
284
284
|
* @template Value single schema entry
|
|
285
285
|
*/
|
|
286
|
-
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends
|
|
286
|
+
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;
|
|
287
287
|
//#endregion
|
|
288
288
|
//#region src/models/transform.model.d.ts
|
|
289
289
|
/**
|
|
@@ -307,11 +307,11 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaProp
|
|
|
307
307
|
/**
|
|
308
308
|
* Converts a single type to its schema property equivalent
|
|
309
309
|
*
|
|
310
|
-
* Plain objects become {@link
|
|
310
|
+
* Plain objects become {@link TypedSchematic}; primitives go through {@link ToValueType}
|
|
311
311
|
*
|
|
312
312
|
* @template Value Type to convert
|
|
313
313
|
*/
|
|
314
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ?
|
|
314
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchematic<Value> : ToValueType<Value>;
|
|
315
315
|
/**
|
|
316
316
|
* Converts a TypeScript type to its {@link ValueName} representation, suitable for use as a top-level schema entry
|
|
317
317
|
*
|
|
@@ -321,7 +321,7 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
|
|
|
321
321
|
/**
|
|
322
322
|
* Maps a type to its {@link ValueName} string equivalent
|
|
323
323
|
*
|
|
324
|
-
* Resolves {@link
|
|
324
|
+
* 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
|
|
325
325
|
*
|
|
326
326
|
* @template Value Type to map
|
|
327
327
|
*
|
|
@@ -332,11 +332,11 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
|
|
|
332
332
|
* // ToValueType<Date> => 'date'
|
|
333
333
|
* ```
|
|
334
334
|
*/
|
|
335
|
-
type ToValueType<Value> = Value extends
|
|
335
|
+
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;
|
|
336
336
|
//#endregion
|
|
337
|
-
//#region src/models/
|
|
337
|
+
//#region src/models/schematic.typed.model.d.ts
|
|
338
338
|
/**
|
|
339
|
-
* A typed optional property definition generated by {@link
|
|
339
|
+
* A typed optional property definition generated by {@link TypedSchematic} for optional keys, with `$required` set to `false` and excludes `undefined` from the type
|
|
340
340
|
*
|
|
341
341
|
* @template Value Property's type _(including `undefined`)_
|
|
342
342
|
*
|
|
@@ -354,7 +354,7 @@ type TypedPropertyOptional<Value> = {
|
|
|
354
354
|
$validators?: PropertyValidators<ToSchemaPropertyType<Exclude<Value, undefined>>>;
|
|
355
355
|
};
|
|
356
356
|
/**
|
|
357
|
-
* A typed required property definition generated by {@link
|
|
357
|
+
* A typed required property definition generated by {@link TypedSchematic} for required keys, with `$required` defaulting to `true`
|
|
358
358
|
*
|
|
359
359
|
* @template Value Property's type
|
|
360
360
|
*
|
|
@@ -374,7 +374,7 @@ type TypedPropertyRequired<Value> = {
|
|
|
374
374
|
/**
|
|
375
375
|
* Creates a schema type constrained to match a TypeScript type
|
|
376
376
|
*
|
|
377
|
-
* Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link
|
|
377
|
+
* Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link Schema}
|
|
378
378
|
*
|
|
379
379
|
* @template Model Object type to generate a schema for
|
|
380
380
|
*
|
|
@@ -389,15 +389,15 @@ type TypedPropertyRequired<Value> = {
|
|
|
389
389
|
* };
|
|
390
390
|
* ```
|
|
391
391
|
*/
|
|
392
|
-
type
|
|
392
|
+
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]> }>;
|
|
393
393
|
//#endregion
|
|
394
|
-
//#region src/
|
|
394
|
+
//#region src/schema.d.ts
|
|
395
395
|
/**
|
|
396
|
-
* A
|
|
396
|
+
* A schema for validating objects
|
|
397
397
|
*/
|
|
398
|
-
declare class
|
|
398
|
+
declare class Schema<Model> {
|
|
399
399
|
#private;
|
|
400
|
-
private readonly $
|
|
400
|
+
private readonly $schema;
|
|
401
401
|
constructor(validator: Validator);
|
|
402
402
|
/**
|
|
403
403
|
* Parse a value according to the schema
|
|
@@ -461,7 +461,7 @@ declare class Schematic<Model> {
|
|
|
461
461
|
* @param options Validation options
|
|
462
462
|
* @returns Deeply cloned value, or `undefined` if it's invalid
|
|
463
463
|
*/
|
|
464
|
-
get(value: unknown, options: GetOptions<'none'
|
|
464
|
+
get(value: unknown, options: Partial<GetOptions<'none'>>): Model | undefined;
|
|
465
465
|
/**
|
|
466
466
|
* Parse a value according to the schema
|
|
467
467
|
*
|
|
@@ -533,7 +533,7 @@ declare class Schematic<Model> {
|
|
|
533
533
|
* @param options Validation options
|
|
534
534
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
535
535
|
*/
|
|
536
|
-
is(value: unknown, options: IsOptions<'none'
|
|
536
|
+
is(value: unknown, options: Partial<IsOptions<'none'>>): value is Model;
|
|
537
537
|
/**
|
|
538
538
|
* Does the value match the schema?
|
|
539
539
|
*
|
|
@@ -545,21 +545,21 @@ declare class Schematic<Model> {
|
|
|
545
545
|
is(value: unknown, strict?: true): value is Model;
|
|
546
546
|
}
|
|
547
547
|
/**
|
|
548
|
-
* Create a
|
|
548
|
+
* Create a schema from a schematic
|
|
549
549
|
* @template Model Schema type
|
|
550
|
-
* @param schema
|
|
551
|
-
* @throws Throws {@link SchematicError} if the
|
|
552
|
-
* @returns A
|
|
550
|
+
* @param schema Schematic to create the schema from
|
|
551
|
+
* @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
|
|
552
|
+
* @returns A schema for the given schematic
|
|
553
553
|
*/
|
|
554
|
-
declare function
|
|
554
|
+
declare function schema<Model extends Schematic>(schema: Model): Schema<Infer<Model>>;
|
|
555
555
|
/**
|
|
556
|
-
* Create a
|
|
556
|
+
* Create a schema from a typed schematic
|
|
557
557
|
* @template Model Existing type
|
|
558
|
-
* @param schema Typed
|
|
559
|
-
* @throws Throws {@link SchematicError} if the
|
|
560
|
-
* @returns A
|
|
558
|
+
* @param schema Typed schematic to create the schema from
|
|
559
|
+
* @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
|
|
560
|
+
* @returns A schema for the given typed schematic
|
|
561
561
|
*/
|
|
562
|
-
declare function
|
|
562
|
+
declare function schema<Model extends PlainObject>(schema: TypedSchematic<Model>): Schema<Model>;
|
|
563
563
|
//#endregion
|
|
564
564
|
//#region src/models/validation.model.d.ts
|
|
565
565
|
type ReportingInformation = Record<ReportingType, boolean> & {
|
|
@@ -648,6 +648,6 @@ declare function instanceOf<Instance>(constructor: Constructor<Instance>): (valu
|
|
|
648
648
|
* @param value Value to check
|
|
649
649
|
* @returns `true` if the value is a schematic, `false` otherwise
|
|
650
650
|
*/
|
|
651
|
-
declare function
|
|
651
|
+
declare function isSchema(value: unknown): value is Schema<never>;
|
|
652
652
|
//#endregion
|
|
653
|
-
export { type GetOptions, type IsOptions, type Schema, type Schematic, SchematicError, type
|
|
653
|
+
export { type GetOptions, type IsOptions, type Schema, type Schematic, SchematicError, type TypedSchematic, ValidationError, instanceOf, isSchema, schema };
|
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const NAME_ERROR_SCHEMATIC = "SchematicError";
|
|
|
12
12
|
const NAME_ERROR_VALIDATION = "ValidationError";
|
|
13
13
|
const PROPERTY_DEFAULT = "$default";
|
|
14
14
|
const PROPERTY_REQUIRED = "$required";
|
|
15
|
-
const
|
|
15
|
+
const PROPERTY_SCHEMA = "$schema";
|
|
16
16
|
const PROPERTY_TYPE = "$type";
|
|
17
17
|
const PROPERTY_VALIDATORS = "$validators";
|
|
18
18
|
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
|
|
@@ -125,8 +125,8 @@ function instanceOf(constructor) {
|
|
|
125
125
|
* @param value Value to check
|
|
126
126
|
* @returns `true` if the value is a schematic, `false` otherwise
|
|
127
127
|
*/
|
|
128
|
-
function
|
|
129
|
-
return typeof value === "object" && value !== null && "$
|
|
128
|
+
function isSchema(value) {
|
|
129
|
+
return typeof value === "object" && value !== null && "$schema" in value && value["$schema"] === true;
|
|
130
130
|
}
|
|
131
131
|
//#endregion
|
|
132
132
|
//#region src/models/validation.model.ts
|
|
@@ -319,9 +319,9 @@ const namedValidators = {
|
|
|
319
319
|
undefined: (value) => value === void 0
|
|
320
320
|
};
|
|
321
321
|
//#endregion
|
|
322
|
-
//#region src/validator/
|
|
323
|
-
function
|
|
324
|
-
const validator =
|
|
322
|
+
//#region src/validator/schema.validator.ts
|
|
323
|
+
function getSchemaValidator(schematic) {
|
|
324
|
+
const validator = schemaValidators.get(schematic);
|
|
325
325
|
return (input, parameters, get) => {
|
|
326
326
|
let result;
|
|
327
327
|
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
@@ -357,8 +357,8 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
357
357
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
358
358
|
const key = keys[keyIndex];
|
|
359
359
|
const value = original[key];
|
|
360
|
-
if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
|
|
361
360
|
const prefixedKey = origin == null ? key : join([origin.full, key], ".");
|
|
361
|
+
if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
|
|
362
362
|
const fullKey = {
|
|
363
363
|
full: prefixedKey,
|
|
364
364
|
short: key
|
|
@@ -389,8 +389,8 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
389
389
|
case isPlainObject(type):
|
|
390
390
|
validator = getObjectValidator(type, fullKey, typed);
|
|
391
391
|
break;
|
|
392
|
-
case
|
|
393
|
-
validator =
|
|
392
|
+
case isSchema(type):
|
|
393
|
+
validator = getSchemaValidator(type);
|
|
394
394
|
break;
|
|
395
395
|
case TYPE_ALL.has(type):
|
|
396
396
|
validator = getNamedValidator(fullKey, type, handlers);
|
|
@@ -414,20 +414,18 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
414
414
|
}
|
|
415
415
|
const validatorsLength = items.length;
|
|
416
416
|
return (input, parameters, get) => {
|
|
417
|
-
if (!isPlainObject(input)) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return [information];
|
|
430
|
-
}
|
|
417
|
+
if (!isPlainObject(input)) return origin == null ? report({
|
|
418
|
+
key: {
|
|
419
|
+
full: "",
|
|
420
|
+
short: ""
|
|
421
|
+
},
|
|
422
|
+
message: {
|
|
423
|
+
arguments: [input],
|
|
424
|
+
callback: getInputTypeMessage
|
|
425
|
+
},
|
|
426
|
+
original: parameters,
|
|
427
|
+
value: input
|
|
428
|
+
}, true) : [];
|
|
431
429
|
if (parameters.strict) {
|
|
432
430
|
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
433
431
|
if (unknownKeys.length > 0) {
|
|
@@ -444,6 +442,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
444
442
|
return [information];
|
|
445
443
|
}
|
|
446
444
|
}
|
|
445
|
+
const getAndClone = get && parameters.clone;
|
|
447
446
|
const allInformation = [];
|
|
448
447
|
const output = {};
|
|
449
448
|
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
@@ -452,22 +451,24 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
452
451
|
if (value === void 0) {
|
|
453
452
|
if (required) {
|
|
454
453
|
if (get && defaults != null) {
|
|
455
|
-
|
|
454
|
+
const defaultValue = clone(defaults.value);
|
|
455
|
+
if (parameters.clone) output[key.short] = defaultValue;
|
|
456
|
+
else input[key.short] = defaultValue;
|
|
456
457
|
continue;
|
|
457
458
|
}
|
|
458
459
|
if (parameters.reporting.none) return [];
|
|
459
|
-
const
|
|
460
|
+
const reported = report({
|
|
460
461
|
key,
|
|
461
462
|
value,
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return
|
|
463
|
+
information: { all: allInformation },
|
|
464
|
+
message: {
|
|
465
|
+
arguments: [key.full, types],
|
|
466
|
+
callback: getInputPropertyMissingMessage
|
|
467
|
+
},
|
|
468
|
+
original: parameters
|
|
469
|
+
});
|
|
470
|
+
if (reported == null) continue;
|
|
471
|
+
return reported;
|
|
471
472
|
}
|
|
472
473
|
continue;
|
|
473
474
|
}
|
|
@@ -476,23 +477,32 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
476
477
|
const result = validator(value, parameters, get);
|
|
477
478
|
parameters.output = previousOutput;
|
|
478
479
|
if (result === true) {
|
|
479
|
-
if (
|
|
480
|
+
if (getAndClone && !isPlainObject(value)) output[key.short] = clone(value);
|
|
480
481
|
continue;
|
|
481
482
|
}
|
|
482
483
|
if (parameters.reporting.none) return [];
|
|
483
|
-
const
|
|
484
|
+
const reported = report({
|
|
484
485
|
key,
|
|
485
486
|
value,
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
487
|
+
extract: false,
|
|
488
|
+
information: {
|
|
489
|
+
all: allInformation,
|
|
490
|
+
existing: typeof result !== "boolean" && result.length > 0 ? result : void 0
|
|
491
|
+
},
|
|
492
|
+
message: {
|
|
493
|
+
arguments: [
|
|
494
|
+
key.full,
|
|
495
|
+
types,
|
|
496
|
+
value
|
|
497
|
+
],
|
|
498
|
+
callback: getInputPropertyTypeMessage
|
|
499
|
+
},
|
|
500
|
+
original: parameters
|
|
501
|
+
});
|
|
502
|
+
if (reported == null) continue;
|
|
503
|
+
return reported;
|
|
494
504
|
}
|
|
495
|
-
if (
|
|
505
|
+
if (getAndClone) if (origin == null) parameters.output = output;
|
|
496
506
|
else parameters.output[origin.short] = output;
|
|
497
507
|
return allInformation.length === 0 ? true : allInformation;
|
|
498
508
|
};
|
|
@@ -503,22 +513,34 @@ function getRequired(obj, key, allowed) {
|
|
|
503
513
|
if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
|
|
504
514
|
return obj[PROPERTY_REQUIRED];
|
|
505
515
|
}
|
|
516
|
+
function report(parameters, getReports) {
|
|
517
|
+
const { information, message, original } = parameters;
|
|
518
|
+
const reported = information?.existing ?? [{
|
|
519
|
+
key: parameters.key,
|
|
520
|
+
value: parameters.value,
|
|
521
|
+
message: message.callback(...message.arguments)
|
|
522
|
+
}];
|
|
523
|
+
if (original.reporting.throw) throw new ValidationError(reported);
|
|
524
|
+
information?.all.push(...reported);
|
|
525
|
+
if (parameters.extract ?? true) original.information?.push(...reported);
|
|
526
|
+
if ((getReports ?? false) || !original.reporting.all) return reported;
|
|
527
|
+
}
|
|
506
528
|
//#endregion
|
|
507
|
-
//#region src/
|
|
529
|
+
//#region src/schema.ts
|
|
508
530
|
/**
|
|
509
|
-
* A
|
|
531
|
+
* A schema for validating objects
|
|
510
532
|
*/
|
|
511
|
-
var
|
|
533
|
+
var Schema = class {
|
|
512
534
|
#validator;
|
|
513
535
|
constructor(validator) {
|
|
514
|
-
Object.defineProperty(this,
|
|
536
|
+
Object.defineProperty(this, PROPERTY_SCHEMA, { value: true });
|
|
515
537
|
this.#validator = validator;
|
|
516
|
-
|
|
538
|
+
schemaValidators.set(this, validator);
|
|
517
539
|
}
|
|
518
540
|
get(value, options) {
|
|
519
541
|
const parameters = getParameters(options);
|
|
520
542
|
const result = this.#validator(value, parameters, true);
|
|
521
|
-
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
|
|
543
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.clone ? parameters.output : value : ok(parameters.clone ? parameters.output : value);
|
|
522
544
|
if (parameters.reporting.none) return;
|
|
523
545
|
return error(parameters.reporting.all ? result : result[0]);
|
|
524
546
|
}
|
|
@@ -530,11 +552,11 @@ var Schematic = class {
|
|
|
530
552
|
return error(parameters.reporting.all ? result : result[0]);
|
|
531
553
|
}
|
|
532
554
|
};
|
|
533
|
-
function
|
|
534
|
-
if (
|
|
555
|
+
function schema(schema) {
|
|
556
|
+
if (isSchema(schema)) return schema;
|
|
535
557
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
536
|
-
return new
|
|
558
|
+
return new Schema(getObjectValidator(schema));
|
|
537
559
|
}
|
|
538
|
-
const
|
|
560
|
+
const schemaValidators = /* @__PURE__ */ new WeakMap();
|
|
539
561
|
//#endregion
|
|
540
|
-
export { SchematicError, ValidationError, instanceOf,
|
|
562
|
+
export { SchematicError, ValidationError, instanceOf, isSchema, schema };
|