Compare commits

..

58 Commits

Author SHA1 Message Date
Julien Valverdé
d9213e0083 TraitExpression fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 22:41:20 +01:00
Julien Valverdé
df7e7f3401 Fixed TraitExpressionBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-19 22:08:24 +01:00
Julien Valverdé
eee35e7d59 NonExtendableKeys
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 21:19:25 +01:00
Julien Valverdé
9f36ce85be Extend work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 19:22:07 +01:00
Julien Valverdé
b9dc68d97b Extendable
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 18:23:09 +01:00
Julien Valverdé
394d267d74 Fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 17:53:23 +01:00
Julien Valverdé
8de5750d2e ExtendPlain -> Extend
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 17:50:34 +01:00
Julien Valverdé
49f0f7b987 Fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 17:31:22 +01:00
Julien Valverdé
7c4e754b24 Trait refactoring
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 17:26:44 +01:00
Julien Valverdé
ec82537380 Fixed TraitExpression
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-19 17:07:28 +01:00
Julien Valverdé
4ba0a19037 TraitExpression work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-19 03:57:23 +01:00
Julien Valverdé
2e716e7f96 TraitExpression work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-19 02:48:21 +01:00
Julien Valverdé
3c470a63f2 Fixed TraitBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-19 01:40:24 +01:00
Julien Valverdé
34c91707ae TraitExpression work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-19 01:11:22 +01:00
Julien Valverdé
40eaa80eb6 TraitBuilder work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-18 22:06:33 +01:00
Julien Valverdé
20554ec55a Trait work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-18 21:44:19 +01:00
Julien Valverdé
9524458c0f Trait work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-18 20:51:58 +01:00
Julien Valverdé
a0369ef2e6 Added TODO
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-18 05:01:06 +01:00
Julien Valverdé
2acee3f2a3 Fixed TraitBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-18 04:59:47 +01:00
Julien Valverdé
517792b1c2 Found working approach
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-18 04:10:20 +01:00
Julien Valverdé
45ec2dd0e3 Tests
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-18 03:33:36 +01:00
Julien Valverdé
3667e69d69 Slowly getting insane
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-18 02:55:22 +01:00
Julien Valverdé
c1f48b9bb2 TraitBuilder work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-17 21:23:08 +01:00
Julien Valverdé
04146f6c69 SubtraitAbstract
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-17 17:12:46 +01:00
Julien Valverdé
2fa71aaf37 TraitBuilder work
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-17 05:13:38 +01:00
Julien Valverdé
e5e8b7fad7 Pure TS implementation attempt
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-17 04:11:17 +01:00
Julien Valverdé
15c5548fde Fixed TraitBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-17 03:31:46 +01:00
Julien Valverdé
932d8576d9 Fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-16 19:54:48 +01:00
Julien Valverdé
df54a39eeb Cleanup
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-16 03:48:30 +01:00
Julien Valverdé
f37f15e466 TraitBuilder work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-16 01:30:04 +01:00
Julien Valverdé
9f2c42db14 Refactoring
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-16 01:14:36 +01:00
Julien Valverdé
af8884cdee TraitExpression work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-15 22:29:14 +01:00
Julien Valverdé
fe667e87fe TraitExpression work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-15 21:00:12 +01:00
Julien Valverdé
e928a11ee4 TraitBuilder work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-15 19:49:11 +01:00
Julien Valverdé
ceba99326d Fix
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-15 18:11:40 +01:00
Julien Valverdé
bc4b1b6492 Fix
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 23:18:17 +01:00
Julien Valverdé
d0b8981d45 Fix
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 22:59:37 +01:00
Julien Valverdé
0b0ca2326c extendStaticAbstract
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 22:33:23 +01:00
Julien Valverdé
a065daec1e extendAbstract
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-14 21:57:48 +01:00
Julien Valverdé
1758649507 Complete refactoring
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-14 21:13:02 +01:00
Julien Valverdé
5873926dc5 TraitExpression subtrait work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-14 03:27:03 +01:00
Julien Valverdé
14ceae27ec Regenerated lockfile
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 03:03:28 +01:00
Julien Valverdé
b5d97b5904 Exports
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 02:07:12 +01:00
Julien Valverdé
f849715a40 TraitBuilder use in tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 02:04:12 +01:00
Julien Valverdé
a9181567a2 TraitBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-14 01:37:05 +01:00
Julien Valverdé
cb0dd26ccb Ideas
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-10 00:26:19 +01:00
Julien Valverdé
30ad086b90 TraitBuilder
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 22:49:58 +01:00
Julien Valverdé
04f15b5b45 Trait expression uniq
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 20:06:53 +01:00
Julien Valverdé
2ad7ca0a0d Cleanup
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 19:18:45 +01:00
Julien Valverdé
48c64178f5 Fixed static abstract
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 18:35:15 +01:00
Julien Valverdé
688e01c96c Added export
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 18:29:18 +01:00
Julien Valverdé
3cf5733869 Fixed static abstract apply
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 18:28:50 +01:00
Julien Valverdé
7191b35c7a Working implementsStatic
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 14:46:24 +01:00
Julien Valverdé
4e59c60cdc implementsStatic fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-09 14:41:38 +01:00
Julien Valverdé
a64f9f46d7 Fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-09 14:39:18 +01:00
Julien Valverdé
e6d8a10f98 StaticImplements -> ImplementsStatic
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-09 14:38:23 +01:00
Julien Valverdé
e31ddeaa6e Static abstract
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-09 14:30:10 +01:00
Julien Valverdé
1a88ceb296 Static implements tests
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-09 02:27:50 +01:00
20 changed files with 266 additions and 768 deletions

View File

