From bb5e85573cb48f30bee310dfa12eb85f3e26ecdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 4 Feb 2024 04:26:20 +0100 Subject: [PATCH] TraitExpressionBuilder work --- src/TraitExpression.ts | 110 ++++------------------------ src/TraitExpressionBuilder.ts | 134 ++++++++++++++++++++++++++++++++++ src/index.ts | 1 + src/trait.ts | 2 +- 4 files changed, 149 insertions(+), 98 deletions(-) create mode 100644 src/TraitExpressionBuilder.ts diff --git a/src/TraitExpression.ts b/src/TraitExpression.ts index 2d3f207..0e9cc13 100644 --- a/src/TraitExpression.ts +++ b/src/TraitExpression.ts @@ -7,19 +7,21 @@ import { ExtendFn, ExtendableFn, SimplifyFn, StaticMembersFn } from "./util" export class TraitExpressionNullSuperclass {} export class TraitExpression< - Super extends AbstractClass<{}>, - Traits extends Trait[], + Super extends AbstractClass<{}>, + OwnTraits extends Trait[], + AllTraits extends Trait[], > { constructor( readonly superclass: Super, - readonly traits: Traits, + readonly ownTraits: OwnTraits, + readonly allTraits: AllTraits, ) {} get extends(): ( AbstractClass< Pipe<[ InstanceType, - ...Call, Traits>, + ...Call, OwnTraits>, ], [ ExtendFn, SimplifyFn, @@ -30,14 +32,14 @@ export class TraitExpression< Pipe<[ Super, - ...Call, Traits>, + ...Call, OwnTraits>, ], [ Tuples.Map, ExtendFn, SimplifyFn, ]> ) { - return this.traits.reduce( + return this.ownTraits.reduce( (previous, trait) => trait.apply(previous), this.superclass as Opaque, ) as any @@ -60,7 +62,11 @@ export class TraitExpression< } } -export const emptyTraitExpression = new TraitExpression(TraitExpressionNullSuperclass, [] as const) +export const emptyTraitExpression = new TraitExpression( + TraitExpressionNullSuperclass, + [] as const, + [] as const, +) interface PrependTraitSupertraitsFn extends Fn { return: this["arg0"] extends Trait @@ -95,93 +101,3 @@ export type Implements> = ( ]> : never ) - - -class TraitExpressionBuilder< - Super extends AbstractClass<{}>, - Traits extends Trait[], -> { - constructor(public expression: TraitExpression) {} - - extends< - NewSuper extends AbstractClass - >(superclass: NewSuper) { - return new TraitExpressionBuilder( - new TraitExpression( - superclass, - this.expression.traits, - ) - ) - } - - expresses< - AppendTraits extends Trait[] - >(...traits: AppendTraits) { - return new TraitExpressionBuilder( - new TraitExpression( - this.expression.superclass, - [...this.expression.traits, ...traits] as const, - ) - ) - } - - get() { - return this.expression as GetTraitExpression - } - - then(fn: (expression: ReturnType) => V): V { - return fn(this.get()) - } -} - - -type AbstractMembersExtendable< - Super extends AbstractClass<{}>, - Traits extends Trait[], -> = ( - Call, - ...Call, Traits>, - ]> -) - -type ImplInstanceExtendable< - Super extends AbstractClass<{}>, - Traits extends Trait[], -> = ( - Call, - ...Call, Traits>, - ]> -) - -type ImplStaticMembersExtendable< - Super extends AbstractClass<{}>, - Traits extends Trait[], -> = ( - Pipe<[ - Super, - ...Call, Traits>, - ], [ - Tuples.Map, - ExtendableFn, - ]> -) - -type GetTraitExpression< - Super extends AbstractClass<{}>, - Traits extends Trait[], -> = ( - Call extends true - ? "Cannot express an empty list of traits." - : AbstractMembersExtendable extends false - ? "Type conflict between the traits abstract members and/or the superclass instance." - : ImplInstanceExtendable extends false - ? "Type conflict between the traits implementation instances and/or the superclass instance." - : ImplStaticMembersExtendable extends false - ? "Type conflict between the traits implementation static members and/or the superclass static members." - : TraitExpression -) - - -export const expression = new TraitExpressionBuilder(emptyTraitExpression) diff --git a/src/TraitExpressionBuilder.ts b/src/TraitExpressionBuilder.ts new file mode 100644 index 0000000..9de8c52 --- /dev/null +++ b/src/TraitExpressionBuilder.ts @@ -0,0 +1,134 @@ +import { Call, Fn, Pipe, Tuples } from "hotscript" +import { AbstractClass } from "type-fest" +import { Trait, TraitExpression, TraitOwnAbstractFn, TraitOwnImplClassFn, TraitOwnImplInstanceFn, TraitSupertraitsFn, emptyTraitExpression } from "." +import { ExtendableFn, StaticMembersFn } from "./util" + + +class TraitExpressionBuilder< + Super extends AbstractClass<{}>, + OwnTraits extends Trait[], + AllTraits extends Trait[], +> { + constructor(public expression: TraitExpression) {} + + extends< + NewSuper extends AbstractClass + >(superclass: NewSuper) { + return new TraitExpressionBuilder( + new TraitExpression( + superclass, + this.expression.ownTraits, + this.expression.allTraits, + ) + ) + } + + expresses< + Traits extends Trait[] + >( + ...traits: Traits + ) { + return new TraitExpressionBuilder( + new TraitExpression( + this.expression.superclass, + [...this.expression.ownTraits, ...traits] as const, + [ + ...this.expression.allTraits, + ...this.spreadSupertraits(traits) as SpreadTraitsHierarchy, + ] as const, + ) + ) + } + + private spreadSupertraits< + Traits extends Trait< + TraitExpression[]>, + any, + any + >[] + >( + traits: Traits + ) { + return traits.flatMap(trait => [ + ...trait.superExpression.allTraits, + trait, + ]) + } + + get() { + return this.expression as GetTraitExpression + } + + then(fn: (expression: ReturnType) => V): V { + return fn(this.get()) + } +} + + +type SpreadTraitsHierarchy[]> = ( + Call< + Tuples.FlatMap, + Traits + > +) +interface PrependTraitSupertraitsFn extends Fn { + return: this["arg0"] extends Trait + ? [ + ...Call, + this["arg0"], + ] + : never +} + + +type AbstractMembersExtendable< + Super extends AbstractClass<{}>, + Traits extends Trait[], +> = ( + Call, + ...Call, Traits>, + ]> +) + +type ImplInstanceExtendable< + Super extends AbstractClass<{}>, + Traits extends Trait[], +> = ( + Call, + ...Call, Traits>, + ]> +) + +type ImplStaticMembersExtendable< + Super extends AbstractClass<{}>, + Traits extends Trait[], +> = ( + Pipe<[ + Super, + ...Call, Traits>, + ], [ + Tuples.Map, + ExtendableFn, + ]> +) + +type GetTraitExpression< + Super extends AbstractClass<{}>, + OwnTraits extends Trait[], + AllTraits extends Trait[], +> = ( + Call extends true + ? "Cannot express an empty list of traits." + : AbstractMembersExtendable extends false + ? "Type conflict between the traits abstract members and/or the superclass instance." + : ImplInstanceExtendable extends false + ? "Type conflict between the traits implementation instances and/or the superclass instance." + : ImplStaticMembersExtendable extends false + ? "Type conflict between the traits implementation static members and/or the superclass static members." + : TraitExpression +) + + +export const expression = new TraitExpressionBuilder(emptyTraitExpression) diff --git a/src/index.ts b/src/index.ts index b92ea0f..f9de698 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export * from "./TraitExpression" +export * from "./TraitExpressionBuilder" export * from "./abstract" export * from "./trait" diff --git a/src/trait.ts b/src/trait.ts index fda5316..75d859e 100644 --- a/src/trait.ts +++ b/src/trait.ts @@ -28,7 +28,7 @@ type RemoveAbstractFromImplClass< export class Trait< - Super extends TraitExpression, + Super extends TraitExpression[], Trait[]>, Abstract extends {}, ImplClass extends Class<{}, []>, > {