135 lines
3.9 KiB
TypeScript
135 lines
3.9 KiB
TypeScript
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<any, any, any>[],
|
|
AllTraits extends Trait<any, any, any>[],
|
|
> {
|
|
constructor(public expression: TraitExpression<Super, OwnTraits, AllTraits>) {}
|
|
|
|
extends<
|
|
NewSuper extends AbstractClass<any>
|
|
>(superclass: NewSuper) {
|
|
return new TraitExpressionBuilder(
|
|
new TraitExpression(
|
|
superclass,
|
|
this.expression.ownTraits,
|
|
this.expression.allTraits,
|
|
)
|
|
)
|
|
}
|
|
|
|
expresses<
|
|
Traits extends Trait<any, any, any>[]
|
|
>(
|
|
...traits: Traits
|
|
): TraitExpressionBuilder<
|
|
Super,
|
|
[...OwnTraits, ...Traits],
|
|
[...AllTraits, SpreadSupertraits<Traits>]
|
|
> {
|
|
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, Trait<any, any, any>[]>,
|
|
any,
|
|
any
|
|
>[]
|
|
>(
|
|
traits: Traits
|
|
) {
|
|
return traits.flatMap(trait => [
|
|
...trait.supertraits.allTraits,
|
|
trait,
|
|
]) as SpreadSupertraits<Traits>
|
|
}
|
|
|
|
get() {
|
|
return this.expression as GetTraitExpression<Super, OwnTraits, AllTraits>
|
|
}
|
|
|
|
then<V>(fn: (expression: ReturnType<typeof this.get>) => V): V {
|
|
return fn(this.get())
|
|
}
|
|
}
|
|
|
|
|
|
type SpreadSupertraits<Traits extends Trait<any, any, any>[]> = (
|
|
Call<
|
|
Tuples.FlatMap<PrependTraitSupertraitsFn>,
|
|
Traits
|
|
>
|
|
)
|
|
interface PrependTraitSupertraitsFn extends Fn {
|
|
return: this["arg0"] extends Trait<infer Super, any, any>
|
|
? Super extends TraitExpression<any, any, infer AllTraits>
|
|
? [...AllTraits, this["arg0"]]
|
|
: never
|
|
: never
|
|
}
|
|
|
|
|
|
type AbstractMembersExtendable<
|
|
Super extends AbstractClass<{}>,
|
|
Traits extends Trait<any, any, any>[],
|
|
> = (
|
|
Call<ExtendableFn, [
|
|
InstanceType<Super>,
|
|
...Call<Tuples.Map<Trait.OwnAbstractFn>, Traits>,
|
|
]>
|
|
)
|
|
|
|
type ImplInstanceExtendable<
|
|
Super extends AbstractClass<{}>,
|
|
Traits extends Trait<any, any, any>[],
|
|
> = (
|
|
Call<ExtendableFn, [
|
|
InstanceType<Super>,
|
|
...Call<Tuples.Map<Trait.OwnImplInstanceFn>, Traits>,
|
|
]>
|
|
)
|
|
|
|
type ImplStaticMembersExtendable<
|
|
Super extends AbstractClass<{}>,
|
|
Traits extends Trait<any, any, any>[],
|
|
> = (
|
|
Pipe<[
|
|
Super,
|
|
...Call<Tuples.Map<Trait.OwnImplClassFn>, Traits>,
|
|
], [
|
|
Tuples.Map<StaticMembersFn>,
|
|
ExtendableFn,
|
|
]>
|
|
)
|
|
|
|
type GetTraitExpression<
|
|
Super extends AbstractClass<{}>,
|
|
OwnTraits extends Trait<any, any, any>[],
|
|
AllTraits extends Trait<any, any, any>[],
|
|
> = (
|
|
Call<Tuples.IsEmpty, OwnTraits> extends true
|
|
? "Cannot express an empty list of traits."
|
|
: AbstractMembersExtendable<Super, OwnTraits> extends false
|
|
? "Type conflict between the traits abstract members and/or the superclass instance."
|
|
: ImplInstanceExtendable<Super, OwnTraits> extends false
|
|
? "Type conflict between the traits implementation instances and/or the superclass instance."
|
|
: ImplStaticMembersExtendable<Super, OwnTraits> extends false
|
|
? "Type conflict between the traits implementation static members and/or the superclass static members."
|
|
: TraitExpression<Super, OwnTraits, AllTraits>
|
|
)
|
|
|
|
|
|
export const expression = new TraitExpressionBuilder(emptyTraitExpression)
|