@oscarpalmer/jhunal 0.21.0 → 0.23.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 +7 -3
- package/dist/constants.mjs +34 -12
- package/dist/helpers/message.helper.d.mts +11 -0
- package/dist/helpers/message.helper.mjs +70 -0
- package/dist/helpers/misc.helper.d.mts +22 -0
- package/dist/helpers/misc.helper.mjs +56 -0
- package/dist/index.d.mts +318 -328
- package/dist/index.mjs +324 -295
- package/dist/models/schema.plain.model.d.mts +2 -8
- package/dist/models/validation.model.d.mts +26 -59
- package/dist/schematic.d.mts +28 -10
- package/dist/schematic.mjs +15 -16
- package/dist/validator/base.validator.d.mts +6 -0
- package/dist/validator/base.validator.mjs +19 -0
- package/dist/validator/function.validator.d.mts +6 -0
- package/dist/validator/function.validator.mjs +9 -0
- package/dist/validator/named.handler.d.mts +6 -0
- package/dist/validator/named.handler.mjs +22 -0
- package/dist/validator/named.validator.d.mts +7 -0
- package/dist/validator/named.validator.mjs +39 -0
- package/dist/validator/object.validator.d.mts +7 -0
- package/dist/validator/object.validator.mjs +167 -0
- package/dist/validator/schematic.validator.d.mts +7 -0
- package/dist/validator/schematic.validator.mjs +16 -0
- package/package.json +1 -1
- package/src/constants.ts +42 -10
- package/src/helpers/message.helper.ts +152 -0
- package/src/helpers/misc.helper.ts +93 -0
- package/src/index.ts +7 -2
- package/src/models/schema.plain.model.ts +1 -8
- package/src/models/validation.model.ts +55 -77
- package/src/schematic.ts +49 -27
- package/src/validator/base.validator.ts +31 -0
- package/src/validator/function.validator.ts +9 -0
- package/src/validator/named.handler.ts +50 -0
- package/src/validator/named.validator.ts +62 -0
- package/src/validator/object.validator.ts +340 -0
- package/src/validator/schematic.validator.ts +25 -0
- package/dist/helpers.d.mts +0 -28
- package/dist/helpers.mjs +0 -119
- package/dist/validation/property.validation.d.mts +0 -7
- package/dist/validation/property.validation.mjs +0 -92
- package/dist/validation/value.validation.d.mts +0 -7
- package/dist/validation/value.validation.mjs +0 -162
- package/src/helpers.ts +0 -246
- package/src/validation/property.validation.ts +0 -217
- package/src/validation/value.validation.ts +0 -293
package/src/constants.ts
CHANGED
|
@@ -25,6 +25,8 @@ export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
|
|
|
25
25
|
|
|
26
26
|
export const NAME_SCHEMATIC = 'Schematic';
|
|
27
27
|
|
|
28
|
+
export const NAME_SCHEMATIC_PREFIXED = 'a Schematic';
|
|
29
|
+
|
|
28
30
|
export const NAME_ERROR_SCHEMATIC = 'SchematicError';
|
|
29
31
|
|
|
30
32
|
export const NAME_ERROR_VALIDATION = 'ValidationError';
|
|
@@ -45,7 +47,7 @@ export const PROPERTY_VALIDATORS = '$validators';
|
|
|
45
47
|
|
|
46
48
|
// #region Property validation
|
|
47
49
|
|
|
48
|
-
export const VALIDATION_MESSAGE_INVALID_INPUT =
|
|
50
|
+
export const VALIDATION_MESSAGE_INVALID_INPUT = 'Expected an object as input but received <>';
|
|
49
51
|
|
|
50
52
|
export const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
|
|
51
53
|
|
|
@@ -116,24 +118,54 @@ export const TEMPLATE_PATTERN = '<>';
|
|
|
116
118
|
|
|
117
119
|
export const TYPE_ARRAY = 'array';
|
|
118
120
|
|
|
121
|
+
const TYPE_BIGINT = 'bigint';
|
|
122
|
+
|
|
123
|
+
const TYPE_BOOLEAN = 'boolean';
|
|
124
|
+
|
|
125
|
+
const TYPE_DATE = 'date';
|
|
126
|
+
|
|
127
|
+
export const TYPE_FUNCTION = 'function';
|
|
128
|
+
|
|
129
|
+
export const TYPE_FUNCTION_RESULT = 'a validated value';
|
|
130
|
+
|
|
119
131
|
export const TYPE_NULL = 'null';
|
|
120
132
|
|
|
133
|
+
const TYPE_NUMBER = 'number';
|
|
134
|
+
|
|
121
135
|
export const TYPE_OBJECT = 'object';
|
|
122
136
|
|
|
137
|
+
const TYPE_STRING = 'string';
|
|
138
|
+
|
|
139
|
+
const TYPE_SYMBOL = 'symbol';
|
|
140
|
+
|
|
123
141
|
export const TYPE_UNDEFINED = 'undefined';
|
|
124
142
|
|
|
125
143
|
export const VALIDATABLE_TYPES = new Set<ValueName>([
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
'string',
|
|
133
|
-
'symbol',
|
|
144
|
+
TYPE_ARRAY,
|
|
145
|
+
TYPE_BIGINT,
|
|
146
|
+
TYPE_BOOLEAN,
|
|
147
|
+
TYPE_DATE,
|
|
148
|
+
TYPE_FUNCTION,
|
|
149
|
+
TYPE_NUMBER,
|
|
134
150
|
TYPE_OBJECT,
|
|
151
|
+
TYPE_STRING,
|
|
152
|
+
TYPE_SYMBOL,
|
|
135
153
|
]);
|
|
136
154
|
|
|
137
|
-
export const TYPE_ALL = new Set<ValueName>([...VALIDATABLE_TYPES,
|
|
155
|
+
export const TYPE_ALL = new Set<ValueName>([...VALIDATABLE_TYPES, TYPE_NULL, TYPE_UNDEFINED]);
|
|
156
|
+
|
|
157
|
+
export const PREFIXED_TYPES: Record<ValueName, string> = {
|
|
158
|
+
[TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
|
|
159
|
+
[TYPE_BIGINT]: `a ${TYPE_BIGINT}`,
|
|
160
|
+
[TYPE_BOOLEAN]: `a ${TYPE_BOOLEAN}`,
|
|
161
|
+
[TYPE_DATE]: `a ${TYPE_DATE}`,
|
|
162
|
+
[TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
|
|
163
|
+
[TYPE_NULL]: TYPE_NULL,
|
|
164
|
+
[TYPE_NUMBER]: `a ${TYPE_NUMBER}`,
|
|
165
|
+
[TYPE_STRING]: `a ${TYPE_STRING}`,
|
|
166
|
+
[TYPE_SYMBOL]: `a ${TYPE_SYMBOL}`,
|
|
167
|
+
[TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
|
|
168
|
+
[TYPE_UNDEFINED]: TYPE_UNDEFINED,
|
|
169
|
+
};
|
|
138
170
|
|
|
139
171
|
// #endregion
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {
|
|
3
|
+
COMMA,
|
|
4
|
+
CONJUNCTION_AND,
|
|
5
|
+
CONJUNCTION_AND_COMMA,
|
|
6
|
+
CONJUNCTION_OR,
|
|
7
|
+
CONJUNCTION_OR_COMMA,
|
|
8
|
+
PREFIXED_TYPES,
|
|
9
|
+
TEMPLATE_PATTERN,
|
|
10
|
+
TYPE_ALL,
|
|
11
|
+
TYPE_ARRAY,
|
|
12
|
+
TYPE_FUNCTION,
|
|
13
|
+
TYPE_FUNCTION_RESULT,
|
|
14
|
+
TYPE_NULL,
|
|
15
|
+
TYPE_OBJECT,
|
|
16
|
+
VALIDATION_MESSAGE_INVALID_INPUT,
|
|
17
|
+
VALIDATION_MESSAGE_INVALID_REQUIRED,
|
|
18
|
+
VALIDATION_MESSAGE_INVALID_TYPE,
|
|
19
|
+
VALIDATION_MESSAGE_INVALID_VALUE,
|
|
20
|
+
VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX,
|
|
21
|
+
VALIDATION_MESSAGE_UNKNOWN_KEYS,
|
|
22
|
+
} from '../constants';
|
|
23
|
+
import type {ValueName} from '../models/misc.model';
|
|
24
|
+
import type {ValidatorType} from '../models/validation.model';
|
|
25
|
+
|
|
26
|
+
export function getInvalidInputMessage(actual: unknown): string {
|
|
27
|
+
return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getInvalidMissingMessage(key: string, types: ValidatorType[]): string {
|
|
31
|
+
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
32
|
+
|
|
33
|
+
message = message.replace(TEMPLATE_PATTERN, key);
|
|
34
|
+
|
|
35
|
+
return message;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getInvalidTypeMessage(
|
|
39
|
+
key: string,
|
|
40
|
+
types: ValidatorType[],
|
|
41
|
+
actual: unknown,
|
|
42
|
+
): string {
|
|
43
|
+
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
44
|
+
|
|
45
|
+
message = message.replace(TEMPLATE_PATTERN, key);
|
|
46
|
+
message = message.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
47
|
+
|
|
48
|
+
return message;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getInvalidValidatorMessage(
|
|
52
|
+
key: string,
|
|
53
|
+
type: ValueName,
|
|
54
|
+
index: number,
|
|
55
|
+
length: number,
|
|
56
|
+
): string {
|
|
57
|
+
let message = VALIDATION_MESSAGE_INVALID_VALUE.replace(TEMPLATE_PATTERN, key);
|
|
58
|
+
|
|
59
|
+
message = message.replace(TEMPLATE_PATTERN, type);
|
|
60
|
+
|
|
61
|
+
if (length > 1) {
|
|
62
|
+
message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace(TEMPLATE_PATTERN, String(index));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return message;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getPropertyType(type: ValidatorType): string {
|
|
69
|
+
switch (true) {
|
|
70
|
+
case typeof type === 'function':
|
|
71
|
+
return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
|
|
72
|
+
|
|
73
|
+
case TYPE_ALL.has(type as ValueName):
|
|
74
|
+
return PREFIXED_TYPES[type as ValueName];
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
return PREFIXED_TYPES[TYPE_OBJECT];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function getUnknownKeysMessage(keys: string[]): string {
|
|
82
|
+
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getValueType(value: unknown): string {
|
|
86
|
+
const valueType = typeof value;
|
|
87
|
+
|
|
88
|
+
switch (true) {
|
|
89
|
+
case value === null:
|
|
90
|
+
return TYPE_NULL;
|
|
91
|
+
|
|
92
|
+
case Array.isArray(value):
|
|
93
|
+
return PREFIXED_TYPES[TYPE_ARRAY];
|
|
94
|
+
|
|
95
|
+
case isPlainObject(value):
|
|
96
|
+
return PREFIXED_TYPES[TYPE_OBJECT];
|
|
97
|
+
|
|
98
|
+
case valueType !== TYPE_OBJECT:
|
|
99
|
+
return PREFIXED_TYPES[valueType as ValueName];
|
|
100
|
+
|
|
101
|
+
default:
|
|
102
|
+
return (value as object).constructor.name;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function renderKeys(keys: string[]): string {
|
|
107
|
+
return renderParts(
|
|
108
|
+
keys.map(key => `'${key}'`),
|
|
109
|
+
CONJUNCTION_AND,
|
|
110
|
+
CONJUNCTION_AND_COMMA,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function renderParts(parts: string[], delimiterShort: string, delimiterLong: string): string {
|
|
115
|
+
const {length} = parts;
|
|
116
|
+
|
|
117
|
+
if (length === 1) {
|
|
118
|
+
return parts[0];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let rendered = '';
|
|
122
|
+
|
|
123
|
+
for (let index = 0; index < length; index += 1) {
|
|
124
|
+
rendered += parts[index];
|
|
125
|
+
|
|
126
|
+
if (index < length - 2) {
|
|
127
|
+
rendered += COMMA;
|
|
128
|
+
} else if (index === length - 2) {
|
|
129
|
+
rendered += parts.length > 2 ? delimiterLong : delimiterShort;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return rendered;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderTypes(types: ValidatorType[]): string {
|
|
137
|
+
const unique = new Set<string>();
|
|
138
|
+
const parts: string[] = [];
|
|
139
|
+
|
|
140
|
+
for (let index = 0; index < types.length; index += 1) {
|
|
141
|
+
const rendered = getPropertyType(types[index]);
|
|
142
|
+
|
|
143
|
+
if (unique.has(rendered)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
unique.add(rendered);
|
|
148
|
+
parts.push(rendered);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
152
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Constructor, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {
|
|
4
|
+
MESSAGE_CONSTRUCTOR,
|
|
5
|
+
PROPERTY_SCHEMATIC,
|
|
6
|
+
REPORTING_ALL,
|
|
7
|
+
REPORTING_FIRST,
|
|
8
|
+
REPORTING_NONE,
|
|
9
|
+
REPORTING_THROW,
|
|
10
|
+
REPORTING_TYPES,
|
|
11
|
+
TYPE_OBJECT,
|
|
12
|
+
} from '../constants';
|
|
13
|
+
import type {
|
|
14
|
+
ReportingInformation,
|
|
15
|
+
ReportingType,
|
|
16
|
+
ValidatorParameters,
|
|
17
|
+
} from '../models/validation.model';
|
|
18
|
+
import type {Schematic} from '../schematic';
|
|
19
|
+
|
|
20
|
+
export function getParameters(input?: unknown): ValidatorParameters {
|
|
21
|
+
if (typeof input === 'boolean') {
|
|
22
|
+
return {
|
|
23
|
+
clone: true,
|
|
24
|
+
output: {},
|
|
25
|
+
reporting: getReporting(REPORTING_NONE),
|
|
26
|
+
strict: input,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (REPORTING_TYPES.has(input as ReportingType)) {
|
|
31
|
+
return {
|
|
32
|
+
clone: true,
|
|
33
|
+
output: {},
|
|
34
|
+
reporting: getReporting(input as ReportingType),
|
|
35
|
+
strict: false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const options = isPlainObject(input) ? input : {};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
clone: typeof options.clone === 'boolean' ? options.clone : true,
|
|
43
|
+
output: {},
|
|
44
|
+
reporting: getReporting(options.errors),
|
|
45
|
+
strict: typeof options.strict === 'boolean' ? options.strict : false,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getReporting(value: unknown): ReportingInformation {
|
|
50
|
+
const type = REPORTING_TYPES.has(value as ReportingType)
|
|
51
|
+
? (value as ReportingType)
|
|
52
|
+
: REPORTING_NONE;
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
type,
|
|
56
|
+
[REPORTING_ALL]: type === REPORTING_ALL,
|
|
57
|
+
[REPORTING_FIRST]: type === REPORTING_FIRST,
|
|
58
|
+
[REPORTING_NONE]: type === REPORTING_NONE,
|
|
59
|
+
[REPORTING_THROW]: type === REPORTING_THROW,
|
|
60
|
+
} as ReportingInformation;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates a validator function for a given constructor
|
|
65
|
+
* @param constructor - Constructor to check against
|
|
66
|
+
* @throws Will throw a `TypeError` if the provided argument is not a valid constructor
|
|
67
|
+
* @returns Validator function that checks if a value is an instance of the constructor
|
|
68
|
+
*/
|
|
69
|
+
export function instanceOf<Instance>(
|
|
70
|
+
constructor: Constructor<Instance>,
|
|
71
|
+
): (value: unknown) => value is Instance {
|
|
72
|
+
if (!isConstructor(constructor)) {
|
|
73
|
+
throw new TypeError(MESSAGE_CONSTRUCTOR);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (value: unknown): value is Instance => {
|
|
77
|
+
return value instanceof constructor;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Is the value a schematic?
|
|
83
|
+
* @param value Value to check
|
|
84
|
+
* @returns `true` if the value is a schematic, `false` otherwise
|
|
85
|
+
*/
|
|
86
|
+
export function isSchematic(value: unknown): value is Schematic<never> {
|
|
87
|
+
return (
|
|
88
|
+
typeof value === TYPE_OBJECT &&
|
|
89
|
+
value !== null &&
|
|
90
|
+
PROPERTY_SCHEMATIC in (value as PlainObject) &&
|
|
91
|
+
(value as PlainObject)[PROPERTY_SCHEMATIC] === true
|
|
92
|
+
);
|
|
93
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
export {instanceOf, isSchematic} from './helpers';
|
|
1
|
+
export {instanceOf, isSchematic} from './helpers/misc.helper';
|
|
2
2
|
export type {Schema} from './models/schema.plain.model';
|
|
3
3
|
export type {TypedSchema} from './models/schema.typed.model';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
SchematicError,
|
|
6
|
+
ValidationError,
|
|
7
|
+
type GetOptions,
|
|
8
|
+
type IsOptions,
|
|
9
|
+
} from './models/validation.model';
|
|
5
10
|
export {schematic, type Schematic} from './schematic';
|
|
@@ -25,7 +25,7 @@ export type PlainSchema = {
|
|
|
25
25
|
* };
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export type Schema =
|
|
28
|
+
export type Schema = PlainSchema;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* A union of all valid types for a single schema entry
|
|
@@ -40,13 +40,6 @@ export type SchemaEntry =
|
|
|
40
40
|
| ValueName
|
|
41
41
|
| ((value: unknown) => boolean);
|
|
42
42
|
|
|
43
|
-
/**
|
|
44
|
-
* Index signature interface backing {@link Schema}, allowing string-keyed entries of {@link PlainSchema}, {@link SchemaEntry}, or arrays of {@link SchemaEntry}
|
|
45
|
-
*/
|
|
46
|
-
export interface SchemaIndex {
|
|
47
|
-
[key: string]: PlainSchema | SchemaEntry | SchemaEntry[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
43
|
/**
|
|
51
44
|
* A property definition with explicit type(s), an optional requirement flag, and optional validators
|
|
52
45
|
*
|
|
@@ -4,11 +4,18 @@ import {NAME_ERROR_SCHEMATIC, NAME_ERROR_VALIDATION} from '../constants';
|
|
|
4
4
|
import type {Schematic} from '../schematic';
|
|
5
5
|
import type {ValueName} from './misc.model';
|
|
6
6
|
|
|
7
|
+
// #region Named validation
|
|
8
|
+
|
|
9
|
+
export type NamedValidatorHandlers = {
|
|
10
|
+
[Key in ValueName]?: Array<(value: unknown) => boolean>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type NamedValidators = Record<ValueName, (value: unknown) => boolean>;
|
|
14
|
+
|
|
15
|
+
// #endregion
|
|
16
|
+
|
|
7
17
|
// #region Reporting
|
|
8
18
|
|
|
9
|
-
/**
|
|
10
|
-
* Maps each {@link ReportingType} to a boolean flag
|
|
11
|
-
*/
|
|
12
19
|
export type ReportingInformation = Record<ReportingType, boolean> & {
|
|
13
20
|
type: ReportingType;
|
|
14
21
|
};
|
|
@@ -16,16 +23,16 @@ export type ReportingInformation = Record<ReportingType, boolean> & {
|
|
|
16
23
|
/**
|
|
17
24
|
* Controls how validation failures are reported
|
|
18
25
|
*
|
|
19
|
-
* - `'none'
|
|
20
|
-
* - `'first'
|
|
21
|
-
* - `'all'
|
|
22
|
-
* - `'throw'
|
|
26
|
+
* - `'none'`, returns a boolean _(default)_
|
|
27
|
+
* - `'first'`, returns the first failure as a `Result`
|
|
28
|
+
* - `'all'`, returns all failures as a `Result` _(from same level)_
|
|
29
|
+
* - `'throw'`, throws a {@link ValidationError} on failure
|
|
23
30
|
*/
|
|
24
31
|
export type ReportingType = 'all' | 'first' | 'none' | 'throw';
|
|
25
32
|
|
|
26
33
|
// #endregion
|
|
27
34
|
|
|
28
|
-
// #region
|
|
35
|
+
// #region Errors
|
|
29
36
|
|
|
30
37
|
/**
|
|
31
38
|
* Thrown when a schema definition is invalid
|
|
@@ -38,66 +45,6 @@ export class SchematicError extends Error {
|
|
|
38
45
|
}
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
// #endregion
|
|
42
|
-
|
|
43
|
-
// #region Validated property
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The runtime representation of a parsed schema property, used internally during validation
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```ts
|
|
50
|
-
* const parsed: ValidatedProperty = {
|
|
51
|
-
* key: 'age',
|
|
52
|
-
* required: true,
|
|
53
|
-
* types: ['number'],
|
|
54
|
-
* validators: { number: [(v) => v > 0] },
|
|
55
|
-
* };
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
export type ValidatedProperty = {
|
|
59
|
-
/**
|
|
60
|
-
* The property name in the schema
|
|
61
|
-
*/
|
|
62
|
-
key: string;
|
|
63
|
-
/**
|
|
64
|
-
* Whether the property is required
|
|
65
|
-
*/
|
|
66
|
-
required: boolean;
|
|
67
|
-
/**
|
|
68
|
-
* The allowed types for this property
|
|
69
|
-
*/
|
|
70
|
-
types: ValidatedPropertyType[];
|
|
71
|
-
/**
|
|
72
|
-
* Custom validators grouped by {@link ValueName}
|
|
73
|
-
*/
|
|
74
|
-
validators: ValidatedPropertyValidators;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* A union of valid types for a {@link ValidatedProperty}'s `types` array
|
|
79
|
-
*
|
|
80
|
-
* Can be a callback _(custom validator)_, a {@link Schematic}, a nested {@link ValidatedProperty}, or a {@link ValueName} string
|
|
81
|
-
*/
|
|
82
|
-
export type ValidatedPropertyType =
|
|
83
|
-
| GenericCallback
|
|
84
|
-
| ValidatedProperty[]
|
|
85
|
-
| Schematic<unknown>
|
|
86
|
-
| ValueName;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* A map of validator functions keyed by {@link ValueName}, used at runtime in {@link ValidatedProperty}
|
|
90
|
-
*
|
|
91
|
-
* Each key holds an array of validator functions that receive an `unknown` value and return a `boolean`
|
|
92
|
-
*/
|
|
93
|
-
export type ValidatedPropertyValidators = {
|
|
94
|
-
[Key in ValueName]?: Array<(value: unknown) => boolean>;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// #endregion
|
|
98
|
-
|
|
99
|
-
// #region Property validation
|
|
100
|
-
|
|
101
48
|
/**
|
|
102
49
|
* Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
|
|
103
50
|
*/
|
|
@@ -114,6 +61,10 @@ export class ValidationError extends Error {
|
|
|
114
61
|
}
|
|
115
62
|
}
|
|
116
63
|
|
|
64
|
+
// #endregion
|
|
65
|
+
|
|
66
|
+
// #region Results
|
|
67
|
+
|
|
117
68
|
/**
|
|
118
69
|
* Describes a single validation failure
|
|
119
70
|
*/
|
|
@@ -129,34 +80,61 @@ export type ValidationInformation = {
|
|
|
129
80
|
};
|
|
130
81
|
|
|
131
82
|
/**
|
|
132
|
-
*
|
|
83
|
+
*
|
|
133
84
|
*/
|
|
134
85
|
export type ValidationInformationKey = {
|
|
135
86
|
full: string;
|
|
136
87
|
short: string;
|
|
137
88
|
};
|
|
138
89
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
90
|
+
// #endregion
|
|
91
|
+
|
|
92
|
+
// #region Options
|
|
93
|
+
|
|
94
|
+
type BaseOptions<Errors extends ReportingType> = {
|
|
143
95
|
/**
|
|
144
96
|
* How should validation failures be reported; see {@link ReportingType} _(defaults to `'none'`)_
|
|
145
97
|
*/
|
|
146
|
-
errors
|
|
98
|
+
errors: Errors;
|
|
147
99
|
/**
|
|
148
100
|
* Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
149
101
|
*/
|
|
150
102
|
strict?: boolean;
|
|
151
103
|
};
|
|
152
104
|
|
|
153
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Options for validating and getting a value from an input
|
|
107
|
+
*/
|
|
108
|
+
export type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
|
|
109
|
+
/**
|
|
110
|
+
* Get a deeply cloned version of the input? _(defaults to `true`)_
|
|
111
|
+
*/
|
|
112
|
+
clone?: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Options for validation an input value
|
|
117
|
+
*/
|
|
118
|
+
export type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
|
|
119
|
+
|
|
120
|
+
// #endregion
|
|
121
|
+
|
|
122
|
+
// #region Validator
|
|
123
|
+
|
|
124
|
+
export type Validator = (
|
|
125
|
+
input: unknown,
|
|
126
|
+
parameters: ValidatorParameters,
|
|
127
|
+
get: boolean,
|
|
128
|
+
) => true | ValidationInformation[];
|
|
129
|
+
|
|
130
|
+
export type ValidatorParameters = {
|
|
131
|
+
clone: boolean;
|
|
154
132
|
information?: ValidationInformation[];
|
|
155
|
-
origin?: ValidatedProperty;
|
|
156
133
|
output: PlainObject;
|
|
157
|
-
prefix?: string;
|
|
158
134
|
reporting: ReportingInformation;
|
|
159
135
|
strict: boolean;
|
|
160
136
|
};
|
|
161
137
|
|
|
138
|
+
export type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
|
|
139
|
+
|
|
162
140
|
// #endregion
|