@oscarpalmer/jhunal 0.22.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 +304 -275
- package/dist/index.mjs +187 -154
- package/dist/models/validation.model.d.mts +18 -7
- package/dist/schematic.d.mts +25 -7
- package/dist/schematic.mjs +6 -4
- 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/{validation.mjs → validator/object.validator.mjs} +20 -98
- 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 +3 -3
- package/src/models/validation.model.ts +19 -6
- package/src/schematic.ts +43 -16
- 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/{validation.ts → validator/object.validator.ts} +23 -181
- package/src/validator/schematic.validator.ts +25 -0
- package/dist/helpers.d.mts +0 -28
- package/dist/helpers.mjs +0 -120
- package/dist/validation.d.mts +0 -7
- package/src/helpers.ts +0 -249
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/validator/base.validator.ts
|
|
2
|
+
function getBaseValidator(validators) {
|
|
3
|
+
const { length } = validators;
|
|
4
|
+
return (input, parameters, get) => {
|
|
5
|
+
const allInformation = [];
|
|
6
|
+
for (let index = 0; index < length; index += 1) {
|
|
7
|
+
const previousInformation = parameters.information;
|
|
8
|
+
parameters.information = [];
|
|
9
|
+
const result = validators[index](input, parameters, get);
|
|
10
|
+
parameters.information = previousInformation;
|
|
11
|
+
if (result === true) return true;
|
|
12
|
+
parameters.information?.push(...result);
|
|
13
|
+
allInformation.push(...result);
|
|
14
|
+
}
|
|
15
|
+
return allInformation;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { getBaseValidator };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { instanceOf } from "../helpers/misc.helper.mjs";
|
|
2
|
+
import { isConstructor } from "@oscarpalmer/atoms/is";
|
|
3
|
+
//#region src/validator/function.validator.ts
|
|
4
|
+
function getFunctionValidator(fn) {
|
|
5
|
+
const validator = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
6
|
+
return (input) => validator(input) ? true : [];
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { getFunctionValidator };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
|
|
2
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
|
+
//#region src/validator/named.handler.ts
|
|
4
|
+
function getNamedHandlers(original, prefix) {
|
|
5
|
+
const handlers = {};
|
|
6
|
+
if (original == null) return handlers;
|
|
7
|
+
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
8
|
+
const keys = Object.keys(original);
|
|
9
|
+
const { length } = keys;
|
|
10
|
+
for (let index = 0; index < length; index += 1) {
|
|
11
|
+
const key = keys[index];
|
|
12
|
+
if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
13
|
+
const value = original[key];
|
|
14
|
+
handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
15
|
+
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
|
|
16
|
+
return item;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return handlers;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { getNamedHandlers };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NamedValidatorHandlers, ValidationInformationKey, Validator } from "../models/validation.model.mjs";
|
|
2
|
+
import { ValueName } from "../models/misc.model.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/validator/named.validator.d.ts
|
|
5
|
+
declare function getNamedValidator(key: ValidationInformationKey, name: ValueName, handlers: NamedValidatorHandlers): Validator;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getNamedValidator };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "../constants.mjs";
|
|
2
|
+
import { getInvalidValidatorMessage } from "../helpers/message.helper.mjs";
|
|
3
|
+
//#region src/validator/named.validator.ts
|
|
4
|
+
function getNamedValidator(key, name, handlers) {
|
|
5
|
+
const validator = namedValidators[name];
|
|
6
|
+
const named = handlers[name] ?? [];
|
|
7
|
+
const { length } = named;
|
|
8
|
+
return (input, parameters) => {
|
|
9
|
+
if (!validator(input)) return [];
|
|
10
|
+
for (let index = 0; index < length; index += 1) {
|
|
11
|
+
const handler = named[index];
|
|
12
|
+
if (handler(input) === true) continue;
|
|
13
|
+
const information = {
|
|
14
|
+
key,
|
|
15
|
+
validator,
|
|
16
|
+
message: getInvalidValidatorMessage(key.full, name, index, length),
|
|
17
|
+
value: input
|
|
18
|
+
};
|
|
19
|
+
parameters.information?.push(information);
|
|
20
|
+
return parameters.reporting.none ? [] : [information];
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const namedValidators = {
|
|
26
|
+
array: Array.isArray,
|
|
27
|
+
bigint: (value) => typeof value === "bigint",
|
|
28
|
+
boolean: (value) => typeof value === "boolean",
|
|
29
|
+
date: (value) => value instanceof Date,
|
|
30
|
+
function: (value) => typeof value === "function",
|
|
31
|
+
null: (value) => value === null,
|
|
32
|
+
number: (value) => typeof value === "number",
|
|
33
|
+
object: (value) => typeof value === "object" && value !== null,
|
|
34
|
+
string: (value) => typeof value === "string",
|
|
35
|
+
symbol: (value) => typeof value === "symbol",
|
|
36
|
+
undefined: (value) => value === void 0
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { getNamedValidator };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationInformationKey, Validator } from "../models/validation.model.mjs";
|
|
2
|
+
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
3
|
+
|
|
4
|
+
//#region src/validator/object.validator.d.ts
|
|
5
|
+
declare function getObjectValidator(original: PlainObject, origin?: ValidationInformationKey, fromType?: boolean): Validator;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getObjectValidator };
|
|
@@ -1,58 +1,21 @@
|
|
|
1
|
-
import { PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, 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,
|
|
2
|
-
import {
|
|
3
|
-
import { SchematicError, ValidationError } from "
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, 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, TYPE_ALL } from "../constants.mjs";
|
|
2
|
+
import { isSchematic } from "../helpers/misc.helper.mjs";
|
|
3
|
+
import { SchematicError, ValidationError } from "../models/validation.model.mjs";
|
|
4
|
+
import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getUnknownKeysMessage } from "../helpers/message.helper.mjs";
|
|
5
|
+
import { getBaseValidator } from "./base.validator.mjs";
|
|
6
|
+
import { getFunctionValidator } from "./function.validator.mjs";
|
|
7
|
+
import { getNamedHandlers } from "./named.handler.mjs";
|
|
8
|
+
import { getNamedValidator } from "./named.validator.mjs";
|
|
9
|
+
import { getSchematicValidator } from "./schematic.validator.mjs";
|
|
10
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
11
|
+
import { join } from "@oscarpalmer/atoms/string";
|
|
7
12
|
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
8
|
-
//#region src/
|
|
13
|
+
//#region src/validator/object.validator.ts
|
|
9
14
|
function getDisallowedProperty(obj) {
|
|
10
15
|
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
11
16
|
if ("$type" in obj) return PROPERTY_TYPE;
|
|
12
17
|
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
13
18
|
}
|
|
14
|
-
function getFunctionValidator(fn) {
|
|
15
|
-
const validator = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
16
|
-
return (input) => validator(input) === true;
|
|
17
|
-
}
|
|
18
|
-
function getNamedValidator(key, name, handlers) {
|
|
19
|
-
const validator = namedValidators[name];
|
|
20
|
-
const named = handlers[name] ?? [];
|
|
21
|
-
const { length } = named;
|
|
22
|
-
return (input, parameters) => {
|
|
23
|
-
if (!validator(input)) return false;
|
|
24
|
-
for (let index = 0; index < length; index += 1) {
|
|
25
|
-
const handler = named[index];
|
|
26
|
-
if (handler(input) === true) continue;
|
|
27
|
-
const information = {
|
|
28
|
-
key,
|
|
29
|
-
validator,
|
|
30
|
-
message: getInvalidValidatorMessage(key.full, name, index, length),
|
|
31
|
-
value: input
|
|
32
|
-
};
|
|
33
|
-
parameters.information?.push(information);
|
|
34
|
-
return parameters.reporting.none ? false : [information];
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function getNamedHandlers(original, prefix) {
|
|
40
|
-
const handlers = {};
|
|
41
|
-
if (original == null) return handlers;
|
|
42
|
-
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
43
|
-
const keys = Object.keys(original);
|
|
44
|
-
const { length } = keys;
|
|
45
|
-
for (let index = 0; index < length; index += 1) {
|
|
46
|
-
const key = keys[index];
|
|
47
|
-
if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
48
|
-
const value = original[key];
|
|
49
|
-
handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
50
|
-
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
|
|
51
|
-
return item;
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return handlers;
|
|
55
|
-
}
|
|
56
19
|
function getObjectValidator(original, origin, fromType) {
|
|
57
20
|
const keys = Object.keys(original);
|
|
58
21
|
const keysLength = keys.length;
|
|
@@ -111,13 +74,13 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
111
74
|
types,
|
|
112
75
|
key: fullKey,
|
|
113
76
|
required: required && !types.includes("undefined"),
|
|
114
|
-
validator:
|
|
77
|
+
validator: getBaseValidator(validators)
|
|
115
78
|
});
|
|
116
79
|
}
|
|
117
80
|
const validatorsLength = items.length;
|
|
118
81
|
return (input, parameters, get) => {
|
|
119
82
|
if (!isPlainObject(input)) {
|
|
120
|
-
if (origin != null) return
|
|
83
|
+
if (origin != null) return [];
|
|
121
84
|
const information = {
|
|
122
85
|
key: {
|
|
123
86
|
full: "",
|
|
@@ -128,7 +91,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
128
91
|
};
|
|
129
92
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
130
93
|
parameters.information?.push(information);
|
|
131
|
-
return
|
|
94
|
+
return [information];
|
|
132
95
|
}
|
|
133
96
|
if (parameters.strict) {
|
|
134
97
|
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
@@ -143,7 +106,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
143
106
|
};
|
|
144
107
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
145
108
|
parameters.information?.push(information);
|
|
146
|
-
return
|
|
109
|
+
return [information];
|
|
147
110
|
}
|
|
148
111
|
}
|
|
149
112
|
const allInformation = [];
|
|
@@ -153,7 +116,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
153
116
|
const value = input[key.short];
|
|
154
117
|
if (value === void 0) {
|
|
155
118
|
if (required) {
|
|
156
|
-
if (parameters.reporting.none) return
|
|
119
|
+
if (parameters.reporting.none) return [];
|
|
157
120
|
const information = {
|
|
158
121
|
key,
|
|
159
122
|
value,
|
|
@@ -173,12 +136,11 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
173
136
|
parameters.output = output;
|
|
174
137
|
const result = validator(value, parameters, get);
|
|
175
138
|
parameters.output = previousOutput;
|
|
176
|
-
if (result === false) continue;
|
|
177
139
|
if (result === true) {
|
|
178
|
-
if (get) output[key.short] = clone(value);
|
|
140
|
+
if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
|
|
179
141
|
continue;
|
|
180
142
|
}
|
|
181
|
-
if (parameters.reporting.none) return
|
|
143
|
+
if (parameters.reporting.none) return [];
|
|
182
144
|
const information = typeof result !== "boolean" && result.length > 0 ? result : [{
|
|
183
145
|
key,
|
|
184
146
|
value,
|
|
@@ -193,7 +155,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
193
155
|
}
|
|
194
156
|
if (get) if (origin == null) parameters.output = output;
|
|
195
157
|
else parameters.output[origin.short] = output;
|
|
196
|
-
return
|
|
158
|
+
return allInformation.length === 0 ? true : allInformation;
|
|
197
159
|
};
|
|
198
160
|
}
|
|
199
161
|
function getRequired(key, obj) {
|
|
@@ -201,45 +163,5 @@ function getRequired(key, obj) {
|
|
|
201
163
|
if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
202
164
|
return obj[PROPERTY_REQUIRED];
|
|
203
165
|
}
|
|
204
|
-
function getSchematicValidator(schematic) {
|
|
205
|
-
const validator = schematicValidator.get(schematic);
|
|
206
|
-
return (input, parameters, get) => {
|
|
207
|
-
let result = false;
|
|
208
|
-
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
209
|
-
if (typeof result === "boolean") return result;
|
|
210
|
-
parameters.information?.push(...result);
|
|
211
|
-
return result.length === 0 ? true : result;
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
function getValidator(validators) {
|
|
215
|
-
const { length } = validators;
|
|
216
|
-
return (input, parameters, get) => {
|
|
217
|
-
const allInformation = [];
|
|
218
|
-
for (let index = 0; index < length; index += 1) {
|
|
219
|
-
const previousInformation = parameters.information;
|
|
220
|
-
parameters.information = [];
|
|
221
|
-
const result = validators[index](input, parameters, get);
|
|
222
|
-
parameters.information = previousInformation;
|
|
223
|
-
if (result === false) continue;
|
|
224
|
-
if (result === true) return true;
|
|
225
|
-
parameters.information?.push(...result);
|
|
226
|
-
allInformation.push(...result);
|
|
227
|
-
}
|
|
228
|
-
return allInformation;
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
const namedValidators = {
|
|
232
|
-
array: Array.isArray,
|
|
233
|
-
bigint: (value) => typeof value === "bigint",
|
|
234
|
-
boolean: (value) => typeof value === "boolean",
|
|
235
|
-
date: (value) => value instanceof Date,
|
|
236
|
-
function: (value) => typeof value === "function",
|
|
237
|
-
null: (value) => value === null,
|
|
238
|
-
number: (value) => typeof value === "number",
|
|
239
|
-
object: (value) => typeof value === "object" && value !== null,
|
|
240
|
-
string: (value) => typeof value === "string",
|
|
241
|
-
symbol: (value) => typeof value === "symbol",
|
|
242
|
-
undefined: (value) => value === void 0
|
|
243
|
-
};
|
|
244
166
|
//#endregion
|
|
245
167
|
export { getObjectValidator };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Validator } from "../models/validation.model.mjs";
|
|
2
|
+
import { Schematic } from "../schematic.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/validator/schematic.validator.d.ts
|
|
5
|
+
declare function getSchematicValidator(schematic: Schematic<unknown>): Validator;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getSchematicValidator };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { schematicValidator } from "../schematic.mjs";
|
|
2
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
|
+
//#region src/validator/schematic.validator.ts
|
|
4
|
+
function getSchematicValidator(schematic) {
|
|
5
|
+
const validator = schematicValidator.get(schematic);
|
|
6
|
+
return (input, parameters, get) => {
|
|
7
|
+
let result;
|
|
8
|
+
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
9
|
+
else result = [];
|
|
10
|
+
if (result === true) return result;
|
|
11
|
+
parameters.information?.push(...result);
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { getSchematicValidator };
|
package/package.json
CHANGED
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
|
+
}
|