1- import { z } from " zod" ;
2- import type { DynamicValue , DataModel , LogicExpression } from " ./types" ;
3- import { DynamicValueSchema , resolveDynamicValue } from " ./types" ;
4- import { LogicExpressionSchema , evaluateLogicExpression } from " ./visibility" ;
1+ import { z } from ' zod' ;
2+ import type { DynamicValue , DataModel , LogicExpression } from ' ./types' ;
3+ import { DynamicValueSchema , resolveDynamicValue } from ' ./types' ;
4+ import { LogicExpressionSchema , evaluateLogicExpression } from ' ./visibility' ;
55
66/**
77 * Validation check definition
@@ -22,7 +22,7 @@ export interface ValidationConfig {
2222 /** Array of checks to run */
2323 checks ?: ValidationCheck [ ] ;
2424 /** When to run validation */
25- validateOn ?: " change" | " blur" | " submit" ;
25+ validateOn ?: ' change' | ' blur' | ' submit' ;
2626 /** Condition for when validation is enabled */
2727 enabled ?: LogicExpression ;
2828}
@@ -41,7 +41,7 @@ export const ValidationCheckSchema = z.object({
4141 */
4242export const ValidationConfigSchema = z . object ( {
4343 checks : z . array ( ValidationCheckSchema ) . optional ( ) ,
44- validateOn : z . enum ( [ " change" , " blur" , " submit" ] ) . optional ( ) ,
44+ validateOn : z . enum ( [ ' change' , ' blur' , ' submit' ] ) . optional ( ) ,
4545 enabled : LogicExpressionSchema . optional ( ) ,
4646} ) ;
4747
@@ -50,7 +50,7 @@ export const ValidationConfigSchema = z.object({
5050 */
5151export type ValidationFunction = (
5252 value : unknown ,
53- args ?: Record < string , unknown > ,
53+ args ?: Record < string , unknown >
5454) => boolean ;
5555
5656/**
@@ -72,7 +72,7 @@ export const builtInValidationFunctions: Record<string, ValidationFunction> = {
7272 */
7373 required : ( value : unknown ) => {
7474 if ( value === null || value === undefined ) return false ;
75- if ( typeof value === " string" ) return value . trim ( ) . length > 0 ;
75+ if ( typeof value === ' string' ) return value . trim ( ) . length > 0 ;
7676 if ( Array . isArray ( value ) ) return value . length > 0 ;
7777 return true ;
7878 } ,
@@ -81,37 +81,49 @@ export const builtInValidationFunctions: Record<string, ValidationFunction> = {
8181 * Check if value is a valid email address
8282 */
8383 email : ( value : unknown ) => {
84- if ( typeof value !== " string" ) return false ;
84+ if ( typeof value !== ' string' ) return false ;
8585 return / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / . test ( value ) ;
8686 } ,
8787
8888 /**
8989 * Check minimum string length
9090 */
9191 minLength : ( value : unknown , args ?: Record < string , unknown > ) => {
92- if ( typeof value !== " string" ) return false ;
92+ if ( typeof value !== ' string' ) return false ;
9393 const min = args ?. min ;
94- if ( typeof min !== "number" ) return false ;
94+ if ( min === undefined ) {
95+ console . warn ( 'minLength validation requires a min argument' ) ;
96+ return false ;
97+ }
98+ if ( typeof min !== 'number' ) return false ;
9599 return value . length >= min ;
96100 } ,
97101
98102 /**
99103 * Check maximum string length
100104 */
101105 maxLength : ( value : unknown , args ?: Record < string , unknown > ) => {
102- if ( typeof value !== " string" ) return false ;
106+ if ( typeof value !== ' string' ) return false ;
103107 const max = args ?. max ;
104- if ( typeof max !== "number" ) return false ;
108+ if ( max === undefined ) {
109+ console . warn ( 'maxLength validation requires a max argument' ) ;
110+ return false ;
111+ }
112+ if ( typeof max !== 'number' ) return false ;
105113 return value . length <= max ;
106114 } ,
107115
108116 /**
109117 * Check if string matches a regex pattern
110118 */
111119 pattern : ( value : unknown , args ?: Record < string , unknown > ) => {
112- if ( typeof value !== " string" ) return false ;
120+ if ( typeof value !== ' string' ) return false ;
113121 const pattern = args ?. pattern ;
114- if ( typeof pattern !== "string" ) return false ;
122+ if ( pattern === undefined ) {
123+ console . warn ( 'pattern validation requires a pattern argument' ) ;
124+ return false ;
125+ }
126+ if ( typeof pattern !== 'string' ) return false ;
115127 try {
116128 return new RegExp ( pattern ) . test ( value ) ;
117129 } catch {
@@ -123,36 +135,44 @@ export const builtInValidationFunctions: Record<string, ValidationFunction> = {
123135 * Check minimum numeric value
124136 */
125137 min : ( value : unknown , args ?: Record < string , unknown > ) => {
126- if ( typeof value !== " number" ) return false ;
138+ if ( typeof value !== ' number' ) return false ;
127139 const min = args ?. min ;
128- if ( typeof min !== "number" ) return false ;
140+ if ( min === undefined ) {
141+ console . warn ( 'min validation requires a value argument' ) ;
142+ return false ;
143+ }
144+ if ( typeof min !== 'number' ) return false ;
129145 return value >= min ;
130146 } ,
131147
132148 /**
133149 * Check maximum numeric value
134150 */
135151 max : ( value : unknown , args ?: Record < string , unknown > ) => {
136- if ( typeof value !== " number" ) return false ;
152+ if ( typeof value !== ' number' ) return false ;
137153 const max = args ?. max ;
138- if ( typeof max !== "number" ) return false ;
154+ if ( max === undefined ) {
155+ console . warn ( 'max validation requires a value argument' ) ;
156+ return false ;
157+ }
158+ if ( typeof max !== 'number' ) return false ;
139159 return value <= max ;
140160 } ,
141161
142162 /**
143163 * Check if value is a number
144164 */
145165 numeric : ( value : unknown ) => {
146- if ( typeof value === " number" ) return ! isNaN ( value ) ;
147- if ( typeof value === " string" ) return ! isNaN ( parseFloat ( value ) ) ;
166+ if ( typeof value === ' number' ) return ! isNaN ( value ) ;
167+ if ( typeof value === ' string' ) return ! isNaN ( parseFloat ( value ) ) ;
148168 return false ;
149169 } ,
150170
151171 /**
152172 * Check if value is a valid URL
153173 */
154174 url : ( value : unknown ) => {
155- if ( typeof value !== " string" ) return false ;
175+ if ( typeof value !== ' string' ) return false ;
156176 try {
157177 new URL ( value ) ;
158178 return true ;
@@ -166,6 +186,10 @@ export const builtInValidationFunctions: Record<string, ValidationFunction> = {
166186 */
167187 matches : ( value : unknown , args ?: Record < string , unknown > ) => {
168188 const other = args ?. other ;
189+ if ( other === undefined ) {
190+ console . warn ( 'matches validation requires a value argument' ) ;
191+ return false ;
192+ }
169193 return value === other ;
170194 } ,
171195} ;
@@ -205,7 +229,7 @@ export interface ValidationContext {
205229 */
206230export function runValidationCheck (
207231 check : ValidationCheck ,
208- ctx : ValidationContext ,
232+ ctx : ValidationContext
209233) : ValidationCheckResult {
210234 const { value, dataModel, customFunctions } = ctx ;
211235
@@ -244,7 +268,7 @@ export function runValidationCheck(
244268 */
245269export function runValidation (
246270 config : ValidationConfig ,
247- ctx : ValidationContext & { authState ?: { isSignedIn : boolean } } ,
271+ ctx : ValidationContext & { authState ?: { isSignedIn : boolean } }
248272) : ValidationResult {
249273 const checks : ValidationCheckResult [ ] = [ ] ;
250274 const errors : string [ ] = [ ] ;
@@ -282,56 +306,56 @@ export function runValidation(
282306 * Helper to create validation checks
283307 */
284308export const check = {
285- required : ( message = " This field is required" ) : ValidationCheck => ( {
286- fn : " required" ,
309+ required : ( message = ' This field is required' ) : ValidationCheck => ( {
310+ fn : ' required' ,
287311 message,
288312 } ) ,
289313
290- email : ( message = " Invalid email address" ) : ValidationCheck => ( {
291- fn : " email" ,
314+ email : ( message = ' Invalid email address' ) : ValidationCheck => ( {
315+ fn : ' email' ,
292316 message,
293317 } ) ,
294318
295319 minLength : ( min : number , message ?: string ) : ValidationCheck => ( {
296- fn : " minLength" ,
320+ fn : ' minLength' ,
297321 args : { min } ,
298322 message : message ?? `Must be at least ${ min } characters` ,
299323 } ) ,
300324
301325 maxLength : ( max : number , message ?: string ) : ValidationCheck => ( {
302- fn : " maxLength" ,
326+ fn : ' maxLength' ,
303327 args : { max } ,
304328 message : message ?? `Must be at most ${ max } characters` ,
305329 } ) ,
306330
307- pattern : ( pattern : string , message = " Invalid format" ) : ValidationCheck => ( {
308- fn : " pattern" ,
331+ pattern : ( pattern : string , message = ' Invalid format' ) : ValidationCheck => ( {
332+ fn : ' pattern' ,
309333 args : { pattern } ,
310334 message,
311335 } ) ,
312336
313337 min : ( min : number , message ?: string ) : ValidationCheck => ( {
314- fn : " min" ,
338+ fn : ' min' ,
315339 args : { min } ,
316340 message : message ?? `Must be at least ${ min } ` ,
317341 } ) ,
318342
319343 max : ( max : number , message ?: string ) : ValidationCheck => ( {
320- fn : " max" ,
344+ fn : ' max' ,
321345 args : { max } ,
322346 message : message ?? `Must be at most ${ max } ` ,
323347 } ) ,
324348
325- url : ( message = " Invalid URL" ) : ValidationCheck => ( {
326- fn : " url" ,
349+ url : ( message = ' Invalid URL' ) : ValidationCheck => ( {
350+ fn : ' url' ,
327351 message,
328352 } ) ,
329353
330354 matches : (
331355 otherPath : string ,
332- message = " Fields must match" ,
356+ message = ' Fields must match'
333357 ) : ValidationCheck => ( {
334- fn : " matches" ,
358+ fn : ' matches' ,
335359 args : { other : { path : otherPath } } ,
336360 message,
337361 } ) ,
0 commit comments