151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
import { Pipe, Tuples } from "hotscript"
|
|
import { AbstractClass, Class } from "type-fest"
|
|
import { Trait, TraitClass, TraitConcreteClass, TraitInstance } from "./Trait"
|
|
import { TraitExpression } from "./TraitExpression"
|
|
import { ExtendFn, SimplifyFn, StaticMembers } from "./util"
|
|
|
|
|
|
type ExtendAbstractSuper<SuperExpression, Abstract> = (
|
|
Pipe<SuperExpression, [
|
|
TraitExpression.TraitsFn,
|
|
Tuples.Map<Trait.OwnAbstractFn>,
|
|
Tuples.Append<Abstract>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|
|
|
|
type ExtendStaticAbstractSuper<SuperExpression, StaticAbstract> = (
|
|
Pipe<SuperExpression, [
|
|
TraitExpression.TraitsFn,
|
|
Tuples.Map<Trait.OwnStaticAbstractFn>,
|
|
Tuples.Append<StaticAbstract>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|
|
|
|
|
|
type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super"
|
|
|
|
type RemoveAbstractFromImplClass<
|
|
ImplClassWithAbstract extends (
|
|
Class<Abstract, []> &
|
|
StaticAbstract &
|
|
{ _tag: TraitApplierSuperTag }
|
|
),
|
|
Abstract extends object,
|
|
StaticAbstract extends object,
|
|
> = (
|
|
Class<
|
|
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
|
|
ConstructorParameters<ImplClassWithAbstract>
|
|
> &
|
|
Omit<StaticMembers<ImplClassWithAbstract>, keyof StaticAbstract | "_tag">
|
|
)
|
|
|
|
|
|
export class TraitBuilder<
|
|
SuperExpression extends TraitExpression<
|
|
typeof TraitExpression.NullSuperclass,
|
|
Trait<any, any, any, any>[]
|
|
>,
|
|
Abstract extends object,
|
|
StaticAbstract extends object,
|
|
ImplClass extends Class<object, []>,
|
|
> {
|
|
constructor(
|
|
private readonly traitSuperExpression: SuperExpression,
|
|
private readonly traitAbstract: Abstract,
|
|
private readonly traitStaticAbstract: StaticAbstract,
|
|
private readonly traitApply: (Super: AbstractClass<object>) => ImplClass,
|
|
) {}
|
|
|
|
abstract<A extends ExtendAbstractSuper<SuperExpression, Abstract>>() {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
{} as A,
|
|
this.traitStaticAbstract,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
extendAbstract<A extends ExtendAbstractSuper<SuperExpression, Abstract>>(
|
|
_: (
|
|
Super: AbstractClass<
|
|
ExtendAbstractSuper<SuperExpression, Abstract>
|
|
>
|
|
) => AbstractClass<A, []>
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
{} as A,
|
|
this.traitStaticAbstract,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
staticAbstract<A extends ExtendStaticAbstractSuper<SuperExpression, StaticAbstract>>() {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
{} as A,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
extendStaticAbstract<A extends ExtendStaticAbstractSuper<SuperExpression, StaticAbstract>>(
|
|
_: (Super: AbstractClass<
|
|
ExtendStaticAbstractSuper<SuperExpression, StaticAbstract>
|
|
>) => AbstractClass<A, []>
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
{} as A,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
implement<
|
|
ImplClassWithAbstract extends (
|
|
TraitConcreteClass<
|
|
Trait<SuperExpression, Abstract, StaticAbstract, ImplClass>
|
|
> &
|
|
{ _tag: TraitApplierSuperTag }
|
|
)
|
|
>(
|
|
apply: (
|
|
Super: (
|
|
TraitClass<
|
|
Trait<SuperExpression, Abstract, StaticAbstract, ImplClass>
|
|
> &
|
|
{ _tag: TraitApplierSuperTag }
|
|
)
|
|
) => ImplClassWithAbstract
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
this.traitStaticAbstract,
|
|
apply as unknown as (Super: AbstractClass<object>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract, StaticAbstract>,
|
|
)
|
|
}
|
|
|
|
build() {
|
|
return new Trait(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
this.traitStaticAbstract,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
}
|
|
|
|
export const trait = new TraitBuilder(
|
|
new TraitExpression(TraitExpression.NullSuperclass, []),
|
|
{},
|
|
{},
|
|
Super => class extends Super {},
|
|
)
|