import { Trait, TraitExpression, TraitExpressionBuilder } from "@thilawyn/traitify-ts" import { AbstractClass } from "type-fest" import { JsonifiableObject } from "type-fest/source/jsonifiable" import { z } from "zod" import { ZodSchemaAbstractClass } from "../shapes/ZodSchemaClass" import { DejsonifiableZodSchemaObject } from "../traits/DejsonifiableZodSchemaObject" import { JsonifiableZodSchemaObject } from "../traits/JsonifiableZodSchemaObject" import { ZodSchemaObject } from "../traits/ZodSchemaObject" import { StaticMembers } from "../util" export class ZodSchemaClassBuilder< Superclass extends AbstractClass, const Traits extends readonly Trait[], > extends TraitExpressionBuilder { declare ["constructor"]: typeof ZodSchemaClassBuilder schema< Super extends AbstractClass & { schema?: never, schemaWithDefaultValues?: never }, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, SchemaWithDefaultValuesT extends z.ZodRawShape, SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, >( this: ZodSchemaClassBuilder, { schema, schemaWithDefaultValues }: { schema: z.ZodObject schemaWithDefaultValues: ( schema: z.ZodObject ) => z.ZodObject }, ) { class ZodSchemaObjectConstructor extends (this.expressionSuperclass as AbstractClass) { constructor(values: Values) { super() Object.assign(this, values) } } return new this.constructor( ZodSchemaObjectConstructor as unknown as ( AbstractClass< InstanceType & Values, [values: Values] > & StaticMembers ), [...this.expressionTraits, ZodSchemaObject(schema, schemaWithDefaultValues(schema))], ) } jsonifiable< Super extends ZodSchemaAbstractClass & { jsonifySchema?: never, dejsonifySchema?: never }, Instance extends Values, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, SchemaWithDefaultValuesT extends z.ZodRawShape, SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, Values extends object, PartialValues extends Partial, JsonifySchemaT extends z.ZodRawShape, JsonifySchemaUnknownKeys extends z.UnknownKeysParam, JsonifySchemaCatchall extends z.ZodTypeAny, DejsonifySchemaT extends z.ZodRawShape, DejsonifySchemaUnknownKeys extends z.UnknownKeysParam, DejsonifySchemaCatchall extends z.ZodTypeAny, JsonifiedValues extends JsonifiableObject, >( this: ZodSchemaClassBuilder< Super | ZodSchemaAbstractClass, Traits >, props: { jsonifySchema: ( schema: z.ZodObject ) => z.ZodObject dejsonifySchema: ( schema: z.ZodObject ) => z.ZodObject }, ) { const jsonifySchema = props.jsonifySchema(this.expressionSuperclass.schema) const dejsonifySchema = props.dejsonifySchema(this.expressionSuperclass.schema) class JsonifiableSchemas extends (this.expressionSuperclass as AbstractClass) { static readonly jsonifySchema = jsonifySchema readonly jsonifySchema = jsonifySchema static readonly dejsonifySchema = dejsonifySchema readonly dejsonifySchema = dejsonifySchema } return new this.constructor( JsonifiableSchemas as unknown as ( AbstractClass< Instance & JsonifiableSchemas, // TODO: for some reason, ConstructorParameters does not work here. Maybe try to find a fix? ConstructorParameters> > & StaticMembers & StaticMembers ), [ ...this.expressionTraits, JsonifiableZodSchemaObject, DejsonifiableZodSchemaObject, ], ) } } export interface ZodSchemaClassBuilder< Superclass extends AbstractClass, Traits extends readonly Trait[], > { extends< Super extends AbstractClass >( // \/ Ensures `extends` can only be called once at the beginning this: ZodSchemaClassBuilder, superclass: Super, ): ZodSchemaClassBuilder expresses< const T extends readonly Trait< TraitExpression< typeof TraitExpression.NullSuperclass, readonly Trait[] >, any, any, any >[] >( ...traits: T ): ZodSchemaClassBuilder< Superclass, TraitExpressionBuilder.ExpressesReturnTypeTraits > expressesFirst< const T extends readonly Trait< TraitExpression< typeof TraitExpression.NullSuperclass, readonly Trait[] >, any, any, any >[] >( ...traits: T ): ZodSchemaClassBuilder< Superclass, TraitExpressionBuilder.ExpressesFirstReturnTypeTraits > } export const zodSchemaClass = new ZodSchemaClassBuilder(TraitExpression.NullSuperclass, [])