@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
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
2
2
|
import { join } from "@oscarpalmer/atoms/string";
|
|
3
3
|
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
4
|
-
import { join as join$1 } from "@oscarpalmer/atoms";
|
|
5
4
|
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
6
5
|
//#region src/constants.ts
|
|
7
6
|
const CONJUNCTION_OR = " or ";
|
|
@@ -9,14 +8,13 @@ const CONJUNCTION_OR_COMMA = ", or ";
|
|
|
9
8
|
const CONJUNCTION_AND = " and ";
|
|
10
9
|
const CONJUNCTION_AND_COMMA = ", and ";
|
|
11
10
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
12
|
-
const NAME_SCHEMATIC = "Schematic";
|
|
13
11
|
const NAME_ERROR_SCHEMATIC = "SchematicError";
|
|
14
12
|
const NAME_ERROR_VALIDATION = "ValidationError";
|
|
15
13
|
const PROPERTY_REQUIRED = "$required";
|
|
16
14
|
const PROPERTY_SCHEMATIC = "$schematic";
|
|
17
15
|
const PROPERTY_TYPE = "$type";
|
|
18
16
|
const PROPERTY_VALIDATORS = "$validators";
|
|
19
|
-
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected
|
|
17
|
+
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
|
|
20
18
|
const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
|
|
21
19
|
const VALIDATION_MESSAGE_INVALID_TYPE = "Expected <> for '<>' but received <>";
|
|
22
20
|
const VALIDATION_MESSAGE_INVALID_VALUE = "Value does not satisfy validator for '<>' and type '<>'";
|
|
@@ -41,71 +39,68 @@ const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
|
41
39
|
const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE = "Validators must be an object";
|
|
42
40
|
const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE = "Validator '<>' must be a function or an array of functions";
|
|
43
41
|
const TYPE_ARRAY = "array";
|
|
42
|
+
const TYPE_BIGINT = "bigint";
|
|
43
|
+
const TYPE_BOOLEAN = "boolean";
|
|
44
|
+
const TYPE_DATE = "date";
|
|
45
|
+
const TYPE_FUNCTION = "function";
|
|
46
|
+
const TYPE_FUNCTION_RESULT = "a validated value";
|
|
44
47
|
const TYPE_NULL = "null";
|
|
48
|
+
const TYPE_NUMBER = "number";
|
|
45
49
|
const TYPE_OBJECT = "object";
|
|
50
|
+
const TYPE_STRING = "string";
|
|
51
|
+
const TYPE_SYMBOL = "symbol";
|
|
46
52
|
const TYPE_UNDEFINED = "undefined";
|
|
47
53
|
const TYPE_ALL = new Set([
|
|
48
54
|
...new Set([
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
TYPE_ARRAY,
|
|
56
|
+
TYPE_BIGINT,
|
|
57
|
+
TYPE_BOOLEAN,
|
|
58
|
+
TYPE_DATE,
|
|
59
|
+
TYPE_FUNCTION,
|
|
60
|
+
TYPE_NUMBER,
|
|
61
|
+
TYPE_OBJECT,
|
|
62
|
+
TYPE_STRING,
|
|
63
|
+
TYPE_SYMBOL
|
|
58
64
|
]),
|
|
59
|
-
|
|
65
|
+
TYPE_NULL,
|
|
60
66
|
TYPE_UNDEFINED
|
|
61
67
|
]);
|
|
68
|
+
const PREFIXED_TYPES = {
|
|
69
|
+
[TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
|
|
70
|
+
[TYPE_BIGINT]: `a ${TYPE_BIGINT}`,
|
|
71
|
+
[TYPE_BOOLEAN]: `a ${TYPE_BOOLEAN}`,
|
|
72
|
+
[TYPE_DATE]: `a ${TYPE_DATE}`,
|
|
73
|
+
[TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
|
|
74
|
+
[TYPE_NULL]: TYPE_NULL,
|
|
75
|
+
[TYPE_NUMBER]: `a ${TYPE_NUMBER}`,
|
|
76
|
+
[TYPE_STRING]: `a ${TYPE_STRING}`,
|
|
77
|
+
[TYPE_SYMBOL]: `a ${TYPE_SYMBOL}`,
|
|
78
|
+
[TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
|
|
79
|
+
[TYPE_UNDEFINED]: TYPE_UNDEFINED
|
|
80
|
+
};
|
|
62
81
|
//#endregion
|
|
63
|
-
//#region src/helpers.ts
|
|
64
|
-
function getInvalidInputMessage(actual) {
|
|
65
|
-
return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
|
|
66
|
-
}
|
|
67
|
-
function getInvalidMissingMessage(key, types) {
|
|
68
|
-
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
|
|
69
|
-
message = message.replace("<>", key);
|
|
70
|
-
return message;
|
|
71
|
-
}
|
|
72
|
-
function getInvalidTypeMessage(key, types, actual) {
|
|
73
|
-
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
|
|
74
|
-
message = message.replace("<>", key);
|
|
75
|
-
message = message.replace("<>", getValueType(actual));
|
|
76
|
-
return message;
|
|
77
|
-
}
|
|
78
|
-
function getInvalidValidatorMessage(key, type, index, length) {
|
|
79
|
-
let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
|
|
80
|
-
message = message.replace("<>", type);
|
|
81
|
-
if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
|
|
82
|
-
return message;
|
|
83
|
-
}
|
|
82
|
+
//#region src/helpers/misc.helper.ts
|
|
84
83
|
function getParameters(input) {
|
|
85
84
|
if (typeof input === "boolean") return {
|
|
85
|
+
clone: true,
|
|
86
86
|
output: {},
|
|
87
87
|
reporting: getReporting(REPORTING_NONE),
|
|
88
88
|
strict: input
|
|
89
89
|
};
|
|
90
90
|
if (REPORTING_TYPES.has(input)) return {
|
|
91
|
+
clone: true,
|
|
91
92
|
output: {},
|
|
92
93
|
reporting: getReporting(input),
|
|
93
94
|
strict: false
|
|
94
95
|
};
|
|
95
96
|
const options = isPlainObject(input) ? input : {};
|
|
96
97
|
return {
|
|
98
|
+
clone: typeof options.clone === "boolean" ? options.clone : true,
|
|
97
99
|
output: {},
|
|
98
100
|
reporting: getReporting(options.errors),
|
|
99
101
|
strict: typeof options.strict === "boolean" ? options.strict : false
|
|
100
102
|
};
|
|
101
103
|
}
|
|
102
|
-
function getPropertyType(original) {
|
|
103
|
-
if (typeof original === "function") return "a validated value";
|
|
104
|
-
if (Array.isArray(original)) return `'array'`;
|
|
105
|
-
if (isPlainObject(original)) return `'${TYPE_OBJECT}'`;
|
|
106
|
-
if (isSchematic(original)) return `a ${NAME_SCHEMATIC}`;
|
|
107
|
-
return `'${String(original)}'`;
|
|
108
|
-
}
|
|
109
104
|
function getReporting(value) {
|
|
110
105
|
const type = REPORTING_TYPES.has(value) ? value : REPORTING_NONE;
|
|
111
106
|
return {
|
|
@@ -116,21 +111,6 @@ function getReporting(value) {
|
|
|
116
111
|
[REPORTING_THROW]: type === REPORTING_THROW
|
|
117
112
|
};
|
|
118
113
|
}
|
|
119
|
-
function getUnknownKeysMessage(keys) {
|
|
120
|
-
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
|
|
121
|
-
}
|
|
122
|
-
function getValueType(value) {
|
|
123
|
-
const valueType = typeof value;
|
|
124
|
-
switch (true) {
|
|
125
|
-
case value === null: return `'${TYPE_NULL}'`;
|
|
126
|
-
case value === void 0: return `'${TYPE_UNDEFINED}'`;
|
|
127
|
-
case valueType !== TYPE_OBJECT: return `'${valueType}'`;
|
|
128
|
-
case Array.isArray(value): return `'${TYPE_ARRAY}'`;
|
|
129
|
-
case isPlainObject(value): return `'${TYPE_OBJECT}'`;
|
|
130
|
-
case isSchematic(value): return `a ${NAME_SCHEMATIC}`;
|
|
131
|
-
default: return value.constructor.name;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
114
|
/**
|
|
135
115
|
* Creates a validator function for a given constructor
|
|
136
116
|
* @param constructor - Constructor to check against
|
|
@@ -151,6 +131,69 @@ function instanceOf(constructor) {
|
|
|
151
131
|
function isSchematic(value) {
|
|
152
132
|
return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
|
|
153
133
|
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/models/validation.model.ts
|
|
136
|
+
/**
|
|
137
|
+
* Thrown when a schema definition is invalid
|
|
138
|
+
*/
|
|
139
|
+
var SchematicError = class extends Error {
|
|
140
|
+
constructor(message) {
|
|
141
|
+
super(message);
|
|
142
|
+
this.name = NAME_ERROR_SCHEMATIC;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Thrown in `'throw'` mode when one or more properties fail validation; `information` holds all failures
|
|
147
|
+
*/
|
|
148
|
+
var ValidationError = class extends Error {
|
|
149
|
+
constructor(information) {
|
|
150
|
+
super(join(information.map((item) => item.message), "; "));
|
|
151
|
+
this.information = information;
|
|
152
|
+
this.name = NAME_ERROR_VALIDATION;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/helpers/message.helper.ts
|
|
157
|
+
function getInvalidInputMessage(actual) {
|
|
158
|
+
return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
|
|
159
|
+
}
|
|
160
|
+
function getInvalidMissingMessage(key, types) {
|
|
161
|
+
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
|
|
162
|
+
message = message.replace("<>", key);
|
|
163
|
+
return message;
|
|
164
|
+
}
|
|
165
|
+
function getInvalidTypeMessage(key, types, actual) {
|
|
166
|
+
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
|
|
167
|
+
message = message.replace("<>", key);
|
|
168
|
+
message = message.replace("<>", getValueType(actual));
|
|
169
|
+
return message;
|
|
170
|
+
}
|
|
171
|
+
function getInvalidValidatorMessage(key, type, index, length) {
|
|
172
|
+
let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
|
|
173
|
+
message = message.replace("<>", type);
|
|
174
|
+
if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
|
|
175
|
+
return message;
|
|
176
|
+
}
|
|
177
|
+
function getPropertyType(type) {
|
|
178
|
+
switch (true) {
|
|
179
|
+
case typeof type === "function": return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
|
|
180
|
+
case TYPE_ALL.has(type): return PREFIXED_TYPES[type];
|
|
181
|
+
default: return PREFIXED_TYPES[TYPE_OBJECT];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function getUnknownKeysMessage(keys) {
|
|
185
|
+
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
|
|
186
|
+
}
|
|
187
|
+
function getValueType(value) {
|
|
188
|
+
const valueType = typeof value;
|
|
189
|
+
switch (true) {
|
|
190
|
+
case value === null: return TYPE_NULL;
|
|
191
|
+
case Array.isArray(value): return PREFIXED_TYPES[TYPE_ARRAY];
|
|
192
|
+
case isPlainObject(value): return PREFIXED_TYPES[TYPE_OBJECT];
|
|
193
|
+
case valueType !== TYPE_OBJECT: return PREFIXED_TYPES[valueType];
|
|
194
|
+
default: return value.constructor.name;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
154
197
|
function renderKeys(keys) {
|
|
155
198
|
return renderParts(keys.map((key) => `'${key}'`), CONJUNCTION_AND, CONJUNCTION_AND_COMMA);
|
|
156
199
|
}
|
|
@@ -177,43 +220,56 @@ function renderTypes(types) {
|
|
|
177
220
|
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
178
221
|
}
|
|
179
222
|
//#endregion
|
|
180
|
-
//#region src/
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.information = information;
|
|
197
|
-
this.name = NAME_ERROR_VALIDATION;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region src/validation.ts
|
|
202
|
-
function getDisallowedProperty(obj) {
|
|
203
|
-
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
204
|
-
if ("$type" in obj) return PROPERTY_TYPE;
|
|
205
|
-
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
223
|
+
//#region src/validator/base.validator.ts
|
|
224
|
+
function getBaseValidator(validators) {
|
|
225
|
+
const { length } = validators;
|
|
226
|
+
return (input, parameters, get) => {
|
|
227
|
+
const allInformation = [];
|
|
228
|
+
for (let index = 0; index < length; index += 1) {
|
|
229
|
+
const previousInformation = parameters.information;
|
|
230
|
+
parameters.information = [];
|
|
231
|
+
const result = validators[index](input, parameters, get);
|
|
232
|
+
parameters.information = previousInformation;
|
|
233
|
+
if (result === true) return true;
|
|
234
|
+
parameters.information?.push(...result);
|
|
235
|
+
allInformation.push(...result);
|
|
236
|
+
}
|
|
237
|
+
return allInformation;
|
|
238
|
+
};
|
|
206
239
|
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/validator/function.validator.ts
|
|
207
242
|
function getFunctionValidator(fn) {
|
|
208
243
|
const validator = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
209
|
-
return (input) => validator(input)
|
|
244
|
+
return (input) => validator(input) ? true : [];
|
|
210
245
|
}
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/validator/named.handler.ts
|
|
248
|
+
function getNamedHandlers(original, prefix) {
|
|
249
|
+
const handlers = {};
|
|
250
|
+
if (original == null) return handlers;
|
|
251
|
+
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
252
|
+
const keys = Object.keys(original);
|
|
253
|
+
const { length } = keys;
|
|
254
|
+
for (let index = 0; index < length; index += 1) {
|
|
255
|
+
const key = keys[index];
|
|
256
|
+
if (!TYPE_ALL.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
257
|
+
const value = original[key];
|
|
258
|
+
handlers[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
259
|
+
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key).replace("<>", prefix));
|
|
260
|
+
return item;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return handlers;
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/validator/named.validator.ts
|
|
211
267
|
function getNamedValidator(key, name, handlers) {
|
|
212
268
|
const validator = namedValidators[name];
|
|
213
269
|
const named = handlers[name] ?? [];
|
|
214
270
|
const { length } = named;
|
|
215
271
|
return (input, parameters) => {
|
|
216
|
-
if (!validator(input)) return
|
|
272
|
+
if (!validator(input)) return [];
|
|
217
273
|
for (let index = 0; index < length; index += 1) {
|
|
218
274
|
const handler = named[index];
|
|
219
275
|
if (handler(input) === true) continue;
|
|
@@ -224,27 +280,43 @@ function getNamedValidator(key, name, handlers) {
|
|
|
224
280
|
value: input
|
|
225
281
|
};
|
|
226
282
|
parameters.information?.push(information);
|
|
227
|
-
return parameters.reporting.none ?
|
|
283
|
+
return parameters.reporting.none ? [] : [information];
|
|
228
284
|
}
|
|
229
285
|
return true;
|
|
230
286
|
};
|
|
231
287
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
288
|
+
const namedValidators = {
|
|
289
|
+
array: Array.isArray,
|
|
290
|
+
bigint: (value) => typeof value === "bigint",
|
|
291
|
+
boolean: (value) => typeof value === "boolean",
|
|
292
|
+
date: (value) => value instanceof Date,
|
|
293
|
+
function: (value) => typeof value === "function",
|
|
294
|
+
null: (value) => value === null,
|
|
295
|
+
number: (value) => typeof value === "number",
|
|
296
|
+
object: (value) => typeof value === "object" && value !== null,
|
|
297
|
+
string: (value) => typeof value === "string",
|
|
298
|
+
symbol: (value) => typeof value === "symbol",
|
|
299
|
+
undefined: (value) => value === void 0
|
|
300
|
+
};
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region src/validator/schematic.validator.ts
|
|
303
|
+
function getSchematicValidator(schematic) {
|
|
304
|
+
const validator = schematicValidator.get(schematic);
|
|
305
|
+
return (input, parameters, get) => {
|
|
306
|
+
let result;
|
|
307
|
+
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
308
|
+
else result = [];
|
|
309
|
+
if (result === true) return result;
|
|
310
|
+
parameters.information?.push(...result);
|
|
311
|
+
return result;
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/validator/object.validator.ts
|
|
316
|
+
function getDisallowedProperty(obj) {
|
|
317
|
+
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
318
|
+
if ("$type" in obj) return PROPERTY_TYPE;
|
|
319
|
+
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
248
320
|
}
|
|
249
321
|
function getObjectValidator(original, origin, fromType) {
|
|
250
322
|
const keys = Object.keys(original);
|
|
@@ -259,8 +331,8 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
259
331
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
260
332
|
const key = keys[keyIndex];
|
|
261
333
|
const value = original[key];
|
|
262
|
-
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join
|
|
263
|
-
const prefixedKey = origin == null ? key : join
|
|
334
|
+
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
|
|
335
|
+
const prefixedKey = origin == null ? key : join([origin.full, key], ".");
|
|
264
336
|
const fullKey = {
|
|
265
337
|
full: prefixedKey,
|
|
266
338
|
short: key
|
|
@@ -304,13 +376,13 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
304
376
|
types,
|
|
305
377
|
key: fullKey,
|
|
306
378
|
required: required && !types.includes("undefined"),
|
|
307
|
-
validator:
|
|
379
|
+
validator: getBaseValidator(validators)
|
|
308
380
|
});
|
|
309
381
|
}
|
|
310
382
|
const validatorsLength = items.length;
|
|
311
383
|
return (input, parameters, get) => {
|
|
312
384
|
if (!isPlainObject(input)) {
|
|
313
|
-
if (origin != null) return
|
|
385
|
+
if (origin != null) return [];
|
|
314
386
|
const information = {
|
|
315
387
|
key: {
|
|
316
388
|
full: "",
|
|
@@ -321,7 +393,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
321
393
|
};
|
|
322
394
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
323
395
|
parameters.information?.push(information);
|
|
324
|
-
return
|
|
396
|
+
return [information];
|
|
325
397
|
}
|
|
326
398
|
if (parameters.strict) {
|
|
327
399
|
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
@@ -336,7 +408,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
336
408
|
};
|
|
337
409
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
338
410
|
parameters.information?.push(information);
|
|
339
|
-
return
|
|
411
|
+
return [information];
|
|
340
412
|
}
|
|
341
413
|
}
|
|
342
414
|
const allInformation = [];
|
|
@@ -346,7 +418,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
346
418
|
const value = input[key.short];
|
|
347
419
|
if (value === void 0) {
|
|
348
420
|
if (required) {
|
|
349
|
-
if (parameters.reporting.none) return
|
|
421
|
+
if (parameters.reporting.none) return [];
|
|
350
422
|
const information = {
|
|
351
423
|
key,
|
|
352
424
|
value,
|
|
@@ -366,12 +438,11 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
366
438
|
parameters.output = output;
|
|
367
439
|
const result = validator(value, parameters, get);
|
|
368
440
|
parameters.output = previousOutput;
|
|
369
|
-
if (result === false) continue;
|
|
370
441
|
if (result === true) {
|
|
371
|
-
if (get) output[key.short] = clone(value);
|
|
442
|
+
if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
|
|
372
443
|
continue;
|
|
373
444
|
}
|
|
374
|
-
if (parameters.reporting.none) return
|
|
445
|
+
if (parameters.reporting.none) return [];
|
|
375
446
|
const information = typeof result !== "boolean" && result.length > 0 ? result : [{
|
|
376
447
|
key,
|
|
377
448
|
value,
|
|
@@ -386,7 +457,7 @@ function getObjectValidator(original, origin, fromType) {
|
|
|
386
457
|
}
|
|
387
458
|
if (get) if (origin == null) parameters.output = output;
|
|
388
459
|
else parameters.output[origin.short] = output;
|
|
389
|
-
return
|
|
460
|
+
return allInformation.length === 0 ? true : allInformation;
|
|
390
461
|
};
|
|
391
462
|
}
|
|
392
463
|
function getRequired(key, obj) {
|
|
@@ -394,46 +465,6 @@ function getRequired(key, obj) {
|
|
|
394
465
|
if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
395
466
|
return obj[PROPERTY_REQUIRED];
|
|
396
467
|
}
|
|
397
|
-
function getSchematicValidator(schematic) {
|
|
398
|
-
const validator = schematicValidator.get(schematic);
|
|
399
|
-
return (input, parameters, get) => {
|
|
400
|
-
let result = false;
|
|
401
|
-
if (isPlainObject(input)) result = validator(input, parameters, get);
|
|
402
|
-
if (typeof result === "boolean") return result;
|
|
403
|
-
parameters.information?.push(...result);
|
|
404
|
-
return result.length === 0 ? true : result;
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
function getValidator(validators) {
|
|
408
|
-
const { length } = validators;
|
|
409
|
-
return (input, parameters, get) => {
|
|
410
|
-
const allInformation = [];
|
|
411
|
-
for (let index = 0; index < length; index += 1) {
|
|
412
|
-
const previousInformation = parameters.information;
|
|
413
|
-
parameters.information = [];
|
|
414
|
-
const result = validators[index](input, parameters, get);
|
|
415
|
-
parameters.information = previousInformation;
|
|
416
|
-
if (result === false) continue;
|
|
417
|
-
if (result === true) return true;
|
|
418
|
-
parameters.information?.push(...result);
|
|
419
|
-
allInformation.push(...result);
|
|
420
|
-
}
|
|
421
|
-
return allInformation;
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
const namedValidators = {
|
|
425
|
-
array: Array.isArray,
|
|
426
|
-
bigint: (value) => typeof value === "bigint",
|
|
427
|
-
boolean: (value) => typeof value === "boolean",
|
|
428
|
-
date: (value) => value instanceof Date,
|
|
429
|
-
function: (value) => typeof value === "function",
|
|
430
|
-
null: (value) => value === null,
|
|
431
|
-
number: (value) => typeof value === "number",
|
|
432
|
-
object: (value) => typeof value === "object" && value !== null,
|
|
433
|
-
string: (value) => typeof value === "string",
|
|
434
|
-
symbol: (value) => typeof value === "symbol",
|
|
435
|
-
undefined: (value) => value === void 0
|
|
436
|
-
};
|
|
437
468
|
//#endregion
|
|
438
469
|
//#region src/schematic.ts
|
|
439
470
|
/**
|
|
@@ -449,13 +480,15 @@ var Schematic = class {
|
|
|
449
480
|
get(value, options) {
|
|
450
481
|
const parameters = getParameters(options);
|
|
451
482
|
const result = this.#validator(value, parameters, true);
|
|
452
|
-
if (
|
|
483
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
|
|
484
|
+
if (parameters.reporting.none) return;
|
|
453
485
|
return error(parameters.reporting.all ? result : result[0]);
|
|
454
486
|
}
|
|
455
487
|
is(value, options) {
|
|
456
488
|
const parameters = getParameters(options);
|
|
457
489
|
const result = this.#validator(value, parameters, false);
|
|
458
|
-
if (
|
|
490
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
|
|
491
|
+
if (parameters.reporting.none) return false;
|
|
459
492
|
return error(parameters.reporting.all ? result : result[0]);
|
|
460
493
|
}
|
|
461
494
|
};
|
|
@@ -46,21 +46,32 @@ type ValidationInformationKey = {
|
|
|
46
46
|
full: string;
|
|
47
47
|
short: string;
|
|
48
48
|
};
|
|
49
|
-
|
|
50
|
-
* Options for validation
|
|
51
|
-
*/
|
|
52
|
-
type ValidationOptions<Errors extends ReportingType> = {
|
|
49
|
+
type BaseOptions<Errors extends ReportingType> = {
|
|
53
50
|
/**
|
|
54
51
|
* How should validation failures be reported; see {@link ReportingType} _(defaults to `'none'`)_
|
|
55
52
|
*/
|
|
56
|
-
errors
|
|
53
|
+
errors: Errors;
|
|
57
54
|
/**
|
|
58
55
|
* Validate if unknown keys are present in the object? _(defaults to `false`)_
|
|
59
56
|
*/
|
|
60
57
|
strict?: boolean;
|
|
61
58
|
};
|
|
62
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Options for validating and getting a value from an input
|
|
61
|
+
*/
|
|
62
|
+
type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
|
|
63
|
+
/**
|
|
64
|
+
* Get a deeply cloned version of the input? _(defaults to `true`)_
|
|
65
|
+
*/
|
|
66
|
+
clone?: boolean;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Options for validation an input value
|
|
70
|
+
*/
|
|
71
|
+
type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
|
|
72
|
+
type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => true | ValidationInformation[];
|
|
63
73
|
type ValidatorParameters = {
|
|
74
|
+
clone: boolean;
|
|
64
75
|
information?: ValidationInformation[];
|
|
65
76
|
output: PlainObject;
|
|
66
77
|
reporting: ReportingInformation;
|
|
@@ -68,4 +79,4 @@ type ValidatorParameters = {
|
|
|
68
79
|
};
|
|
69
80
|
type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
|
|
70
81
|
//#endregion
|
|
71
|
-
export { NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey,
|
|
82
|
+
export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorParameters, ValidatorType };
|
package/dist/schematic.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Infer } from "./models/infer.model.mjs";
|
|
2
2
|
import { TypedSchema } from "./models/schema.typed.model.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { GetOptions, IsOptions, ValidationInformation, Validator } from "./models/validation.model.mjs";
|
|
4
4
|
import { Schema } from "./models/schema.plain.model.mjs";
|
|
5
5
|
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
6
6
|
import { Result } from "@oscarpalmer/atoms/result/models";
|
|
@@ -21,7 +21,7 @@ declare class Schematic<Model> {
|
|
|
21
21
|
* @param options Validation options
|
|
22
22
|
* @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
|
|
23
23
|
*/
|
|
24
|
-
get(value: unknown, options:
|
|
24
|
+
get(value: unknown, options: GetOptions<'throw'>): Model;
|
|
25
25
|
/**
|
|
26
26
|
* Parse a value according to the schema
|
|
27
27
|
*
|
|
@@ -39,7 +39,7 @@ declare class Schematic<Model> {
|
|
|
39
39
|
* @param options Validation options
|
|
40
40
|
* @returns Result holding deeply cloned value or all validation information
|
|
41
41
|
*/
|
|
42
|
-
get(value: unknown, options:
|
|
42
|
+
get(value: unknown, options: GetOptions<'all'>): Result<Model, ValidationInformation[]>;
|
|
43
43
|
/**
|
|
44
44
|
* Parse a value according to the schema
|
|
45
45
|
*
|
|
@@ -57,7 +57,7 @@ declare class Schematic<Model> {
|
|
|
57
57
|
* @param options Validation options
|
|
58
58
|
* @returns Result holding deeply cloned value or all validation information
|
|
59
59
|
*/
|
|
60
|
-
get(value: unknown, options:
|
|
60
|
+
get(value: unknown, options: GetOptions<'first'>): Result<Model, ValidationInformation>;
|
|
61
61
|
/**
|
|
62
62
|
* Parse a value according to the schema
|
|
63
63
|
*
|
|
@@ -67,6 +67,15 @@ declare class Schematic<Model> {
|
|
|
67
67
|
* @returns Result holding deeply cloned value or all validation information
|
|
68
68
|
*/
|
|
69
69
|
get(value: unknown, errors: 'first'): Result<Model, ValidationInformation>;
|
|
70
|
+
/**
|
|
71
|
+
* Parse a value according to the schema
|
|
72
|
+
*
|
|
73
|
+
* Returns a deeply cloned version of the value or `undefined` if the value does not match the schema
|
|
74
|
+
* @param value Value to parse
|
|
75
|
+
* @param options Validation options
|
|
76
|
+
* @returns Deeply cloned value, or `undefined` if it's invalid
|
|
77
|
+
*/
|
|
78
|
+
get(value: unknown, options: GetOptions<'none'>): Model | undefined;
|
|
70
79
|
/**
|
|
71
80
|
* Parse a value according to the schema
|
|
72
81
|
*
|
|
@@ -84,7 +93,7 @@ declare class Schematic<Model> {
|
|
|
84
93
|
* @param options Validation options
|
|
85
94
|
* @returns `true` if the value matches the schema, otherwise throws an error
|
|
86
95
|
*/
|
|
87
|
-
is(value: unknown, options:
|
|
96
|
+
is(value: unknown, options: IsOptions<'throw'>): asserts value is Model;
|
|
88
97
|
/**
|
|
89
98
|
* Does the value match the schema?
|
|
90
99
|
*
|
|
@@ -102,7 +111,7 @@ declare class Schematic<Model> {
|
|
|
102
111
|
* @param options Validation options
|
|
103
112
|
* @returns Result holding `true` or all validation information
|
|
104
113
|
*/
|
|
105
|
-
is(value: unknown, options:
|
|
114
|
+
is(value: unknown, options: IsOptions<'all'>): Result<true, ValidationInformation[]>;
|
|
106
115
|
/**
|
|
107
116
|
* Does the value match the schema?
|
|
108
117
|
*
|
|
@@ -120,7 +129,7 @@ declare class Schematic<Model> {
|
|
|
120
129
|
* @param options Validation options
|
|
121
130
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
122
131
|
*/
|
|
123
|
-
is(value: unknown, options:
|
|
132
|
+
is(value: unknown, options: IsOptions<'first'>): Result<true, ValidationInformation>;
|
|
124
133
|
/**
|
|
125
134
|
* Does the value match the schema?
|
|
126
135
|
*
|
|
@@ -130,6 +139,15 @@ declare class Schematic<Model> {
|
|
|
130
139
|
* @returns `true` if the value matches the schema, otherwise `false`
|
|
131
140
|
*/
|
|
132
141
|
is(value: unknown, errors: 'first'): Result<true, ValidationInformation>;
|
|
142
|
+
/**
|
|
143
|
+
* Does the value match the schema?
|
|
144
|
+
*
|
|
145
|
+
* Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
|
|
146
|
+
* @param value Value to validate
|
|
147
|
+
* @param options Validation options
|
|
148
|
+
* @returns `true` if the value matches the schema, otherwise `false`
|
|
149
|
+
*/
|
|
150
|
+
is(value: unknown, options: IsOptions<'none'>): value is Model;
|
|
133
151
|
/**
|
|
134
152
|
* Does the value match the schema?
|
|
135
153
|
*
|
package/dist/schematic.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
|
|
2
|
-
import { getParameters, isSchematic } from "./helpers.mjs";
|
|
2
|
+
import { getParameters, isSchematic } from "./helpers/misc.helper.mjs";
|
|
3
3
|
import { SchematicError } from "./models/validation.model.mjs";
|
|
4
|
-
import { getObjectValidator } from "./
|
|
4
|
+
import { getObjectValidator } from "./validator/object.validator.mjs";
|
|
5
5
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
6
|
import { error, ok } from "@oscarpalmer/atoms/result/misc";
|
|
7
7
|
//#region src/schematic.ts
|
|
@@ -18,13 +18,15 @@ var Schematic = class {
|
|
|
18
18
|
get(value, options) {
|
|
19
19
|
const parameters = getParameters(options);
|
|
20
20
|
const result = this.#validator(value, parameters, true);
|
|
21
|
-
if (
|
|
21
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
|
|
22
|
+
if (parameters.reporting.none) return;
|
|
22
23
|
return error(parameters.reporting.all ? result : result[0]);
|
|
23
24
|
}
|
|
24
25
|
is(value, options) {
|
|
25
26
|
const parameters = getParameters(options);
|
|
26
27
|
const result = this.#validator(value, parameters, false);
|
|
27
|
-
if (
|
|
28
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
|
|
29
|
+
if (parameters.reporting.none) return false;
|
|
28
30
|
return error(parameters.reporting.all ? result : result[0]);
|
|
29
31
|
}
|
|
30
32
|
};
|