1
- import { IContext , IValidationOptions , IValidationResult } from "../Interface" ;
1
+ import {
2
+ IContext ,
3
+ ITraverseItem ,
4
+ IValidationOptions ,
5
+ IValidationResult ,
6
+ } from "../Interface" ;
2
7
import { getMessage } from "../Locale" ;
3
8
import { Definition , ValidationResult } from "../Types" ;
4
9
import { toRuleDefinition } from "../Factory" ;
5
- import { getValueViaPath } from "./getValueViaPath" ;
6
10
import { getOptions } from "../Options" ;
7
11
8
12
export const validate = async (
@@ -29,6 +33,65 @@ export const validate = async (
29
33
} ;
30
34
} ;
31
35
36
+ const toTraverseArray = ( data : any , definition : Definition ) => {
37
+ function resolvePath ( data : any , path : string ) {
38
+ const parts = path . split ( "." ) ;
39
+ const result : Array < { path : string ; value : any } > = [ ] ;
40
+
41
+ function traverse (
42
+ current : any ,
43
+ index = 0 ,
44
+ resolvedPath : Array < string | number > = [ ]
45
+ ) {
46
+ if ( index >= parts . length ) {
47
+ result . push ( { path : resolvedPath . join ( "." ) , value : current } ) ;
48
+ return ;
49
+ }
50
+
51
+ const part = parts [ index ] ;
52
+
53
+ if ( part === "*" ) {
54
+ if ( Array . isArray ( current ) ) {
55
+ current . forEach ( ( item , i ) => {
56
+ traverse ( item , index + 1 , [ ...resolvedPath , i ] ) ;
57
+ } ) ;
58
+ } else if ( current && typeof current === "object" ) {
59
+ Object . keys ( current ) . forEach ( ( key ) => {
60
+ traverse ( current [ key ] , index + 1 , [ ...resolvedPath , key ] ) ;
61
+ } ) ;
62
+ } else {
63
+ result . push ( {
64
+ path : [ ...resolvedPath , "*" ] . join ( "." ) ,
65
+ value : current ,
66
+ } ) ;
67
+ }
68
+ } else {
69
+ if ( current && typeof current === "object" && part in current ) {
70
+ traverse ( current [ part ] , index + 1 , [ ...resolvedPath , part ] ) ;
71
+ } else {
72
+ result . push ( {
73
+ path : [ ...resolvedPath , part ] . join ( "." ) ,
74
+ value : undefined ,
75
+ } ) ;
76
+ }
77
+ }
78
+ }
79
+
80
+ traverse ( data ) ;
81
+ return result ;
82
+ }
83
+
84
+ const checks : ITraverseItem [ ] = [ ] ;
85
+
86
+ // Example usage
87
+ Object . entries ( definition ) . forEach ( ( [ path , rules ] ) => {
88
+ const resolved = resolvePath ( data , path ) ;
89
+ checks . push ( { path, rules, resolved } ) ;
90
+ } ) ;
91
+
92
+ return checks ;
93
+ } ;
94
+
32
95
const getResults = async (
33
96
data : any ,
34
97
definition : Definition ,
@@ -38,69 +101,63 @@ const getResults = async (
38
101
const fields : Record < string , boolean > = { } ;
39
102
const results : ValidationResult = { } ;
40
103
41
- // Checking all validations
42
- for ( const field in definition ) {
43
- fields [ field ] = true ;
44
- // Parsing the rules
45
- const params = definition [ field ] ;
46
- let ruleGroup : string = "" ;
47
- if ( Array . isArray ( params ) ) {
48
- ruleGroup = params . join ( "|" ) ;
49
- } else {
50
- ruleGroup = params ;
51
- }
104
+ const traverse = toTraverseArray ( data , definition ) ;
52
105
53
- const rules = toRuleNameArray ( ruleGroup ) . map ( toRuleDefinition ) ;
106
+ for ( const item of traverse ) {
107
+ const { path, rules, resolved } = item ;
108
+ fields [ path ] = true ;
54
109
55
- // Getting the value by the path
56
- const value = getValueViaPath ( data , field ) ;
110
+ const rulesAsString = Array . isArray ( rules ) ? rules . join ( "|" ) : rules ;
111
+
112
+ const ruleDefinitions =
113
+ toRuleNameArray ( rulesAsString ) . map ( toRuleDefinition ) ;
57
114
58
115
const context : IContext = {
59
116
data,
60
- field,
61
- definition : ruleGroup ,
117
+ field : path ,
118
+ definition : rulesAsString ,
62
119
} ;
63
120
64
- // Checking all rules one by one
65
- for ( const rule of rules ) {
66
- // If the value is empty but the rule is not required, we don't execute
67
- // the rules
68
- if ( rule . name !== "required" && ( value === null || value === undefined ) ) {
69
- continue ;
70
- }
71
-
72
- // Calling the rule function with the validation parameters
73
- const isRuleValid = await rule . callback (
74
- value ,
75
- ...[ ...rule . params , context ]
76
- ) ;
77
-
78
- // Is the value valid?
79
- if ( isRuleValid === false ) {
80
- if ( ! results [ field ] ) {
81
- results [ field ] = [ ] ;
121
+ for ( const check of resolved ) {
122
+ // Checking all rules one by one
123
+ for ( const rule of ruleDefinitions ) {
124
+ // If the value is empty but the rule is not required, we don't execute
125
+ // the rules
126
+ if (
127
+ rule . name !== "required" &&
128
+ ( check . value === null || check . value === undefined )
129
+ ) {
130
+ continue ;
82
131
}
83
-
84
- isValid = false ;
85
- fields [ field ] = false ;
86
-
87
- // Setting the rule and the error message
88
- results [ field ] . push ( {
89
- rule : rule . name ,
90
- message : getMessage (
91
- rule . name ,
92
- rule . params ,
93
- options . language ,
94
- options . translations || { }
95
- ) ,
96
- } ) ;
97
-
98
- if ( options . stopOnFail ) {
99
- return {
100
- isValid : false ,
101
- fields,
102
- results,
103
- } ;
132
+ // Calling the rule function with the validation parameters
133
+ const isRuleValid = await rule . callback (
134
+ check . value ,
135
+ ...[ ...rule . params , context ]
136
+ ) ;
137
+ // Is the value valid?
138
+ if ( isRuleValid === false ) {
139
+ if ( ! results [ check . path ] ) {
140
+ results [ check . path ] = [ ] ;
141
+ }
142
+ isValid = false ;
143
+ fields [ path ] = false ;
144
+ // Setting the rule and the error message
145
+ results [ check . path ] . push ( {
146
+ rule : rule . name ,
147
+ message : getMessage (
148
+ rule . name ,
149
+ rule . params ,
150
+ options . language ,
151
+ options . translations || { }
152
+ ) ,
153
+ } ) ;
154
+ if ( options . stopOnFail ) {
155
+ return {
156
+ isValid : false ,
157
+ fields,
158
+ results,
159
+ } ;
160
+ }
104
161
}
105
162
}
106
163
}
@@ -114,5 +171,9 @@ const getResults = async (
114
171
} ;
115
172
116
173
const toRuleNameArray = ( rules : string ) : string [ ] => {
174
+ if ( Array . isArray ( rules ) ) {
175
+ return rules ;
176
+ }
177
+
117
178
return rules . split ( "|" ) ;
118
179
} ;
0 commit comments