import { Call, Fn, Pipe, Tuples } from "hotscript" import { AbstractClass } from "type-fest" import { Trait, TraitExpression, emptyTraitExpression } from "." import { ExtendableFn, StaticMembersFn } from "./util" class TraitExpressionBuilder< Super extends AbstractClass<{}>, OwnTraits extends Trait[], AllTraits extends Trait[], > { constructor(public expression: TraitExpression) {} extends< NewSuper extends AbstractClass >(superclass: NewSuper) { return new TraitExpressionBuilder( new TraitExpression( superclass, this.expression.ownTraits, this.expression.allTraits, ) ) } expresses< Traits extends Trait[] >( ...traits: Traits ): TraitExpressionBuilder< Super, [...OwnTraits, ...Traits], [...AllTraits, SpreadSupertraits] > { return new TraitExpressionBuilder( new TraitExpression( this.expression.superclass, [...this.expression.ownTraits, ...traits] as const, [...this.expression.allTraits, ...this.spreadSupertraits(traits)] as const, ) ) as any } private spreadSupertraits< Traits extends Trait< TraitExpression[]>, any, any >[] >( traits: Traits ) { return traits.flatMap(trait => [ ...trait.supertraits.allTraits, trait, ]) as SpreadSupertraits } get() { return this.expression as GetTraitExpression } then(fn: (expression: ReturnType) => V): V { return fn(this.get()) } } type SpreadSupertraits[]> = ( Call< Tuples.FlatMap, Traits > ) interface PrependTraitSupertraitsFn extends Fn { return: this["arg0"] extends Trait ? Super extends TraitExpression ? [...AllTraits, this["arg0"]] : never : never } type AbstractMembersExtendable< Super extends AbstractClass<{}>, Traits extends Trait[], > = ( Call, ...Call, Traits>, ]> ) type ImplInstanceExtendable< Super extends AbstractClass<{}>, Traits extends Trait[], > = ( Call, ...Call, Traits>, ]> ) type ImplStaticMembersExtendable< Super extends AbstractClass<{}>, Traits extends Trait[], > = ( Pipe<[ Super, ...Call, Traits>, ], [ Tuples.Map, ExtendableFn, ]> ) type GetTraitExpression< Super extends AbstractClass<{}>, OwnTraits extends Trait[], AllTraits extends Trait[], > = ( Call extends true ? "Cannot express an empty list of traits." : AbstractMembersExtendable extends false ? "Type conflict between the traits abstract members and/or the superclass instance." : ImplInstanceExtendable extends false ? "Type conflict between the traits implementation instances and/or the superclass instance." : ImplStaticMembersExtendable extends false ? "Type conflict between the traits implementation static members and/or the superclass static members." : TraitExpression ) export const expression = new TraitExpressionBuilder(emptyTraitExpression)