import { ReactNode } from 'react' ; import { AnySchema as YupSchema , ValidationError as YupValidationError } from 'yup' ; function get ( obj , path , defaultValue ? ) { const result = String . prototype . split . call ( path , /[,[\].]+?/ ) . filter ( Boolean ) . reduce ( ( res , key ) => ( res !== null && res !== undefined ? res [ key ] : res ) , obj ) ; return result === undefined || result === obj ? defaultValue : result ; } function set ( obj , path , value ) { if ( Object ( obj ) !== obj ) return obj ; if ( ! Array . isArray ( path ) ) path = path . toString ( ) . match ( /[^.[\]]+/g ) || [ ] ; path . slice ( 0 , - 1 ) . reduce ( ( a , c , i ) => Object ( a [ c ] ) === a [ c ] ? a [ c ] : ( a [ c ] = Math . abs ( path [ i + 1 ] ) >> 0 === + path [ i + 1 ] ? [ ] : { } ) , obj ) [ path [ path . length - 1 ] ] = value ; return obj ; } export type Translator = ( errorObj : YupValidationError ) => string | ReactNode ; export interface ValidationError { [ key ] : ValidationError | string ; } function normalizeValidationError ( err , translator ? ) { return err . inner . reduce ( ( errors , innerError ) => { const { path , message } = innerError ; const el = translator ? translator ( innerError ) : message ; if ( path && errors . hasOwnProperty ( path ) ) { const prev = get ( errors , path ) ; prev . push ( el ) ; set ( errors , path , prev ) ; } else { set ( errors , path , [ el ] ) ; } return errors ; } , { } ) ; } /**
 * Wraps the execution of a Yup schema to return an Promise<ValidationError>
 * where the key is the form field and the value is the error string.
 */ export function makeValidate < T > ( validator , translator ? ) { return async ( values ) : Promise < ValidationError > => { try { await validator . validate ( values , { abortEarly : false } ) ; return { } ; } catch ( err ) { return normalizeValidationError ( err as YupValidationError , translator ) ; } } ; } /**
 * Wraps the sync execution of a Yup schema to return an ValidationError
 * where the key is the form field and the value is the error string.
 */ export function makeValidateSync < T > ( validator , translator ? ) { return ( values ) : ValidationError => { try { validator . validateSync ( values , { abortEarly : false } ) ; return { } ; } catch ( err ) { return normalizeValidationError ( err as YupValidationError , translator ) ; } } ; } /**
 * Uses the private _exclusive field in the schema to get whether or not
 * the field is marked as required or not.
 */ export function makeRequired < T > ( schema ) { const fields = ( schema as any ) . fields ; return Object . keys ( fields ) . reduce ( ( accu , field ) => { if ( fields [ field ] . fields ) { accu [ field ] = makeRequired ( fields [ field ] ) ; } else { accu [ field ] = ! ! fields [ field ] . exclusiveTests . required ; } return accu ; } , { } as any ) ; }