Files
traitify-ts/src/TraitExpressionBuilder.ts
Julien Valverdé 50e360d7ff
All checks were successful
continuous-integration/drone/push Build is passing
Fixed SpreadSupertraits
2024-02-20 00:12:19 +01:00

110 lines
2.8 KiB
TypeScript

import { uniq } from "lodash-es"
import { AbstractClass } from "type-fest"
import { Trait, TraitTuple } from "./Trait"
import { TraitExpression } from "./TraitExpression"
import { Extendable, StaticMembers } from "./util"
type SpreadSupertraits<T> = (
T extends [infer Trait, ...infer Rest]
? [
...Trait.Supertraits<Trait>,
Trait,
...SpreadSupertraits<Rest>,
]
: []
)
type InstanceExtendable<
Superclass extends AbstractClass<object>,
Traits extends Trait<any, any, any, any>[],
> = (
Extendable<[
InstanceType<Superclass>,
...TraitTuple.MapInstance<Traits>,
]>
)
type StaticMembersExtendable<
Superclass extends AbstractClass<object>,
Traits extends Trait<any, any, any, any>[],
> = (
Extendable<[
StaticMembers<Superclass>,
...TraitTuple.MapStaticMembers<Traits>,
]>
)
type BuildTraitExpression<
Superclass extends AbstractClass<object>,
Traits extends Trait<any, any, any, any>[],
> = (
InstanceExtendable<Superclass, Traits> extends false
? "Type conflict on the instance side."
: StaticMembersExtendable<Superclass, Traits> extends false
? "Type conflict on the static side."
: TraitExpression<Superclass, Traits>
)
class TraitExpressionBuilder<
Superclass extends AbstractClass<object>,
const Traits extends Trait<any, any, any, any>[],
> {
constructor(
private readonly expressionSuperclass: Superclass,
private readonly expressionTraits: Traits,
) {}
extends<
Super extends AbstractClass<object>
>(
superclass: Super
) {
return new TraitExpressionBuilder(
superclass,
this.expressionTraits,
)
}
expresses<
const T extends Trait<
TraitExpression<
typeof TraitExpression.NullSuperclass,
Trait<any, any, any, any>[]
>,
any,
any,
any
>[]
>(
...traits: T
) {
return new TraitExpressionBuilder(
this.expressionSuperclass,
uniq([
...this.expressionTraits,
...traits.flatMap(trait => [
...trait.superExpression.traits,
trait,
]),
]) as [...Traits, ...SpreadSupertraits<T>],
)
}
build() {
return new TraitExpression(
this.expressionSuperclass,
this.expressionTraits,
) as BuildTraitExpression<Superclass, Traits>
}
then<V>(fn: (expression: ReturnType<typeof this.build>) => V): V {
return fn(this.build())
}
}
export const expression = new TraitExpressionBuilder(TraitExpression.NullSuperclass, [])