import { implStaticInstantiableThis, trait } from "@thilawyn/traitify-ts" import { Class, HasRequiredKeys } from "type-fest" import { z } from "zod" import { parseZodSchemaEffect, stripZodObjectDefaults } from "../util" type CreateArgs = ( HasRequiredKeys extends true ? [values: Input, params?: Partial] : [] | [values: Input, params?: Partial] ) export const ZodSchemaObject = < T extends z.ZodRawShape, Catchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, >( schemaWithDefaults: z.ZodObject, ) => trait .implement(Super => { class ZodSchemaObjectImpl extends Super { static readonly schema = stripZodObjectDefaults(schemaWithDefaults) static readonly schemaWithDefaults = schemaWithDefaults static pipeSchemaIntoInstance< Instance extends Values, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, SchemaOutput extends Values, SchemaInput, >( this: Class, schema: z.ZodObject, ) { return schema.transform(values => new this(values)) } static pipeInstanceIntoSchema< Self extends Class, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, SchemaOutput, SchemaInput extends Values, >( this: Self, schema: z.ZodObject, ) { return z.instanceof(this).pipe(schema) } static create< Instance extends Values >( this: Class, ...[values, params]: CreateArgs ) { const t = implStaticInstantiableThis(ZodSchemaObjectImpl, this) return t .pipeSchemaIntoInstance(t.schemaWithDefaults) .parse(values, params) } static createPromise< Instance extends Values >( this: Class, ...[values, params]: CreateArgs ) { const t = implStaticInstantiableThis(ZodSchemaObjectImpl, this) return t .pipeSchemaIntoInstance(t.schemaWithDefaults) .parseAsync(values, params) } static createEffect< Instance extends Values >( this: Class, ...[values, params]: CreateArgs ) { const t = implStaticInstantiableThis(ZodSchemaObjectImpl, this) return parseZodSchemaEffect( t.pipeSchemaIntoInstance(t.schemaWithDefaults), values, params, ) } } return ZodSchemaObjectImpl }) .build() export type ZodSchemaObjectTrait< T extends z.ZodRawShape, Catchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, > = ( ReturnType< typeof ZodSchemaObject > )