UNPKG

fortify-schema

Version:

A modern TypeScript validation library designed around familiar interface syntax and powerful conditional validation. Experience schema validation that feels natural to TypeScript developers while unlocking advanced runtime validation capabilities.

225 lines (221 loc) 10.1 kB
'use strict'; var TypeValidators = require('../../mode/interfaces/validators/TypeValidators.js'); var ConstraintParser = require('../../mode/interfaces/validators/ConstraintParser.js'); var ValidationHelpers = require('../../mode/interfaces/validators/ValidationHelpers.js'); var ErrorHandler = require('../../mode/interfaces/errors/ErrorHandler.js'); var errors_type = require('../../mode/interfaces/errors/types/errors.type.js'); /** * Validation Engine - Core validation logic for schema extensions * * This module provides the core validation engine that powers all schema extensions. * It acts as a bridge between extensions and the main validation system, delegating * actual validation to the TypeValidators module to avoid duplication. */ /** * Core validation engine for schema validation */ class ValidationEngine { /** * Validate a value against a schema field definition * Delegates to TypeValidators for actual validation logic */ static validateField(fieldSchema, value) { if (typeof fieldSchema === "string") { return this.validateStringSchema(fieldSchema, value); } if (typeof fieldSchema === "object" && !Array.isArray(fieldSchema)) { return this.validateObjectSchema(fieldSchema, value); } // Default: accept any value return { isValid: true, errors: [] }; } /** * Validate against string-based schema definitions * Uses TypeValidators for consistent validation logic */ static validateStringSchema(fieldSchema, value) { // Parse the field schema using ConstraintParser const parsed = ConstraintParser.ConstraintParser.parseConstraints(fieldSchema); const { type, constraints, optional } = parsed; // Handle null/undefined for optional fields if (optional && (value === null || value === undefined)) { return { isValid: true, errors: [] }; } // Required field cannot be null/undefined if (!optional && (value === null || value === undefined)) { return { isValid: false, errors: [`Field is required but received ${value}`], }; } // Use TypeValidators for actual validation const options = { loose: false }; // Default options let validationResult; try { // Delegate to appropriate TypeValidator method based on type switch (type) { case "string": validationResult = TypeValidators.TypeValidators.validateString(value, options, constraints); break; case "number": case "float": case "double": validationResult = TypeValidators.TypeValidators.validateNumber(value, options, constraints); break; case "int": case "integer": case "positive": case "negative": validationResult = TypeValidators.TypeValidators.validateInteger(value, options, constraints, type); break; case "boolean": validationResult = TypeValidators.TypeValidators.validateBoolean(value, options, {}); break; case "date": validationResult = TypeValidators.TypeValidators.validateDate(value, options, {}, "date"); break; case "email": validationResult = TypeValidators.TypeValidators.validateEmail(value); break; case "url": validationResult = TypeValidators.TypeValidators.validateUrl(value, "url.web"); break; case "uuid": case "guid": validationResult = TypeValidators.TypeValidators.validateUuid(value, type); break; default: // Handle arrays and other complex types if (type.includes("[]")) { // For arrays, use ValidationHelpers.validateArrayWithConstraints const elementType = type.replace("[]", ""); validationResult = ValidationHelpers.ValidationHelpers.validateArrayWithConstraints(value, elementType, constraints, (elemType, elemValue) => { // Recursively validate each element and convert result format const fieldResult = this.validateStringSchema(elemType, elemValue); // Convert string errors to ValidationError objects const validationErrors = fieldResult.errors.map((errorMsg) => { if (typeof errorMsg === "string") { // console.log("converting string error to ValidationError"); return ErrorHandler.ErrorHandler.convertStringToError(errorMsg, errors_type.ErrorCode.VALIDATION_ERROR); } // If it's already a ValidationError object, return as is if (errorMsg && typeof errorMsg === "object" && "message" in errorMsg) { return errorMsg; } // Fallback: convert to string and then to ValidationError // console.log( // "converting unknown error format to ValidationError" // ); return ErrorHandler.ErrorHandler.convertStringToError(String(errorMsg), errors_type.ErrorCode.VALIDATION_ERROR); }); return { success: fieldResult.isValid, errors: validationErrors, warnings: [], data: elemValue, }; }); } else { // // Unknown type - accept any value validationResult = { success: true, errors: [], warnings: [], data: value, }; } } // Convert TypeValidators result format to ValidationEngine format return { isValid: validationResult.success, errors: (validationResult.errors || []).map((error) => { if (typeof error === "string") { return error; } if (error && typeof error === "object" && error.message) { return error.message; } // Fallback: try to extract meaningful information if (error && typeof error === "object") { if (error.toString && error.toString !== Object.prototype.toString) { return error.toString(); } return JSON.stringify(error); } return String(error); }), }; } catch (error) { return { isValid: false, errors: [ `Validation error: ${error instanceof Error ? error.message : "Unknown error"}`, ], }; } } /** * Validate against object schema definitions */ static validateObjectSchema(fieldSchema, value) { const errors = []; if (typeof value !== "object" || value === null) { errors.push("Expected object but received " + typeof value); return { isValid: false, errors }; } // Validate all nested fields for (const [nestedField, nestedSchema] of Object.entries(fieldSchema)) { const nestedResult = this.validateField(nestedSchema, value[nestedField]); if (!nestedResult.isValid) { const errRes = nestedResult.errors.map((err) => { // Handle both string and ValidationError object cases const errorMessage = typeof err === "string" ? err : err && typeof err === "object" && "message" in err ? err.message : JSON.stringify(err); return `${nestedField}: ${errorMessage}`; }); errors.push(...errRes); } } return { isValid: errors.length === 0, errors }; } // All individual validation methods removed - now delegated to TypeValidators /** * Validate entire object against schema */ static validateObject(schema, data) { const errors = {}; let isValid = true; if (!data || typeof data !== "object") { return { isValid: false, data, errors: { _root: ["Expected object but received " + typeof data] }, timestamp: new Date(), }; } // Validate each field in the schema for (const [fieldName, fieldSchema] of Object.entries(schema)) { const fieldResult = this.validateField(fieldSchema, data[fieldName]); if (!fieldResult.isValid) { errors[fieldName] = fieldResult.errors; isValid = false; } } return { isValid, data, errors, timestamp: new Date(), }; } } exports.ValidationEngine = ValidationEngine; //# sourceMappingURL=validation-engine.js.map