UNPKG

@meta-system/object-definition

Version:

Standard Object Definition For Meta-System

132 lines 6.34 kB
import { CUSTOM_TYPES, customTypesValidations } from "../custom-types.js"; const simpleVerificationTypes = ["string", "boolean", "date", "number", "function", "cloudedObject"]; export const validateObject = (objectToValidate, definition) => { return validationObjectCycle(objectToValidate, definition); }; const validateForType = (typeDefinition, key, objectToValidate, cumulativePath = "", errors = []) => { if (simpleVerificationTypes.includes(typeDefinition.type)) { const isValid = validateFlatTypeDefinition(objectToValidate[key], typeDefinition); if (!isValid) { errors.push({ path: `${cumulativePath}${key}`, error: `Type not respected: ${typeDefinition.type} - got <${typeof objectToValidate[key]}>` }); } return; } if (typeDefinition.type === "object") { const subtype = typeDefinition.subtype; const property = objectToValidate[key]; const isObject = typeof property === "object" && !Array.isArray(property); if (typeDefinition.required && typeof property === "undefined") { errors.push({ path: `${cumulativePath}${key}`, error: `Type not respected: ${typeDefinition.type} - got <${typeof objectToValidate[key]}>` }); return; } if (!!typeDefinition.required === false && typeof property === "undefined") { return; } if (!isObject) { errors.push({ path: `${cumulativePath}${key}`, error: `Type not respected: ${typeDefinition.type} - got <${typeof objectToValidate[key]}>` }); return; } const computedResult = validationObjectCycle(objectToValidate[key], subtype, `${cumulativePath}${key}.`).errors; encapsulateRequire(objectToValidate[key], typeDefinition.required, computedResult.length === 0, computedResult, errors); return; } if (typeDefinition.type === "array") { const subtype = typeDefinition.subtype; const property = objectToValidate[key]; const isArray = Array.isArray(property); if (typeDefinition.required && typeof property === "undefined") { errors.push({ path: `${cumulativePath}${key}`, error: `Type not respected: ${typeDefinition.type} - got <${typeof objectToValidate[key]}>` }); return; } if (!!typeDefinition.required === false && typeof property === "undefined") { return; } if (!isArray) { errors.push({ path: `${cumulativePath}${key}`, error: `Type not respected: ${typeDefinition.type} - got <${typeof objectToValidate[key]}>` }); return; } property.forEach((element, index) => { if (typeof subtype === "string") { if (!validateFlatTypeDefinition(element, { type: subtype })) { errors.push({ path: `${cumulativePath}${key}.${index}`, error: `Array subtype not respected: ${subtype} - got <${typeof element}>` }); } ; return; } errors.push(...validationObjectCycle(element, subtype, `${cumulativePath}${key}.${index}.`).errors); }); return; } if (typeDefinition.type === "enum") { const validValues = typeDefinition.subtype; encapsulateRequire(objectToValidate[key], typeDefinition.required, validValues.includes(objectToValidate[key]), [{ path: `${cumulativePath}${key}`, error: `Enum values not respected: ["${validValues.join('", "')}"] - got <${objectToValidate[key]}>` }], errors); return; } const CustomTypesList = Object.values(CUSTOM_TYPES); if (CustomTypesList.includes(typeDefinition.type)) { errors.push(...customTypesValidations[typeDefinition.type](objectToValidate[key], `${cumulativePath}${key}`).errors); } }; const encapsulateRequire = (value, isRequired, rule, possibleErrors, errors) => { if (isRequired) { if (!rule) { return errors.push(...possibleErrors); } } if (value !== undefined && !rule) { errors.push(...possibleErrors); } }; // validateObject({}, {}, "", [{ path: "schemas.identifier", validator: (value) => { ;} }]) /** Validates Objects against an object definition, returning an array of errors - which may be empty if there are none. * * This function does not support types references to other object definitions, like `"type": "$reference"` */ const validationObjectCycle = (objectToValidate, definition, cumulativePath = "") => { const definitionKeys = Object.keys(definition); const errors = []; for (const key of definitionKeys) { const typeDefinition = definition[key]; if (Array.isArray(typeDefinition)) { let leastErrorBranch = []; let shouldkeepValidating = true; typeDefinition.forEach((singleDef, index) => { const currentBranchErrors = []; validateForType(singleDef, key, objectToValidate, cumulativePath, currentBranchErrors); if (currentBranchErrors.length === 0) { shouldkeepValidating = false; leastErrorBranch = []; return; } // If it is the first, we should set it doesn't matter the result if (currentBranchErrors.length <= leastErrorBranch.length || index === 0) { leastErrorBranch = currentBranchErrors; } }); errors.push(...leastErrorBranch); continue; } validateForType(typeDefinition, key, objectToValidate, cumulativePath, errors); } return { errors }; }; const validateFlatTypeDefinition = (property, typeDefinition) => { const type = typeof property; const isRequired = !!typeDefinition.required; if (type === "undefined" && isRequired) { return false; } if (type === "undefined" && !isRequired) { return true; } if (simpleVerificationTypes.includes(type)) { return type === typeDefinition.type; } if (typeDefinition.type === "date") { return property instanceof Date; } if (typeDefinition.type === "cloudedObject") { return type === "object" && Array.isArray(property) === false; } }; //# sourceMappingURL=validate-object.js.map