import { AbstractClass, Class, Simplify } from "type-fest" import { Trait, TraitInstance, TraitStaticMembers, Traits } from "./Trait" import { TraitBuilder } from "./TraitBuilder" import { ExtendPlain, StaticMembers } from "./util" export class TraitExpression< Superclass extends AbstractClass, const T extends Trait[], > { constructor( readonly superclass: Superclass, readonly traits: T, ) {} get extends(): ( AbstractClass< Simplify< ExtendPlain<[ InstanceType, ...Traits.MapImplInstance, ]> >, ConstructorParameters > & Simplify< ExtendPlain<[ StaticMembers, ...Traits.MapImplStaticMembers, ]> > ) { return this.traits.reduce( (previous, trait) => trait.apply(previous), this.superclass, ) as any } implementsStatic(target: ImplementsStatic, context: any) {} subtrait< This extends TraitExpression >( this: This ) { return new TraitBuilder< This, Simplify< ExtendPlain> >, Simplify< ExtendPlain> >, AbstractClass< Simplify< ExtendPlain> > > & Simplify< ExtendPlain> > >( this, {} as any, {} as any, Super => class extends Super {} as any, ) } } export namespace TraitExpression { export class NullSuperclass { static readonly _tag = "@thilawyn/traitify-ts/TraitExpression.NullSuperclass" constructor(...args: any[]) {} } export type Superclass = ( T extends TraitExpression ? Superclass : never ) export type Traits = ( T extends TraitExpression ? Traits : never ) } export type Implements< Exp extends TraitExpression[]> > = ( Simplify< ExtendPlain< Traits.MapAbstract< TraitExpression.Traits > > > ) export type ImplementsStatic< Exp extends TraitExpression[]> > = ( Simplify< ExtendPlain< Traits.MapStaticAbstract< TraitExpression.Traits > > > ) export type TraitExpressionClass< Exp extends TraitExpression[]> > = ( AbstractClass< TraitExpressionInstance, ConstructorParameters> > & TraitExpressionStaticMembers ) export type TraitExpressionConcreteClass< Exp extends TraitExpression[]> > = ( Class< TraitExpressionInstance, ConstructorParameters> > & TraitExpressionStaticMembers ) export type TraitExpressionInstance< Exp extends TraitExpression[]> > = ( Simplify< ExtendPlain<[ InstanceType>, ...MapTraitsInstance>, ]> > ) type MapTraitsInstance = { [K in keyof T]: K extends keyof [] ? T[K] : T[K] extends Trait ? TraitInstance : never } export type TraitExpressionStaticMembers< Exp extends TraitExpression[]> > = ( Simplify< ExtendPlain<[ StaticMembers>, ...MapTraitsStaticMembers>, ]> > ) type MapTraitsStaticMembers = { [K in keyof T]: K extends keyof [] ? T[K] : T[K] extends Trait ? TraitStaticMembers : never }