33import * as React from 'react' ;
44import RefId from 'canner-ref-id' ;
55import Ajv from 'ajv' ;
6- import { isEmpty , isArray , isPlainObject , isFunction , get } from 'lodash' ;
6+ import { isEmpty , isObject , isArray , isPlainObject , isFunction , get } from 'lodash' ;
77import type { HOCProps } from './types' ;
88
99type State = {
1010 error : boolean ,
1111 errorInfo : Array < any >
1212}
1313
14+ const _isRequiredValidation = async ( value ) => {
15+ const valid = Boolean ( value )
16+ return {
17+ error : ! valid ,
18+ errorInfo : ! valid ? [ { message : 'should be required' } ] :[ ]
19+ }
20+ }
21+
22+ const checkValidation = ( validation ) => {
23+ return ( isObject ( validation ) && ! isEmpty ( validation ) )
24+ }
25+
26+ const checkSchema = ( schema ) => {
27+ return ( isObject ( schema ) && ! isEmpty ( schema ) )
28+ }
29+ const checkValidator = ( validator ) => {
30+ return ( isFunction ( validator ) )
31+ }
32+
33+ const _schemaValidation = ( schema , errorMessage ) => {
34+ const ajv = new Ajv ( ) ;
35+ const validate = ajv . compile ( schema ) ;
36+ return async ( value ) => {
37+ try {
38+ const error = ! validate ( value )
39+ const errorInfo = error ? ( { message : errorMessage } || validate . error ) : [ ]
40+ return {
41+ error,
42+ errorInfo
43+ }
44+ }
45+ catch ( err ) {
46+ return {
47+ error : true ,
48+ errorInfo : [ { message : err } ]
49+ }
50+ }
51+
52+ }
53+ }
54+ const _customizedValidator = ( validator ) => async ( value ) => {
55+ try {
56+ const errorMessage = await validator ( value )
57+ return {
58+ error : Boolean ( errorMessage ) ,
59+ errorInfo : [ { message : errorMessage } ]
60+ }
61+ }
62+ catch ( err ) {
63+ return {
64+ error : true ,
65+ errorInfo : [ { message : err } ]
66+ }
67+ }
68+ }
69+
1470export default function withValidation ( Com : React . ComponentType < * > ) {
1571 return class ComponentWithValidation extends React . Component < HOCProps , State > {
1672 key : string ;
@@ -35,52 +91,53 @@ export default function withValidation(Com: React.ComponentType<*>) {
3591 this . removeOnDeploy ( ) ;
3692 }
3793
38- validate = async ( result : any ) => {
39- const { refId, validation = { } , required = false } = this . props ;
40- // required
41- const paths = refId . getPathArr ( ) . slice ( 1 ) ;
42- const { value} = getValueAndPaths ( result . data , paths ) ;
43- const isRequiredValid = required ? Boolean ( value ) : true ;
94+ handleValidationResult = ( results ) => {
4495
45- const { schema , validator , errorMessage } = validation ;
46- let validate = null ;
96+ let error = false ;
97+ let errorInfo = [ ] ;
4798
48- // Ajv validation
49- if ( schema && ! isEmpty ( schema ) ) {
50- const ajv = new Ajv ( ) ;
51- validate = ajv . compile ( schema ) ;
52- }
53- // custom validator
54- const reject = message => ( { error : true , message} ) ;
55- const validatorResult = ( validator && isFunction ( validator ) ) && validator ( value , reject ) ;
56-
57- let customValid = ! ( validatorResult && validatorResult . error ) ;
58-
59- // if value is empty, should not validate with ajv
60- if ( customValid && isRequiredValid && ( ! ( value && isFunction ( validate ) ) || validate ( value ) ) ) {
61- this . setState ( {
62- error : false ,
63- errorInfo : [ ]
64- } ) ;
65- return result ;
99+ for ( let index = 0 ; index < results . length ; index ++ ) {
100+ error = error || results [ index ] . error
101+ errorInfo = errorInfo . concat ( results [ index ] . errorInfo ) ;
66102 }
67-
68-
69- const errorInfo = [ ]
70- . concat ( isRequiredValid ? [ ] : {
71- message : 'should be required'
72- } )
73- . concat ( validate . errors ? ( errorMessage ? { message : errorMessage } : validate . errors ) : [ ] )
74- . concat ( customValid ? [ ] : validatorResult ) ;
75103
76104 this . setState ( {
77- error : true ,
78- errorInfo : errorInfo
105+ error,
106+ errorInfo
79107 } ) ;
108+
109+ return {
110+ error,
111+ errorInfo
112+ }
113+ }
114+
115+ validate = async ( result : any ) => {
116+ const { refId, required = false , validation} = this . props ;
117+ // required
118+ const paths = refId . getPathArr ( ) . slice ( 1 ) ;
119+ const { value} = getValueAndPaths ( result . data , paths ) ;
120+ const promiseQueue = [ ] ;
121+
122+ // check whether value is required in first step
123+ if ( required ) {
124+ promiseQueue . push ( _isRequiredValidation ) ;
125+ }
126+
127+ // skip validation if object validation is undefined or empty
128+ if ( checkValidation ( validation ) ) {
129+ const { schema, errorMessage, validator} = validation ;
130+ if ( checkSchema ( schema ) ) {
131+ promiseQueue . pop ( _schemaValidation ( schema , errorMessage ) ( value ) ) ;
132+ }
133+ if ( checkValidator ( validator ) ) {
134+ promiseQueue . pop ( _customizedValidator ( validator ) ( value ) ) ;
135+ }
136+ }
137+ const ValidationResult = await Promise . all ( promiseQueue ) ;
80138 return {
81139 ...result ,
82- error : true ,
83- errorInfo : errorInfo
140+ ...this . handleValidationResult ( ValidationResult )
84141 }
85142 }
86143
0 commit comments