import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers'; import { AsyncValidator, ValidationErrors, Validator, } from 'fluentvalidation-ts'; import { FieldError, FieldValues, Resolver } from 'react-hook-form'; function traverseObject( object: ValidationErrors, errors: Record, parentIndices: (string | number)[] = [], ) { for (const key in object) { const currentIndex = [...parentIndices, key]; const currentValue = object[key]; if (Array.isArray(currentValue)) { currentValue.forEach((item: any, index: number) => { traverseObject(item, errors, [...currentIndex, index]); }); } else if (typeof currentValue === 'object' && currentValue !== null) { traverseObject(currentValue, errors, currentIndex); } else if (typeof currentValue === 'string') { errors[currentIndex.join('.')] = { type: 'validation', message: currentValue, }; } } } const parseErrorSchema = ( validationErrors: ValidationErrors, validateAllFieldCriteria: boolean, ) => { if (validateAllFieldCriteria) { // TODO: check this but i think its always one validation error } const errors: Record = {}; traverseObject(validationErrors, errors); return errors; }; export function fluentValidationResolver( validator: Validator, ): Resolver { return async (values, _context, options) => { const validationResult = validator.validate(values); const isValid = Object.keys(validationResult).length === 0; options.shouldUseNativeValidation && validateFieldsNatively({}, options); return isValid ? { values: values, errors: {}, } : { values: {}, errors: toNestErrors( parseErrorSchema( validationResult, !options.shouldUseNativeValidation && options.criteriaMode === 'all', ), options, ), }; }; } export function fluentAsyncValidationResolver< TFieldValues extends FieldValues, TValidator extends AsyncValidator, >(validator: TValidator): Resolver { return async (values, _context, options) => { const validationResult = await validator.validateAsync(values); const isValid = Object.keys(validationResult).length === 0; options.shouldUseNativeValidation && validateFieldsNatively({}, options); return isValid ? { values: values, errors: {}, } : { values: {}, errors: toNestErrors( parseErrorSchema( validationResult, !options.shouldUseNativeValidation && options.criteriaMode === 'all', ), options, ), }; }; }