128 lines
4.9 KiB
TypeScript
128 lines
4.9 KiB
TypeScript
import { Fn, Pipe, Tuples } from "hotscript"
|
|
import { AbstractClass, Class, Opaque } from "type-fest"
|
|
import { RemoveAbstractFromImplClass, Trait, TraitApplierSuperTag } from "./Trait"
|
|
import { AbstractTag } from "./abstract"
|
|
import { ExtendFn, SimplifyFn, StaticMembersFn } from "./util"
|
|
|
|
|
|
// type RemoveSupertraitsAbstractFromAbstract<Left, Right> = {
|
|
// [Key in Extract<keyof Left, keyof Right>]: Left[Key]
|
|
// } & {
|
|
// [Key in Exclude<keyof Left, keyof Right>]: Left[Key]
|
|
// }
|
|
|
|
|
|
export class TraitExpression<
|
|
Superclass extends AbstractClass<{}>,
|
|
const OwnTraits extends Trait<any, any, any, any>[],
|
|
const AllTraits extends Trait<any, any, any, any>[],
|
|
> {
|
|
constructor(
|
|
readonly superclass: Superclass,
|
|
readonly ownTraits: OwnTraits,
|
|
readonly allTraits: AllTraits,
|
|
) {}
|
|
|
|
get extends(): (
|
|
AbstractClass<
|
|
Pipe<AllTraits, [
|
|
Tuples.Map<Trait.OwnImplInstanceFn>, // Map all the traits to the instance of their implementation class
|
|
Tuples.Prepend<InstanceType<Superclass>>, // Add the instance of the superclass at the top of the list
|
|
ExtendFn, // Reduce to a single instance that extends all the instances in the list
|
|
SimplifyFn, // Make readable for IDEs
|
|
]>,
|
|
|
|
ConstructorParameters<Superclass>
|
|
> &
|
|
|
|
Pipe<AllTraits, [
|
|
Tuples.Map<Trait.OwnImplClassFn>, // Map all the traits to their implementation class
|
|
Tuples.Prepend<Superclass>, // Add the superclass at the top of the list
|
|
Tuples.Map<StaticMembersFn>, // Map all the classes to an object containing their static members
|
|
ExtendFn, // Reduce to a single object that extends all the objects in the list
|
|
SimplifyFn, // Make readable for IDEs
|
|
]>
|
|
) {
|
|
return this.allTraits.reduce(
|
|
(previous, trait) => trait.apply(previous),
|
|
this.superclass,
|
|
) as any
|
|
}
|
|
|
|
implementsStatic(target: ImplementsStatic<typeof this>, context: any) {}
|
|
|
|
subtrait<
|
|
This extends TraitExpression<typeof TraitExpression.NullSuperclass, any, any>,
|
|
SubtraitAbstract extends Implements<This>,
|
|
SubtraitStaticAbstract extends ImplementsStatic<This>,
|
|
SubtraitImplClassWithAbstract extends Class<SubtraitAbstract, []> & SubtraitStaticAbstract & { _tag: TraitApplierSuperTag },
|
|
>(
|
|
this: This,
|
|
abstract: (expression: This) => Opaque<SubtraitAbstract, AbstractTag>,
|
|
staticAbstract: (expression: This) => Opaque<SubtraitStaticAbstract, AbstractTag>,
|
|
apply: (Super: AbstractClass<SubtraitAbstract> & SubtraitStaticAbstract & { _tag: TraitApplierSuperTag }) => SubtraitImplClassWithAbstract,
|
|
) {
|
|
return new Trait(
|
|
this,
|
|
// {} as RemoveSupertraitsAbstractFromAbstract<SubtraitAbstract, Implements<typeof this>>,
|
|
{} as SubtraitAbstract, // TODO: find a way to cleanly substract Implements<typeof this> from this.
|
|
{} as SubtraitStaticAbstract, // TODO: find a way to cleanly substract StaticImplements<typeof this> from this.
|
|
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<SubtraitImplClassWithAbstract, SubtraitAbstract, SubtraitStaticAbstract>,
|
|
)
|
|
}
|
|
}
|
|
|
|
export namespace TraitExpression {
|
|
export class NullSuperclass {
|
|
static readonly _tag = "@thilawyn/traitify-ts/TraitExpression.NullSuperclass"
|
|
}
|
|
|
|
export type Superclass<T> = (
|
|
T extends TraitExpression<infer Superclass, any, any>
|
|
? Superclass
|
|
: never
|
|
)
|
|
export interface SuperclassFn extends Fn {
|
|
return: TraitExpression.Superclass<this["arg0"]>
|
|
}
|
|
|
|
export type OwnTraits<T> = (
|
|
T extends TraitExpression<any, infer OwnTraits, any>
|
|
? OwnTraits
|
|
: never
|
|
)
|
|
export interface OwnTraitsFn extends Fn {
|
|
return: TraitExpression.OwnTraits<this["arg0"]>
|
|
}
|
|
|
|
export type AllTraits<T> = (
|
|
T extends TraitExpression<any, any, infer AllTraits>
|
|
? AllTraits
|
|
: never
|
|
)
|
|
export interface AllTraitsFn extends Fn {
|
|
return: TraitExpression.AllTraits<this["arg0"]>
|
|
}
|
|
}
|
|
|
|
export const emptyTraitExpression = new TraitExpression(TraitExpression.NullSuperclass, [], [])
|
|
|
|
|
|
export type Implements<Exp extends TraitExpression<any, any, any>> = (
|
|
Pipe<Exp, [
|
|
TraitExpression.AllTraitsFn,
|
|
Tuples.Map<Trait.OwnAbstractFn>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|
|
|
|
export type ImplementsStatic<Exp extends TraitExpression<any, any, any>> = (
|
|
Pipe<Exp, [
|
|
TraitExpression.AllTraitsFn,
|
|
Tuples.Map<Trait.OwnStaticAbstractFn>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|