@@ -39,6 +39,7 @@ export type Validate<
3939
4040const effectMapCache = new WeakMap < object , boolean > ( ) ;
4141
42+ // @DCI -context
4243export async function validateField < T extends AnyZodObject , M > (
4344 path : string [ ] ,
4445 formOptions : FormOptions < T , M > ,
@@ -47,10 +48,48 @@ export async function validateField<T extends AnyZodObject, M>(
4748 Tainted : SuperForm < T , M > [ 'tainted' ] ,
4849 options : ValidateOptions < unknown > = { }
4950) : Promise < string [ ] | undefined > {
51+ function Errors_clear ( ) {
52+ clearErrors ( Errors , { undefinePath : path , clearFormLevelErrors : true } ) ;
53+ }
54+
55+ function Errors_update ( errorMsgs : null | undefined | string | string [ ] ) {
56+ if ( typeof errorMsgs === 'string' ) errorMsgs = [ errorMsgs ] ;
57+
58+ if ( options . update === true || options . update == 'errors' ) {
59+ Errors . update ( ( errors ) => {
60+ const error = traversePath (
61+ errors ,
62+ path as FieldPath < typeof errors > ,
63+ ( node ) => {
64+ if ( isInvalidPath ( path , node ) ) {
65+ throw new SuperFormError (
66+ 'Errors can only be added to form fields, not to arrays or objects in the schema. Path: ' +
67+ node . path . slice ( 0 , - 1 )
68+ ) ;
69+ } else if ( node . value === undefined ) {
70+ node . parent [ node . key ] = { } ;
71+ return node . parent [ node . key ] ;
72+ } else {
73+ return node . value ;
74+ }
75+ }
76+ ) ;
77+
78+ if ( ! error )
79+ throw new SuperFormError (
80+ 'Error path could not be created: ' + path
81+ ) ;
82+
83+ error . parent [ error . key ] = errorMsgs ?? undefined ;
84+ return errors ;
85+ } ) ;
86+ }
87+ return errorMsgs ?? undefined ;
88+ }
89+
5090 const errors = await _validateField (
5191 path ,
5292 formOptions . validators ,
53- formOptions . defaultValidator ,
5493 data ,
5594 Errors ,
5695 Tainted ,
@@ -61,7 +100,6 @@ export async function validateField<T extends AnyZodObject, M>(
61100 const delayedErrors = await _validateField (
62101 path ,
63102 formOptions . delayedValidators ,
64- formOptions . defaultValidator ,
65103 data ,
66104 Errors ,
67105 Tainted ,
@@ -71,11 +109,20 @@ export async function validateField<T extends AnyZodObject, M>(
71109 return delayedErrors . errors ;
72110 }
73111
74- // We validated the whole data structure, so clear all errors on success after delayed validators.
75- // but also set the current path to undefined, so it will be used in the tainted+error
76- // check in oninput.
77- if ( errors . validatedAll && ! errors . errors ) {
78- clearErrors ( Errors , { undefinePath : path , clearFormLevelErrors : true } ) ;
112+ if ( errors . validated ) {
113+ if ( errors . validated === 'all' && ! errors . errors ) {
114+ // We validated the whole data structure, so clear all errors on success after delayed validators.
115+ // it will also set the current path to undefined, so it can be used in
116+ // the tainted+error check in oninput.
117+ Errors_clear ( ) ;
118+ } else {
119+ return Errors_update ( errors . errors ) ;
120+ }
121+ } else if (
122+ errors . validated === false &&
123+ formOptions . defaultValidator == 'clear'
124+ ) {
125+ return Errors_update ( undefined ) ;
79126 }
80127
81128 return errors . errors ;
@@ -87,14 +134,14 @@ async function _validateField<T extends AnyZodObject, M>(
87134 validators :
88135 | FormOptions < T , M > [ 'validators' ]
89136 | FormOptions < T , M > [ 'delayedValidators' ] ,
90- defaultValidator : FormOptions < T , M > [ 'defaultValidator' ] ,
91137 data : SuperForm < T , M > [ 'form' ] ,
92138 Errors : SuperForm < T , M > [ 'errors' ] ,
93139 Tainted : SuperForm < T , M > [ 'tainted' ] ,
94140 options : ValidateOptions < unknown > = { }
95- ) : Promise < { validatedAll : boolean ; errors : string [ ] | undefined } > {
141+ ) : Promise < { validated : boolean | 'all' ; errors : string [ ] | undefined } > {
96142 if ( options . update === undefined ) options . update = true ;
97143 if ( options . taint === undefined ) options . taint = false ;
144+ if ( typeof options . errors == 'string' ) options . errors = [ options . errors ] ;
98145
99146 const Context = {
100147 value : options . value ,
@@ -105,10 +152,7 @@ async function _validateField<T extends AnyZodObject, M>(
105152 } ;
106153
107154 async function defaultValidate ( ) {
108- if ( defaultValidator == 'clear' ) {
109- Errors_update ( undefined ) ;
110- }
111- return undefined ;
155+ return { validated : false , errors : undefined } as const ;
112156 }
113157
114158 function extractValidator (
@@ -159,40 +203,7 @@ async function _validateField<T extends AnyZodObject, M>(
159203 return mapErrors ( errors . format ( ) ) ;
160204 }
161205
162- function Errors_update ( errorMsgs : null | undefined | string | string [ ] ) {
163- if ( typeof errorMsgs === 'string' ) errorMsgs = [ errorMsgs ] ;
164-
165- if ( options . update === true || options . update == 'errors' ) {
166- Errors . update ( ( errors ) => {
167- const error = traversePath (
168- errors ,
169- path as FieldPath < typeof errors > ,
170- ( node ) => {
171- if ( isInvalidPath ( path , node ) ) {
172- throw new SuperFormError (
173- 'Errors can only be added to form fields, not to arrays or objects in the schema. Path: ' +
174- node . path . slice ( 0 , - 1 )
175- ) ;
176- } else if ( node . value === undefined ) {
177- node . parent [ node . key ] = { } ;
178- return node . parent [ node . key ] ;
179- } else {
180- return node . value ;
181- }
182- }
183- ) ;
184-
185- if ( ! error )
186- throw new SuperFormError (
187- 'Error path could not be created: ' + path
188- ) ;
189-
190- error . parent [ error . key ] = errorMsgs ?? undefined ;
191- return errors ;
192- } ) ;
193- }
194- return errorMsgs ?? undefined ;
195- }
206+ ///////////////////////////////////////////////////////////////////
196207
197208 if ( ! ( 'value' in options ) ) {
198209 // Use value from data
@@ -220,7 +231,7 @@ async function _validateField<T extends AnyZodObject, M>(
220231 //console.log('🚀 ~ file: index.ts:871 ~ validate:', path, value);
221232
222233 if ( typeof validators !== 'object' ) {
223- return { validatedAll : false , errors : await defaultValidate ( ) } ;
234+ return defaultValidate ( ) ;
224235 }
225236
226237 if ( 'safeParseAsync' in validators ) {
@@ -270,11 +281,11 @@ async function _validateField<T extends AnyZodObject, M>(
270281 if ( ! result . success ) {
271282 const errors = result . error . format ( ) ;
272283 return {
273- validatedAll : false ,
274- errors : Errors_update ( errors . _errors )
284+ validated : true ,
285+ errors : errors . _errors
275286 } ;
276287 } else {
277- return { validatedAll : false , errors : Errors_update ( undefined ) } ;
288+ return { validated : true , errors : undefined } ;
278289 }
279290 }
280291 }
@@ -293,13 +304,13 @@ async function _validateField<T extends AnyZodObject, M>(
293304 ) ;
294305
295306 if ( ! result . success ) {
307+ let currentErrors : ValidationErrors < UnwrapEffects < T > > = { } ;
296308 const newErrors = Errors_fromZod ( result . error ) ;
297309
298310 if ( options . update === true || options . update == 'errors' ) {
299311 // Set errors for other (tainted) fields, that may have been changed
300312 const taintedFields = get ( Tainted ) ;
301- const currentErrors = Errors_get ( ) ;
302- let updated = false ;
313+ currentErrors = Errors_get ( ) ;
303314
304315 // Special check for form level errors
305316 if ( currentErrors . _errors !== newErrors . _errors ) {
@@ -309,20 +320,18 @@ async function _validateField<T extends AnyZodObject, M>(
309320 currentErrors . _errors . join ( '' ) != newErrors . _errors . join ( '' )
310321 ) {
311322 currentErrors . _errors = newErrors . _errors ;
312- updated = true ;
313323 }
314324 }
315325
316326 traversePaths ( newErrors , ( pathData ) => {
317327 if ( ! Array . isArray ( pathData . value ) ) return ;
318328 if ( Tainted_isPathTainted ( pathData . path , taintedFields ) ) {
319329 setPaths ( currentErrors , [ pathData . path ] , pathData . value ) ;
320- updated = true ;
321330 }
322331 return 'skip' ;
323332 } ) ;
324333
325- if ( updated ) Errors_set ( currentErrors ) ;
334+ Errors_set ( currentErrors ) ;
326335 }
327336
328337 // Finally, set errors for the specific field
@@ -334,11 +343,11 @@ async function _validateField<T extends AnyZodObject, M>(
334343 ) ;
335344
336345 return {
337- validatedAll : true ,
338- errors : Errors_update ( options . errors ?? current ?. value )
346+ validated : true ,
347+ errors : options . errors ?? current ?. value
339348 } ;
340349 } else {
341- return { validatedAll : true , errors : undefined } ;
350+ return { validated : true , errors : undefined } ;
342351 }
343352 } else {
344353 // SuperForms validator
@@ -353,12 +362,15 @@ async function _validateField<T extends AnyZodObject, M>(
353362 throw new SuperFormError ( 'No Superforms validator found: ' + path ) ;
354363 } else if ( validator . value === undefined ) {
355364 // No validator, use default
356- return { validatedAll : false , errors : await defaultValidate ( ) } ;
365+ return defaultValidate ( ) ;
357366 } else {
358- const result = await validator . value ( Context . value ) ;
367+ const result = ( await validator . value ( Context . value ) ) as
368+ | string [ ]
369+ | undefined ;
370+
359371 return {
360- validatedAll : false ,
361- errors : Errors_update ( result ? options . errors ?? result : result )
372+ validated : true ,
373+ errors : result ? options . errors ?? result : result
362374 } ;
363375 }
364376 }
0 commit comments