@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/helpers.d.mts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { ReportingInformation, ValidatedPropertyType, ValidationParameters } from "./models/validation.model.mjs";
|
|
2
|
-
import { Schematic } from "./schematic.mjs";
|
|
3
|
-
import { ValueName } from "./models/misc.model.mjs";
|
|
4
|
-
import { Constructor } from "@oscarpalmer/atoms/models";
|
|
5
|
-
|
|
6
|
-
//#region src/helpers.d.ts
|
|
7
|
-
declare function getInvalidInputMessage(actual: unknown): string;
|
|
8
|
-
declare function getInvalidMissingMessage(key: string, types: ValidatedPropertyType[]): string;
|
|
9
|
-
declare function getInvalidTypeMessage(key: string, types: ValidatedPropertyType[], actual: unknown): string;
|
|
10
|
-
declare function getInvalidValidatorMessage(key: string, type: ValueName, index: number, length: number): string;
|
|
11
|
-
declare function getParameters(input?: unknown): ValidationParameters;
|
|
12
|
-
declare function getReporting(value: unknown): ReportingInformation;
|
|
13
|
-
declare function getUnknownKeysMessage(keys: string[]): string;
|
|
14
|
-
/**
|
|
15
|
-
* Creates a validator function for a given constructor
|
|
16
|
-
* @param constructor - Constructor to check against
|
|
17
|
-
* @throws Will throw a `TypeError` if the provided argument is not a valid constructor
|
|
18
|
-
* @returns Validator function that checks if a value is an instance of the constructor
|
|
19
|
-
*/
|
|
20
|
-
declare function instanceOf<Instance>(constructor: Constructor<Instance>): (value: unknown) => value is Instance;
|
|
21
|
-
/**
|
|
22
|
-
* Is the value a schematic?
|
|
23
|
-
* @param value Value to check
|
|
24
|
-
* @returns `true` if the value is a schematic, `false` otherwise
|
|
25
|
-
*/
|
|
26
|
-
declare function isSchematic(value: unknown): value is Schematic<never>;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, getParameters, getReporting, getUnknownKeysMessage, instanceOf, isSchematic };
|
package/dist/helpers.mjs
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { CONJUNCTION_AND, CONJUNCTION_AND_COMMA, CONJUNCTION_OR, CONJUNCTION_OR_COMMA, MESSAGE_CONSTRUCTOR, NAME_SCHEMATIC, REPORTING_FIRST, REPORTING_NONE, REPORTING_THROW, REPORTING_TYPES, TYPE_ARRAY, TYPE_NULL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATION_MESSAGE_INVALID_INPUT, VALIDATION_MESSAGE_INVALID_REQUIRED, VALIDATION_MESSAGE_INVALID_TYPE, VALIDATION_MESSAGE_INVALID_VALUE, VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX, VALIDATION_MESSAGE_UNKNOWN_KEYS } from "./constants.mjs";
|
|
2
|
-
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
|
-
//#region src/helpers.ts
|
|
4
|
-
function getInvalidInputMessage(actual) {
|
|
5
|
-
return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
|
|
6
|
-
}
|
|
7
|
-
function getInvalidMissingMessage(key, types) {
|
|
8
|
-
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
|
|
9
|
-
message = message.replace("<>", key);
|
|
10
|
-
return message;
|
|
11
|
-
}
|
|
12
|
-
function getInvalidTypeMessage(key, types, actual) {
|
|
13
|
-
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
|
|
14
|
-
message = message.replace("<>", key);
|
|
15
|
-
message = message.replace("<>", getValueType(actual));
|
|
16
|
-
return message;
|
|
17
|
-
}
|
|
18
|
-
function getInvalidValidatorMessage(key, type, index, length) {
|
|
19
|
-
let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
|
|
20
|
-
message = message.replace("<>", type);
|
|
21
|
-
if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
|
|
22
|
-
return message;
|
|
23
|
-
}
|
|
24
|
-
function getParameters(input) {
|
|
25
|
-
if (typeof input === "boolean") return {
|
|
26
|
-
output: {},
|
|
27
|
-
reporting: getReporting(REPORTING_NONE),
|
|
28
|
-
strict: input
|
|
29
|
-
};
|
|
30
|
-
if (REPORTING_TYPES.has(input)) return {
|
|
31
|
-
output: {},
|
|
32
|
-
reporting: getReporting(input),
|
|
33
|
-
strict: false
|
|
34
|
-
};
|
|
35
|
-
const options = isPlainObject(input) ? input : {};
|
|
36
|
-
return {
|
|
37
|
-
output: {},
|
|
38
|
-
reporting: getReporting(options.errors),
|
|
39
|
-
strict: typeof options.strict === "boolean" ? options.strict : false
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function getPropertyType(original) {
|
|
43
|
-
if (typeof original === "function") return "a validated value";
|
|
44
|
-
if (Array.isArray(original)) return `'${TYPE_OBJECT}'`;
|
|
45
|
-
if (isSchematic(original)) return `a ${NAME_SCHEMATIC}`;
|
|
46
|
-
return `'${String(original)}'`;
|
|
47
|
-
}
|
|
48
|
-
function getReporting(value) {
|
|
49
|
-
const type = REPORTING_TYPES.has(value) ? value : REPORTING_NONE;
|
|
50
|
-
return {
|
|
51
|
-
type,
|
|
52
|
-
["all"]: type === "all",
|
|
53
|
-
[REPORTING_FIRST]: type === REPORTING_FIRST,
|
|
54
|
-
[REPORTING_NONE]: type === REPORTING_NONE,
|
|
55
|
-
[REPORTING_THROW]: type === REPORTING_THROW
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function getUnknownKeysMessage(keys) {
|
|
59
|
-
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
|
|
60
|
-
}
|
|
61
|
-
function getValueType(value) {
|
|
62
|
-
const valueType = typeof value;
|
|
63
|
-
switch (true) {
|
|
64
|
-
case value === null: return `'${TYPE_NULL}'`;
|
|
65
|
-
case value === void 0: return `'${TYPE_UNDEFINED}'`;
|
|
66
|
-
case valueType !== TYPE_OBJECT: return `'${valueType}'`;
|
|
67
|
-
case Array.isArray(value): return `'${TYPE_ARRAY}'`;
|
|
68
|
-
case isPlainObject(value): return `'${TYPE_OBJECT}'`;
|
|
69
|
-
case isSchematic(value): return `a ${NAME_SCHEMATIC}`;
|
|
70
|
-
default: return value.constructor.name;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Creates a validator function for a given constructor
|
|
75
|
-
* @param constructor - Constructor to check against
|
|
76
|
-
* @throws Will throw a `TypeError` if the provided argument is not a valid constructor
|
|
77
|
-
* @returns Validator function that checks if a value is an instance of the constructor
|
|
78
|
-
*/
|
|
79
|
-
function instanceOf(constructor) {
|
|
80
|
-
if (!isConstructor(constructor)) throw new TypeError(MESSAGE_CONSTRUCTOR);
|
|
81
|
-
return (value) => {
|
|
82
|
-
return value instanceof constructor;
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Is the value a schematic?
|
|
87
|
-
* @param value Value to check
|
|
88
|
-
* @returns `true` if the value is a schematic, `false` otherwise
|
|
89
|
-
*/
|
|
90
|
-
function isSchematic(value) {
|
|
91
|
-
return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
|
|
92
|
-
}
|
|
93
|
-
function renderKeys(keys) {
|
|
94
|
-
return renderParts(keys.map((key) => `'${key}'`), CONJUNCTION_AND, CONJUNCTION_AND_COMMA);
|
|
95
|
-
}
|
|
96
|
-
function renderParts(parts, delimiterShort, delimiterLong) {
|
|
97
|
-
const { length } = parts;
|
|
98
|
-
if (length === 1) return parts[0];
|
|
99
|
-
let rendered = "";
|
|
100
|
-
for (let index = 0; index < length; index += 1) {
|
|
101
|
-
rendered += parts[index];
|
|
102
|
-
if (index < length - 2) rendered += ", ";
|
|
103
|
-
else if (index === length - 2) rendered += parts.length > 2 ? delimiterLong : delimiterShort;
|
|
104
|
-
}
|
|
105
|
-
return rendered;
|
|
106
|
-
}
|
|
107
|
-
function renderTypes(types) {
|
|
108
|
-
const unique = /* @__PURE__ */ new Set();
|
|
109
|
-
const parts = [];
|
|
110
|
-
for (let index = 0; index < types.length; index += 1) {
|
|
111
|
-
const rendered = getPropertyType(types[index]);
|
|
112
|
-
if (unique.has(rendered)) continue;
|
|
113
|
-
unique.add(rendered);
|
|
114
|
-
parts.push(rendered);
|
|
115
|
-
}
|
|
116
|
-
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
117
|
-
}
|
|
118
|
-
//#endregion
|
|
119
|
-
export { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, getParameters, getReporting, getUnknownKeysMessage, instanceOf, isSchematic };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { ValidatedProperty } from "../models/validation.model.mjs";
|
|
2
|
-
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
3
|
-
|
|
4
|
-
//#region src/validation/property.validation.d.ts
|
|
5
|
-
declare function getProperties(original: PlainObject, prefix?: string, fromType?: boolean): ValidatedProperty[];
|
|
6
|
-
//#endregion
|
|
7
|
-
export { getProperties };
|
|
@@ -1,92 +0,0 @@
|
|
|
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, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL, TYPE_UNDEFINED, VALIDATABLE_TYPES } from "../constants.mjs";
|
|
2
|
-
import { instanceOf, isSchematic } from "../helpers.mjs";
|
|
3
|
-
import { SchematicError } from "../models/validation.model.mjs";
|
|
4
|
-
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
5
|
-
import { join } from "@oscarpalmer/atoms/string";
|
|
6
|
-
//#region src/validation/property.validation.ts
|
|
7
|
-
function getDisallowedProperty(obj) {
|
|
8
|
-
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
9
|
-
if ("$type" in obj) return PROPERTY_TYPE;
|
|
10
|
-
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
11
|
-
}
|
|
12
|
-
function getProperties(original, prefix, fromType) {
|
|
13
|
-
if (Object.keys(original).length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
14
|
-
if (fromType ?? false) {
|
|
15
|
-
const property = getDisallowedProperty(original);
|
|
16
|
-
if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", property));
|
|
17
|
-
}
|
|
18
|
-
const keys = Object.keys(original);
|
|
19
|
-
const keysLength = keys.length;
|
|
20
|
-
const properties = [];
|
|
21
|
-
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
22
|
-
const key = keys[keyIndex];
|
|
23
|
-
const value = original[key];
|
|
24
|
-
if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([prefix, key], ".")));
|
|
25
|
-
const types = [];
|
|
26
|
-
let required = true;
|
|
27
|
-
let validators = {};
|
|
28
|
-
if (isPlainObject(value)) {
|
|
29
|
-
required = getRequired(key, value) ?? required;
|
|
30
|
-
validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
31
|
-
const hasType = PROPERTY_TYPE in value;
|
|
32
|
-
types.push(...getTypes(key, hasType ? value[PROPERTY_TYPE] : value, prefix, hasType));
|
|
33
|
-
} else types.push(...getTypes(key, value, prefix));
|
|
34
|
-
if (!required && !types.includes("undefined")) types.push(TYPE_UNDEFINED);
|
|
35
|
-
properties.push({
|
|
36
|
-
key,
|
|
37
|
-
types,
|
|
38
|
-
validators,
|
|
39
|
-
required: required && !types.includes("undefined")
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return properties;
|
|
43
|
-
}
|
|
44
|
-
function getRequired(key, obj) {
|
|
45
|
-
if (!("$required" in obj)) return;
|
|
46
|
-
if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
47
|
-
return obj[PROPERTY_REQUIRED];
|
|
48
|
-
}
|
|
49
|
-
function getTypes(key, original, prefix, fromType) {
|
|
50
|
-
const array = Array.isArray(original) ? original : [original];
|
|
51
|
-
const { length } = array;
|
|
52
|
-
const types = [];
|
|
53
|
-
for (let index = 0; index < length; index += 1) {
|
|
54
|
-
const value = array[index];
|
|
55
|
-
switch (true) {
|
|
56
|
-
case typeof value === "function":
|
|
57
|
-
types.push(isConstructor(value) ? instanceOf(value) : value);
|
|
58
|
-
break;
|
|
59
|
-
case isPlainObject(value):
|
|
60
|
-
types.push(getProperties(value, join([prefix, key], "."), fromType));
|
|
61
|
-
break;
|
|
62
|
-
case isSchematic(value):
|
|
63
|
-
types.push(value);
|
|
64
|
-
break;
|
|
65
|
-
case TYPE_ALL.has(value):
|
|
66
|
-
types.push(value);
|
|
67
|
-
break;
|
|
68
|
-
default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", join([prefix, key], ".")));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", join([prefix, key], ".")));
|
|
72
|
-
return types;
|
|
73
|
-
}
|
|
74
|
-
function getValidators(original) {
|
|
75
|
-
const validators = {};
|
|
76
|
-
if (original == null) return validators;
|
|
77
|
-
if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
78
|
-
const keys = Object.keys(original);
|
|
79
|
-
const { length } = keys;
|
|
80
|
-
for (let index = 0; index < length; index += 1) {
|
|
81
|
-
const key = keys[index];
|
|
82
|
-
if (!VALIDATABLE_TYPES.has(key)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace("<>", key));
|
|
83
|
-
const value = original[key];
|
|
84
|
-
validators[key] = (Array.isArray(value) ? value : [value]).map((item) => {
|
|
85
|
-
if (typeof item !== "function") throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace("<>", key));
|
|
86
|
-
return item;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return validators;
|
|
90
|
-
}
|
|
91
|
-
//#endregion
|
|
92
|
-
export { getProperties };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { ValidatedProperty, ValidationInformation, ValidationParameters } from "../models/validation.model.mjs";
|
|
2
|
-
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
3
|
-
|
|
4
|
-
//#region src/validation/value.validation.d.ts
|
|
5
|
-
declare function validateObject(obj: unknown, properties: ValidatedProperty[], parameters: ValidationParameters, get: boolean): PlainObject | ValidationInformation[] | undefined;
|
|
6
|
-
//#endregion
|
|
7
|
-
export { validateObject };
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import "../constants.mjs";
|
|
2
|
-
import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, getUnknownKeysMessage, isSchematic } from "../helpers.mjs";
|
|
3
|
-
import { ValidationError } from "../models/validation.model.mjs";
|
|
4
|
-
import { schematicProperties } from "../schematic.mjs";
|
|
5
|
-
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
|
-
import { join } from "@oscarpalmer/atoms/string";
|
|
7
|
-
import { clone } from "@oscarpalmer/atoms/value/clone";
|
|
8
|
-
//#region src/validation/value.validation.ts
|
|
9
|
-
function validateNamed(name, value, parameters) {
|
|
10
|
-
if (!validators[name](value)) return false;
|
|
11
|
-
const propertyValidators = parameters.origin.validators[name];
|
|
12
|
-
if (propertyValidators == null || propertyValidators.length === 0) return true;
|
|
13
|
-
const { length } = propertyValidators;
|
|
14
|
-
for (let index = 0; index < length; index += 1) {
|
|
15
|
-
const validator = propertyValidators[index];
|
|
16
|
-
if (!validator(value)) {
|
|
17
|
-
parameters.information.push({
|
|
18
|
-
value,
|
|
19
|
-
key: {
|
|
20
|
-
full: parameters.prefix,
|
|
21
|
-
short: parameters.origin.key
|
|
22
|
-
},
|
|
23
|
-
message: getInvalidValidatorMessage(parameters.prefix, name, index, length),
|
|
24
|
-
validator
|
|
25
|
-
});
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
function validateObject(obj, properties, parameters, get) {
|
|
32
|
-
if (!isPlainObject(obj)) {
|
|
33
|
-
const key = parameters?.origin == null ? {
|
|
34
|
-
full: "",
|
|
35
|
-
short: ""
|
|
36
|
-
} : {
|
|
37
|
-
full: parameters.prefix,
|
|
38
|
-
short: parameters.origin.key
|
|
39
|
-
};
|
|
40
|
-
const information = {
|
|
41
|
-
key,
|
|
42
|
-
message: parameters?.origin == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(key.full, parameters.origin.types, obj),
|
|
43
|
-
value: obj
|
|
44
|
-
};
|
|
45
|
-
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
46
|
-
parameters?.information?.push(information);
|
|
47
|
-
return parameters.reporting.none ? void 0 : [information];
|
|
48
|
-
}
|
|
49
|
-
if (parameters.strict) {
|
|
50
|
-
const objKeys = Object.keys(obj);
|
|
51
|
-
const propertiesKeys = new Set(properties.map((property) => property.key));
|
|
52
|
-
const unknownKeys = objKeys.filter((key) => !propertiesKeys.has(key));
|
|
53
|
-
if (unknownKeys.length > 0) {
|
|
54
|
-
const information = {
|
|
55
|
-
key: parameters?.origin == null ? {
|
|
56
|
-
full: "",
|
|
57
|
-
short: ""
|
|
58
|
-
} : {
|
|
59
|
-
full: join([parameters.prefix, parameters.origin?.key], "."),
|
|
60
|
-
short: parameters.origin.key
|
|
61
|
-
},
|
|
62
|
-
message: getUnknownKeysMessage(unknownKeys.map((key) => join([parameters?.prefix, key], "."))),
|
|
63
|
-
value: obj
|
|
64
|
-
};
|
|
65
|
-
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
66
|
-
parameters?.information?.push(information);
|
|
67
|
-
return parameters.reporting.none ? void 0 : [information];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const allInformation = [];
|
|
71
|
-
const output = {};
|
|
72
|
-
const propertiesLength = properties.length;
|
|
73
|
-
outer: for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
|
|
74
|
-
const property = properties[propertyIndex];
|
|
75
|
-
const { key, required, types } = property;
|
|
76
|
-
const value = obj[key];
|
|
77
|
-
if (get && value === void 0 && !required) continue;
|
|
78
|
-
if (value === void 0 && required) {
|
|
79
|
-
const prefixedKey = join([parameters.prefix, key], ".");
|
|
80
|
-
const information = {
|
|
81
|
-
value,
|
|
82
|
-
key: {
|
|
83
|
-
full: prefixedKey,
|
|
84
|
-
short: key
|
|
85
|
-
},
|
|
86
|
-
message: getInvalidMissingMessage(prefixedKey, property.types)
|
|
87
|
-
};
|
|
88
|
-
if (parameters.reporting.throw) throw new ValidationError([information]);
|
|
89
|
-
parameters?.information?.push(information);
|
|
90
|
-
if (parameters.reporting.all) {
|
|
91
|
-
allInformation.push(information);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
return parameters.reporting.none ? void 0 : [information];
|
|
95
|
-
}
|
|
96
|
-
const prefixedKey = join([parameters.prefix, key], ".");
|
|
97
|
-
const typesLength = types.length;
|
|
98
|
-
const information = [];
|
|
99
|
-
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
100
|
-
const type = types[typeIndex];
|
|
101
|
-
if (validateValue(type, value, {
|
|
102
|
-
information,
|
|
103
|
-
output,
|
|
104
|
-
origin: property,
|
|
105
|
-
prefix: prefixedKey,
|
|
106
|
-
reporting: parameters.reporting,
|
|
107
|
-
strict: parameters.strict
|
|
108
|
-
}, get)) {
|
|
109
|
-
if (get) output[key] = clone(value);
|
|
110
|
-
continue outer;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (information.length === 0) information.push({
|
|
114
|
-
value,
|
|
115
|
-
key: {
|
|
116
|
-
full: prefixedKey,
|
|
117
|
-
short: key
|
|
118
|
-
},
|
|
119
|
-
message: getInvalidTypeMessage(prefixedKey, property.types, value)
|
|
120
|
-
});
|
|
121
|
-
if (parameters.reporting.throw) throw new ValidationError(information);
|
|
122
|
-
parameters?.information?.push(...information);
|
|
123
|
-
if (parameters.reporting.all) {
|
|
124
|
-
allInformation.push(...information);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
return parameters.reporting.none ? void 0 : information;
|
|
128
|
-
}
|
|
129
|
-
if (get) if (parameters.origin == null) parameters.output = output;
|
|
130
|
-
else parameters.output[parameters.origin.key] = output;
|
|
131
|
-
return parameters.reporting.none || allInformation.length === 0 ? parameters.output : allInformation;
|
|
132
|
-
}
|
|
133
|
-
function validateSchematic(schematic, value, parameters, get) {
|
|
134
|
-
const result = validateObject(value, schematicProperties.get(schematic), parameters, get);
|
|
135
|
-
return result == null || Array.isArray(result) ? false : true;
|
|
136
|
-
}
|
|
137
|
-
function validateValue(type, value, parameters, get) {
|
|
138
|
-
switch (true) {
|
|
139
|
-
case typeof type === "function": return type(value);
|
|
140
|
-
case Array.isArray(type): {
|
|
141
|
-
const result = validateObject(value, type, parameters, get);
|
|
142
|
-
return result == null || Array.isArray(result) ? false : true;
|
|
143
|
-
}
|
|
144
|
-
case isSchematic(type): return validateSchematic(type, value, parameters, get);
|
|
145
|
-
default: return validateNamed(type, value, parameters);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const validators = {
|
|
149
|
-
array: Array.isArray,
|
|
150
|
-
bigint: (value) => typeof value === "bigint",
|
|
151
|
-
boolean: (value) => typeof value === "boolean",
|
|
152
|
-
date: (value) => value instanceof Date,
|
|
153
|
-
function: (value) => typeof value === "function",
|
|
154
|
-
null: (value) => value === null,
|
|
155
|
-
number: (value) => typeof value === "number",
|
|
156
|
-
object: (value) => typeof value === "object" && value !== null,
|
|
157
|
-
string: (value) => typeof value === "string",
|
|
158
|
-
symbol: (value) => typeof value === "symbol",
|
|
159
|
-
undefined: (value) => value === void 0
|
|
160
|
-
};
|
|
161
|
-
//#endregion
|
|
162
|
-
export { validateObject };
|
package/src/helpers.ts
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import type {Constructor} from '@oscarpalmer/atoms/models';
|
|
3
|
-
import {
|
|
4
|
-
COMMA,
|
|
5
|
-
CONJUNCTION_AND,
|
|
6
|
-
CONJUNCTION_AND_COMMA,
|
|
7
|
-
CONJUNCTION_OR,
|
|
8
|
-
CONJUNCTION_OR_COMMA,
|
|
9
|
-
MESSAGE_CONSTRUCTOR,
|
|
10
|
-
NAME_SCHEMATIC,
|
|
11
|
-
PROPERTY_SCHEMATIC,
|
|
12
|
-
REPORTING_ALL,
|
|
13
|
-
REPORTING_FIRST,
|
|
14
|
-
REPORTING_NONE,
|
|
15
|
-
REPORTING_THROW,
|
|
16
|
-
REPORTING_TYPES,
|
|
17
|
-
TEMPLATE_PATTERN,
|
|
18
|
-
TYPE_ARRAY,
|
|
19
|
-
TYPE_NULL,
|
|
20
|
-
TYPE_OBJECT,
|
|
21
|
-
TYPE_UNDEFINED,
|
|
22
|
-
VALIDATION_MESSAGE_INVALID_INPUT,
|
|
23
|
-
VALIDATION_MESSAGE_INVALID_REQUIRED,
|
|
24
|
-
VALIDATION_MESSAGE_INVALID_TYPE,
|
|
25
|
-
VALIDATION_MESSAGE_INVALID_VALUE,
|
|
26
|
-
VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX,
|
|
27
|
-
VALIDATION_MESSAGE_UNKNOWN_KEYS,
|
|
28
|
-
} from './constants';
|
|
29
|
-
import type {ValueName} from './models/misc.model';
|
|
30
|
-
import type {
|
|
31
|
-
ReportingInformation,
|
|
32
|
-
ReportingType,
|
|
33
|
-
ValidatedProperty,
|
|
34
|
-
ValidatedPropertyType,
|
|
35
|
-
ValidationParameters,
|
|
36
|
-
} from './models/validation.model';
|
|
37
|
-
import type {Schematic} from './schematic';
|
|
38
|
-
|
|
39
|
-
export function getInvalidInputMessage(actual: unknown): string {
|
|
40
|
-
return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function getInvalidMissingMessage(key: string, types: ValidatedPropertyType[]): string {
|
|
44
|
-
let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
45
|
-
|
|
46
|
-
message = message.replace(TEMPLATE_PATTERN, key);
|
|
47
|
-
|
|
48
|
-
return message;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function getInvalidTypeMessage(
|
|
52
|
-
key: string,
|
|
53
|
-
types: ValidatedPropertyType[],
|
|
54
|
-
actual: unknown,
|
|
55
|
-
): string {
|
|
56
|
-
let message = VALIDATION_MESSAGE_INVALID_TYPE.replace(TEMPLATE_PATTERN, renderTypes(types));
|
|
57
|
-
|
|
58
|
-
message = message.replace(TEMPLATE_PATTERN, key);
|
|
59
|
-
message = message.replace(TEMPLATE_PATTERN, getValueType(actual));
|
|
60
|
-
|
|
61
|
-
return message;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function getInvalidValidatorMessage(
|
|
65
|
-
key: string,
|
|
66
|
-
type: ValueName,
|
|
67
|
-
index: number,
|
|
68
|
-
length: number,
|
|
69
|
-
): string {
|
|
70
|
-
let message = VALIDATION_MESSAGE_INVALID_VALUE.replace(TEMPLATE_PATTERN, key);
|
|
71
|
-
|
|
72
|
-
message = message.replace(TEMPLATE_PATTERN, type);
|
|
73
|
-
|
|
74
|
-
if (length > 1) {
|
|
75
|
-
message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace(TEMPLATE_PATTERN, String(index));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return message;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function getParameters(input?: unknown): ValidationParameters {
|
|
82
|
-
if (typeof input === 'boolean') {
|
|
83
|
-
return {
|
|
84
|
-
output: {},
|
|
85
|
-
reporting: getReporting(REPORTING_NONE),
|
|
86
|
-
strict: input,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (REPORTING_TYPES.has(input as ReportingType)) {
|
|
91
|
-
return {
|
|
92
|
-
output: {},
|
|
93
|
-
reporting: getReporting(input as ReportingType),
|
|
94
|
-
strict: false,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const options = isPlainObject(input) ? input : {};
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
output: {},
|
|
102
|
-
reporting: getReporting(options.errors),
|
|
103
|
-
strict: typeof options.strict === 'boolean' ? options.strict : false,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getPropertyType(original: ValidatedPropertyType): string {
|
|
108
|
-
if (typeof original === 'function') {
|
|
109
|
-
return 'a validated value';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (Array.isArray(original)) {
|
|
113
|
-
return `'${TYPE_OBJECT}'`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (isSchematic(original)) {
|
|
117
|
-
return `a ${NAME_SCHEMATIC}`;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return `'${String(original)}'`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function getReporting(value: unknown): ReportingInformation {
|
|
124
|
-
const type = REPORTING_TYPES.has(value as ReportingType)
|
|
125
|
-
? (value as ReportingType)
|
|
126
|
-
: REPORTING_NONE;
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
type,
|
|
130
|
-
[REPORTING_ALL]: type === REPORTING_ALL,
|
|
131
|
-
[REPORTING_FIRST]: type === REPORTING_FIRST,
|
|
132
|
-
[REPORTING_NONE]: type === REPORTING_NONE,
|
|
133
|
-
[REPORTING_THROW]: type === REPORTING_THROW,
|
|
134
|
-
} as ReportingInformation;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function getUnknownKeysMessage(keys: string[]): string {
|
|
138
|
-
return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function getValueType(value: unknown): string {
|
|
142
|
-
const valueType = typeof value;
|
|
143
|
-
|
|
144
|
-
switch (true) {
|
|
145
|
-
case value === null:
|
|
146
|
-
return `'${TYPE_NULL}'`;
|
|
147
|
-
|
|
148
|
-
case value === undefined:
|
|
149
|
-
return `'${TYPE_UNDEFINED}'`;
|
|
150
|
-
|
|
151
|
-
case valueType !== TYPE_OBJECT:
|
|
152
|
-
return `'${valueType}'`;
|
|
153
|
-
|
|
154
|
-
case Array.isArray(value):
|
|
155
|
-
return `'${TYPE_ARRAY}'`;
|
|
156
|
-
|
|
157
|
-
case isPlainObject(value):
|
|
158
|
-
return `'${TYPE_OBJECT}'`;
|
|
159
|
-
|
|
160
|
-
case isSchematic(value):
|
|
161
|
-
return `a ${NAME_SCHEMATIC}`;
|
|
162
|
-
|
|
163
|
-
default:
|
|
164
|
-
return value.constructor.name;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Creates a validator function for a given constructor
|
|
170
|
-
* @param constructor - Constructor to check against
|
|
171
|
-
* @throws Will throw a `TypeError` if the provided argument is not a valid constructor
|
|
172
|
-
* @returns Validator function that checks if a value is an instance of the constructor
|
|
173
|
-
*/
|
|
174
|
-
export function instanceOf<Instance>(
|
|
175
|
-
constructor: Constructor<Instance>,
|
|
176
|
-
): (value: unknown) => value is Instance {
|
|
177
|
-
if (!isConstructor(constructor)) {
|
|
178
|
-
throw new TypeError(MESSAGE_CONSTRUCTOR);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return (value: unknown): value is Instance => {
|
|
182
|
-
return value instanceof constructor;
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Is the value a schematic?
|
|
188
|
-
* @param value Value to check
|
|
189
|
-
* @returns `true` if the value is a schematic, `false` otherwise
|
|
190
|
-
*/
|
|
191
|
-
export function isSchematic(value: unknown): value is Schematic<never> {
|
|
192
|
-
return (
|
|
193
|
-
typeof value === 'object' &&
|
|
194
|
-
value !== null &&
|
|
195
|
-
PROPERTY_SCHEMATIC in value &&
|
|
196
|
-
value[PROPERTY_SCHEMATIC] === true
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function renderKeys(keys: string[]): string {
|
|
201
|
-
return renderParts(
|
|
202
|
-
keys.map(key => `'${key}'`),
|
|
203
|
-
CONJUNCTION_AND,
|
|
204
|
-
CONJUNCTION_AND_COMMA,
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function renderParts(parts: string[], delimiterShort: string, delimiterLong: string): string {
|
|
209
|
-
const {length} = parts;
|
|
210
|
-
|
|
211
|
-
if (length === 1) {
|
|
212
|
-
return parts[0];
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
let rendered = '';
|
|
216
|
-
|
|
217
|
-
for (let index = 0; index < length; index += 1) {
|
|
218
|
-
rendered += parts[index];
|
|
219
|
-
|
|
220
|
-
if (index < length - 2) {
|
|
221
|
-
rendered += COMMA;
|
|
222
|
-
} else if (index === length - 2) {
|
|
223
|
-
rendered += parts.length > 2 ? delimiterLong : delimiterShort;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return rendered;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function renderTypes(types: ValidatedPropertyType[]): string {
|
|
231
|
-
const unique = new Set<string>();
|
|
232
|
-
const parts: string[] = [];
|
|
233
|
-
|
|
234
|
-
for (let index = 0; index < types.length; index += 1) {
|
|
235
|
-
const rendered = getPropertyType(types[index]);
|
|
236
|
-
|
|
237
|
-
if (unique.has(rendered)) {
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
unique.add(rendered);
|
|
242
|
-
parts.push(rendered);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
|
|
246
|
-
}
|