All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Julien Valverdé <julien.valverde@mailo.com> Reviewed-on: https://git.jvalver.de/Thilawyn/traitify-ts/pulls/3
158 lines
4.5 KiB
TypeScript
158 lines
4.5 KiB
TypeScript
import { Fn, Pipe, Tuples } from "hotscript"
|
|
import { AbstractClass, Class, Opaque } from "type-fest"
|
|
import { TraitExpression, emptyTraitExpression } from "./TraitExpression"
|
|
import { AbstractTag } from "./abstract"
|
|
import { ExtendFn, SimplifyFn, StaticMembers, StaticMembersFn } from "./util"
|
|
|
|
|
|
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper"
|
|
|
|
|
|
export type AddAbstractToImplClass<
|
|
ImplClass extends Class<{}, []>,
|
|
Abstract extends {},
|
|
> = (
|
|
Class<
|
|
Abstract & InstanceType<ImplClass>,
|
|
ConstructorParameters<ImplClass>
|
|
> &
|
|
StaticMembers<ImplClass>
|
|
)
|
|
|
|
export type RemoveAbstractFromImplClass<
|
|
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
|
Abstract extends {},
|
|
> = (
|
|
Class<
|
|
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
|
|
ConstructorParameters<ImplClassWithAbstract>
|
|
> &
|
|
Omit<StaticMembers<ImplClassWithAbstract>, "_tag">
|
|
)
|
|
|
|
|
|
export class Trait<
|
|
Supertraits extends TraitExpression<typeof TraitExpression.NullSuperclass, Trait<any, any, any>[], Trait<any, any, any>[]>,
|
|
Abstract extends {},
|
|
ImplClass extends Class<{}, []>,
|
|
> {
|
|
constructor(
|
|
readonly supertraits: Supertraits,
|
|
readonly abstract: Abstract,
|
|
readonly apply: (Super: AbstractClass<{}>) => ImplClass,
|
|
) {}
|
|
}
|
|
|
|
export namespace Trait {
|
|
export type OwnSupertraits<T> = (
|
|
T extends Trait<infer Supertraits, any, any>
|
|
? Supertraits
|
|
: never
|
|
)
|
|
export interface OwnSupertraitsFn extends Fn {
|
|
return: Trait.OwnSupertraits<this["arg0"]>
|
|
}
|
|
|
|
export type OwnAbstract<T> = (
|
|
T extends Trait<any, infer Abstract, any>
|
|
? Abstract
|
|
: never
|
|
)
|
|
export interface OwnAbstractFn extends Fn {
|
|
return: Trait.OwnAbstract<this["arg0"]>
|
|
}
|
|
|
|
export type OwnImplClass<T> = (
|
|
T extends Trait<any, any, infer ImplClass>
|
|
? ImplClass
|
|
: never
|
|
)
|
|
export interface OwnImplClassFn extends Fn {
|
|
return: Trait.OwnImplClass<this["arg0"]>
|
|
}
|
|
|
|
export type OwnImplInstance<T> = (
|
|
T extends Trait<any, any, infer ImplClass>
|
|
? InstanceType<ImplClass>
|
|
: never
|
|
)
|
|
export interface OwnImplInstanceFn extends Fn {
|
|
return: Trait.OwnImplInstance<this["arg0"]>
|
|
}
|
|
|
|
export type OwnClass<T> = (
|
|
T extends Trait<any, infer Abstract, infer ImplClass>
|
|
? AddAbstractToImplClass<ImplClass, Abstract>
|
|
: never
|
|
)
|
|
export interface OwnClassFn extends Fn {
|
|
return: Trait.OwnClass<this["arg0"]>
|
|
}
|
|
|
|
export type OwnInstance<T> = (
|
|
T extends Trait<any, infer Abstract, infer ImplClass>
|
|
? InstanceType<
|
|
AddAbstractToImplClass<ImplClass, Abstract>
|
|
>
|
|
: never
|
|
)
|
|
export interface OwnInstanceFn extends Fn {
|
|
return: Trait.OwnInstance<this["arg0"]>
|
|
}
|
|
|
|
export type Supertraits<T> = (
|
|
T extends Trait<infer Supertraits, any, any>
|
|
? TraitExpression.AllTraits<Supertraits>
|
|
: never
|
|
)
|
|
export interface SupertraitsFn extends Fn {
|
|
return: Trait.Supertraits<this["arg0"]>
|
|
}
|
|
|
|
export type Class<T> = (
|
|
AbstractClass<
|
|
Trait.Instance<T>,
|
|
any[]
|
|
> &
|
|
Pipe<T, [
|
|
Trait.SupertraitsFn,
|
|
Tuples.Append<T>,
|
|
Tuples.Map<Trait.OwnClassFn>,
|
|
Tuples.Map<StaticMembersFn>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|
|
export interface ClassFn extends Fn {
|
|
return: Trait.Class<this["arg0"]>
|
|
}
|
|
|
|
export type Instance<T> = (
|
|
Pipe<T, [
|
|
Trait.SupertraitsFn,
|
|
Tuples.Append<T>,
|
|
Tuples.Map<Trait.OwnInstanceFn>,
|
|
ExtendFn,
|
|
SimplifyFn,
|
|
]>
|
|
)
|
|
export interface InstanceFn extends Fn {
|
|
return: Trait.Instance<this["arg0"]>
|
|
}
|
|
}
|
|
|
|
|
|
export function trait<
|
|
Abstract extends {},
|
|
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
|
>(
|
|
abstract: Opaque<Abstract, AbstractTag>,
|
|
apply: (Super: AbstractClass<Abstract> & { _tag: TraitApplierSuperTag }) => ImplClassWithAbstract,
|
|
) {
|
|
return new Trait(
|
|
emptyTraitExpression,
|
|
abstract as Abstract,
|
|
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract>,
|
|
)
|
|
}
|