@@ -16,8 +16,8 @@ local lint_step = {
local build_step = { local build_step = {
name: "build", name: "build",
image: node_image, image: bun_image,
commands: ["npm run build"], commands: ["bun run build"],
}; };
local pack_step = { local pack_step = {

BIN
bun.lockb

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"name": "@thilawyn/traitify-ts", "name": "@thilawyn/traitify-ts",
"version": "0.1.24", "version": "0.1.4",
"type": "module", "type": "module",
"publishConfig": { "publishConfig": {
"registry": "https://git.jvalver.de/api/packages/thilawyn/npm/" "registry": "https://git.jvalver.de/api/packages/thilawyn/npm/"
@@ -8,58 +8,40 @@
"files": [ "files": [
"./dist" "./dist"
], ],
"types": "./dist/lib.d.ts",
"exports": { "exports": {
".": { ".": {
"import": { "import": {
"types": "./dist/lib.d.ts", "types": "./dist/lib.d.mts",
"default": "./dist/lib.js" "default": "./dist/lib.mjs"
}, },
"require": { "require": {
"types": "./dist/lib.d.cts", "types": "./dist/lib.d.cts",
"default": "./dist/lib.cjs" "default": "./dist/lib.cjs"
} }
},
"./effect": {
"import": {
"types": "./dist/effect/lib.d.ts",
"default": "./dist/effect/lib.js"
},
"require": {
"types": "./dist/effect/lib.d.cts",
"default": "./dist/effect/lib.cjs"
}
},
"./traitsUnique-DCJN7XEW": {
"import": {
"types": "./dist/traitsUnique-DCJN7XEW.d.ts"
},
"require": {
"types": "./dist/traitsUnique-DCJN7XEW.d.ts"
}
} }
}, },
"scripts": { "scripts": {
"build": "tsup", "build": "rollup -c rollup.config.ts",
"lint:tsc": "tsc --noEmit", "lint:tsc": "tsc --noEmit",
"clean:cache": "rm -f tsconfig.tsbuildinfo", "clean:cache": "rm -f tsconfig.tsbuildinfo",
"clean:dist": "rm -rf dist", "clean:dist": "rm -rf dist",
"clean:node": "rm -rf node_modules" "clean:node": "rm -rf node_modules"
}, },
"dependencies": { "dependencies": {
"remeda": "^1.61.0", "hotscript": "^1.0.13",
"type-fest": "^4.18.2" "lodash-es": "^4.17.21",
"type-fest": "^4.10.2"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/lodash-es": "^4.17.12",
"bun-types": "latest", "bun-types": "latest",
"npm-check-updates": "^16.14.20", "npm-check-updates": "^16.14.14",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",
"tsup": "^8.0.2", "rollup": "^4.9.6",
"tsx": "^4.10.1", "rollup-plugin-cleanup": "^3.2.1",
"typescript": "^5.4.5" "rollup-plugin-ts": "^3.4.5",
}, "tsx": "^4.7.0",
"optionalDependencies": { "typescript": "^5.3.3"
"@effect/schema": "^0.67.0",
"effect": "^3.1.3"
} }
} }

43
rollup.config.ts Normal file
View File

@@ -0,0 +1,43 @@
import { nodeResolve } from "@rollup/plugin-node-resolve"
import { defineConfig } from "rollup"
import cleanup from "rollup-plugin-cleanup"
import ts from "rollup-plugin-ts"
import pkg from "./package.json" assert { type: "json" }
export const createBundleConfig = (
input: string,
name: keyof typeof pkg.exports,
) => (
defineConfig({
input,
output: [
{
file: pkg.exports[name].import.default,
format: "esm",
},
{
file: pkg.exports[name].require.default,
format: "cjs",
},
],
external: id => !/^[./]/.test(id),
plugins: [
nodeResolve(),
ts(),
cleanup({
comments: "jsdoc",
extensions: ["ts"],
}),
],
})
)
export default [
createBundleConfig("src/lib.ts", "."),
]

View File

@@ -1,22 +1,22 @@
import { AbstractConstructor, Constructor, Simplify } from "type-fest" import { AbstractClass, Class, Simplify } from "type-fest"
import { TraitExpression } from "./TraitExpression" import { TraitExpression } from "./TraitExpression"
import { Extend, StaticMembers } from "./util" import { Extend, StaticMembers as StaticMembersUtil } from "./util"
export class Trait< export class Trait<
SuperExpression extends TraitExpression< SuperExpression extends TraitExpression<
typeof TraitExpression.NullSuperclass, typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[] Trait<any, any, any, any>[]
>, >,
Abstract extends object, Abstract extends object,
StaticAbstract extends object, StaticAbstract extends object,
ImplClass extends AbstractConstructor<object, []>, ImplClass extends AbstractClass<object, []>,
> { > {
constructor( constructor(
readonly superExpression: SuperExpression, readonly superExpression: SuperExpression,
readonly abstract: Abstract, readonly abstract: Abstract,
readonly staticAbstract: StaticAbstract, readonly staticAbstract: StaticAbstract,
readonly apply: (Super: AbstractConstructor<object>) => ImplClass, readonly apply: (Super: AbstractClass<object>) => ImplClass,
) {} ) {}
} }
@@ -54,7 +54,7 @@ export namespace Trait {
) )
export type ImplStaticMembers<T> = ( export type ImplStaticMembers<T> = (
StaticMembers<Trait.ImplClass<T>> StaticMembersUtil<Trait.ImplClass<T>>
) )
export type Instance<T> = ( export type Instance<T> = (
@@ -64,7 +64,7 @@ export namespace Trait {
]> ]>
) )
export type Static<T> = ( export type StaticMembers<T> = (
Extend<[ Extend<[
Trait.StaticAbstract<T>, Trait.StaticAbstract<T>,
Trait.ImplStaticMembers<T>, Trait.ImplStaticMembers<T>,
@@ -74,56 +74,56 @@ export namespace Trait {
export namespace TraitTuple { export namespace TraitTuple {
export type MapAbstract<T> = { export type MapAbstract<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.Abstract<T[K]> : Trait.Abstract<T[K]>
} }
export type MapStaticAbstract<T> = { export type MapStaticAbstract<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.StaticAbstract<T[K]> : Trait.StaticAbstract<T[K]>
} }
export type MapImplClass<T> = { export type MapImplClass<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.ImplClass<T[K]> : Trait.ImplClass<T[K]>
} }
export type MapImplInstance<T> = { export type MapImplInstance<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.ImplInstance<T[K]> : Trait.ImplInstance<T[K]>
} }
export type MapImplStaticMembers<T> = { export type MapImplStaticMembers<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.ImplStaticMembers<T[K]> : Trait.ImplStaticMembers<T[K]>
} }
export type MapInstance<T> = { export type MapInstance<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.Instance<T[K]> : Trait.Instance<T[K]>
} }
export type MapStaticMembers<T> = { export type MapStaticMembers<T> = {
[K in keyof T]: K extends keyof readonly [] [K in keyof T]: K extends keyof []
? T[K] ? T[K]
: Trait.Static<T[K]> : Trait.StaticMembers<T[K]>
} }
} }
export type TraitClass<T extends Trait<any, any, any, any>> = ( export type TraitClass<T extends Trait<any, any, any, any>> = (
AbstractConstructor<TraitInstance<T>, any[]> & AbstractClass<TraitInstance<T>, any[]> &
TraitStaticMembers<T> TraitStaticMembers<T>
) )
export type TraitConcreteClass<T extends Trait<any, any, any, any>> = ( export type TraitConcreteClass<T extends Trait<any, any, any, any>> = (
Constructor<TraitInstance<T>, any[]> & Class<TraitInstance<T>, any[]> &
TraitStaticMembers<T> TraitStaticMembers<T>
) )
@@ -132,5 +132,5 @@ export type TraitInstance<T extends Trait<any, any, any, any>> = (
) )
export type TraitStaticMembers<T extends Trait<any, any, any, any>> = ( export type TraitStaticMembers<T extends Trait<any, any, any, any>> = (
Simplify<Trait.Static<T>> Simplify<Trait.StaticMembers<T>>
) )

