@oscarpalmer/jhunal 0.16.0 → 0.17.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 +2 -2
- package/dist/constants.mjs +2 -2
- package/dist/index.d.mts +16 -39
- package/dist/index.mjs +4 -9
- package/dist/models.d.mts +12 -35
- package/dist/models.mjs +1 -6
- package/dist/schematic.d.mts +5 -5
- package/dist/schematic.mjs +1 -1
- package/dist/validation/property.validation.mjs +2 -2
- package/package.json +3 -3
- package/src/constants.ts +3 -2
- package/src/models.ts +14 -40
- package/src/schematic.ts +5 -5
- package/src/validation/property.validation.ts +10 -5
package/dist/constants.d.mts
CHANGED
|
@@ -2,10 +2,10 @@ import { Values } from "./models.mjs";
|
|
|
2
2
|
|
|
3
3
|
//#region src/constants.d.ts
|
|
4
4
|
declare const ERROR_NAME = "SchematicError";
|
|
5
|
-
declare const EXPRESSION_PROPERTY: RegExp;
|
|
6
5
|
declare const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
7
6
|
declare const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
8
7
|
declare const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
8
|
+
declare const MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE = "'<>' property must not be 'null' or 'undefined'";
|
|
9
9
|
declare const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
10
10
|
declare const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
11
11
|
declare const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
@@ -24,4 +24,4 @@ declare const TYPE_UNDEFINED = "undefined";
|
|
|
24
24
|
declare const VALIDATABLE_TYPES: Set<keyof Values>;
|
|
25
25
|
declare const TYPE_ALL: Set<keyof Values>;
|
|
26
26
|
//#endregion
|
|
27
|
-
export { ERROR_NAME,
|
|
27
|
+
export { ERROR_NAME, MESSAGE_CONSTRUCTOR, MESSAGE_SCHEMA_INVALID_EMPTY, MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE, MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, MESSAGE_SCHEMA_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_KEY, MESSAGE_VALIDATOR_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_VALUE, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_NAME, TEMPLATE_PATTERN, TEMPLATE_PATTERN_KEY, TEMPLATE_PATTERN_PROPERTY, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES };
|
package/dist/constants.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
//#region src/constants.ts
|
|
2
2
|
const ERROR_NAME = "SchematicError";
|
|
3
|
-
const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
4
3
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
5
4
|
const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
6
5
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
6
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE = "'<>' property must not be 'null' or 'undefined'";
|
|
7
7
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
8
8
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
9
9
|
const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
@@ -36,4 +36,4 @@ const TYPE_ALL = new Set([
|
|
|
36
36
|
TYPE_UNDEFINED
|
|
37
37
|
]);
|
|
38
38
|
//#endregion
|
|
39
|
-
export { ERROR_NAME,
|
|
39
|
+
export { ERROR_NAME, MESSAGE_CONSTRUCTOR, MESSAGE_SCHEMA_INVALID_EMPTY, MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE, MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, MESSAGE_SCHEMA_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_KEY, MESSAGE_VALIDATOR_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_VALUE, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_NAME, TEMPLATE_PATTERN, TEMPLATE_PATTERN_KEY, TEMPLATE_PATTERN_PROPERTY, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES };
|
package/dist/index.d.mts
CHANGED
|
@@ -83,7 +83,7 @@ type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryVa
|
|
|
83
83
|
*
|
|
84
84
|
* @template Value - single schema entry
|
|
85
85
|
*/
|
|
86
|
-
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends
|
|
86
|
+
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends PlainSchema ? Infer<Value & Schema> : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
|
|
87
87
|
/**
|
|
88
88
|
* Determines whether a schema entry is optional
|
|
89
89
|
*
|
|
@@ -91,11 +91,7 @@ type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ?
|
|
|
91
91
|
*
|
|
92
92
|
* @template Value - Schema entry to check
|
|
93
93
|
*/
|
|
94
|
-
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false :
|
|
95
|
-
$required?: boolean;
|
|
96
|
-
} ? Value extends {
|
|
97
|
-
$required: false;
|
|
98
|
-
} ? true : false : false;
|
|
94
|
+
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false : false;
|
|
99
95
|
/**
|
|
100
96
|
* Extracts the last member from a union type by leveraging intersection of function return types
|
|
101
97
|
*
|
|
@@ -114,24 +110,6 @@ type MapToValueTypes<Value extends unknown[]> = Value extends [infer Head, ...in
|
|
|
114
110
|
* @template Value - Tuple of types to map
|
|
115
111
|
*/
|
|
116
112
|
type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToSchemaPropertyTypeEach<Head>, ...MapToSchemaPropertyTypes<Tail>] : [];
|
|
117
|
-
/**
|
|
118
|
-
* A nested schema definition that may include a `$required` flag alongside arbitrary string-keyed properties
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```ts
|
|
122
|
-
* const address: NestedSchema = {
|
|
123
|
-
* $required: false,
|
|
124
|
-
* street: 'string',
|
|
125
|
-
* city: 'string',
|
|
126
|
-
* };
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
type NestedSchema = {
|
|
130
|
-
/**
|
|
131
|
-
* Whether the nested schema is required (defaults to `true`)
|
|
132
|
-
*/
|
|
133
|
-
$required?: boolean;
|
|
134
|
-
} & Schema;
|
|
135
113
|
/**
|
|
136
114
|
* Extracts keys from an object type that are optional
|
|
137
115
|
*
|
|
@@ -142,7 +120,11 @@ type OptionalKeys<Value> = { [Key in keyof Value]-?: {} extends Pick<Value, Key>
|
|
|
142
120
|
* A generic schema allowing {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry} as values
|
|
143
121
|
*/
|
|
144
122
|
type PlainSchema = {
|
|
145
|
-
[key: string]:
|
|
123
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[] | undefined;
|
|
124
|
+
} & {
|
|
125
|
+
$required?: never;
|
|
126
|
+
$type?: never;
|
|
127
|
+
$validators?: never;
|
|
146
128
|
};
|
|
147
129
|
/**
|
|
148
130
|
* A map of optional validator functions keyed by {@link ValueName}, used to add custom validation to {@link SchemaProperty} definitions
|
|
@@ -183,12 +165,12 @@ type Schema = SchemaIndex;
|
|
|
183
165
|
*
|
|
184
166
|
* Can be a {@link Constructor}, nested {@link Schema}, {@link SchemaProperty}, {@link Schematic}, {@link ValueName} string, or a custom validator function
|
|
185
167
|
*/
|
|
186
|
-
type SchemaEntry = Constructor |
|
|
168
|
+
type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
187
169
|
/**
|
|
188
170
|
* Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
|
|
189
171
|
*/
|
|
190
172
|
interface SchemaIndex {
|
|
191
|
-
[key: string]:
|
|
173
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
|
|
192
174
|
}
|
|
193
175
|
/**
|
|
194
176
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
@@ -226,12 +208,7 @@ type SchemaProperty = {
|
|
|
226
208
|
*/
|
|
227
209
|
type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
228
210
|
/**
|
|
229
|
-
* A custom error class for
|
|
230
|
-
*
|
|
231
|
-
* @example
|
|
232
|
-
* ```ts
|
|
233
|
-
* throw new SchematicError('Expected a string, received a number');
|
|
234
|
-
* ```
|
|
211
|
+
* A custom error class for schematic validation failures
|
|
235
212
|
*/
|
|
236
213
|
declare class SchematicError extends Error {
|
|
237
214
|
constructor(message: string);
|
|
@@ -251,7 +228,7 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaProp
|
|
|
251
228
|
*
|
|
252
229
|
* @template Value - type to convert
|
|
253
230
|
*/
|
|
254
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends
|
|
231
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
|
|
255
232
|
/**
|
|
256
233
|
* Converts a type into its corresponding {@link ValueName}-representation
|
|
257
234
|
*
|
|
@@ -513,23 +490,23 @@ declare class Schematic<Model> {
|
|
|
513
490
|
constructor(properties: ValidatedProperty[]);
|
|
514
491
|
/**
|
|
515
492
|
* Does the value match the schema?
|
|
516
|
-
* @param value
|
|
493
|
+
* @param value Value to validate
|
|
517
494
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
518
495
|
*/
|
|
519
496
|
is(value: unknown): value is Model;
|
|
520
497
|
}
|
|
521
498
|
/**
|
|
522
499
|
* Create a schematic from a schema
|
|
523
|
-
* @template Model
|
|
524
|
-
* @param schema
|
|
500
|
+
* @template Model Schema type
|
|
501
|
+
* @param schema Schema to create the schematic from
|
|
525
502
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
526
503
|
* @returns A schematic for the given schema
|
|
527
504
|
*/
|
|
528
505
|
declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer<Model>>;
|
|
529
506
|
/**
|
|
530
507
|
* Create a schematic from a typed schema
|
|
531
|
-
* @template Model
|
|
532
|
-
* @param schema
|
|
508
|
+
* @template Model Existing type
|
|
509
|
+
* @param schema Typed schema to create the schematic from
|
|
533
510
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
534
511
|
* @returns A schematic for the given typed schema
|
|
535
512
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -2,10 +2,10 @@ import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
|
2
2
|
import { join } from "@oscarpalmer/atoms/string";
|
|
3
3
|
//#region src/constants.ts
|
|
4
4
|
const ERROR_NAME = "SchematicError";
|
|
5
|
-
const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
6
5
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
7
6
|
const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
8
7
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
8
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE = "'<>' property must not be 'null' or 'undefined'";
|
|
9
9
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
10
10
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
11
11
|
const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
@@ -61,12 +61,7 @@ function isSchematic(value) {
|
|
|
61
61
|
//#endregion
|
|
62
62
|
//#region src/models.ts
|
|
63
63
|
/**
|
|
64
|
-
* A custom error class for
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* throw new SchematicError('Expected a string, received a number');
|
|
69
|
-
* ```
|
|
64
|
+
* A custom error class for schematic validation failures
|
|
70
65
|
*/
|
|
71
66
|
var SchematicError = class extends Error {
|
|
72
67
|
constructor(message) {
|
|
@@ -92,8 +87,8 @@ function getProperties(original, prefix, fromType) {
|
|
|
92
87
|
const properties = [];
|
|
93
88
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
94
89
|
const key = keys[keyIndex];
|
|
95
|
-
if (EXPRESSION_PROPERTY.test(key)) continue;
|
|
96
90
|
const value = original[key];
|
|
91
|
+
if (value == null) throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([prefix, key], ".")));
|
|
97
92
|
const types = [];
|
|
98
93
|
let required = true;
|
|
99
94
|
let validators = {};
|
|
@@ -213,7 +208,7 @@ var Schematic = class {
|
|
|
213
208
|
}
|
|
214
209
|
/**
|
|
215
210
|
* Does the value match the schema?
|
|
216
|
-
* @param value
|
|
211
|
+
* @param value Value to validate
|
|
217
212
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
218
213
|
*/
|
|
219
214
|
is(value) {
|
package/dist/models.d.mts
CHANGED
|
@@ -84,7 +84,7 @@ type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryVa
|
|
|
84
84
|
*
|
|
85
85
|
* @template Value - single schema entry
|
|
86
86
|
*/
|
|
87
|
-
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends
|
|
87
|
+
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends PlainSchema ? Infer<Value & Schema> : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
|
|
88
88
|
/**
|
|
89
89
|
* Determines whether a schema entry is optional
|
|
90
90
|
*
|
|
@@ -92,11 +92,7 @@ type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ?
|
|
|
92
92
|
*
|
|
93
93
|
* @template Value - Schema entry to check
|
|
94
94
|
*/
|
|
95
|
-
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false :
|
|
96
|
-
$required?: boolean;
|
|
97
|
-
} ? Value extends {
|
|
98
|
-
$required: false;
|
|
99
|
-
} ? true : false : false;
|
|
95
|
+
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false : false;
|
|
100
96
|
/**
|
|
101
97
|
* Extracts the last member from a union type by leveraging intersection of function return types
|
|
102
98
|
*
|
|
@@ -115,24 +111,6 @@ type MapToValueTypes<Value extends unknown[]> = Value extends [infer Head, ...in
|
|
|
115
111
|
* @template Value - Tuple of types to map
|
|
116
112
|
*/
|
|
117
113
|
type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToSchemaPropertyTypeEach<Head>, ...MapToSchemaPropertyTypes<Tail>] : [];
|
|
118
|
-
/**
|
|
119
|
-
* A nested schema definition that may include a `$required` flag alongside arbitrary string-keyed properties
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```ts
|
|
123
|
-
* const address: NestedSchema = {
|
|
124
|
-
* $required: false,
|
|
125
|
-
* street: 'string',
|
|
126
|
-
* city: 'string',
|
|
127
|
-
* };
|
|
128
|
-
* ```
|
|
129
|
-
*/
|
|
130
|
-
type NestedSchema = {
|
|
131
|
-
/**
|
|
132
|
-
* Whether the nested schema is required (defaults to `true`)
|
|
133
|
-
*/
|
|
134
|
-
$required?: boolean;
|
|
135
|
-
} & Schema;
|
|
136
114
|
/**
|
|
137
115
|
* Extracts keys from an object type that are optional
|
|
138
116
|
*
|
|
@@ -143,7 +121,11 @@ type OptionalKeys<Value> = { [Key in keyof Value]-?: {} extends Pick<Value, Key>
|
|
|
143
121
|
* A generic schema allowing {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry} as values
|
|
144
122
|
*/
|
|
145
123
|
type PlainSchema = {
|
|
146
|
-
[key: string]:
|
|
124
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[] | undefined;
|
|
125
|
+
} & {
|
|
126
|
+
$required?: never;
|
|
127
|
+
$type?: never;
|
|
128
|
+
$validators?: never;
|
|
147
129
|
};
|
|
148
130
|
/**
|
|
149
131
|
* A map of optional validator functions keyed by {@link ValueName}, used to add custom validation to {@link SchemaProperty} definitions
|
|
@@ -184,12 +166,12 @@ type Schema = SchemaIndex;
|
|
|
184
166
|
*
|
|
185
167
|
* Can be a {@link Constructor}, nested {@link Schema}, {@link SchemaProperty}, {@link Schematic}, {@link ValueName} string, or a custom validator function
|
|
186
168
|
*/
|
|
187
|
-
type SchemaEntry = Constructor |
|
|
169
|
+
type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
188
170
|
/**
|
|
189
171
|
* Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
|
|
190
172
|
*/
|
|
191
173
|
interface SchemaIndex {
|
|
192
|
-
[key: string]:
|
|
174
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
|
|
193
175
|
}
|
|
194
176
|
/**
|
|
195
177
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
@@ -227,12 +209,7 @@ type SchemaProperty = {
|
|
|
227
209
|
*/
|
|
228
210
|
type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
229
211
|
/**
|
|
230
|
-
* A custom error class for
|
|
231
|
-
*
|
|
232
|
-
* @example
|
|
233
|
-
* ```ts
|
|
234
|
-
* throw new SchematicError('Expected a string, received a number');
|
|
235
|
-
* ```
|
|
212
|
+
* A custom error class for schematic validation failures
|
|
236
213
|
*/
|
|
237
214
|
declare class SchematicError extends Error {
|
|
238
215
|
constructor(message: string);
|
|
@@ -252,7 +229,7 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaProp
|
|
|
252
229
|
*
|
|
253
230
|
* @template Value - type to convert
|
|
254
231
|
*/
|
|
255
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends
|
|
232
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
|
|
256
233
|
/**
|
|
257
234
|
* Converts a type into its corresponding {@link ValueName}-representation
|
|
258
235
|
*
|
|
@@ -504,4 +481,4 @@ type Values = {
|
|
|
504
481
|
undefined: undefined;
|
|
505
482
|
};
|
|
506
483
|
//#endregion
|
|
507
|
-
export { Infer,
|
|
484
|
+
export { Infer, Schema, SchemaProperty, SchematicError, TypedPropertyOptional, TypedPropertyRequired, TypedSchema, ValidatedProperty, ValidatedPropertyType, ValidatedPropertyValidators, ValueName, Values };
|
package/dist/models.mjs
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { ERROR_NAME } from "./constants.mjs";
|
|
2
2
|
//#region src/models.ts
|
|
3
3
|
/**
|
|
4
|
-
* A custom error class for
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* throw new SchematicError('Expected a string, received a number');
|
|
9
|
-
* ```
|
|
4
|
+
* A custom error class for schematic validation failures
|
|
10
5
|
*/
|
|
11
6
|
var SchematicError = class extends Error {
|
|
12
7
|
constructor(message) {
|
package/dist/schematic.d.mts
CHANGED
|
@@ -11,23 +11,23 @@ declare class Schematic<Model> {
|
|
|
11
11
|
constructor(properties: ValidatedProperty[]);
|
|
12
12
|
/**
|
|
13
13
|
* Does the value match the schema?
|
|
14
|
-
* @param value
|
|
14
|
+
* @param value Value to validate
|
|
15
15
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
16
16
|
*/
|
|
17
17
|
is(value: unknown): value is Model;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Create a schematic from a schema
|
|
21
|
-
* @template Model
|
|
22
|
-
* @param schema
|
|
21
|
+
* @template Model Schema type
|
|
22
|
+
* @param schema Schema to create the schematic from
|
|
23
23
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
24
24
|
* @returns A schematic for the given schema
|
|
25
25
|
*/
|
|
26
26
|
declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer<Model>>;
|
|
27
27
|
/**
|
|
28
28
|
* Create a schematic from a typed schema
|
|
29
|
-
* @template Model
|
|
30
|
-
* @param schema
|
|
29
|
+
* @template Model Existing type
|
|
30
|
+
* @param schema Typed schema to create the schematic from
|
|
31
31
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
32
32
|
* @returns A schematic for the given typed schema
|
|
33
33
|
*/
|
package/dist/schematic.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MESSAGE_SCHEMA_INVALID_EMPTY, MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE, MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, MESSAGE_VALIDATOR_INVALID_KEY, MESSAGE_VALIDATOR_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_VALUE, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, TEMPLATE_PATTERN_KEY, TEMPLATE_PATTERN_PROPERTY, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES } from "../constants.mjs";
|
|
2
2
|
import { instanceOf, isSchematic } from "../helpers.mjs";
|
|
3
3
|
import { SchematicError } from "../models.mjs";
|
|
4
4
|
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
@@ -20,8 +20,8 @@ function getProperties(original, prefix, fromType) {
|
|
|
20
20
|
const properties = [];
|
|
21
21
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
22
22
|
const key = keys[keyIndex];
|
|
23
|
-
if (EXPRESSION_PROPERTY.test(key)) continue;
|
|
24
23
|
const value = original[key];
|
|
24
|
+
if (value == null) throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([prefix, key], ".")));
|
|
25
25
|
const types = [];
|
|
26
26
|
let required = true;
|
|
27
27
|
let validators = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/jhunal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Flies free beneath the glistening moons…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"watch": "npx vite build --watch"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@oscarpalmer/atoms": "^0.
|
|
41
|
+
"@oscarpalmer/atoms": "^0.168"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^25.5",
|
|
@@ -51,4 +51,4 @@
|
|
|
51
51
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
52
52
|
},
|
|
53
53
|
"packageManager": "npm@11.11.1"
|
|
54
|
-
}
|
|
54
|
+
}
|
package/src/constants.ts
CHANGED
|
@@ -2,8 +2,6 @@ import type {ValueName} from './models';
|
|
|
2
2
|
|
|
3
3
|
export const ERROR_NAME = 'SchematicError';
|
|
4
4
|
|
|
5
|
-
export const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
6
|
-
|
|
7
5
|
export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
|
|
8
6
|
|
|
9
7
|
export const MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
|
|
@@ -11,6 +9,9 @@ export const MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one prope
|
|
|
11
9
|
export const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
|
|
12
10
|
"'<key>.<property>' property is not allowed for schemas in $type";
|
|
13
11
|
|
|
12
|
+
export const MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE =
|
|
13
|
+
"'<>' property must not be 'null' or 'undefined'";
|
|
14
|
+
|
|
14
15
|
export const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
15
16
|
|
|
16
17
|
export const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
package/src/models.ts
CHANGED
|
@@ -135,8 +135,8 @@ type InferSchemaEntryValue<Value> =
|
|
|
135
135
|
? Model
|
|
136
136
|
: Value extends SchemaProperty
|
|
137
137
|
? InferPropertyType<Value['$type']>
|
|
138
|
-
: Value extends
|
|
139
|
-
? Infer<
|
|
138
|
+
: Value extends PlainSchema
|
|
139
|
+
? Infer<Value & Schema>
|
|
140
140
|
: Value extends ValueName
|
|
141
141
|
? Values[Value & ValueName]
|
|
142
142
|
: Value extends Schema
|
|
@@ -154,11 +154,7 @@ type IsOptionalProperty<Value> = Value extends SchemaProperty
|
|
|
154
154
|
? Value['$required'] extends false
|
|
155
155
|
? true
|
|
156
156
|
: false
|
|
157
|
-
:
|
|
158
|
-
? Value extends {$required: false}
|
|
159
|
-
? true
|
|
160
|
-
: false
|
|
161
|
-
: false;
|
|
157
|
+
: false;
|
|
162
158
|
|
|
163
159
|
/**
|
|
164
160
|
* Extracts the last member from a union type by leveraging intersection of function return types
|
|
@@ -188,25 +184,6 @@ type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer He
|
|
|
188
184
|
? [ToSchemaPropertyTypeEach<Head>, ...MapToSchemaPropertyTypes<Tail>]
|
|
189
185
|
: [];
|
|
190
186
|
|
|
191
|
-
/**
|
|
192
|
-
* A nested schema definition that may include a `$required` flag alongside arbitrary string-keyed properties
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* ```ts
|
|
196
|
-
* const address: NestedSchema = {
|
|
197
|
-
* $required: false,
|
|
198
|
-
* street: 'string',
|
|
199
|
-
* city: 'string',
|
|
200
|
-
* };
|
|
201
|
-
* ```
|
|
202
|
-
*/
|
|
203
|
-
export type NestedSchema = {
|
|
204
|
-
/**
|
|
205
|
-
* Whether the nested schema is required (defaults to `true`)
|
|
206
|
-
*/
|
|
207
|
-
$required?: boolean;
|
|
208
|
-
} & Schema;
|
|
209
|
-
|
|
210
187
|
/**
|
|
211
188
|
* Extracts keys from an object type that are optional
|
|
212
189
|
*
|
|
@@ -220,7 +197,11 @@ type OptionalKeys<Value> = {
|
|
|
220
197
|
* A generic schema allowing {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry} as values
|
|
221
198
|
*/
|
|
222
199
|
type PlainSchema = {
|
|
223
|
-
[key: string]:
|
|
200
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[] | undefined;
|
|
201
|
+
} & {
|
|
202
|
+
$required?: never;
|
|
203
|
+
$type?: never;
|
|
204
|
+
$validators?: never;
|
|
224
205
|
};
|
|
225
206
|
|
|
226
207
|
/**
|
|
@@ -271,7 +252,7 @@ export type Schema = SchemaIndex;
|
|
|
271
252
|
*/
|
|
272
253
|
type SchemaEntry =
|
|
273
254
|
| Constructor
|
|
274
|
-
|
|
|
255
|
+
| PlainSchema
|
|
275
256
|
| SchemaProperty
|
|
276
257
|
| Schematic<unknown>
|
|
277
258
|
| ValueName
|
|
@@ -281,7 +262,7 @@ type SchemaEntry =
|
|
|
281
262
|
* Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link NestedSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
|
|
282
263
|
*/
|
|
283
264
|
interface SchemaIndex {
|
|
284
|
-
[key: string]:
|
|
265
|
+
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
|
|
285
266
|
}
|
|
286
267
|
|
|
287
268
|
/**
|
|
@@ -327,12 +308,7 @@ type SchemaPropertyType =
|
|
|
327
308
|
| ((value: unknown) => boolean);
|
|
328
309
|
|
|
329
310
|
/**
|
|
330
|
-
* A custom error class for
|
|
331
|
-
*
|
|
332
|
-
* @example
|
|
333
|
-
* ```ts
|
|
334
|
-
* throw new SchematicError('Expected a string, received a number');
|
|
335
|
-
* ```
|
|
311
|
+
* A custom error class for schematic validation failures
|
|
336
312
|
*/
|
|
337
313
|
export class SchematicError extends Error {
|
|
338
314
|
constructor(message: string) {
|
|
@@ -360,11 +336,9 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<
|
|
|
360
336
|
*
|
|
361
337
|
* @template Value - type to convert
|
|
362
338
|
*/
|
|
363
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends
|
|
364
|
-
?
|
|
365
|
-
: Value
|
|
366
|
-
? TypedSchema<Value>
|
|
367
|
-
: ToValueType<Value>;
|
|
339
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject
|
|
340
|
+
? TypedSchema<Value>
|
|
341
|
+
: ToValueType<Value>;
|
|
368
342
|
|
|
369
343
|
/**
|
|
370
344
|
* Converts a type into its corresponding {@link ValueName}-representation
|
package/src/schematic.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class Schematic<Model> {
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Does the value match the schema?
|
|
33
|
-
* @param value
|
|
33
|
+
* @param value Value to validate
|
|
34
34
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
35
35
|
*/
|
|
36
36
|
is(value: unknown): value is Model {
|
|
@@ -40,8 +40,8 @@ export class Schematic<Model> {
|
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Create a schematic from a schema
|
|
43
|
-
* @template Model
|
|
44
|
-
* @param schema
|
|
43
|
+
* @template Model Schema type
|
|
44
|
+
* @param schema Schema to create the schematic from
|
|
45
45
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
46
46
|
* @returns A schematic for the given schema
|
|
47
47
|
*/
|
|
@@ -49,8 +49,8 @@ export function schematic<Model extends Schema>(schema: Model): Schematic<Infer<
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Create a schematic from a typed schema
|
|
52
|
-
* @template Model
|
|
53
|
-
* @param schema
|
|
52
|
+
* @template Model Existing type
|
|
53
|
+
* @param schema Typed schema to create the schematic from
|
|
54
54
|
* @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
|
|
55
55
|
* @returns A schematic for the given typed schema
|
|
56
56
|
*/
|
|
@@ -2,9 +2,9 @@ import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
|
2
2
|
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {join} from '@oscarpalmer/atoms/string';
|
|
4
4
|
import {
|
|
5
|
-
EXPRESSION_PROPERTY,
|
|
6
5
|
MESSAGE_SCHEMA_INVALID_EMPTY,
|
|
7
6
|
MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
|
|
7
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE,
|
|
8
8
|
MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED,
|
|
9
9
|
MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE,
|
|
10
10
|
MESSAGE_VALIDATOR_INVALID_KEY,
|
|
@@ -74,12 +74,17 @@ export function getProperties(
|
|
|
74
74
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
75
75
|
const key = keys[keyIndex];
|
|
76
76
|
|
|
77
|
-
if (EXPRESSION_PROPERTY.test(key)) {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
77
|
const value = original[key];
|
|
82
78
|
|
|
79
|
+
if (value == null) {
|
|
80
|
+
throw new SchematicError(
|
|
81
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace(
|
|
82
|
+
TEMPLATE_PATTERN,
|
|
83
|
+
join([prefix, key], '.'),
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
const types: ValidatedPropertyType[] = [];
|
|
84
89
|
|
|
85
90
|
let required = true;
|