import { EMPTY_ERRORS } from './Errors' ; import errToJSON from './utils/errToJSON' ; import { trim , inPath } from './utils/paths' ; import { ValidationError } from 'yup' ; import { Errors } from './types' ; import uniqBy from 'lodash/uniqBy' ; export interface ValidationPathSpec { path : string ; shallow : boolean ; } function trimChildren ( rootPath , errors ) { let result = { } ; Object . keys ( errors ) . forEach ( ( path ) => { if ( rootPath !== path && inPath ( rootPath , path ) ) return ; result [ path ] = errors [ path ] ; } ) ; return result ; } function reduce ( paths ) { paths = uniqBy ( paths , ( p ) => p . path ) ; if ( paths . length <= 1 ) return paths ; return paths . reduce < ValidationPathSpec [ ] > ( ( innerPaths , current ) => { innerPaths = innerPaths . filter ( ( p ) => ! inPath ( current . path , p . path ) ) ; if ( ! innerPaths . some ( ( p ) => inPath ( p . path , current . path ) ) ) innerPaths . push ( current ) ; return innerPaths ; } , [ ] ) ; } export let isValidationError = ( err ) : err is ValidationError => err && err . name === 'ValidationError' ; export default function errorManager < TOptions > ( handleValidation ) { return { async collect ( paths , pristineErrors = EMPTY_ERRORS , options ? ) { const specs = reduce ( paths . map ( ( p ) => typeof p === 'string' ? { path : p , shallow : false } : p ) ) ; let errors = { ... pristineErrors } ; let nextErrors = errors ; let workDone = false ; specs . forEach ( ( { path , shallow } ) => { nextErrors = trim ( path , nextErrors , shallow ) ; if ( errors !== nextErrors ) workDone = true ; } ) ; let validations = specs . map ( ( spec ) => Promise . resolve ( handleValidation ( spec , options ) ) . then ( ( validationError ) => { if ( ! validationError ) return true ; if ( ! isValidationError ( validationError ) ) throw validationError ; if ( ! spec . shallow ) { errToJSON ( validationError , nextErrors ) ; return ; } const fieldErrors = errToJSON ( validationError ) ; Object . assign ( nextErrors , trimChildren ( spec . path , fieldErrors ) ) ; } ) ) ; const results = await Promise . all ( validations ) ; if ( ! workDone && results . every ( Boolean ) ) return pristineErrors ; return nextErrors ; } , } ; }