import JSON5 from 'json5'; import type { JsonValue } from 'type-fest'; import { z } from 'zod'; export function looseArray( schema: T, catchCallback?: () => void ): z.ZodEffects< z.ZodCatch>, 'many'>>, z.TypeOf[], unknown > { type Elem = z.infer; const nullableSchema = schema.nullable().catch( catchCallback ? () => { catchCallback(); return null; } : null ); const arrayOfNullables = z.array(nullableSchema); const arrayWithFallback = catchCallback ? arrayOfNullables.catch(() => { catchCallback(); return []; }) : arrayOfNullables.catch([]); const filteredArray = arrayWithFallback.transform((xs) => xs.filter((x): x is Elem => x !== null) ); return filteredArray; } export function looseRecord( schema: T, catchCallback?: () => void ): z.ZodEffects< z.ZodCatch>>>, Record>, unknown > { type Elem = z.infer; const nullableSchema = schema.nullable().catch( catchCallback ? () => { catchCallback(); return null; } : null ); const recordOfNullables = z.record(nullableSchema); const recordWithFallback = catchCallback ? recordOfNullables.catch(() => { catchCallback(); return {}; }) : recordOfNullables.catch({}); const filteredRecord = recordWithFallback.transform( (rec): Record => { for (const key of Object.keys(rec)) { if (rec[key] === null) { delete rec[key]; } } return rec; } ); return filteredRecord; } export function looseValue( schema: z.ZodType, catchCallback?: () => void ): z.ZodCatch>> { const nullableSchema = schema.nullable(); const schemaWithFallback = catchCallback ? nullableSchema.catch(() => { catchCallback(); return null; }) : nullableSchema.catch(null); return schemaWithFallback; } export const Json = z.string().transform((str, ctx): JsonValue => { try { return JSON.parse(str); } catch (e) { ctx.addIssue({ code: 'custom', message: 'Invalid JSON' }); return z.NEVER; } }); type Json = z.infer; export const Json5 = z.string().transform((str, ctx): JsonValue => { try { return JSON5.parse(str); } catch (e) { ctx.addIssue({ code: 'custom', message: 'Invalid JSON5' }); return z.NEVER; } });