View File

@@ -1,105 +1,10 @@
import { AbstractConstructor, Constructor, Simplify } from "type-fest" import { AbstractClass, Simplify } from "type-fest"
import { Trait } from "./Trait" import { Trait } from "./Trait"
import { TraitExpression } from "./TraitExpression" import { TraitExpression } from "./TraitExpression"
import { Extend, StaticMembers, type } from "./util" import { Extend, StaticMembers } from "./util"
declare const implSuperSymbol: unique symbol type ImplSuper<This> = (
export class TraitBuilder<
SuperExpression extends TraitExpression<
typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[]
>,
Abstract extends object,
StaticAbstract extends object,
ImplClass extends AbstractConstructor<object, []>,
> {
constructor(
readonly traitSuperExpression: SuperExpression,
readonly traitAbstract: Abstract,
readonly traitStaticAbstract: StaticAbstract,
readonly traitApply: (Super: AbstractConstructor<object>) => ImplClass,
) {}
abstract<A extends AbstractConstructor<Abstract> & StaticAbstract>(
_: (Super: AbstractConstructor<Abstract> & StaticAbstract) => A
) {
return new TraitBuilder(
this.traitSuperExpression,
{} as Simplify<InstanceType<A>>,
{} as Simplify<StaticMembers<A>>,
this.traitApply,
)
}
abstractType<A extends Abstract>(
_: (Super: Abstract) => typeof type<A>
) {
return new TraitBuilder(
this.traitSuperExpression,
{} as Simplify<A>,
this.traitStaticAbstract,
this.traitApply,
)
}
staticAbstractType<A extends StaticAbstract>(
_: (Super: StaticAbstract) => typeof type<A>
) {
return new TraitBuilder(
this.traitSuperExpression,
this.traitAbstract,
{} as Simplify<A>,
this.traitApply,
)
}
implement<
ImplClassWithAbstract extends TraitBuilder.ImplSuper<typeof this> // TODO: find a way to set the constraint to concrete classes while keeping the Super arg as an abstract class
>(
apply: (Super: TraitBuilder.ImplSuper<typeof this>) => ImplClassWithAbstract
) {
return new TraitBuilder(
this.traitSuperExpression,
this.traitAbstract,
this.traitStaticAbstract,
apply as unknown as (Super: AbstractConstructor<object>) => (
AbstractConstructor<
Simplify<
Omit<
InstanceType<ImplClassWithAbstract>,
keyof Abstract | "constructor"
>
>
> &
Simplify<
Omit<
StaticMembers<ImplClassWithAbstract>,
keyof StaticAbstract | typeof implSuperSymbol
>
>
),
)
}
build() {
return new Trait(
this.traitSuperExpression,
this.traitAbstract,
this.traitStaticAbstract,
this.traitApply,
)
}
}
export namespace TraitBuilder {
export type ImplSuper<This> = (
This extends TraitBuilder< This extends TraitBuilder<
any, any,
infer Abstract, infer Abstract,
@@ -107,7 +12,7 @@ export namespace TraitBuilder {
infer ImplClass infer ImplClass
> >
? ( ? (
AbstractConstructor< AbstractClass<
Simplify< Simplify<
Extend<[ Extend<[
Abstract, Abstract,
@@ -122,59 +27,93 @@ export namespace TraitBuilder {
StaticMembers<ImplClass>, StaticMembers<ImplClass>,
]> ]>
> & > &
{ readonly [implSuperSymbol]: true } { readonly _tag: "@thilawyn/traitify-ts/Super" } // TODO: replace with unique symbol?
) )
: never : never
)
}
export type ImplStatic<
ImplClass extends AbstractConstructor<object> & { readonly [implSuperSymbol]: true }
> = (
Simplify<
Omit<StaticMembers<ImplClass>, typeof implSuperSymbol>
>
) )
export function implStaticThis<
ImplClass extends AbstractConstructor<object> & { readonly [implSuperSymbol]: true },
This extends AbstractConstructor<object>,
>(
_Impl: ImplClass,
thisArg: This,
) {
return thisArg as unknown as (
AbstractConstructor<
InstanceType<ImplClass> & InstanceType<This>,
ConstructorParameters<This>
> &
ImplStatic<ImplClass> &
StaticMembers<This>
)
}
export function implStaticInstantiableThis< export class TraitBuilder<
ImplClass extends AbstractConstructor<object> & { readonly [implSuperSymbol]: true }, SuperExpression extends TraitExpression<
This extends Constructor<object>, typeof TraitExpression.NullSuperclass,
>( Trait<any, any, any, any>[]
_Impl: ImplClass, >,
thisArg: This, Abstract extends object,
) { StaticAbstract extends object,
return thisArg as unknown as ( ImplClass extends AbstractClass<object, []>,
Constructor< > {
InstanceType<ImplClass> & InstanceType<This>, constructor(
ConstructorParameters<This> private readonly traitSuperExpression: SuperExpression,
> & private readonly traitAbstract: Abstract,
ImplStatic<ImplClass> & private readonly traitStaticAbstract: StaticAbstract,
StaticMembers<This> private readonly traitApply: (Super: AbstractClass<object>) => ImplClass,
) ) {}
}
abstract<A extends Abstract>(
_: (Super: AbstractClass<Abstract>) => AbstractClass<A, []>
) {
return new TraitBuilder(
this.traitSuperExpression,
{} as Simplify<A>,
this.traitStaticAbstract,
this.traitApply,
)
}
staticAbstract<A extends StaticAbstract>(
_: (Super: AbstractClass<StaticAbstract>) => AbstractClass<A, []>
) {
return new TraitBuilder(
this.traitSuperExpression,
this.traitAbstract,
{} as Simplify<A>,
this.traitApply,
)
}
implement<
ImplClassWithAbstract extends ImplSuper<typeof this>
>(
apply: (Super: ImplSuper<typeof this>) => ImplClassWithAbstract
) {
return new TraitBuilder(
this.traitSuperExpression,
this.traitAbstract,
this.traitStaticAbstract,
apply as unknown as (Super: AbstractClass<object>) => (
AbstractClass<
Simplify<
Omit<
InstanceType<ImplClassWithAbstract>,
keyof Abstract
>
>
> &
Simplify<
Omit<
StaticMembers<ImplClassWithAbstract>,
keyof StaticAbstract | "_tag"
>
>
),
)
}
build() {
return new Trait(
this.traitSuperExpression,
this.traitAbstract,
this.traitStaticAbstract,
this.traitApply,
)
}
}
export const trait = new TraitBuilder( export const trait = new TraitBuilder(
new TraitExpression(TraitExpression.NullSuperclass, []), new TraitExpression(TraitExpression.NullSuperclass, []),
{} as {}, {} as object,
{} as {}, {} as object,
Super => class extends Super {} as AbstractConstructor<{}>, Super => class extends Super {} as AbstractClass<object>,
) )

View File

@@ -1,35 +1,26 @@
import { AbstractConstructor, Constructor, Simplify } from "type-fest" import { AbstractClass, Class, Simplify } from "type-fest"
import { Trait, TraitTuple } from "./Trait" import { Trait, TraitTuple } from "./Trait"
import { TraitBuilder } from "./TraitBuilder" import { TraitBuilder } from "./TraitBuilder"
import { Extend, StaticMembers } from "./util" import { Extend, StaticMembers } from "./util"
export type TraitExpressionLike<
Superclass extends AbstractConstructor<object>,
Traits extends readonly Trait<any, any, any, any>[],
> = {
readonly superclass: Superclass,
readonly traits: Traits,
}
export class TraitExpression< export class TraitExpression<
Superclass extends AbstractConstructor<object>, Superclass extends AbstractClass<object>,
const Traits extends readonly Trait<any, any, any, any>[], const Traits extends Trait<any, any, any, any>[],
> > {
implements TraitExpressionLike<Superclass, Traits> {
constructor( constructor(
readonly superclass: Superclass, readonly superclass: Superclass,
readonly traits: Traits, readonly traits: Traits,
) {} ) {}
get extends(): ( get extends(): (
AbstractConstructor< AbstractClass<
InstanceType<Superclass> & // Keep the instance of the superclass outside of any kind of type manipulation InstanceType<Superclass> & // Keep the instance of the superclass outside of any kind of type manipulation
// as it can accidentely remove abstract properties // as it can accidentely remove abstract properties
Simplify< Simplify<
Extend<TraitTuple.MapImplInstance<Traits>> Extend<
TraitTuple.MapImplInstance<Traits>
>
>, >,
ConstructorParameters<Superclass> ConstructorParameters<Superclass>
@@ -48,20 +39,16 @@ implements TraitExpressionLike<Superclass, Traits> {
) as any ) as any
} }
implementsStatic(target: ImplementsStatic<typeof this>, context: any) {}
staticImplements(_target: StaticImplements<typeof this>, _context: any) {}
get staticImplementsStage2() {
return (_target: StaticImplements<typeof this>) => {}
}
subtrait< subtrait<
This extends TraitExpression<typeof TraitExpression.NullSuperclass, any> This extends TraitExpression<typeof TraitExpression.NullSuperclass, any>
>( >(
this: This this: This
) { ) {
return new TraitBuilder<This, return new TraitBuilder<
This,
Simplify< Simplify<
Extend<TraitTuple.MapAbstract<Traits>> Extend<TraitTuple.MapAbstract<Traits>>
>, >,
@@ -69,7 +56,7 @@ implements TraitExpressionLike<Superclass, Traits> {
Extend<TraitTuple.MapStaticAbstract<Traits>> Extend<TraitTuple.MapStaticAbstract<Traits>>
>, >,
AbstractConstructor< AbstractClass<
Simplify< Simplify<
Extend<TraitTuple.MapImplInstance<Traits>> Extend<TraitTuple.MapImplInstance<Traits>>
> >
@@ -87,20 +74,19 @@ implements TraitExpressionLike<Superclass, Traits> {
} }
export namespace TraitExpression { export namespace TraitExpression {
const nullSuperclassSymbol = Symbol()
export class NullSuperclass { export class NullSuperclass {
static readonly [nullSuperclassSymbol]: true static readonly _tag = "@thilawyn/traitify-ts/TraitExpression.NullSuperclass"
constructor(..._args: any[]) {} constructor(...args: any[]) {}
} }
export type Superclass<T> = ( export type Superclass<T> = (
T extends TraitExpressionLike<infer Superclass, any> T extends TraitExpression<infer Superclass, any>
? Superclass ? Superclass
: never : never
) )
export type Traits<T> = ( export type Traits<T> = (
T extends TraitExpressionLike<any, infer Traits> T extends TraitExpression<any, infer Traits>
? Traits ? Traits
: never : never
) )
@@ -108,7 +94,7 @@ export namespace TraitExpression {
export type Implements< export type Implements<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
Simplify< Simplify<
Extend< Extend<
@@ -119,8 +105,8 @@ export type Implements<
> >
) )
export type StaticImplements< export type ImplementsStatic<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
Simplify< Simplify<
Extend< Extend<
@@ -133,19 +119,19 @@ export type StaticImplements<
export type TraitExpressionClass< export type TraitExpressionClass<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
AbstractConstructor< AbstractClass<
TraitExpressionInstance<Exp>, TraitExpressionInstance<Exp>,
ConstructorParameters<TraitExpression.Superclass<Exp>> ConstructorParameters<TraitExpression.Superclass<Exp>>
> & > &
TraitExpressionStaticMembers<Exp> TraitExpressionStaticMembers<Exp>
) )
export type TraitExpressionInstantiableClass< export type TraitExpressionConcreteClass<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
Constructor< Class<
TraitExpressionInstance<Exp>, TraitExpressionInstance<Exp>,
ConstructorParameters<TraitExpression.Superclass<Exp>> ConstructorParameters<TraitExpression.Superclass<Exp>>
> & > &
@@ -153,7 +139,7 @@ export type TraitExpressionInstantiableClass<
) )
export type TraitExpressionInstance< export type TraitExpressionInstance<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
InstanceType<TraitExpression.Superclass<Exp>> & // Keep the instance of the superclass outside of any kind of type manipulation InstanceType<TraitExpression.Superclass<Exp>> & // Keep the instance of the superclass outside of any kind of type manipulation
// as it can accidentely remove abstract properties // as it can accidentely remove abstract properties
@@ -165,7 +151,7 @@ export type TraitExpressionInstance<
) )
export type TraitExpressionStaticMembers< export type TraitExpressionStaticMembers<
Exp extends TraitExpressionLike<any, readonly Trait<any, any, any, any>[]> Exp extends TraitExpression<any, Trait<any, any, any, any>[]>
> = ( > = (
Simplify< Simplify<
Extend<[ Extend<[

View File

@@ -1,23 +1,65 @@
import { AbstractConstructor } from "type-fest" import { Call, Fn, Tuples } from "hotscript"
import { uniq } from "lodash-es"
import { AbstractClass } from "type-fest"
import { Trait, TraitTuple } from "./Trait" import { Trait, TraitTuple } from "./Trait"
import { TraitExpression } from "./TraitExpression" import { TraitExpression } from "./TraitExpression"
import { SpreadSupertraits, spreadSupertraits } from "./spreadSupertraits"
import { TraitsUnique, traitsUnique } from "./traitsUnique"
import { Extendable, StaticMembers } from "./util" import { Extendable, StaticMembers } from "./util"
export class TraitExpressionBuilder< type SpreadSupertraits<Traits extends Trait<any, any, any, any>[]> = (
Superclass extends AbstractConstructor<object>, Call<
const Traits extends readonly Trait<any, any, any, any>[], Tuples.FlatMap<PrependTraitSupertraitsFn>,
Traits
>
)
interface PrependTraitSupertraitsFn extends Fn {
return: [...Trait.Supertraits<this["arg0"]>, this["arg0"]]
}
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( constructor(
readonly expressionSuperclass: Superclass, private readonly expressionSuperclass: Superclass,
readonly expressionTraits: Traits, private readonly expressionTraits: Traits,
) {} ) {}
extends< extends<
Super extends AbstractConstructor<object> Super extends AbstractClass<object>
>( >(
superclass: Super superclass: Super
) { ) {
@@ -28,10 +70,10 @@ export class TraitExpressionBuilder<
} }
expresses< expresses<
const T extends readonly Trait< const T extends Trait<
TraitExpression< TraitExpression<
typeof TraitExpression.NullSuperclass, typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[] Trait<any, any, any, any>[]
>, >,
any, any,
any, any,
@@ -41,110 +83,31 @@ export class TraitExpressionBuilder<
...traits: T ...traits: T
): TraitExpressionBuilder< ): TraitExpressionBuilder<
Superclass, Superclass,
TraitExpressionBuilder.ExpressesReturnTypeTraits<Traits, T> [...Traits, ...SpreadSupertraits<T>]
> { > {
return new TraitExpressionBuilder( return new TraitExpressionBuilder(
this.expressionSuperclass, this.expressionSuperclass,
traitsUnique([ uniq([
...this.expressionTraits, ...this.expressionTraits,
...spreadSupertraits(traits), ...traits.flatMap(trait => [
...trait.superExpression.traits,
trait,
]), ]),
]) as [...Traits, ...SpreadSupertraits<T>],
) )
} }
expressesFirst<
const T extends readonly Trait<
TraitExpression<
typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[]
>,
any,
any,
any
>[]
>(
...traits: T
): TraitExpressionBuilder<
Superclass,
TraitExpressionBuilder.ExpressesFirstReturnTypeTraits<Traits, T>
> {
return new TraitExpressionBuilder(
this.expressionSuperclass,
traitsUnique([
...spreadSupertraits(traits),
...this.expressionTraits,
]),
)
}
build() { build() {
return new TraitExpression( return new TraitExpression(
this.expressionSuperclass, this.expressionSuperclass,
this.expressionTraits, this.expressionTraits,
) as TraitExpressionBuilder.BuildTraitExpression<Superclass, Traits> ) as BuildTraitExpression<Superclass, Traits>
} }
then<V>(fn: (expression: ReturnType<typeof this.build>) => V): V { then<V>(fn: (expression: ReturnType<typeof this.build>) => V): V {
return fn(this.build()) return fn(this.build())
} }
buildAnyway() {
return new TraitExpression(
this.expressionSuperclass,
this.expressionTraits,
)
}
thenAnyway<V>(fn: (expression: ReturnType<typeof this.buildAnyway>) => V): V {
return fn(this.buildAnyway())
}
} }
export namespace TraitExpressionBuilder {
export type ExpressesReturnTypeTraits<
Traits extends readonly Trait<any, any, any, any>[],
T extends readonly Trait<any, any, any, any>[],
> = (
TraitsUnique<readonly [
...Traits,
...SpreadSupertraits<T>,
]>
)
export type ExpressesFirstReturnTypeTraits<
Traits extends readonly Trait<any, any, any, any>[],
T extends readonly Trait<any, any, any, any>[],
> = (
TraitsUnique<readonly [
...SpreadSupertraits<T>,
...Traits,
]>
)
export type BuildTraitExpression<
Superclass extends AbstractConstructor<object>,
Traits extends readonly Trait<any, any, any, any>[],
> = (
Extendable<TraitTuple.MapAbstract<Traits>> extends false
? "Type conflict between the traits abstract definitions."
: Extendable<TraitTuple.MapStaticAbstract<Traits>> extends false
? "Type conflict between the traits static abstract definitions."
: Extendable<[
InstanceType<Superclass>,
...TraitTuple.MapImplInstance<Traits>,
]> extends false
? "Type conflict between the traits implementation instance and/or the superclass instance."
: Extendable<[
StaticMembers<Superclass>,
...TraitTuple.MapImplStaticMembers<Traits>,
]> extends false
? "Type conflict between the traits implementation static members and/or the superclass static members."
: TraitExpression<Superclass, Traits>
)
}
export const expression = new TraitExpressionBuilder(TraitExpression.NullSuperclass, []) export const expression = new TraitExpressionBuilder(TraitExpression.NullSuperclass, [])

