Files
traitify-ts/src/TraitBuilder.ts
Julien Valverdé f37f15e466
Some checks failed
continuous-integration/drone/push Build is failing
TraitBuilder work
2024-02-16 01:30:04 +01:00

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 {},
)