@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/dist/index.mjs
CHANGED
|
@@ -8,14 +8,13 @@ const CONJUNCTION_OR_COMMA = ", or ";
|
|
|
8
8
|
const CONJUNCTION_AND = " and ";
|
|
9
9
|
const CONJUNCTION_AND_COMMA = ", and ";
|
|
10
10
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
11
|
-
const NAME_SCHEMATIC = "Schematic";
|
|
12
11
|
const NAME_ERROR_SCHEMATIC = "SchematicError";
|
|
13
12
|
const NAME_ERROR_VALIDATION = "ValidationError";
|
|
14
13
|
const PROPERTY_REQUIRED = "$required";
|
|
15
14
|
const PROPERTY_SCHEMATIC = "$schematic";
|
|
16
15
|
const PROPERTY_TYPE = "$type";
|
|
17
16
|
const PROPERTY_VALIDATORS = "$validators";
|
|
18
|
-
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected
|
|
17
|
+
const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
|
|
19
18
|
const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
|
|
20
19
|
const VALIDATION_MESSAGE_INVALID_TYPE = "Expected <> for '<>' but received <>";
|
|
21
20
|
const VALIDATION_MESSAGE_INVALID_VALUE = "Value does not satisfy validator for '<>' and type '<>'";
|
|
@@ -40,71 +39,68 @@ const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
|
40
39
|
const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE = "Validators must be an object";
|
|
41
40
|
const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE = "Validator '<>' must be a function or an array of functions";
|
|
42
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";
|
|
43
47
|
const TYPE_NULL = "null";
|
|
48
|
+
const TYPE_NUMBER = "number";
|
|
44
49
|
const TYPE_OBJECT = "object";
|
|
50
|
+
const TYPE_STRING = "string";
|
|
51
|
+
const TYPE_SYMBOL = "symbol";
|
|
45
52
|
const TYPE_UNDEFINED = "undefined";
|
|
46
|
-
const VALIDATABLE_TYPES = new Set([
|
|
47
|
-
"array",
|
|
48
|
-
"bigint",
|
|
49
|
-
"boolean",
|
|
50
|
-
"date",
|
|
51
|
-
"function",
|
|
52
|
-
"number",
|
|
53
|
-
"string",
|
|
54
|
-
"symbol",
|
|
55
|
-
TYPE_OBJECT
|
|
56
|
-
]);
|
|
57
53
|
const TYPE_ALL = new Set([
|
|
58
|
-
...
|
|
59
|
-
|
|
54
|
+
...new Set([
|
|
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
|
|
64
|
+
]),
|
|
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 `'${TYPE_OBJECT}'`;
|
|
105
|
-
if (isSchematic(original)) return `a ${NAME_SCHEMATIC}`;
|
|
106
|
-
return `'${String(original)}'`;
|
|
107
|
-
}
|
|
108
104
|
function getReporting(value) {
|
|
109
105
|
const type = REPORTING_TYPES.has(value) ? value : REPORTING_NONE;
|
|
110
106
|
return {
|
|
@@ -115,21 +111,6 @@ function getReporting(value) {
|
|
|
115
111
|
[REPORTING_THROW]: type === REPORTING_THROW
|
|
116
112
|
};
|
|
117
113
|
}
|
|
118
|
-
function getUnknownKeysMessage(keys) {
|
|
119
|
-
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
|
|
120
|
-
}
|
|
121
|
-
function getValueType(value) {
|
|
122
|
-
const valueType = typeof value;
|
|
123
|
-
switch (true) {
|
|
124
|
-
case value === null: return `'${TYPE_NULL}'`;
|
|
125
|
-
case value === void 0: return `'${TYPE_UNDEFINED}'`;
|
|
126
|
-
case valueType !== TYPE_OBJECT: return `'${valueType}'`;
|
|
127
|
-
case Array.isArray(value): return `'${TYPE_ARRAY}'`;
|
|
128
|
-
case isPlainObject(value): return `'${TYPE_OBJECT}'`;
|
|
129
|
-
case isSchematic(value): return `a ${NAME_SCHEMATIC}`;
|
|
130
|
-
default: return value.constructor.name;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
114
|
/**
|
|
134
115
|
* Creates a validator function for a given constructor
|
|
135
116
|
* @param constructor - Constructor to check against
|
|
@@ -150,6 +131,69 @@ function instanceOf(constructor) {
|
|
|
150
131
|
function isSchematic(value) {
|
|
151
132
|
return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
|
|
152
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
|
+
}
|
|
153
197
|
function renderKeys(keys) {
|
|
154
198
|
return renderParts(keys.map((key) => `'${key}'`), CONJUNCTION_AND, CONJUNCTION_AND_COMMA);
|
|
155
199
|
}
|
|
@@ -176,298 +220,283 @@ function renderTypes(types) {
|
|
|
176
220
|
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
177
221
|
}
|
|
178
222
|
//#endregion
|
|
179
|
-
//#region src/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/validator/function.validator.ts
|
|
242
|
+
function getFunctionValidator(fn) {
|
|
243
|
+
const validator = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
244
|
+
return (input) => validator(input) ? true : [];
|
|
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
|
+
});
|
|
197
262
|
}
|
|
263
|
+
return handlers;
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/validator/named.validator.ts
|
|
267
|
+
function getNamedValidator(key, name, handlers) {
|
|
268
|
+
const validator = namedValidators[name];
|
|
269
|
+
const named = handlers[name] ?? [];
|
|
270
|
+
const { length } = named;
|
|
271
|
+
return (input, parameters) => {
|
|
272
|
+
if (!validator(input)) return [];
|
|
273
|
+
for (let index = 0; index < length; index += 1) {
|
|
274
|
+
const handler = named[index];
|
|
275
|
+
if (handler(input) === true) continue;
|
|
276
|
+
const information = {
|
|
277
|
+
key,
|
|
278
|
+
validator,
|
|
279
|
+
message: getInvalidValidatorMessage(key.full, name, index, length),
|
|
280
|
+
value: input
|
|
281
|
+
};
|
|
282
|
+
parameters.information?.push(information);
|
|
283
|
+
return parameters.reporting.none ? [] : [information];
|
|
284
|
+
}
|
|
285
|
+
return true;
|
|
286
|
+
};
|
|
287
|
+
}
|
|
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
|
|
198
300
|
};
|
|
199
301
|
//#endregion
|
|
200
|
-
//#region src/
|
|
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
|
|
201
316
|
function getDisallowedProperty(obj) {
|
|
202
317
|
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
203
318
|
if ("$type" in obj) return PROPERTY_TYPE;
|
|
204
319
|
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
205
320
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
321
|
+
function getObjectValidator(original, origin, fromType) {
|
|
322
|
+
const keys = Object.keys(original);
|
|
323
|
+
const keysLength = keys.length;
|
|
324
|
+
if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
208
325
|
if (fromType ?? false) {
|
|
209
326
|
const property = getDisallowedProperty(original);
|
|
210
|
-
if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>",
|
|
327
|
+
if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
|
|
211
328
|
}
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const properties = [];
|
|
329
|
+
const set = /* @__PURE__ */ new Set();
|
|
330
|
+
const items = [];
|
|
215
331
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
216
332
|
const key = keys[keyIndex];
|
|
217
333
|
const value = original[key];
|
|
218
|
-
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([
|
|
219
|
-
const
|
|
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], ".");
|
|
336
|
+
const fullKey = {
|
|
337
|
+
full: prefixedKey,
|
|
338
|
+
short: key
|
|
339
|
+
};
|
|
340
|
+
let handlers = {};
|
|
220
341
|
let required = true;
|
|
221
|
-
let
|
|
342
|
+
let typed = false;
|
|
343
|
+
let types;
|
|
344
|
+
const validators = [];
|
|
222
345
|
if (isPlainObject(value)) {
|
|
346
|
+
typed = PROPERTY_TYPE in value;
|
|
347
|
+
const type = typed ? value[PROPERTY_TYPE] : value;
|
|
348
|
+
handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
|
|
223
349
|
required = getRequired(key, value) ?? required;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
for (let index = 0; index < length; index += 1) {
|
|
248
|
-
const value = array[index];
|
|
249
|
-
switch (true) {
|
|
250
|
-
case typeof value === "function":
|
|
251
|
-
types.push(isConstructor(value) ? instanceOf(value) : value);
|
|
252
|
-
break;
|
|
253
|
-
case isPlainObject(value):
|
|
254
|
-
types.push(getProperties(value, join([prefix, key], "."), fromType));
|
|
255
|
-
break;
|
|
256
|
-
case isSchematic(value):
|
|
257
|
-
types.push(value);
|
|
258
|
-
break;
|
|
259
|
-
case TYPE_ALL.has(value):
|
|
260
|
-
types.push(value);
|
|
261
|
-
break;
|
|
262
|
-
default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", join([prefix, key], ".")));
|
|
350
|
+
types = Array.isArray(type) ? type : [type];
|
|
351
|
+
} else types = Array.isArray(value) ? value : [value];
|
|
352
|
+
if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
|
|
353
|
+
const typesLength = types.length;
|
|
354
|
+
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
355
|
+
const type = types[typeIndex];
|
|
356
|
+
let validator;
|
|
357
|
+
switch (true) {
|
|
358
|
+
case typeof type === "function":
|
|
359
|
+
validator = getFunctionValidator(type);
|
|
360
|
+
break;
|
|
361
|
+
case isPlainObject(type):
|
|
362
|
+
validator = getObjectValidator(type, fullKey, typed);
|
|
363
|
+
break;
|
|
364
|
+
case isSchematic(type):
|
|
365
|
+
validator = getSchematicValidator(type);
|
|
366
|
+
break;
|
|
367
|
+
case TYPE_ALL.has(type):
|
|
368
|
+
validator = getNamedValidator(fullKey, type, handlers);
|
|
369
|
+
break;
|
|
370
|
+
default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
|
|
371
|
+
}
|
|
372
|
+
validators.push(validator);
|
|
263
373
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (original == null) return validators;
|
|
271
|
-
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
272
|
-
const keys = Object.keys(original);
|
|
273
|
-
const { length } = keys;
|
|
274
|
-
for (let index = 0; index < length; index += 1) {
|
|
275
|
-
const key = keys[index];
|
|
276
|
-
if (!VALIDATABLE_TYPES.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
277
|
-
const value = original[key];
|
|
278
|
-
validators[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
279
|
-
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key));
|
|
280
|
-
return item;
|
|
374
|
+
set.add(key);
|
|
375
|
+
items.push({
|
|
376
|
+
types,
|
|
377
|
+
key: fullKey,
|
|
378
|
+
required: required && !types.includes("undefined"),
|
|
379
|
+
validator: getBaseValidator(validators)
|
|
281
380
|
});
|
|
282
381
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
function validateNamed(name, value, parameters) {
|
|
288
|
-
if (!validators[name](value)) return false;
|
|
289
|
-
const propertyValidators = parameters.origin.validators[name];
|
|
290
|
-
if (propertyValidators == null || propertyValidators.length === 0) return true;
|
|
291
|
-
const { length } = propertyValidators;
|
|
292
|
-
for (let index = 0; index < length; index += 1) {
|
|
293
|
-
const validator = propertyValidators[index];
|
|
294
|
-
if (!validator(value)) {
|
|
295
|
-
parameters.information.push({
|
|
296
|
-
value,
|
|
297
|
-
key: {
|
|
298
|
-
full: parameters.prefix,
|
|
299
|
-
short: parameters.origin.key
|
|
300
|
-
},
|
|
301
|
-
message: getInvalidValidatorMessage(parameters.prefix, name, index, length),
|
|
302
|
-
validator
|
|
303
|
-
});
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
function validateObject(obj, properties, parameters, get) {
|
|
310
|
-
if (!isPlainObject(obj)) {
|
|
311
|
-
const key = parameters?.origin == null ? {
|
|
312
|
-
full: "",
|
|
313
|
-
short: ""
|
|
314
|
-
} : {
|
|
315
|
-
full: parameters.prefix,
|
|
316
|
-
short: parameters.origin.key
|
|
317
|
-
};
|
|
318
|
-
const information = {
|
|
319
|
-
key,
|
|
320
|
-
message: parameters?.origin == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(key.full, parameters.origin.types, obj),
|
|
321
|
-
value: obj
|
|
322
|
-
};
|
|
323
|
-
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
324
|
-
parameters?.information?.push(information);
|
|
325
|
-
return parameters.reporting.none ? void 0 : [information];
|
|
326
|
-
}
|
|
327
|
-
if (parameters.strict) {
|
|
328
|
-
const objKeys = Object.keys(obj);
|
|
329
|
-
const propertiesKeys = new Set(properties.map((property) => property.key));
|
|
330
|
-
const unknownKeys = objKeys.filter((key) => !propertiesKeys.has(key));
|
|
331
|
-
if (unknownKeys.length > 0) {
|
|
382
|
+
const validatorsLength = items.length;
|
|
383
|
+
return (input, parameters, get) => {
|
|
384
|
+
if (!isPlainObject(input)) {
|
|
385
|
+
if (origin != null) return [];
|
|
332
386
|
const information = {
|
|
333
|
-
key:
|
|
387
|
+
key: {
|
|
334
388
|
full: "",
|
|
335
389
|
short: ""
|
|
336
|
-
} : {
|
|
337
|
-
full: join([parameters.prefix, parameters.origin?.key], "."),
|
|
338
|
-
short: parameters.origin.key
|
|
339
390
|
},
|
|
340
|
-
|
|
341
|
-
|
|
391
|
+
value: input,
|
|
392
|
+
message: getInvalidInputMessage(input)
|
|
342
393
|
};
|
|
343
394
|
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
344
|
-
parameters
|
|
345
|
-
return
|
|
395
|
+
parameters.information?.push(information);
|
|
396
|
+
return [information];
|
|
346
397
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
398
|
+
if (parameters.strict) {
|
|
399
|
+
const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
|
|
400
|
+
if (unknownKeys.length > 0) {
|
|
401
|
+
const information = {
|
|
402
|
+
key: origin ?? {
|
|
403
|
+
full: "",
|
|
404
|
+
short: ""
|
|
405
|
+
},
|
|
406
|
+
message: getUnknownKeysMessage(unknownKeys),
|
|
407
|
+
value: input
|
|
408
|
+
};
|
|
409
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
410
|
+
parameters.information?.push(information);
|
|
411
|
+
return [information];
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const allInformation = [];
|
|
415
|
+
const output = {};
|
|
416
|
+
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
417
|
+
const { key, required, types, validator } = items[validatorIndex];
|
|
418
|
+
const value = input[key.short];
|
|
419
|
+
if (value === void 0) {
|
|
420
|
+
if (required) {
|
|
421
|
+
if (parameters.reporting.none) return [];
|
|
422
|
+
const information = {
|
|
423
|
+
key,
|
|
424
|
+
value,
|
|
425
|
+
message: getInvalidMissingMessage(key.full, types)
|
|
426
|
+
};
|
|
427
|
+
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
428
|
+
parameters.information?.push(information);
|
|
429
|
+
if (parameters.reporting.all) {
|
|
430
|
+
allInformation.push(information);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
return [information];
|
|
434
|
+
}
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const previousOutput = parameters.output;
|
|
438
|
+
parameters.output = output;
|
|
439
|
+
const result = validator(value, parameters, get);
|
|
440
|
+
parameters.output = previousOutput;
|
|
441
|
+
if (result === true) {
|
|
442
|
+
if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (parameters.reporting.none) return [];
|
|
446
|
+
const information = typeof result !== "boolean" && result.length > 0 ? result : [{
|
|
447
|
+
key,
|
|
359
448
|
value,
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
},
|
|
364
|
-
message: getInvalidMissingMessage(prefixedKey, property.types)
|
|
365
|
-
};
|
|
366
|
-
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
367
|
-
parameters?.information?.push(information);
|
|
449
|
+
message: getInvalidTypeMessage(key.full, types, value)
|
|
450
|
+
}];
|
|
451
|
+
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
368
452
|
if (parameters.reporting.all) {
|
|
369
|
-
allInformation.push(information);
|
|
453
|
+
allInformation.push(...information);
|
|
370
454
|
continue;
|
|
371
455
|
}
|
|
372
|
-
return
|
|
456
|
+
return information;
|
|
373
457
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const type = types[typeIndex];
|
|
379
|
-
if (validateValue(type, value, {
|
|
380
|
-
information,
|
|
381
|
-
output,
|
|
382
|
-
origin: property,
|
|
383
|
-
prefix: prefixedKey,
|
|
384
|
-
reporting: parameters.reporting,
|
|
385
|
-
strict: parameters.strict
|
|
386
|
-
}, get)) {
|
|
387
|
-
if (get) output[key] = clone(value);
|
|
388
|
-
continue outer;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
if (information.length === 0) information.push({
|
|
392
|
-
value,
|
|
393
|
-
key: {
|
|
394
|
-
full: prefixedKey,
|
|
395
|
-
short: key
|
|
396
|
-
},
|
|
397
|
-
message: getInvalidTypeMessage(prefixedKey, property.types, value)
|
|
398
|
-
});
|
|
399
|
-
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
400
|
-
parameters?.information?.push(...information);
|
|
401
|
-
if (parameters.reporting.all) {
|
|
402
|
-
allInformation.push(...information);
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
return parameters.reporting.none ? void 0 : information;
|
|
406
|
-
}
|
|
407
|
-
if (get) if (parameters.origin == null) parameters.output = output;
|
|
408
|
-
else parameters.output[parameters.origin.key] = output;
|
|
409
|
-
return parameters.reporting.none || allInformation.length === 0 ? parameters.output : allInformation;
|
|
410
|
-
}
|
|
411
|
-
function validateSchematic(schematic, value, parameters, get) {
|
|
412
|
-
const result = validateObject(value, schematicProperties.get(schematic), parameters, get);
|
|
413
|
-
return result == null || Array.isArray(result) ? false : true;
|
|
458
|
+
if (get) if (origin == null) parameters.output = output;
|
|
459
|
+
else parameters.output[origin.short] = output;
|
|
460
|
+
return allInformation.length === 0 ? true : allInformation;
|
|
461
|
+
};
|
|
414
462
|
}
|
|
415
|
-
function
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const result = validateObject(value, type, parameters, get);
|
|
420
|
-
return result == null || Array.isArray(result) ? false : true;
|
|
421
|
-
}
|
|
422
|
-
case isSchematic(type): return validateSchematic(type, value, parameters, get);
|
|
423
|
-
default: return validateNamed(type, value, parameters);
|
|
424
|
-
}
|
|
463
|
+
function getRequired(key, obj) {
|
|
464
|
+
if (!("$required" in obj)) return;
|
|
465
|
+
if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
466
|
+
return obj[PROPERTY_REQUIRED];
|
|
425
467
|
}
|
|
426
|
-
const validators = {
|
|
427
|
-
array: Array.isArray,
|
|
428
|
-
bigint: (value) => typeof value === "bigint",
|
|
429
|
-
boolean: (value) => typeof value === "boolean",
|
|
430
|
-
date: (value) => value instanceof Date,
|
|
431
|
-
function: (value) => typeof value === "function",
|
|
432
|
-
null: (value) => value === null,
|
|
433
|
-
number: (value) => typeof value === "number",
|
|
434
|
-
object: (value) => typeof value === "object" && value !== null,
|
|
435
|
-
string: (value) => typeof value === "string",
|
|
436
|
-
symbol: (value) => typeof value === "symbol",
|
|
437
|
-
undefined: (value) => value === void 0
|
|
438
|
-
};
|
|
439
468
|
//#endregion
|
|
440
469
|
//#region src/schematic.ts
|
|
441
470
|
/**
|
|
442
471
|
* A schematic for validating objects
|
|
443
472
|
*/
|
|
444
473
|
var Schematic = class {
|
|
445
|
-
#
|
|
446
|
-
constructor(
|
|
474
|
+
#validator;
|
|
475
|
+
constructor(validator) {
|
|
447
476
|
Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
|
|
448
|
-
this.#
|
|
449
|
-
|
|
477
|
+
this.#validator = validator;
|
|
478
|
+
schematicValidator.set(this, validator);
|
|
450
479
|
}
|
|
451
480
|
get(value, options) {
|
|
452
481
|
const parameters = getParameters(options);
|
|
453
|
-
const result =
|
|
454
|
-
if (result
|
|
455
|
-
if (
|
|
482
|
+
const result = this.#validator(value, parameters, true);
|
|
483
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
|
|
484
|
+
if (parameters.reporting.none) return;
|
|
456
485
|
return error(parameters.reporting.all ? result : result[0]);
|
|
457
486
|
}
|
|
458
487
|
is(value, options) {
|
|
459
488
|
const parameters = getParameters(options);
|
|
460
|
-
const result =
|
|
461
|
-
if (result
|
|
462
|
-
if (
|
|
489
|
+
const result = this.#validator(value, parameters, false);
|
|
490
|
+
if (result === true) return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
|
|
491
|
+
if (parameters.reporting.none) return false;
|
|
463
492
|
return error(parameters.reporting.all ? result : result[0]);
|
|
464
493
|
}
|
|
465
494
|
};
|
|
466
495
|
function schematic(schema) {
|
|
467
496
|
if (isSchematic(schema)) return schema;
|
|
468
497
|
if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
|
|
469
|
-
return new Schematic(
|
|
498
|
+
return new Schematic(getObjectValidator(schema));
|
|
470
499
|
}
|
|
471
|
-
const
|
|
500
|
+
const schematicValidator = /* @__PURE__ */ new WeakMap();
|
|
472
501
|
//#endregion
|
|
473
502
|
export { SchematicError, ValidationError, instanceOf, isSchematic, schematic };
|