View File

@@ -1,83 +0,0 @@
import { Schema as S } from "@effect/schema"
import { AbstractConstructor, Simplify } from "type-fest"
import { Trait, TraitTuple } from "../Trait"
import { StaticImplements, TraitExpressionLike } from "../TraitExpression"
import { Extend, StaticMembers } from "../util"
export class EffectSchemaTraitExpression<
Fields extends S.Struct.Fields,
I, R, C,
Inherited extends object,
Proto,
Static extends object,
const Traits extends readonly Trait<any, any, any, any>[],
const Mutability extends "Immutable" | "Mutable",
const EncodedMutability extends "Immutable" | "Mutable",
>
implements TraitExpressionLike<
S.Class<unknown, Fields, I, R, C, Inherited, Proto>,
Traits
> {
constructor(
readonly superclass: S.Class<unknown, Fields, I, R, C, Inherited, Proto>,
readonly superclassStatic: Static,
readonly traits: Traits,
readonly mutability: Mutability,
readonly encodedMutability: EncodedMutability,
) {}
extends<Self>(): (
AbstractConstructor<
Simplify<
ApplyMutability<S.Struct.Type<Fields>, Mutability> &
Extend<[
Omit<Inherited, keyof Fields>,
...TraitTuple.MapImplInstance<Traits>
]> &
Proto
>,
ConstructorParameters<S.Class<unknown, Fields, I, R, C, Inherited, Proto>>
> &
StaticMembers<
S.Class<
Self,
Fields,
ApplyMutability<I, EncodedMutability>,
R, C,
Inherited,
Proto
>
> &
Simplify<
Extend<[
Static,
...TraitTuple.MapImplStaticMembers<Traits>
]>
>
) {
return this.traits.reduce(
(previous, trait) => trait.apply(previous),
this.superclass,
) as any
}
staticImplements(_target: StaticImplements<typeof this>, _context: any) {}
get staticImplementsStage2() {
return (_target: StaticImplements<typeof this>) => {}
}
}
type ApplyMutability<T, Mutability extends "Immutable" | "Mutable"> = (
Mutability extends "Immutable"
? { +readonly [P in keyof T]: T[P] }
: { -readonly [P in keyof T]: T[P] }
)

