import { z } from 'zod'; import axios from 'axios'; interface ValidationMessages { required: string; invalid_type: string; invalid_string: Record; too_small: Record; too_big: Record; invalid_date: string; invalid_enum: string; custom: Record; } interface SchemaField { type: string; items?: string; values?: any[]; validations?: Record; } interface SchemaDefinition { name: string; fields: Record; messages: ValidationMessages; } class UnifiedSchemaBuilder { private static instance: UnifiedSchemaBuilder; private schemaCache: Map = new Map(); private constructor() {} static getInstance(): UnifiedSchemaBuilder { if (!UnifiedSchemaBuilder.instance) { UnifiedSchemaBuilder.instance = new UnifiedSchemaBuilder(); } return UnifiedSchemaBuilder.instance; } async getSchema(modelName: string): Promise { // Check cache first if (this.schemaCache.has(modelName)) { return this.schemaCache.get(modelName)!; } // Fetch schema definition with messages from backend const response = await axios.get( `/api/schema/model/${modelName}`, { headers: { 'Accept-Language': navigator.language || 'tr' } } ); const schema = this.buildSchema(response.data); this.schemaCache.set(modelName, schema); return schema; } private buildSchema(definition: SchemaDefinition): z.ZodSchema { const shape: Record = {}; for (const [fieldName, field] of Object.entries(definition.fields)) { shape[fieldName] = this.buildField(field, definition.messages); } return z.object(shape); } private buildField( field: SchemaField, messages: ValidationMessages ): z.ZodTypeAny { let zodField: z.ZodTypeAny; switch (field.type) { case 'string': zodField = z.string({ required_error: messages.required, invalid_type_error: messages.invalid_type }); break; case 'email': zodField = z.string().email(messages.invalid_string.email); break; case 'number': zodField = z.number({ required_error: messages.required, invalid_type_error: messages.invalid_type }); break; case 'boolean': zodField = z.boolean({ required_error: messages.required, invalid_type_error: messages.invalid_type }); break; case 'date': zodField = z.date({ required_error: messages.required, invalid_type_error: messages.invalid_date }); break; case 'array': zodField = z.array( this.buildField({ type: field.items! }, messages) ); break; case 'enum': zodField = z.enum(field.values as [string, ...string[]], { required_error: messages.required, invalid_type_error: messages.invalid_enum }); break; default: zodField = z.any(); } // Apply validations if any if (field.validations) { zodField = this.applyValidations(zodField, field.validations, messages); } return zodField; } private applyValidations( field: z.ZodTypeAny, validations: Record, messages: ValidationMessages ): z.ZodTypeAny { let result = field; if ('min_length' in validations) { result = (result as z.ZodString).min( validations.min_length, messages.too_small.string.replace( '{min}', validations.min_length.toString() ) ); } if ('max_length' in validations) { result = (result as z.ZodString).max( validations.max_length, messages.too_big.string.replace( '{max}', validations.max_length.toString() ) ); } if ('pattern' in validations) { result = (result as z.ZodString).regex( new RegExp(validations.pattern), messages.custom[validations.pattern_message] || 'Invalid format' ); } if ('gt' in validations) { result = (result as z.ZodNumber).gt( validations.gt, messages.too_small.number.replace( '{min}', (validations.gt + 1).toString() ) ); } if ('lt' in validations) { result = (result as z.ZodNumber).lt( validations.lt, messages.too_big.number.replace( '{max}', (validations.lt - 1).toString() ) ); } return result; } } // Export singleton instance export const schemaBuilder = UnifiedSchemaBuilder.getInstance(); // Usage example: /* import { schemaBuilder } from './validation/unifiedSchemaBuilder'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; function UserForm() { const [schema, setSchema] = useState(null); useEffect(() => { async function loadSchema() { const userSchema = await schemaBuilder.getSchema('User'); setSchema(userSchema); } loadSchema(); }, []); const form = useForm({ resolver: schema ? zodResolver(schema) : undefined }); if (!schema) return
Loading...
; return (
console.log(data))}> {/* Your form fields */}
); } */