import { ImplStatic, TraitInstance, TraitStaticMembers, trait } from "@thilawyn/traitify-ts" import { Class, Jsonifiable } from "type-fest" import { z } from "zod" import { parseZodSchemaEffect } from "../util" import { ZodSchemaObjectTrait } from "./ZodSchemaObject" export type OfClass< Instance extends OfClassInstance, T extends z.ZodRawShape, Catchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, > = ( Class & TraitStaticMembers> ) export type OfClassInstance< T extends z.ZodRawShape, Catchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, > = ( Values & TraitInstance> ) export const JsonifiedZodSchemaObject = < Of extends OfClass, OfInstance extends OfClassInstance, T extends z.ZodRawShape, Catchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, JsonifyT extends z.ZodRawShape, JsonifyCatchall extends z.ZodTypeAny, DejsonifyT extends z.ZodRawShape, DejsonifyCatchall extends z.ZodTypeAny, JsonifiedValues extends object & Jsonifiable, >( of: Of | OfClass, props: { jsonifySchema: ( schema: typeof of.schema ) => z.ZodObject, dejsonifySchema: ( schema: typeof of.schema ) => z.ZodObject, }, ) => trait .implement(Super => class JsonifiedZodSchemaObjectImpl extends Super { declare ["constructor"]: typeof JsonifiedZodSchemaObjectImpl static readonly of = of as Of static readonly jsonifySchema = props.jsonifySchema(of.schema) static readonly dejsonifySchema = props.dejsonifySchema(of.schema) static pipeSchemaIntoInstance< Instance extends JsonifiedValues, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, SchemaOutput extends JsonifiedValues, SchemaInput, >( this: Class, schema: z.ZodObject, ) { return schema.transform(values => new this(values)) } static jsonify< Instance extends JsonifiedValues >( this: ( Class & ImplStatic ), values: Values, params?: Partial, ) { return this .pipeSchemaIntoInstance(this.jsonifySchema) .parse(values, params) } static jsonifyPromise< Instance extends JsonifiedValues >( this: ( Class & ImplStatic ), values: Values, params?: Partial, ) { return this .pipeSchemaIntoInstance(this.jsonifySchema) .parseAsync(values, params) } static jsonifyEffect< Instance extends JsonifiedValues >( this: ( Class & ImplStatic ), values: Values, params?: Partial, ) { return parseZodSchemaEffect( this.pipeSchemaIntoInstance(this.jsonifySchema), values, params, ) } dejsonify(params?: Partial) { return this.constructor.of.pipeSchemaIntoInstance( this.constructor.dejsonifySchema ).parse(this, params) } dejsonifyPromise(params?: Partial) { return this.constructor.of.pipeSchemaIntoInstance( this.constructor.dejsonifySchema ).parseAsync(this, params) } dejsonifyEffect(params?: Partial) { return parseZodSchemaEffect(this.constructor.dejsonifySchema, this, params) } }) .build()