View File

@@ -1,206 +0,0 @@
import { Schema as S } from "@effect/schema"
import { Simplify } from "type-fest"
import { Trait, TraitTuple } from "../Trait"
import { TraitExpression } from "../TraitExpression"
import { TraitExpressionBuilder } from "../TraitExpressionBuilder"
import { spreadSupertraits } from "../spreadSupertraits"
import { traitsUnique } from "../traitsUnique"
import { Extendable, StaticMembers } from "../util"
import { EffectSchemaTraitExpression } from "./EffectSchemaTraitExpression"
export class EffectSchemaInitialTraitExpressionBuilder {
class<
Fields extends S.Struct.Fields
>(
identifier: string,
fields: Fields,
annotations?: S.Annotations.Schema<unknown>,
) {
return new EffectSchemaTraitExpressionBuilder(
S.Class<unknown>(identifier)(fields, annotations),
{},
[],
"Immutable",
"Immutable",
)
}
taggedClass<
Tag extends string,
Fields extends S.Struct.Fields,
>(
tag: Tag,
fields: Fields,
annotations?: S.Annotations.Schema<unknown>,
) {
return new EffectSchemaTraitExpressionBuilder(
S.TaggedClass<unknown>()(tag, fields, annotations),
{},
[],
"Immutable",
"Immutable",
)
}
extends<
Super extends StaticMembers<S.Class<Self, Fields, I, R, C, Inherited, Proto>>,
Self extends object,
Fields extends S.Struct.Fields,
I, R, C,
Inherited extends object,
Proto,
NewFields extends S.Struct.Fields,
>(
superclass: Super | StaticMembers<S.Class<Self, Fields, I, R, C, Inherited, Proto>>,
identifier: string,
fields: NewFields,
annotations?: S.Annotations.Schema<unknown>,
) {
return new EffectSchemaTraitExpressionBuilder(
superclass.extend<unknown>(identifier)(fields, annotations),
{} as Simplify<
Omit<Super,
"prototype" | keyof S.Class<Self, Fields, I, R, C, Inherited, Proto>
>
>,
[],
"Immutable",
"Immutable",
)
}
}
export class EffectSchemaTraitExpressionBuilder<
Fields extends S.Struct.Fields,
I, R, C,
Inherited extends object,
Proto,
Static extends object,
const Traits extends readonly Trait<any, any, any, any>[],
const Mutability extends "Immutable" | "Mutable",
const EncodedMutability extends "Immutable" | "Mutable",
> {
constructor(
readonly expressionSuperclass: S.Class<unknown, Fields, I, R, C, Inherited, Proto>,
readonly expressionSuperclassStatic: Static,
readonly expressionTraits: Traits,
readonly expressionMutability: Mutability,
readonly expressionEncodedMutability: EncodedMutability,
) {}
mutable() {
return new EffectSchemaTraitExpressionBuilder(
this.expressionSuperclass,
this.expressionSuperclassStatic,
this.expressionTraits,
"Mutable",
this.expressionEncodedMutability,
)
}
immutable() {
return new EffectSchemaTraitExpressionBuilder(
this.expressionSuperclass,
this.expressionSuperclassStatic,
this.expressionTraits,
"Immutable",
this.expressionEncodedMutability,
)
}
mutableEncoded() {
return new EffectSchemaTraitExpressionBuilder(
this.expressionSuperclass,
this.expressionSuperclassStatic,
this.expressionTraits,
this.expressionMutability,
"Mutable",
)
}
immutableEncoded() {
return new EffectSchemaTraitExpressionBuilder(
this.expressionSuperclass,
this.expressionSuperclassStatic,
this.expressionTraits,
this.expressionMutability,
"Immutable",
)
}
expresses<
const T extends readonly Trait<
TraitExpression<
typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[]
>,
any,
any,
any
>[]
>(
...traits: T
) {
return new EffectSchemaTraitExpressionBuilder(
this.expressionSuperclass,
this.expressionSuperclassStatic,
traitsUnique([
...this.expressionTraits,
...spreadSupertraits(traits),
]) as TraitExpressionBuilder.ExpressesReturnTypeTraits<Traits, T>,
this.expressionMutability,
this.expressionEncodedMutability,
)
}
build(): (
Extendable<TraitTuple.MapAbstract<Traits>> extends false
? "Type conflict between the traits abstract definitions."
: Extendable<TraitTuple.MapStaticAbstract<Traits>> extends false
? "Type conflict between the traits static abstract definitions."
: Extendable<[
InstanceType<typeof this.expressionSuperclass>,
...TraitTuple.MapImplInstance<Traits>,
]> extends false
? "Type conflict between the traits implementation instance and/or the superclass instance."
: Extendable<[
Static,
...TraitTuple.MapImplStaticMembers<Traits>,
]> extends false
? "Type conflict between the traits implementation static members and/or the superclass static members."
: EffectSchemaTraitExpression<
Fields,
I, R, C,
Inherited,
Proto,
Static,
Traits,
Mutability,
EncodedMutability
>
) {
return new EffectSchemaTraitExpression(
this.expressionSuperclass,
this.expressionSuperclassStatic,
this.expressionTraits,
this.expressionMutability,
this.expressionEncodedMutability,
) as any
}
}
export const effectSchemaExpression = new EffectSchemaInitialTraitExpressionBuilder()

