@apizr-io/class-utils
Version:
Package containing all class-validator function with all custom apizr class validation functions
101 lines • 4.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IsRecord = void 0;
const class_transformer_1 = require("class-transformer");
const class_validator_1 = require("class-validator");
const isObjectType = async (obj, type) => {
switch (type) {
case 'number':
case 'boolean':
case 'string':
case 'object':
return typeof obj === type;
case 'null':
return obj === null;
case 'undefined':
return obj === undefined;
default: {
if ('type' in type) {
const types = Array.isArray(type.type) ? type.type : [type.type];
if (type.array && Array.isArray(obj)) {
const results = await Promise.all(obj.map((el) => isOneOfTypes(types, el)));
return results.reduce((acc, result) => acc && result, true);
}
return isOneOfTypes(types, obj);
}
const instance = (0, class_transformer_1.plainToInstance)(type, obj);
const errors = await (0, class_validator_1.validate)(instance);
return errors.length === 0;
}
}
};
const isOneOfTypes = async (types, obj) => {
for (const type of types) {
const result = await isObjectType(obj, type);
if (result === true) {
return true;
}
}
return false;
};
const areKeysValid = (keys, type) => {
const keysResults = keys.map((key) => {
if (type === 'string') {
return typeof key === 'string';
}
return !isNaN(Number(key));
});
return keysResults.reduce((acc, result) => acc && result, true);
};
const getTypeName = (type) => {
if (typeof type === 'object') {
const types = Array.isArray(type.type) ? type.type : [type.type];
const stringTypes = types.map((el) => getTypeName(el)).join(' | ');
return type.array ? `(${stringTypes})[]` : stringTypes;
}
else if (typeof type === 'string') {
return type;
}
return type.name;
};
const getErrorMessage = (propertyName, keyType, types, each) => {
const recordValueType = types.map((type) => getTypeName(type)).join(' | ');
const singleRecordType = `Record<${keyType}, ${recordValueType}>`;
return `Object ${propertyName} is not compliant to type ${singleRecordType}${each ? '[]' : ''}`;
};
function IsRecord(allowedRecordType, validationOptions) {
return (object, propertyName) => {
const types = Array.isArray(allowedRecordType)
? allowedRecordType
: [allowedRecordType];
const keyType = (validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.key) || 'string';
(0, class_validator_1.registerDecorator)({
name: 'isRecord',
target: object.constructor,
propertyName,
constraints: [],
options: {
message: () => getErrorMessage(propertyName, keyType, types, validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.each),
...validationOptions,
},
validator: {
async validate(value) {
if (!value) {
return false;
}
const objectKeys = Object.keys(value);
if (!areKeysValid(objectKeys, keyType)) {
return false;
}
const valuesToCheck = (validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.each) && Array.isArray(value)
? value.flatMap((obj) => Object.values(obj))
: Object.values(value);
const results = await Promise.all(valuesToCheck.map((obj) => isOneOfTypes(types, obj)));
return results.reduce((acc, el) => acc && el, true);
},
},
});
};
}
exports.IsRecord = IsRecord;
//# sourceMappingURL=is-record.decorator.js.map