| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { z } from 'zod'; |
|
|
| |
| |
| |
| |
| |
| |
| export function buildZodSchema(fields) { |
| const shape = {}; |
|
|
| for (const field of fields) { |
| let validator; |
|
|
| switch (field.component) { |
| |
| case 'toggle': { |
| validator = z |
| .number({ invalid_type_error: `${field.title} is required` }) |
| .int() |
| .min(0) |
| .max(1); |
| |
| validator = validator.or(z.literal(0)).or(z.literal(1)); |
| break; |
| } |
|
|
| |
| case 'segmented': { |
| validator = z |
| .number({ invalid_type_error: `${field.title} is required` }) |
| .int() |
| .min(0) |
| .max(1); |
| break; |
| } |
|
|
| |
| case 'select': { |
| if (field.validation.enum && field.validation.enum.length > 0) { |
| |
| const enumValues = field.validation.enum; |
| if (typeof enumValues[0] === 'string') { |
| validator = z.enum(enumValues, { |
| errorMap: () => ({ message: `Select a valid ${field.title}` }), |
| }); |
| } else { |
| validator = z.number().refine( |
| (v) => enumValues.includes(v), |
| { message: `Select a valid ${field.title}` } |
| ); |
| } |
| } else { |
| validator = z.string().min(1, `${field.title} is required`); |
| } |
| break; |
| } |
|
|
| |
| case 'slider': { |
| let numVal = z |
| .number({ invalid_type_error: `${field.title} is required` }) |
| .int(); |
| if (field.validation.minimum !== undefined) { |
| numVal = numVal.min(field.validation.minimum); |
| } |
| if (field.validation.maximum !== undefined) { |
| numVal = numVal.max(field.validation.maximum); |
| } |
| validator = numVal; |
| break; |
| } |
|
|
| |
| case 'number': { |
| |
| |
| let numVal; |
| if (field.type === 'number') { |
| numVal = z.number({ |
| invalid_type_error: `${field.title} must be a number`, |
| }); |
| } else { |
| numVal = z |
| .number({ invalid_type_error: `${field.title} must be a number` }) |
| .int(); |
| } |
| if (field.validation.minimum !== undefined) { |
| numVal = numVal.min(field.validation.minimum, { |
| message: `${field.title} must be β₯ ${field.validation.minimum}`, |
| }); |
| } |
| if (field.validation.maximum !== undefined) { |
| numVal = numVal.max(field.validation.maximum, { |
| message: `${field.title} must be β€ ${field.validation.maximum}`, |
| }); |
| } |
| |
| if (field.type === 'number') { |
| numVal = numVal.or(z.string().transform((v) => parseFloat(v))); |
| } else { |
| numVal = numVal.or(z.string().transform((v) => parseInt(v, 10))); |
| } |
| validator = numVal; |
| break; |
| } |
|
|
| |
| case 'text': |
| default: { |
| validator = z.string().min(1, `${field.title} is required`); |
| break; |
| } |
| } |
|
|
| |
| if (!field.validation.required) { |
| validator = validator.optional(); |
| } |
|
|
| shape[field.name] = validator; |
| } |
|
|
| return z.object(shape); |
| } |
|
|
|
|