View File

@@ -1,2 +0,0 @@
export { EffectSchemaTraitExpression } from "./EffectSchemaTraitExpression"
export { EffectSchemaInitialTraitExpressionBuilder, EffectSchemaTraitExpressionBuilder, effectSchemaExpression } from "./EffectSchemaTraitExpressionBuilder"

View File

@@ -1,48 +0,0 @@
import { Schema as S } from "@effect/schema"
import { Implements } from "../TraitExpression"
import { effectSchemaExpression } from "./EffectSchemaTraitExpressionBuilder"
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K
}[keyof T]
type InspectSchemaClass<T> = T extends S.Class<infer Self, infer Fields, infer I, infer R, infer C, infer Inherited, infer Proto>
? Inherited
: never
const userExp = effectSchemaExpression
.class("User", {
id: S.BigIntFromSelf,
role: S.Union(S.Literal("User"), S.Literal("Admin")),
})
.mutable()
.mutableEncoded()
.build()
@userExp.staticImplements
export class User extends userExp.extends<User>() implements Implements<typeof userExp> {
aMethodThatShouldBeInherited() {}
static aStaticMethodThatShouldBeInherited() {}
}
User.Encoded
const user = new User({ id: 0n, role: "User" })
user.id = 0n
const adminExp = effectSchemaExpression
.extends(User, "User", {
role: S.Literal("Admin")
})
// .immutable()
.build()
@adminExp.staticImplements
export class Admin extends adminExp.extends<Admin>() implements Implements<typeof adminExp> {
}
const admin = new Admin({ id: 1n, role: "Admin" })
// admin.role = "Admin"

