import { TraitExpression, TraitExpressionBuilder, expression } from "@thilawyn/traitify-ts" import { AbstractClass, Simplify } from "type-fest" import { z } from "zod" import { ExtendableZodSchemaObject } from "./traits/ExtendableZodSchemaObject" import { InstantiableZodSchemaObject } from "./traits/InstantiableZodSchemaObject" import { Extend, StaticMembers } from "./util" export class ZodSchemaClassBuilder< Exp extends TraitExpressionBuilder > { constructor( private readonly expressionBuilder: Exp ) {} extends< This extends ZodSchemaClassBuilder< TraitExpressionBuilder< typeof TraitExpression.NullSuperclass, // Ensures `extends` can only be called when the expression does not have a superclass any > >, Super extends AbstractClass, >( this: This, superclass: Super, ) { return new ZodSchemaClassBuilder( this.expressionBuilder.extends(superclass) ) } schema< This extends ZodSchemaClassBuilder< TraitExpressionBuilder< any, any > >, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, Values extends object, DefaultValues extends Partial, >( this: This, schema: z.ZodObject, defaultValues: DefaultValues, ) { class Schemas extends (this.expressionBuilder.expressionSuperclass as AbstractClass) { static readonly schema = schema static readonly defaultValues = defaultValues constructor(values: Values) { super() Object.assign(this, values) } } return new ZodSchemaClassBuilder( this.expressionBuilder .extends() .expresses( InstantiableZodSchemaObject, ExtendableZodSchemaObject, ) ) } jsonifiable() { } toBuilder() { return this.expressionBuilder } } export function ZodSchemaClassOf< Superclass extends AbstractClass, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, Values extends object, DefaultValues extends Partial, >( of: Superclass, { schema, defaultValues }: { schema: z.ZodObject defaultValues: DefaultValues }, ) { class Schemas extends (of as AbstractClass) { static readonly schema = schema static readonly defaultValues = defaultValues constructor(values: Values) { super() Object.assign(this, values) } } return expression .extends(Schemas as unknown as ( AbstractClass< InstanceType & Simplify< Extend<[Schemas, Values]> >, ConstructorParameters > & Simplify< Extend<[ StaticMembers, StaticMembers, ]> > )) .expresses( InstantiableZodSchemaObject, ExtendableZodSchemaObject, ) } class DefaultRoot {} export function ZodSchemaClass< SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, Values extends object, DefaultValues extends Partial, >( props: { schema: z.ZodObject defaultValues: DefaultValues }, ) { return ZodSchemaClassOf(DefaultRoot, props) }