import { AbstractControl , ValidationErrors } from '@angular/forms' ; import Ajv from 'ajv' ; import addFormats from 'ajv-formats' ; export class ObSchemaValidatorInstance { private readonly ajv = new Ajv ( { allErrors : true , allowUnionTypes : true } ) ; private readonly schema ; constructor ( schema ) { addFormats ( this . ajv ) ; this . addSchema ( schema ) ; this . schema = schema ; } validate ( propertyPath = '' , value ) { if ( this . hasRequiredError ( propertyPath . split ( '.' ) , value ) ) { return { 'ajv.required' : true } ; } if ( this . ajv . getSchema ( propertyPath ) ) { this . ajv . validate ( propertyPath , value ) ; if ( this . ajv . errors && value != null && value !== '' ) { const key = this . ajv . errors [ 0 ] . keyword === 'format' && this . ajv . errors [ 0 ] . params . format === 'date-time' ? '.date' : '' ; return { [ `ajv.${ this . ajv . errors [ 0 ] . keyword }${ key }` ] : this . ajv . errors [ 0 ] . params } ; } } return null ; } getValidator ( propertyPath ) { return ( control ) => this . validate ( propertyPath , control . value ) ; } isRequired ( property , path ) { let schema = JSON . parse ( JSON . stringify ( this . schema ) ) ; path . forEach ( name => { if ( schema ?. properties [ name ] ) { schema = schema . properties [ name ] ; } } ) ; return ( schema . required || [ ] ) . indexOf ( property ) > - 1 ; } private hasRequiredError ( path , value ) { const propertyName = path . pop ( ) ; return ! value && this . isRequired ( propertyName , path ) ; } private addSchema ( schema , parentPropertyName ? ) { Object . keys ( schema . properties || { } ) . forEach ( propertyName => { const propertyPath = parentPropertyName ? `${ parentPropertyName }.${ propertyName }` : propertyName ; if ( schema . properties [ propertyName ] . properties ) { this . addSchema ( schema . properties [ propertyName ] , propertyPath ) ; } else { this . ajv . addSchema ( schema . properties [ propertyName ] , propertyPath ) ; } } ) ; } }