View File

@@ -1,5 +1,4 @@
export { Trait, TraitClass, TraitConcreteClass, TraitInstance, TraitStaticMembers, TraitTuple } from "./Trait" export { Trait, TraitClass, TraitConcreteClass, TraitInstance, TraitStaticMembers, TraitTuple } from "./Trait"
export { ImplStatic, TraitBuilder, implStaticInstantiableThis, implStaticThis, trait } from "./TraitBuilder" export { TraitBuilder, trait } from "./TraitBuilder"
export { Implements, StaticImplements, TraitExpression, TraitExpressionClass, TraitExpressionInstance, TraitExpressionInstantiableClass, TraitExpressionStaticMembers } from "./TraitExpression" export { Implements, ImplementsStatic, TraitExpression, TraitExpressionClass, TraitExpressionConcreteClass, TraitExpressionInstance, TraitExpressionStaticMembers } from "./TraitExpression"
export { TraitExpressionBuilder, expression } from "./TraitExpressionBuilder" export { expression } from "./TraitExpressionBuilder"
export { type } from "./util"

View File

@@ -1,35 +0,0 @@
import { Trait } from "./Trait"
import { TraitExpression } from "./TraitExpression"
export function spreadSupertraits<
const T extends readonly Trait<
TraitExpression<
typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[]
>,
any,
any,
any
>[]
>(
traits: T
) {
return traits.flatMap(trait => [
...trait.superExpression.traits,
trait,
]) as readonly Trait<any, any, any, any>[] as SpreadSupertraits<T>
}
export type SpreadSupertraits<Traits> = (
Traits extends readonly [
infer El extends Trait<any, any, any, any>,
...infer Rest,
]
? readonly [
...Trait.Supertraits<El>,
El,
...SpreadSupertraits<Rest>,
]
: readonly []
)

View File

