diff --git a/bun.lockb b/bun.lockb index 0e06437..24092f7 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 636e6e5..bafe7b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@thilawyn/traitify-ts", - "version": "0.1.10", + "version": "0.1.11", "type": "module", "publishConfig": { "registry": "https://git.jvalver.de/api/packages/thilawyn/npm/" @@ -29,7 +29,7 @@ }, "dependencies": { "lodash-es": "^4.17.21", - "type-fest": "^4.10.2" + "type-fest": "^4.10.3" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", diff --git a/src/Trait.ts b/src/Trait.ts index 9d43662..63109a6 100644 --- a/src/Trait.ts +++ b/src/Trait.ts @@ -6,7 +6,7 @@ import { Extend, StaticMembers } from "./util" export class Trait< SuperExpression extends TraitExpression< typeof TraitExpression.NullSuperclass, - Trait[] + readonly Trait[] >, Abstract extends object, StaticAbstract extends object, diff --git a/src/TraitBuilder.ts b/src/TraitBuilder.ts index b6f698a..abe27ae 100644 --- a/src/TraitBuilder.ts +++ b/src/TraitBuilder.ts @@ -6,44 +6,18 @@ import { Extend, StaticMembers } from "./util" declare const implSuperSymbol: unique symbol -type ImplSuper = ( - This extends TraitBuilder< - any, - infer Abstract, - infer StaticAbstract, - infer ImplClass - > - ? ( - AbstractClass< - Simplify< - Extend<[ - Abstract, - InstanceType, - ]> - > - > & - - Simplify< - Extend<[ - StaticAbstract, - StaticMembers, - ]> - > & - { readonly [implSuperSymbol]: true } - ) - : never -) - export class TraitBuilder< SuperExpression extends TraitExpression< typeof TraitExpression.NullSuperclass, - Trait[] + readonly Trait[] >, Abstract extends object, StaticAbstract extends object, ImplClass extends AbstractClass, > { + declare ["constructor"]: typeof TraitBuilder + constructor( readonly traitSuperExpression: SuperExpression, readonly traitAbstract: Abstract, @@ -51,10 +25,11 @@ export class TraitBuilder< readonly traitApply: (Super: AbstractClass) => ImplClass, ) {} + abstract( _: (Super: AbstractClass) => AbstractClass ) { - return new TraitBuilder( + return new this.constructor( this.traitSuperExpression, {} as Simplify, this.traitStaticAbstract, @@ -65,7 +40,7 @@ export class TraitBuilder< staticAbstract( _: (Super: AbstractClass) => AbstractClass ) { - return new TraitBuilder( + return new this.constructor( this.traitSuperExpression, this.traitAbstract, {} as Simplify, @@ -74,11 +49,11 @@ export class TraitBuilder< } implement< - ImplClassWithAbstract extends ImplSuper // TODO: find a way to set the constraint to concrete classes while keeping the Super arg as an abstract class + ImplClassWithAbstract extends TraitBuilder.ImplSuper // TODO: find a way to set the constraint to concrete classes while keeping the Super arg as an abstract class >( - apply: (Super: ImplSuper) => ImplClassWithAbstract + apply: (Super: TraitBuilder.ImplSuper) => ImplClassWithAbstract ) { - return new TraitBuilder( + return new this.constructor( this.traitSuperExpression, this.traitAbstract, this.traitStaticAbstract, @@ -103,6 +78,7 @@ export class TraitBuilder< ) } + build() { return new Trait( this.traitSuperExpression, @@ -113,6 +89,37 @@ export class TraitBuilder< } } +export namespace TraitBuilder { + export type ImplSuper = ( + This extends TraitBuilder< + any, + infer Abstract, + infer StaticAbstract, + infer ImplClass + > + ? ( + AbstractClass< + Simplify< + Extend<[ + Abstract, + InstanceType, + ]> + > + > & + + Simplify< + Extend<[ + StaticAbstract, + StaticMembers, + ]> + > & + { readonly [implSuperSymbol]: true } + ) + : never + ) +} + + export const trait = new TraitBuilder( new TraitExpression(TraitExpression.NullSuperclass, []), {} as object, diff --git a/src/TraitExpression.ts b/src/TraitExpression.ts index 62b3624..44367d0 100644 --- a/src/TraitExpression.ts +++ b/src/TraitExpression.ts @@ -6,7 +6,7 @@ import { Extend, StaticMembers } from "./util" export class TraitExpression< Superclass extends AbstractClass, - const Traits extends Trait[], + const Traits extends readonly Trait[], > { constructor( readonly superclass: Superclass, @@ -95,7 +95,7 @@ export namespace TraitExpression { export type Implements< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( Simplify< Extend< @@ -107,7 +107,7 @@ export type Implements< ) export type StaticImplements< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( Simplify< Extend< @@ -120,7 +120,7 @@ export type StaticImplements< export type TraitExpressionClass< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( AbstractClass< TraitExpressionInstance, @@ -130,7 +130,7 @@ export type TraitExpressionClass< ) export type TraitExpressionConcreteClass< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( Class< TraitExpressionInstance, @@ -140,7 +140,7 @@ export type TraitExpressionConcreteClass< ) export type TraitExpressionInstance< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( InstanceType> & // Keep the instance of the superclass outside of any kind of type manipulation // as it can accidentely remove abstract properties @@ -152,7 +152,7 @@ export type TraitExpressionInstance< ) export type TraitExpressionStaticMembers< - Exp extends TraitExpression[]> + Exp extends TraitExpression[]> > = ( Simplify< Extend<[ diff --git a/src/TraitExpressionBuilder.ts b/src/TraitExpressionBuilder.ts index 4ade9dd..2885fe6 100644 --- a/src/TraitExpressionBuilder.ts +++ b/src/TraitExpressionBuilder.ts @@ -5,85 +5,70 @@ import { TraitExpression } from "./TraitExpression" import { Extendable, StaticMembers } from "./util" -type SpreadSupertraits = ( - Traits extends [ - infer El extends Trait, - ...infer Rest, - ] - ? [ - ...Trait.Supertraits, - El, - ...SpreadSupertraits, - ] - : [] -) - -type TraitsUniq = ( - Traits extends [ - ...infer Rest, - infer El extends Trait, - ] - ? IsTraitInTupleFromRight extends true - ? TraitsUniq - : [...TraitsUniq, El] - : [] -) -type IsTraitInTupleFromRight = ( - Traits extends [...infer Rest, infer El] - ? IsEqual extends true - ? true - : IsTraitInTupleFromRight - : false -) - - -type BuildTraitExpression< - Superclass extends AbstractClass, - Traits extends Trait[], -> = ( - Extendable> extends false - ? "Type conflict between the traits abstract definitions." - : Extendable> extends false - ? "Type conflict between the traits static abstract definitions." - : Extendable<[ - InstanceType, - ...TraitTuple.MapImplInstance, - ]> extends false - ? "Type conflict between the traits implementation instance and/or the superclass instance." - : Extendable<[ - StaticMembers, - ...TraitTuple.MapImplStaticMembers, - ]> extends false - ? "Type conflict between the traits implementation static members and/or the superclass static members." - : TraitExpression -) - - export class TraitExpressionBuilder< Superclass extends AbstractClass, - const Traits extends Trait[], + const Traits extends readonly Trait[], > { + declare ["constructor"]: typeof TraitExpressionBuilder + constructor( readonly expressionSuperclass: Superclass, readonly expressionTraits: Traits, ) {} + + static spreadSupertraits< + const T extends readonly Trait< + TraitExpression< + typeof TraitExpression.NullSuperclass, + readonly Trait[] + >, + any, + any, + any + >[] + >( + traits: T + ) { + return traits.flatMap(trait => [ + ...trait.superExpression.traits, + trait, + ]) as TraitExpressionBuilder.SpreadSupertraits + } + + static traitsUniq< + const T extends readonly Trait< + TraitExpression< + typeof TraitExpression.NullSuperclass, + readonly Trait[] + >, + any, + any, + any + >[] + >( + traits: T + ) { + return uniq(traits) as TraitExpressionBuilder.TraitsUniq + } + + extends< Super extends AbstractClass >( superclass: Super ) { - return new TraitExpressionBuilder( + return new this.constructor( superclass, this.expressionTraits, ) } expresses< - const T extends Trait< + const T extends readonly Trait< TraitExpression< typeof TraitExpression.NullSuperclass, - Trait[] + readonly Trait[] >, any, any, @@ -91,25 +76,25 @@ export class TraitExpressionBuilder< >[] >( ...traits: T - ) { - return new TraitExpressionBuilder( + ): TraitExpressionBuilder< + Superclass, + TraitExpressionBuilder.ExpressesReturnTypeTraits + > { + return new this.constructor( this.expressionSuperclass, - uniq([ + this.constructor.traitsUniq([ ...this.expressionTraits, - ...traits.flatMap(trait => [ - ...trait.superExpression.traits, - trait, - ]), - ]) as TraitsUniq<[...Traits, ...SpreadSupertraits]>, + ...this.constructor.spreadSupertraits(traits), + ]), ) } expressesFirst< - const T extends Trait< + const T extends readonly Trait< TraitExpression< typeof TraitExpression.NullSuperclass, - Trait[] + readonly Trait[] >, any, any, @@ -117,25 +102,26 @@ export class TraitExpressionBuilder< >[] >( ...traits: T - ) { - return new TraitExpressionBuilder( + ): TraitExpressionBuilder< + Superclass, + TraitExpressionBuilder.ExpressesFirstReturnTypeTraits + > { + return new this.constructor( this.expressionSuperclass, - uniq([ - ...traits.flatMap(trait => [ - ...trait.superExpression.traits, - trait, - ]), + this.constructor.traitsUniq([ + ...this.constructor.spreadSupertraits(traits), ...this.expressionTraits, - ]) as TraitsUniq<[...SpreadSupertraits, ...Traits]>, + ]), ) } + build() { return new TraitExpression( this.expressionSuperclass, this.expressionTraits, - ) as BuildTraitExpression + ) as TraitExpressionBuilder.BuildTraitExpression } then(fn: (expression: ReturnType) => V): V { @@ -154,4 +140,79 @@ export class TraitExpressionBuilder< } } +export namespace TraitExpressionBuilder { + export type SpreadSupertraits = ( + Traits extends [ + infer El extends Trait, + ...infer Rest, + ] + ? [ + ...Trait.Supertraits, + El, + ...SpreadSupertraits, + ] + : [] + ) + + export type TraitsUniq = ( + Traits extends [ + ...infer Rest, + infer El extends Trait, + ] + ? IsTraitInTupleFromRight extends true + ? TraitsUniq + : [...TraitsUniq, El] + : [] + ) + type IsTraitInTupleFromRight = ( + Traits extends [...infer Rest, infer El] + ? IsEqual extends true + ? true + : IsTraitInTupleFromRight + : false + ) + + export type ExpressesReturnTypeTraits< + Traits extends readonly Trait[], + T extends readonly Trait[], + > = ( + TraitExpressionBuilder.TraitsUniq<[ + ...Traits, + ...TraitExpressionBuilder.SpreadSupertraits, + ]> + ) + + export type ExpressesFirstReturnTypeTraits< + Traits extends readonly Trait[], + T extends readonly Trait[], + > = ( + TraitExpressionBuilder.TraitsUniq<[ + ...TraitExpressionBuilder.SpreadSupertraits, + ...Traits, + ]> + ) + + export type BuildTraitExpression< + Superclass extends AbstractClass, + Traits extends readonly Trait[], + > = ( + Extendable> extends false + ? "Type conflict between the traits abstract definitions." + : Extendable> extends false + ? "Type conflict between the traits static abstract definitions." + : Extendable<[ + InstanceType, + ...TraitTuple.MapImplInstance, + ]> extends false + ? "Type conflict between the traits implementation instance and/or the superclass instance." + : Extendable<[ + StaticMembers, + ...TraitTuple.MapImplStaticMembers, + ]> extends false + ? "Type conflict between the traits implementation static members and/or the superclass static members." + : TraitExpression + ) +} + + export const expression = new TraitExpressionBuilder(TraitExpression.NullSuperclass, []) diff --git a/src/tests.ts b/src/tests.ts index 2618486..af9b93f 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -64,6 +64,7 @@ const exp = expression PrintsHelloOnNew, Identifiable(), // Identifiable(), + // StatefulSubscription, ActiveStatefulSubscription, ) .build()