@@ -1,8 +1,9 @@
import { AbstractClass, Simplify } from "type-fest"
import { TraitClass } from "./Trait" import { TraitClass } from "./Trait"
import { trait } from "./TraitBuilder" import { trait } from "./TraitBuilder"
import { Implements, StaticImplements, TraitExpressionClass } from "./TraitExpression" import { Implements, ImplementsStatic, TraitExpressionClass } from "./TraitExpression"
import { expression } from "./TraitExpressionBuilder" import { expression } from "./TraitExpressionBuilder"
import { type } from "./util" import { Extendable, NonExtendableKeys } from "./util"
const PrintsHelloOnNew = trait const PrintsHelloOnNew = trait
@@ -19,12 +20,9 @@ const PrintsHelloOnNew = trait
type PrintsHelloOnNewClass = TraitClass<typeof PrintsHelloOnNew> type PrintsHelloOnNewClass = TraitClass<typeof PrintsHelloOnNew>
const Identifiable = <ID>() => trait const Identifiable = <ID>() => trait
// .abstract(Super => class extends Super { .abstract(Super => class extends Super {
// declare readonly id: ID declare readonly id: ID
// }) })
.abstractType(Super => type<typeof Super & {
readonly id: ID
}>)
.implement(Super => class Identifiable extends Super { .implement(Super => class Identifiable extends Super {
equals(el: Identifiable) { equals(el: Identifiable) {
return this.id === el.id return this.id === el.id
@@ -32,15 +30,6 @@ const Identifiable = <ID>() => trait
}) })
.build() .build()
const ImplementsIdentifiable = <ID>(defaultID: ID) => expression
.expresses(Identifiable<ID>())
.build()
.subtrait()
.implement(Super => class ImplementsIdentifiable extends Super {
readonly id = defaultID
})
.build()
const StatefulSubscription = trait const StatefulSubscription = trait
.abstract(Super => class extends Super { .abstract(Super => class extends Super {
declare readonly isStatefulSubscription: true declare readonly isStatefulSubscription: true
@@ -77,16 +66,15 @@ const exp = expression
PrintsHelloOnNew, PrintsHelloOnNew,
Identifiable<bigint>(), Identifiable<bigint>(),
// Identifiable<number>(), // Identifiable<number>(),
// StatefulSubscription,
ActiveStatefulSubscription, ActiveStatefulSubscription,
) )
.build() .build()
type Abs = Implements<typeof exp> type Abs = Implements<typeof exp>
type AbsStatic = StaticImplements<typeof exp> type AbsStatic = ImplementsStatic<typeof exp>
type ExpClass = TraitExpressionClass<typeof exp> type ExpClass = TraitExpressionClass<typeof exp>
@exp.staticImplements @exp.implementsStatic
class User extends exp.extends implements Implements<typeof exp> { class User extends exp.extends implements Implements<typeof exp> {
readonly isStatefulSubscription: true = true readonly isStatefulSubscription: true = true
readonly isActiveStatefulSubscription: true = true readonly isActiveStatefulSubscription: true = true
@@ -95,3 +83,19 @@ class User extends exp.extends implements Implements<typeof exp> {
} }
console.log(new User()) console.log(new User())
abstract class Test {
abstract prout: string
}
const MappedTest = Test as AbstractClass<Test>
class ConcreteTest extends MappedTest {
}
// type T = NonExtendableKeys<[
// { prout: "gneugneu" },
// { prout: string },
// ]>

View File

@@ -1,39 +0,0 @@
import { unique } from "remeda"
import { IsEqual } from "type-fest"
import { Trait } from "./Trait"
import { TraitExpression } from "./TraitExpression"
export function traitsUnique<
const T extends readonly Trait<
TraitExpression<
typeof TraitExpression.NullSuperclass,
readonly Trait<any, any, any, any>[]
>,
any,
any,
any
>[]
>(
traits: T
) {
return unique(traits) as readonly Trait<any, any, any, any>[] as TraitsUnique<T>
}
export type TraitsUnique<Traits> = (
Traits extends readonly [
...infer Rest,
infer El extends Trait<any, any, any, any>,
]
? IsTraitInTupleFromRight<Rest, El> extends true
? TraitsUnique<Rest>
: readonly [...TraitsUnique<Rest>, El]
: readonly []
)
type IsTraitInTupleFromRight<Traits, T> = (
Traits extends readonly [...infer Rest, infer El]
? IsEqual<El, T> extends true
? true
: IsTraitInTupleFromRight<Rest, T>
: false
)

View File

@@ -20,32 +20,31 @@ import { CommonKeys } from "."
// ]> // ]>
// TODO: use OverrideProperties from type-fest?
export type Extend<T extends readonly object[]> = ( export type Extend<T extends readonly object[]> = (
T extends readonly [ T extends [
infer Super, infer Super,
infer Self, infer Self,
...infer Rest extends readonly object[], ...infer Rest extends object[],
] ]
? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>> ? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>>
? Extend<readonly [ ? Extend<[
Omit<Super, CommonKeys<Self, Super>> & Self, Omit<Super, CommonKeys<Self, Super>> & Self,
...Rest, ...Rest,
]> ]>
: never : never
: T extends readonly [infer Self] : T extends [infer Self]
? Self ? Self
: {} : {}
) )
export type Extendable<T extends readonly object[]> = ( export type Extendable<T extends readonly object[]> = (
T extends readonly [ T extends [
infer Super, infer Super,
infer Self, infer Self,
...infer Rest extends readonly object[], ...infer Rest extends object[],
] ]
? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>> ? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>>
? Extendable<readonly [ ? Extendable<[
Omit<Super, CommonKeys<Self, Super>> & Self, Omit<Super, CommonKeys<Self, Super>> & Self,
...Rest, ...Rest,
]> ]>
@@ -54,16 +53,16 @@ export type Extendable<T extends readonly object[]> = (
) )
export type NonExtendableKeys<T extends readonly object[]> = ( export type NonExtendableKeys<T extends readonly object[]> = (
T extends readonly [ T extends [
infer Super extends object, infer Super extends object,
infer Self extends object, infer Self extends object,
...infer Rest extends readonly object[], ...infer Rest extends object[],
] ]
? {[K in keyof Super & keyof Self]: Self[K] extends Super[K] ? {[K in keyof Super & keyof Self]: Self[K] extends Super[K]
? never ? never
: K : K
}[keyof Super & keyof Self] }[keyof Super & keyof Self]
| NonExtendableKeys<readonly [ | NonExtendableKeys<[
Super & Self, Super & Self,
...Rest, ...Rest,
]> ]>

View File

@@ -1,4 +1,5 @@
import { AbstractConstructor } from "type-fest" import { Fn } from "hotscript"
import { AbstractClass, Simplify } from "type-fest"
/** /**
@@ -8,10 +9,17 @@ import { AbstractConstructor } from "type-fest"
*/ */
export type CommonKeys<A, B> = Extract<keyof A, keyof B> export type CommonKeys<A, B> = Extract<keyof A, keyof B>
export interface SimplifyFn extends Fn {
return: Simplify<this["arg0"]>
}
/** /**
* Represents the static members of a class. * Represents the static members of a class.
* @template Class - A class. * @template Class - A class extending AbstractClass.
*/ */
export type StaticMembers<Class extends AbstractConstructor<any>> = Omit<Class, "prototype"> export type StaticMembers<Class extends AbstractClass<any>> = (
Omit<Class, "prototype">
export function type<T>() { return {} as T } )
export interface StaticMembersFn extends Fn {
return: StaticMembers<this["arg0"]>
}

View File

@@ -8,7 +8,7 @@
// "allowImportingTsExtensions": true, // "allowImportingTsExtensions": true,
// "noEmit": true, // "noEmit": true,
"declaration": true, "declaration": true,
// "composite": true, "composite": true,
"strict": true, "strict": true,
"downlevelIteration": true, "downlevelIteration": true,
"skipLibCheck": true, "skipLibCheck": true,

View File

@@ -1,12 +0,0 @@
import { defineConfig } from "tsup"
export default defineConfig({
entry: ["./src/lib.ts", "./src/effect/lib.ts"],
format: ["esm", "cjs"],
skipNodeModulesBundle: true,
dts: true,
splitting: true,
sourcemap: true,
clean: true,
})