Compare commits

...

35 Commits

Author SHA1 Message Date
Julien Valverdé
73ce4e11ff Cleanup
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-20 01:19:51 +01:00
Julien Valverdé
93f1038e27 ZodSchemaClassOf
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-20 01:08:22 +01:00
Julien Valverdé
3bf22f1f49 Traitify API update
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-20 00:55:21 +01:00
Julien Valverdé
880d77019d Fix
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 01:16:36 +01:00
Julien Valverdé
a4d4c87f54 Fixed instance inference
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-09 01:15:23 +01:00
Julien Valverdé
0d20e7ad69 Package upgrade
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-08 20:04:45 +01:00
Julien Valverdé
443ae01d2d Tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-08 18:35:16 +01:00
Julien Valverdé
65602eac7d types -> shapes
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-08 18:33:58 +01:00
Julien Valverdé
99f071147d Cleanup
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-08 18:28:39 +01:00
Julien Valverdé
5f7fd30459 Working extendable
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 18:26:37 +01:00
Julien Valverdé
041b3f566e ExtendableZodSchemaObject work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 03:25:10 +01:00
Julien Valverdé
9adfe2366c Refactoring
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 03:11:11 +01:00
Julien Valverdé
408d3a7f3a Tests
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 02:52:27 +01:00
Julien Valverdé
e1c298c08a Fixed InstantiableZodSchemaObject
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 02:50:16 +01:00
Julien Valverdé
ae4abf6b9c defaultValues fix
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 02:42:02 +01:00
Julien Valverdé
ed3f8fb643 ZodSchemaClassOf extend
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 02:39:38 +01:00
Julien Valverdé
ffce582e03 ZodSchemaClass work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-08 01:17:01 +01:00
Julien Valverdé
fa7d222f76 ZodSchemaClass work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-07 00:39:37 +01:00
Julien Valverdé
f40bebbc9b InstantiableZodSchemaObject
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-07 00:32:23 +01:00
Julien Valverdé
6ee9337426 Trait work
Some checks failed
continuous-integration/drone/push Build is failing
2024-02-06 05:24:00 +01:00
Julien Valverdé
5297468d17 ZodSchemaClass.old.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-06 03:32:52 +01:00
Julien Valverdé
ff9bbb37e8 Dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2024-02-06 03:30:23 +01:00
Julien Valverdé
9ba149fb4c instantiate -> create
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 16:36:02 +01:00
Julien Valverdé
d867a3b83a Refactoring
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 16:31:44 +01:00
Julien Valverdé
e35db63da8 Refactoring
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 02:33:05 +01:00
Julien Valverdé
a4b8166af8 Inheritance logic refactoring
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 01:57:58 +01:00
Julien Valverdé
d34885a6e4 Dependencies upgrade
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 01:39:10 +01:00
Julien Valverdé
ab328f2cb5 Util refactoring
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-28 01:08:15 +01:00
Julien Valverdé
147034e95d ZodSchemaClassOf refactoring
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-24 21:49:19 +01:00
Julien Valverdé
516ce0ade2 Class type detection
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-24 21:40:27 +01:00
Julien Valverdé
338c750a4b TZodSchemaClass work
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-24 19:06:05 +01:00
Julien Valverdé
b6c2c4bec7 ZodSchemaClassOf work
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-21 23:29:11 +01:00
Julien Valverdé
c073154eeb Working new implementation
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-21 22:58:44 +01:00
Julien Valverdé
6873fae86b ZodSchemaClass
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-21 20:15:25 +01:00
Julien Valverdé
fc95a5d53a Moved current version to legacy
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-20 22:02:14 +01:00
44 changed files with 1256 additions and 1531 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"name": "@thilawyn/schemable-class", "name": "@thilawyn/schemable-class",
"version": "0.1.1", "version": "0.1.2",
"type": "module", "type": "module",
"publishConfig": { "publishConfig": {
"registry": "https://git.jvalver.de/api/packages/thilawyn/npm/" "registry": "https://git.jvalver.de/api/packages/thilawyn/npm/"
@@ -48,20 +48,21 @@
"clean:node": "rm -rf node_modules" "clean:node": "rm -rf node_modules"
}, },
"dependencies": { "dependencies": {
"@thilawyn/traitify-ts": "^0.1.3",
"decimal.js": "^10.4.3", "decimal.js": "^10.4.3",
"effect": "^2.1.1", "effect": "^2.2.5",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mobx": "^6.12.0", "mobx": "^6.12.0",
"type-fest": "^4.9.0", "type-fest": "^4.10.2",
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"bun-types": "latest", "bun-types": "latest",
"npm-check-updates": "^16.14.12", "npm-check-updates": "^16.14.14",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",
"rollup": "^4.9.5", "rollup": "^4.9.6",
"rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-ts": "^3.4.5", "rollup-plugin-ts": "^3.4.5",
"ts-functional-pipe": "^3.1.2", "ts-functional-pipe": "^3.1.2",

View File

@@ -1,54 +0,0 @@
import { z } from "zod"
import { Class, ClassType } from "./util"
export type SchemableClass<
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
Type extends ClassType = "AbstractClass"
> = (
Class<
Type,
{
readonly schema: z.ZodObject<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
readonly defaultValues: DefaultValues
} & Values,
Parameters<(values: Values) => never>
> & {
readonly schema: z.ZodObject<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
readonly defaultValues: DefaultValues
}
)
export type SchemableClassInput<
Values extends {},
DefaultValues extends Partial<Values>,
> = {
[Key in Exclude<keyof Values, keyof DefaultValues>]: Values[Key]
} & {
[Key in keyof DefaultValues]?: Key extends keyof Values
? Values[Key]
: never
}

74
src/ZodSchemaClass.ts Normal file
View File

@@ -0,0 +1,74 @@
import { expression } from "@thilawyn/traitify-ts"
import { AbstractClass } from "type-fest"
import { z } from "zod"
import { ExtendableZodSchemaObject } from "./traits/ExtendableZodSchemaObject"
import { InstantiableZodSchemaObject } from "./traits/InstantiableZodSchemaObject"
import { Extend, StaticMembers } from "./util"
export function ZodSchemaClassOf<
Super extends AbstractClass<object, []>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
of: Super,
{ schema, defaultValues }: {
schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: DefaultValues
},
) {
const exp = expression
.extends(class extends (of as AbstractClass<{}, []>) {
static readonly schema = schema
static readonly defaultValues = defaultValues
constructor(values: Values) {
super()
Object.assign(this, values)
}
})
.expresses(
InstantiableZodSchemaObject,
ExtendableZodSchemaObject,
)
.build()
return exp.extends as AbstractClass<
Extend<[
InstanceType<Super>,
InstanceType<typeof exp.extends>,
Values,
]>,
ConstructorParameters<typeof exp.extends>
> &
Extend<[
StaticMembers<Super>,
StaticMembers<typeof exp.extends>,
]>
}
class DefaultRoot {}
export function ZodSchemaClass<
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
props: {
schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: DefaultValues
},
) {
return ZodSchemaClassOf(DefaultRoot, props)
}

View File

@@ -1,5 +0,0 @@
export * from "./SchemableClass"
export * from "./defineDefaultValues"
export * from "./extendSchemableClass"
export * from "./makeSchemableClass"
export * from "./newSchemable"

View File

@@ -1,80 +0,0 @@
import { Effect } from "effect"
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod"
import { SchemableClass } from ".."
import { Class, ClassType } from "../util"
export type JsonifiableSchemableClass<
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
Type extends ClassType = "AbstractClass"
> = (
SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
Type
> &
Class<
Type,
{
readonly jsonifySchema: z.ZodObject<
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
JsonifiedValues,
Values
>
readonly dejsonifySchema: z.ZodObject<
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
Values,
JsonifiedValues
>
jsonify(): JsonifiedValues
jsonifyPromise(): Promise<JsonifiedValues>
jsonifyEffect(): Effect.Effect<never, z.ZodError<Values>, JsonifiedValues>
},
any[]
> & {
readonly jsonifySchema: z.ZodObject<
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
JsonifiedValues,
Values
>
readonly dejsonifySchema: z.ZodObject<
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
Values,
JsonifiedValues
>
}
)

View File

@@ -1,213 +0,0 @@
import { Effect, pipe } from "effect"
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod"
import { JsonifiableSchemableClass } from "."
import { parseZodTypeEffect } from "../util"
export function dejsonifySchemable<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>(
class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>,
) {
return new class_(
class_.dejsonifySchema.parse(values, params)
) as InstanceType<C>
}
export async function dejsonifySchemablePromise<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>(
class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>,
) {
return new class_(
await class_.dejsonifySchema.parseAsync(values, params)
) as InstanceType<C>
}
export function dejsonifySchemableEffect<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>(
class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>,
) {
return pipe(
parseZodTypeEffect(class_.dejsonifySchema, values, params),
Effect.map(values => new class_(values) as InstanceType<C>),
)
}

View File

@@ -1,4 +0,0 @@
export * from "./JsonifiableSchemableClass"
export * from "./dejsonifySchemable"
export * from "./makeJsonifiableSchemableClass"
export * from "./schema"

View File

@@ -1,134 +0,0 @@
import { Effect } from "effect"
import { AbstractClass, Class as ConcreteClass } from "type-fest"
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod"
import { SchemableClass } from ".."
import { StaticMembers, parseZodTypeEffect } from "../util"
export function makeJsonifiableSchemableClass<
C extends SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>(
extend: C | SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues
>,
props: {
jsonifySchema: (props: {
schema: z.ZodObject<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
shape: SchemaT
}) => z.ZodObject<
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
JsonifiedValues,
Values
>
dejsonifySchema: (props: {
schema: z.ZodObject<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
shape: SchemaT
}) => z.ZodObject<
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
Values,
JsonifiedValues
>
},
) {
type Class<T, Arguments extends unknown[]> = (
C extends ConcreteClass<any>
? ConcreteClass<T, Arguments>
: AbstractClass<T, Arguments>
)
const jsonifySchema = props.jsonifySchema({
schema: extend.schema,
shape: extend.schema.shape,
})
const dejsonifySchema = props.dejsonifySchema({
schema: extend.schema,
shape: extend.schema.shape,
})
return class extends extend {
static readonly jsonifySchema = jsonifySchema
readonly jsonifySchema = jsonifySchema
static readonly dejsonifySchema = dejsonifySchema
readonly dejsonifySchema = dejsonifySchema
jsonify() {
return this.jsonifySchema.parse(this)
}
jsonifyPromise() {
return this.jsonifySchema.parseAsync(this)
}
jsonifyEffect() {
return parseZodTypeEffect(this.jsonifySchema, this)
}
} as unknown as (
Class<
InstanceType<C> & {
readonly jsonifySchema: z.ZodObject<JsonifySchemaT, JsonifySchemaUnknownKeys, JsonifySchemaCatchall, JsonifiedValues, Values>,
readonly dejsonifySchema: z.ZodObject<DejsonifySchemaT, DejsonifySchemaUnknownKeys, DejsonifySchemaCatchall, Values, JsonifiedValues>,
jsonify(): JsonifiedValues
jsonifyPromise(): Promise<JsonifiedValues>
jsonifyEffect(): Effect.Effect<never, z.ZodError<Values>, JsonifiedValues>
},
ConstructorParameters<C>
> &
StaticMembers<C> & {
readonly jsonifySchema: z.ZodObject<JsonifySchemaT, JsonifySchemaUnknownKeys, JsonifySchemaCatchall, JsonifiedValues, Values>,
readonly dejsonifySchema: z.ZodObject<DejsonifySchemaT, DejsonifySchemaUnknownKeys, DejsonifySchemaCatchall, Values, JsonifiedValues>,
}
)
}

View File

@@ -1,28 +0,0 @@
import { Opaque } from "type-fest"
import { z } from "zod"
import { identity } from "../../util"
export type JsonifiedBigInt = Opaque<string, "@thilawyn/schemable-class/JsonifiedBigInt">
export function jsonifyBigIntSchema<S extends z.ZodBigInt>(schema: S) {
return schema.transform(v => v.toString() as JsonifiedBigInt)
}
export function dejsonifyBigIntSchema<S extends z.ZodBigInt>(schema: S) {
return z
.custom<JsonifiedBigInt>(identity)
.pipe(z
.string()
.transform(v => {
try {
return BigInt(v)
}
catch (e) {
return v
}
})
.pipe(schema)
)
}

View File

@@ -1,28 +0,0 @@
import { Opaque } from "type-fest"
import { z } from "zod"
import { identity } from "../../util"
export type JsonifiedDate = Opaque<string, "@thilawyn/schemable-class/JsonifiedDate">
export function jsonifyDateSchema<S extends z.ZodDate>(schema: S) {
return schema.transform(v => v.toString() as JsonifiedDate)
}
export function dejsonifyDateSchema<S extends z.ZodDate>(schema: S) {
return z
.custom<JsonifiedDate>(identity)
.pipe(z
.string()
.transform(v => {
try {
return new Date(v)
}
catch (e) {
return v
}
})
.pipe(schema)
)
}

View File

@@ -1,33 +0,0 @@
import { Decimal } from "decimal.js"
import { Opaque } from "type-fest"
import { z } from "zod"
import { identity } from "../../util"
export type JsonifiedDecimal = Opaque<string, "@thilawyn/schemable-class/JsonifiedDecimal">
export function jsonifyDecimalSchema<
S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>
>(schema: S) {
return schema.transform(v => v.toJSON() as JsonifiedDecimal)
}
export function dejsonifyDecimalSchema<
S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>
>(schema: S) {
return z
.custom<JsonifiedDecimal>(identity)
.pipe(z
.string()
.transform(v => {
try {
return new Decimal(v)
}
catch (e) {
return v
}
})
.pipe(schema)
)
}

View File

@@ -1,4 +0,0 @@
export * from "./bigint"
export * from "./date"
export * from "./decimal"
export * from "./schemable"

View File

@@ -1,139 +0,0 @@
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod"
import { JsonifiableSchemableClass } from ".."
export function jsonifySchemableSchema<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
>(
class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
schema: S,
) {
return schema.pipe(class_.jsonifySchema)
}
export function dejsonifySchemableSchema<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
>(
class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
schema: S,
) {
return class_.dejsonifySchema.transform(v => new class_(v)).pipe(schema)
}

View File

@@ -1,33 +1,21 @@
import { Class } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { Class, ClassType } from "../util"
/** export type SchemableClass<
* Configuration for creating a schemable object with validation schemas. SchemaT extends z.ZodRawShape,
* @template Values - The type representing the expected values. SchemaUnknownKeys extends z.UnknownKeysParam,
* @template Input - The type representing the input values. SchemaCatchall extends z.ZodTypeAny,
* @template SchemaT - The type representing the base validation schema.
* @template SchemaUnknownKeys - The type representing the unknown keys behavior in the base validation schema.
* @template SchemaCatchall - The type representing the catchall behavior in the base validation schema.
* @template SchemaWithDefaultValuesT - The type representing the validation schema with default values.
* @template SchemaWithDefaultValuesUnknownKeys - The type representing the unknown keys behavior in the validation schema with default values.
* @template SchemaWithDefaultValuesCatchall - The type representing the catchall behavior in the validation schema with default values.
*/
export type SchemableConfig<
Values extends {} = {},
Input extends {} = {},
SchemaT extends z.ZodRawShape = z.ZodRawShape, Values extends {},
SchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, DefaultValues extends Partial<Values>,
SchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny,
SchemaWithDefaultValuesT extends z.ZodRawShape = z.ZodRawShape, Type extends ClassType = "AbstractClass"
SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, > = (
SchemaWithDefaultValuesCatchall extends z.ZodTypeAny = z.ZodTypeAny, Class<
> = { Type,
readonly values: Values
readonly input: Input
{
readonly schema: z.ZodObject< readonly schema: z.ZodObject<
SchemaT, SchemaT,
SchemaUnknownKeys, SchemaUnknownKeys,
@@ -36,55 +24,31 @@ export type SchemableConfig<
Values Values
> >
readonly schemaWithDefaultValues: z.ZodObject< readonly defaultValues: DefaultValues
SchemaWithDefaultValuesT, } & Values,
SchemaWithDefaultValuesUnknownKeys,
SchemaWithDefaultValuesCatchall,
Values,
Input
>
}
Parameters<(values: Values) => never>
/**
* Represents a class with validation schemas.
* @template $Config - The configuration type for the schemable object.
*/
export type SchemableClass<
$Config extends SchemableConfig
> = (
Class<
SchemableObject<$Config>,
SchemableClassConstructorParams<$Config>
> & { > & {
readonly $schemableConfig: $Config readonly schema: z.ZodObject<
readonly schema: $Config["schema"] SchemaT,
readonly schemaWithDefaultValues: $Config["schemaWithDefaultValues"] SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
readonly defaultValues: DefaultValues
} }
) )
/**
* Represents the constructor parameters for the schemable object class.
* @template $Config - The configuration type for the schemable object.
*/
export type SchemableClassConstructorParams<
$Config extends SchemableConfig
> = (
Parameters<
(data: $Config["values"]) => void
>
)
/** export type SchemableClassInput<
* Represents an object with validation schemas. Values extends {},
* @template $Config - The configuration type for the schemable object. DefaultValues extends Partial<Values>,
*/ > = {
export type SchemableObject< [Key in Exclude<keyof Values, keyof DefaultValues>]: Values[Key]
$Config extends SchemableConfig } & {
> = ( [Key in keyof DefaultValues]?: Key extends keyof Values
{ ? Values[Key]
readonly $schemableConfig: $Config : never
readonly schema: $Config["schema"] }
readonly schemaWithDefaultValues: $Config["schemaWithDefaultValues"]
} & $Config["values"]
)

View File

@@ -1,7 +1,7 @@
import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest" import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { DefinedDefaultValuesTag, SchemableClass } from "." import { DefinedDefaultValuesTag, SchemableClass } from "."
import { StaticMembers } from "./util" import { StaticMembers } from "../util"
export function extendSchemableClass< export function extendSchemableClass<

View File

@@ -1,3 +1,5 @@
export * from "./SchemableClass" export * from "./SchemableClass"
export * from "./defineDefaultValues"
export * from "./extendSchemableClass"
export * from "./makeSchemableClass" export * from "./makeSchemableClass"
export * from "./newSchemable" export * from "./newSchemable"

View File

@@ -1,66 +1,80 @@
import { Effect } from "effect" import { Effect } from "effect"
import { Class } from "type-fest"
import { JsonifiableObject } from "type-fest/source/jsonifiable" import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod" import { z } from "zod"
import { SchemableClassConstructorParams, SchemableConfig } from ".." import { SchemableClass } from ".."
import { Class, ClassType } from "../../util"
export type JsonifiableSchemableConfig< export type JsonifiableSchemableClass<
$SchemableConfig extends SchemableConfig = SchemableConfig, SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject = {}, Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape = z.ZodRawShape, JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny, JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape = z.ZodRawShape, DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny, DejsonifySchemaCatchall extends z.ZodTypeAny,
> = {
readonly $schemableConfig: $SchemableConfig
readonly jsonifiedValues: JsonifiedValues JsonifiedValues extends JsonifiableObject,
Type extends ClassType = "AbstractClass"
> = (
SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
Type
> &
Class<
Type,
{
readonly jsonifySchema: z.ZodObject< readonly jsonifySchema: z.ZodObject<
JsonifySchemaT, JsonifySchemaT,
JsonifySchemaUnknownKeys, JsonifySchemaUnknownKeys,
JsonifySchemaCatchall, JsonifySchemaCatchall,
JsonifiedValues, JsonifiedValues,
$SchemableConfig["values"] Values
> >
readonly dejsonifySchema: z.ZodObject< readonly dejsonifySchema: z.ZodObject<
DejsonifySchemaT, DejsonifySchemaT,
DejsonifySchemaUnknownKeys, DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall, DejsonifySchemaCatchall,
$SchemableConfig["values"], Values,
JsonifiedValues
>
jsonify(): JsonifiedValues
jsonifyPromise(): Promise<JsonifiedValues>
jsonifyEffect(): Effect.Effect<never, z.ZodError<Values>, JsonifiedValues>
},
any[]
> & {
readonly jsonifySchema: z.ZodObject<
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
JsonifiedValues,
Values
>
readonly dejsonifySchema: z.ZodObject<
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
Values,
JsonifiedValues JsonifiedValues
> >
} }
export type JsonifiableSchemableClass<
$Config extends JsonifiableSchemableConfig
> = (
Class<
JsonifiableSchemableObject<$Config>,
SchemableClassConstructorParams<$Config["$schemableConfig"]>
> & {
readonly $jsonifiableSchemableConfig: $Config
readonly jsonifySchema: $Config["jsonifySchema"]
readonly dejsonifySchema: $Config["dejsonifySchema"]
}
) )
export type JsonifiableSchemableObject<
$Config extends JsonifiableSchemableConfig
> = {
readonly $jsonifiableSchemableConfig: $Config
readonly jsonifySchema: $Config["jsonifySchema"]
readonly dejsonifySchema: $Config["dejsonifySchema"]
jsonify(): $Config["jsonifiedValues"]
jsonifyPromise(): Promise<$Config["jsonifiedValues"]>
jsonifyEffect(): Effect.Effect<never, z.ZodError<$Config["$schemableConfig"]["values"]>, $Config["jsonifiedValues"]>
}

View File

@@ -1,47 +1,213 @@
import { Effect, pipe } from "effect" import { Effect, pipe } from "effect"
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod" import { z } from "zod"
import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from "." import { JsonifiableSchemableClass } from "."
import { parseZodTypeEffect } from "../util" import { parseZodTypeEffect } from "../../util"
export const dejsonifySchemable = < export function dejsonifySchemable<
C extends JsonifiableSchemableClass<$Config>, C extends JsonifiableSchemableClass<
$Config extends JsonifiableSchemableConfig, SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>( >(
class_: C | JsonifiableSchemableClass<$Config>, class_: C | JsonifiableSchemableClass<
values: $Config["jsonifiedValues"], SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>, params?: Partial<z.ParseParams>,
) => ) {
new class_(class_.dejsonifySchema.parse(values, params)) as InstanceType<C> return new class_(
class_.dejsonifySchema.parse(values, params)
) as InstanceType<C>
}
export const dejsonifySchemablePromise = async < export async function dejsonifySchemablePromise<
C extends JsonifiableSchemableClass<$Config>, C extends JsonifiableSchemableClass<
$Config extends JsonifiableSchemableConfig, SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>( >(
class_: C | JsonifiableSchemableClass<$Config>, class_: C | JsonifiableSchemableClass<
values: $Config["jsonifiedValues"], SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>, params?: Partial<z.ParseParams>,
) => ) {
new class_(await class_.dejsonifySchema.parseAsync(values, params)) as InstanceType<C> return new class_(
await class_.dejsonifySchema.parseAsync(values, params)
) as InstanceType<C>
}
export const dejsonifySchemableEffect = < export function dejsonifySchemableEffect<
C extends JsonifiableSchemableClass<$Config>, C extends JsonifiableSchemableClass<
$Config extends JsonifiableSchemableConfig, SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>( >(
class_: C | JsonifiableSchemableClass<$Config>, class_: C | JsonifiableSchemableClass<
values: $Config["jsonifiedValues"], SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
values: JsonifiedValues,
params?: Partial<z.ParseParams>, params?: Partial<z.ParseParams>,
) => pipe( ) {
parseZodTypeEffect< return pipe(
z.output<typeof class_.dejsonifySchema>, parseZodTypeEffect(class_.dejsonifySchema, values, params),
z.input<typeof class_.dejsonifySchema>
>(
class_.dejsonifySchema,
values,
params,
),
Effect.map(values => new class_(values) as InstanceType<C>), Effect.map(values => new class_(values) as InstanceType<C>),
) )
}

View File

@@ -1,16 +1,26 @@
import { Class } from "type-fest" import { Effect } from "effect"
import { AbstractClass, Class as ConcreteClass } from "type-fest"
import { JsonifiableObject } from "type-fest/source/jsonifiable" import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod" import { z } from "zod"
import { JsonifiableSchemableClass, JsonifiableSchemableConfig, JsonifiableSchemableObject } from "." import { SchemableClass } from ".."
import { SchemableClass, SchemableConfig } from ".." import { StaticMembers, parseZodTypeEffect } from "../../util"
import { StaticMembers, parseZodTypeEffect } from "../util"
export function makeJsonifiableSchemableClass< export function makeJsonifiableSchemableClass<
C extends SchemableClass<$SchemableConfig>, C extends SchemableClass<
$SchemableConfig extends SchemableConfig, SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues
>,
JsonifiedValues extends JsonifiableObject, SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape, JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam, JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
@@ -19,58 +29,76 @@ export function makeJsonifiableSchemableClass<
DejsonifySchemaT extends z.ZodRawShape, DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam, DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny, DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
>( >(
class_: C | SchemableClass<$SchemableConfig>, extend: C | SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues
>,
props: { props: {
jsonifySchema: (props: { jsonifySchema: (props: {
schema: $SchemableConfig["schema"] schema: z.ZodObject<
s: $SchemableConfig["schema"]["shape"] SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
shape: SchemaT
}) => z.ZodObject< }) => z.ZodObject<
JsonifySchemaT, JsonifySchemaT,
JsonifySchemaUnknownKeys, JsonifySchemaUnknownKeys,
JsonifySchemaCatchall, JsonifySchemaCatchall,
JsonifiedValues, JsonifiedValues,
$SchemableConfig["values"] Values
> >
dejsonifySchema: (props: { dejsonifySchema: (props: {
schema: $SchemableConfig["schema"] schema: z.ZodObject<
s: $SchemableConfig["schema"]["shape"] SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
Values
>
shape: SchemaT
}) => z.ZodObject< }) => z.ZodObject<
DejsonifySchemaT, DejsonifySchemaT,
DejsonifySchemaUnknownKeys, DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall, DejsonifySchemaCatchall,
$SchemableConfig["values"], Values,
JsonifiedValues JsonifiedValues
> >
}, },
) { ) {
type Class<T, Arguments extends unknown[]> = (
C extends ConcreteClass<any>
? ConcreteClass<T, Arguments>
: AbstractClass<T, Arguments>
)
const jsonifySchema = props.jsonifySchema({ const jsonifySchema = props.jsonifySchema({
schema: class_.schema, schema: extend.schema,
s: class_.schema.shape, shape: extend.schema.shape,
}) })
const dejsonifySchema = props.dejsonifySchema({ const dejsonifySchema = props.dejsonifySchema({
schema: class_.schema, schema: extend.schema,
s: class_.schema.shape, shape: extend.schema.shape,
}) })
const $jsonifiableSchemableConfig = { return class extends extend {
$schemableConfig: class_.$schemableConfig,
jsonifiedValues: undefined as unknown as JsonifiedValues,
jsonifySchema: undefined as unknown as typeof jsonifySchema,
dejsonifySchema: undefined as unknown as typeof dejsonifySchema,
} as const satisfies JsonifiableSchemableConfig
const jsonifiableClass = class JsonifiableSchemableObject extends class_ {
static readonly $jsonifiableSchemableConfig = $jsonifiableSchemableConfig
static readonly jsonifySchema = jsonifySchema static readonly jsonifySchema = jsonifySchema
static readonly dejsonifySchema = dejsonifySchema
readonly $jsonifiableSchemableConfig = $jsonifiableSchemableConfig
readonly jsonifySchema = jsonifySchema readonly jsonifySchema = jsonifySchema
static readonly dejsonifySchema = dejsonifySchema
readonly dejsonifySchema = dejsonifySchema readonly dejsonifySchema = dejsonifySchema
jsonify() { jsonify() {
@@ -84,15 +112,23 @@ export function makeJsonifiableSchemableClass<
jsonifyEffect() { jsonifyEffect() {
return parseZodTypeEffect(this.jsonifySchema, this) return parseZodTypeEffect(this.jsonifySchema, this)
} }
} satisfies JsonifiableSchemableClass<typeof $jsonifiableSchemableConfig> } as unknown as (
return jsonifiableClass as unknown as (
Class< Class<
InstanceType<C> & JsonifiableSchemableObject<typeof $jsonifiableSchemableConfig>, InstanceType<C> & {
readonly jsonifySchema: z.ZodObject<JsonifySchemaT, JsonifySchemaUnknownKeys, JsonifySchemaCatchall, JsonifiedValues, Values>,
readonly dejsonifySchema: z.ZodObject<DejsonifySchemaT, DejsonifySchemaUnknownKeys, DejsonifySchemaCatchall, Values, JsonifiedValues>,
jsonify(): JsonifiedValues
jsonifyPromise(): Promise<JsonifiedValues>
jsonifyEffect(): Effect.Effect<never, z.ZodError<Values>, JsonifiedValues>
},
ConstructorParameters<C> ConstructorParameters<C>
> & > &
StaticMembers<C> &
StaticMembers<JsonifiableSchemableClass<typeof $jsonifiableSchemableConfig>>
)
StaticMembers<C> & {
readonly jsonifySchema: z.ZodObject<JsonifySchemaT, JsonifySchemaUnknownKeys, JsonifySchemaCatchall, JsonifiedValues, Values>,
readonly dejsonifySchema: z.ZodObject<DejsonifySchemaT, DejsonifySchemaUnknownKeys, DejsonifySchemaCatchall, Values, JsonifiedValues>,
}
)
} }

View File

@@ -1,11 +1,19 @@
import { Opaque } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { identity } from "../../../util"
export const jsonifyBigIntSchema = <S extends z.ZodBigInt>(schema: S) => export type JsonifiedBigInt = Opaque<string, "@thilawyn/schemable-class/JsonifiedBigInt">
schema.transform(v => v.toString())
export const dejsonifyBigIntSchema = <S extends z.ZodBigInt>(schema: S) =>
z export function jsonifyBigIntSchema<S extends z.ZodBigInt>(schema: S) {
return schema.transform(v => v.toString() as JsonifiedBigInt)
}
export function dejsonifyBigIntSchema<S extends z.ZodBigInt>(schema: S) {
return z
.custom<JsonifiedBigInt>(identity)
.pipe(z
.string() .string()
.transform(v => { .transform(v => {
try { try {
@@ -16,3 +24,5 @@ export const dejsonifyBigIntSchema = <S extends z.ZodBigInt>(schema: S) =>
} }
}) })
.pipe(schema) .pipe(schema)
)
}

View File

@@ -1,11 +1,19 @@
import { Opaque } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { identity } from "../../../util"
export const jsonifyDateSchema = <S extends z.ZodDate>(schema: S) => export type JsonifiedDate = Opaque<string, "@thilawyn/schemable-class/JsonifiedDate">
schema.transform(v => v.toString())
export const dejsonifyDateSchema = <S extends z.ZodDate>(schema: S) =>
z export function jsonifyDateSchema<S extends z.ZodDate>(schema: S) {
return schema.transform(v => v.toString() as JsonifiedDate)
}
export function dejsonifyDateSchema<S extends z.ZodDate>(schema: S) {
return z
.custom<JsonifiedDate>(identity)
.pipe(z
.string() .string()
.transform(v => { .transform(v => {
try { try {
@@ -16,3 +24,5 @@ export const dejsonifyDateSchema = <S extends z.ZodDate>(schema: S) =>
} }
}) })
.pipe(schema) .pipe(schema)
)
}

View File

@@ -1,12 +1,24 @@
import { Decimal } from "decimal.js" import { Decimal } from "decimal.js"
import { Opaque } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { identity } from "../../../util"
export const jsonifyDecimalSchema = <S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>>(schema: S) => export type JsonifiedDecimal = Opaque<string, "@thilawyn/schemable-class/JsonifiedDecimal">
schema.transform(v => v.toJSON())
export const dejsonifyDecimalSchema = <S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>>(schema: S) =>
z export function jsonifyDecimalSchema<
S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>
>(schema: S) {
return schema.transform(v => v.toJSON() as JsonifiedDecimal)
}
export function dejsonifyDecimalSchema<
S extends z.ZodType<Decimal, z.ZodTypeDef, Decimal>
>(schema: S) {
return z
.custom<JsonifiedDecimal>(identity)
.pipe(z
.string() .string()
.transform(v => { .transform(v => {
try { try {
@@ -17,3 +29,5 @@ export const dejsonifyDecimalSchema = <S extends z.ZodType<Decimal, z.ZodTypeDef
} }
}) })
.pipe(schema) .pipe(schema)
)
}

View File

@@ -1,25 +1,139 @@
import { JsonifiableObject } from "type-fest/source/jsonifiable"
import { z } from "zod" import { z } from "zod"
import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from ".." import { JsonifiableSchemableClass } from ".."
// TODO: try to find a way to get rid of the 'class_' arg export function jsonifySchemableSchema<
export const jsonifySchemableSchema = < C extends JsonifiableSchemableClass<
C extends JsonifiableSchemableClass<$Config>, SchemaT,
$Config extends JsonifiableSchemableConfig, SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>, S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
>( >(
class_: C | JsonifiableSchemableClass<$Config>, class_: C | JsonifiableSchemableClass<
schema: S, SchemaT,
) => SchemaUnknownKeys,
schema.pipe(class_.jsonifySchema) SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
schema: S,
) {
return schema.pipe(class_.jsonifySchema)
}
export function dejsonifySchemableSchema<
C extends JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
JsonifySchemaT extends z.ZodRawShape,
JsonifySchemaUnknownKeys extends z.UnknownKeysParam,
JsonifySchemaCatchall extends z.ZodTypeAny,
DejsonifySchemaT extends z.ZodRawShape,
DejsonifySchemaUnknownKeys extends z.UnknownKeysParam,
DejsonifySchemaCatchall extends z.ZodTypeAny,
JsonifiedValues extends JsonifiableObject,
// TODO: try to find a way to get rid of the 'class_' arg
export const dejsonifySchemableSchema = <
C extends JsonifiableSchemableClass<$Config>,
$Config extends JsonifiableSchemableConfig,
S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>, S extends z.ZodType<InstanceType<C>, z.ZodTypeDef, InstanceType<C>>,
>( >(
class_: C | JsonifiableSchemableClass<$Config>, class_: C | JsonifiableSchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
JsonifySchemaT,
JsonifySchemaUnknownKeys,
JsonifySchemaCatchall,
DejsonifySchemaT,
DejsonifySchemaUnknownKeys,
DejsonifySchemaCatchall,
JsonifiedValues,
"Class"
>,
schema: S, schema: S,
) => ) {
class_.dejsonifySchema.transform(v => new class_(v)).pipe(schema) return class_.dejsonifySchema.transform(v => new class_(v)).pipe(schema)
}

View File

@@ -1,49 +1,82 @@
import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { SchemableClass, SchemableConfig } from "." import { DefinedDefaultValuesTag } from "."
import { zodObjectRemoveDefaults } from "./util" import { StaticMembers } from "../util"
export function makeSchemableClassFrom<
C extends AbstractClass<{
schema?: never
defaultValues?: never
}, []> & {
schema?: never
defaultValues?: never
},
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
extend: C,
{ schema, defaultValues }: {
schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: Opaque<DefaultValues, DefinedDefaultValuesTag>
},
) {
type Class<T, Arguments extends unknown[]> = (
C extends ConcreteClass<any>
? ConcreteClass<T, Arguments>
: AbstractClass<T, Arguments>
)
return class extends (extend as unknown as ConcreteClass<any, []>) {
static readonly schema = schema
readonly schema = schema
static readonly defaultValues = defaultValues
readonly defaultValues = defaultValues
constructor(values: Values) {
super()
Object.assign(this, values)
}
} as unknown as (
Class<
InstanceType<C> &
{
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>,
readonly defaultValues: DefaultValues,
} &
Values,
Parameters<(values: Values) => void>
> &
StaticMembers<C> &
{
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>,
readonly defaultValues: DefaultValues,
}
)
}
export function makeSchemableClass< export function makeSchemableClass<
SchemaWithDefaultValuesT extends z.ZodRawShape, SchemaT extends z.ZodRawShape,
SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, SchemaCatchall extends z.ZodTypeAny,
SchemaWithDefaultValuesOutput extends SchemaWithDefaultValuesInput, // TODO: apply "StripSchemaInputDefaults"?
SchemaWithDefaultValuesInput extends {}, Values extends {},
DefaultValues extends Partial<Values>,
>( >(
{ props: {
schema: schemaWithDefaultValues schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
}: { defaultValues: Opaque<DefaultValues, DefinedDefaultValuesTag>
schema: z.ZodObject<
SchemaWithDefaultValuesT,
SchemaWithDefaultValuesUnknownKeys,
SchemaWithDefaultValuesCatchall,
SchemaWithDefaultValuesOutput,
SchemaWithDefaultValuesInput
>
} }
) { ) {
return makeSchemableClassFrom(Object, props)
const schema = zodObjectRemoveDefaults(schemaWithDefaultValues)
const $schemableConfig = {
values: undefined as unknown as z.output<typeof schemaWithDefaultValues>,
input: undefined as unknown as z.input<typeof schemaWithDefaultValues>,
schema: undefined as unknown as typeof schema,
schemaWithDefaultValues: undefined as unknown as typeof schemaWithDefaultValues,
} as const satisfies SchemableConfig
return class SchemableObject {
static readonly $schemableConfig = $schemableConfig
static readonly schema = schema
static readonly schemaWithDefaultValues = schemaWithDefaultValues
readonly $schemableConfig = $schemableConfig
readonly schema = schema
readonly schemaWithDefaultValues = schemaWithDefaultValues
constructor(data: z.output<typeof schema>) {
Object.assign(this, data)
}
} as SchemableClass<typeof $schemableConfig>
} }

View File

@@ -1,77 +1,127 @@
import { Effect, pipe } from "effect" import { Effect, pipe } from "effect"
import { HasRequiredKeys } from "type-fest" import { HasRequiredKeys } from "type-fest"
import { z } from "zod" import { z } from "zod"
import { SchemableClass, SchemableConfig } from "." import { SchemableClass, SchemableClassInput } from "."
import { parseZodTypeEffect } from "./util" import { parseZodTypeEffect } from "../util"
type ParamsArgs = [] | [Partial<z.ParseParams>] type ParamsArgs = [] | [params: Partial<z.ParseParams>]
type NewSchemableArgs<Input extends object> = type NewSchemableArgs<Input extends object> =
HasRequiredKeys<Input> extends true HasRequiredKeys<Input> extends true
? [Input, ...ParamsArgs] ? [values: Input, ...args: ParamsArgs]
: [] | [Input, ...ParamsArgs] : [] | [values: Input, ...args: ParamsArgs]
/** export function newSchemable<
* Creates a new instance of a SchemableClass with default values. C extends SchemableClass<
* SchemaT,
* @param class_ - The SchemableClass. SchemaUnknownKeys,
* @param values - The values to be parsed and used to create the instance. SchemaCatchall,
* @param params - Optional parameters for parsing. Values,
* @returns A new instance of the specified SchemableClass. DefaultValues,
*/ "Class"
export const newSchemable = < >,
C extends SchemableClass<$Config>,
$Config extends SchemableConfig, SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>( >(
class_: C | SchemableClass<$Config>, class_: C | SchemableClass<
...[values, params]: NewSchemableArgs<$Config["input"]> SchemaT,
) => SchemaUnknownKeys,
new class_(class_.schemaWithDefaultValues.parse(values || {}, params)) as InstanceType<C> SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return new class_(
class_.schema.parse({ ...class_.defaultValues, ...values }, params)
) as InstanceType<C>
}
/** export async function newSchemablePromise<
* Creates a new instance of a SchemableClass with default values asynchronously. C extends SchemableClass<
* SchemaT,
* @param class_ - The SchemableClass. SchemaUnknownKeys,
* @param values - The values to be parsed and used to create the instance. SchemaCatchall,
* @param params - Optional parameters for parsing. Values,
* @returns A Promise resolving to a new instance of the specified SchemableClass. DefaultValues,
*/ "Class"
export const newSchemablePromise = async < >,
C extends SchemableClass<$Config>,
$Config extends SchemableConfig, SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>( >(
class_: C | SchemableClass<$Config>, class_: C | SchemableClass<
...[values, params]: NewSchemableArgs<$Config["input"]> SchemaT,
) => SchemaUnknownKeys,
new class_(await class_.schemaWithDefaultValues.parseAsync(values || {}, params)) as InstanceType<C> SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return new class_(
await class_.schema.parseAsync({ ...class_.defaultValues, ...values }, params)
) as InstanceType<C>
}
/** export function newSchemableEffect<
* Creates a new instance of a SchemableClass with default values as an Effect. C extends SchemableClass<
* SchemaT,
* @param class_ - The SchemableClass. SchemaUnknownKeys,
* @param values - The values to be parsed and used to create the instance. SchemaCatchall,
* @param params - Optional parameters for parsing. Values,
* @returns An Effect producing a new instance of the specified SchemableClass. DefaultValues,
*/ "Class"
export const newSchemableEffect = < >,
C extends SchemableClass<$Config>,
$Config extends SchemableConfig, SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>( >(
class_: C | SchemableClass<$Config>, class_: C | SchemableClass<
...[values, params]: NewSchemableArgs<$Config["input"]> SchemaT,
) => pipe( SchemaUnknownKeys,
parseZodTypeEffect< SchemaCatchall,
z.output<typeof class_.schemaWithDefaultValues>, Values,
z.input<typeof class_.schemaWithDefaultValues> DefaultValues,
>( "Class"
class_.schemaWithDefaultValues, >,
values || {},
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return pipe(
parseZodTypeEffect(
class_.schema,
{ ...class_.defaultValues, ...values },
params, params,
), ),
Effect.map(values => new class_(values) as InstanceType<C>), Effect.map(values => new class_(values) as InstanceType<C>),
) )
}

View File

@@ -1,64 +0,0 @@
import { z } from "zod"
import { makeSchemableClass, newSchemable } from "."
import { dejsonifyBigIntSchema, dejsonifySchemable, dejsonifySchemableSchema, jsonifyBigIntSchema, jsonifySchemableSchema, makeJsonifiableSchemableClass } from "./jsonifiable"
const GroupSchema = z.object({
/** Group ID */
id: z.bigint(),
/** Group name */
name: z.string(),
})
const GroupSchemableObject = makeSchemableClass({ schema: GroupSchema })
const GroupJsonifiableSchemableObject = makeJsonifiableSchemableClass(GroupSchemableObject, {
jsonifySchema: ({ schema, s }) => schema.extend({
id: jsonifyBigIntSchema(s.id)
}),
dejsonifySchema: ({ schema, s }) => schema.extend({
id: dejsonifyBigIntSchema(s.id)
}),
})
class Group extends GroupJsonifiableSchemableObject {}
const UserSchema = z.object({
/** User ID */
id: z.bigint(),
/** Name string */
name: z.string(),
/** User group */
group: z.instanceof(Group),
})
const UserSchemableObject = makeSchemableClass({ schema: UserSchema })
const UserJsonifiableSchemableObject = makeJsonifiableSchemableClass(UserSchemableObject, {
jsonifySchema: ({ schema, s }) => schema.extend({
id: jsonifyBigIntSchema(s.id),
group: jsonifySchemableSchema(Group, s.group),
}),
dejsonifySchema: ({ schema, s }) => schema.extend({
id: dejsonifyBigIntSchema(s.id),
group: dejsonifySchemableSchema(Group, s.group),
}),
})
class User extends UserJsonifiableSchemableObject {}
const group1 = new Group({ id: 1n, name: "Group 1" })
const user1 = new User({ id: 1n, name: "User 1", group: group1 })
const user2 = newSchemable(User, { id: 2n, name: "User 2", group: group1 })
const jsonifiedUser2 = user2.jsonify()
const dejsonifiedUser2 = dejsonifySchemable(User, jsonifiedUser2)
console.log(dejsonifiedUser2)

View File

@@ -1,82 +0,0 @@
import { Effect, pipe } from "effect"
import { mapValues } from "lodash-es"
import { z } from "zod"
/**
* Represents the static members of a class.
* @template C - The class type.
*/
export type StaticMembers<C> = {
[Key in keyof C as Key extends "prototype" ? never : Key]: C[Key]
}
/**
* Removes default values from a ZodObject schema and returns a new schema.
*
* @param schema - The ZodObject schema to process.
* @returns A new ZodObject schema with default values removed.
*/
export const zodObjectRemoveDefaults = <
T extends z.ZodRawShape,
UnknownKeys extends z.UnknownKeysParam,
Catchall extends z.ZodTypeAny,
Output extends {},
Input extends {},
>(
schema: z.ZodObject<
T,
UnknownKeys,
Catchall,
Output,
Input
>
) =>
schema.extend(zodShapeRemoveDefaults(schema.shape))
/**
* Removes default values from a ZodObject shape and returns a new shape.
*
* @param shape - The ZodObject shape to process.
* @returns A new shape with default values removed.
*/
export const zodShapeRemoveDefaults = <
Shape extends z.ZodRawShape
>(
shape: Shape
): {
[K in keyof Shape]:
Shape[K] extends z.ZodDefault<infer T>
? T
: Shape[K]
} =>
mapValues(shape, el =>
el instanceof z.ZodDefault
? el.removeDefault()
: el
)
/**
* Parses a value using a ZodType schema wrapped in an Effect monad.
*
* @param schema - The ZodType schema to use for parsing.
* @param args - The arguments to pass to the `safeParseAsync` method of the schema.
* @returns An Effect monad representing the parsing result.
*/
export const parseZodTypeEffect = <
Output,
Input,
>(
schema: z.ZodType<Output, z.ZodTypeDef, Input>,
...args: Parameters<typeof schema.safeParseAsync>
) => pipe(
Effect.promise(() => schema.safeParseAsync(...args)),
Effect.flatMap(response =>
response.success
? Effect.succeed(response.data)
: Effect.fail(response.error)
),
)

1
src/lib.ts Normal file
View File

@@ -0,0 +1 @@
export { ExtendableZodSchemaObject } from "./traits/ExtendableZodSchemaObject"

View File

@@ -1,82 +0,0 @@
import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest"
import { z } from "zod"
import { DefinedDefaultValuesTag } from "."
import { StaticMembers } from "./util"
export function makeSchemableClassFrom<
C extends AbstractClass<{
schema?: never
defaultValues?: never
}, []> & {
schema?: never
defaultValues?: never
},
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
extend: C,
{ schema, defaultValues }: {
schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: Opaque<DefaultValues, DefinedDefaultValuesTag>
},
) {
type Class<T, Arguments extends unknown[]> = (
C extends ConcreteClass<any>
? ConcreteClass<T, Arguments>
: AbstractClass<T, Arguments>
)
return class extends (extend as unknown as ConcreteClass<any, []>) {
static readonly schema = schema
readonly schema = schema
static readonly defaultValues = defaultValues
readonly defaultValues = defaultValues
constructor(values: Values) {
super()
Object.assign(this, values)
}
} as unknown as (
Class<
InstanceType<C> &
{
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>,
readonly defaultValues: DefaultValues,
} &
Values,
Parameters<(values: Values) => void>
> &
StaticMembers<C> &
{
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>,
readonly defaultValues: DefaultValues,
}
)
}
export function makeSchemableClass<
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
props: {
schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: Opaque<DefaultValues, DefinedDefaultValuesTag>
}
) {
return makeSchemableClassFrom(Object, props)
}

View File

@@ -1,127 +0,0 @@
import { Effect, pipe } from "effect"
import { HasRequiredKeys } from "type-fest"
import { z } from "zod"
import { SchemableClass, SchemableClassInput } from "."
import { parseZodTypeEffect } from "./util"
type ParamsArgs = [] | [params: Partial<z.ParseParams>]
type NewSchemableArgs<Input extends object> =
HasRequiredKeys<Input> extends true
? [values: Input, ...args: ParamsArgs]
: [] | [values: Input, ...args: ParamsArgs]
export function newSchemable<
C extends SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
class_: C | SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return new class_(
class_.schema.parse({ ...class_.defaultValues, ...values }, params)
) as InstanceType<C>
}
export async function newSchemablePromise<
C extends SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
class_: C | SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return new class_(
await class_.schema.parseAsync({ ...class_.defaultValues, ...values }, params)
) as InstanceType<C>
}
export function newSchemableEffect<
C extends SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
class_: C | SchemableClass<
SchemaT,
SchemaUnknownKeys,
SchemaCatchall,
Values,
DefaultValues,
"Class"
>,
...[values, params]: NewSchemableArgs<
SchemableClassInput<Values, DefaultValues>
>
) {
return pipe(
parseZodTypeEffect(
class_.schema,
{ ...class_.defaultValues, ...values },
params,
),
Effect.map(values => new class_(values) as InstanceType<C>),
)
}

View File

@@ -0,0 +1,43 @@
import { AbstractClass, Class } from "type-fest"
import { z } from "zod"
export type ZodSchemaClass<
Instance extends Values,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
> = (
Class<Instance, [values: Values]> &
ZodSchemaClassStatic<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, DefaultValues>
)
export type ZodSchemaAbstractClass<
Instance extends Values,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
> = (
AbstractClass<Instance, [values: Values]> &
ZodSchemaClassStatic<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, DefaultValues>
)
export type ZodSchemaClassStatic<
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
> = {
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
readonly defaultValues: DefaultValues
}

View File

@@ -1,63 +1,43 @@
import { pipeInto } from "ts-functional-pipe"
import { z } from "zod" import { z } from "zod"
import { defineDefaultValues, extendSchemableClass, makeSchemableClass, newSchemable } from "." import { ZodSchemaClass } from "./ZodSchemaClass"
import { dejsonifyBigIntSchema, dejsonifySchemable, jsonifyBigIntSchema, makeJsonifiableSchemableClass } from "./jsonifiable"
import { makeSchemableClassObservable } from "./observable"
const UserLevel = z.enum(["User", "Admin"]) class Test extends ZodSchemaClass({
class User extends pipeInto(
makeSchemableClass({
schema: z.object({ schema: z.object({
id: z.bigint(), id: z.bigint(),
name: z.string(), name: z.string(),
level: UserLevel,
}), }),
defaultValues: defineDefaultValues({ defaultValues: { id: -1n },
level: "User" as const }) {}
}),
const Test2 = ZodSchemaClass({
schema: z.object({
id: z.bigint(),
name: z.string(),
}), }),
v => makeSchemableClassObservable(v), defaultValues: { id: -1n },
v => makeJsonifiableSchemableClass(v, {
jsonifySchema: ({ schema, shape }) => schema.extend({
id: jsonifyBigIntSchema(shape.id)
}),
dejsonifySchema: ({ schema, shape }) => schema.extend({
id: dejsonifyBigIntSchema(shape.id)
}),
}),
) {}
User.schema
const user1 = newSchemable(User, { id: 1n, name: "User" })
user1.schema
const jsonifiedUser1 = user1.jsonify()
console.log(jsonifiedUser1)
console.log(dejsonifySchemable(User, jsonifiedUser1))
const UserWithPhone = extendSchemableClass(User, {
schema: ({ schema }) => schema.extend({
phone: z.string()
}),
defaultValues: defaultValues => defineDefaultValues({
...defaultValues,
phone: "+33600000000",
}),
}) })
UserWithPhone.defaultValues Test.defaultValues
const inst = Test.create({ id: 1n, name: "" })
console.log(inst)
// const user2 = newSchemable(UserWithPhone, { id: 1n, name: "User" }) class SubTest extends Test.extend({
// console.log(user2.jsonify()) schema: ({ schema }) => schema.extend({
prout: z.string()
}),
defaultValues: defaultValues => ({
...defaultValues
}),
}) {}
const subInst = await SubTest.createPromise({ name: "", prout: "" })
console.log(subInst)
// class ChildTest extends Test {}
// ChildTest.instantiate({ name: "" })

View File

@@ -0,0 +1,58 @@
import { trait } from "@thilawyn/traitify-ts"
import { AbstractClass } from "type-fest"
import { z } from "zod"
import { ZodSchemaAbstractClass } from "../shapes/ZodSchemaClass"
import { Extend, StaticMembers } from "../util"
export const ExtendableZodSchemaObject = trait
.implement(Super => class ExtendableZodSchemaObject extends Super {
static extend<
Super extends ZodSchemaAbstractClass<SuperInstance, SuperSchemaT, SuperSchemaUnknownKeys, SuperSchemaCatchall, SuperValues, SuperDefaultValues>,
SuperInstance extends SuperValues,
SuperSchemaT extends z.ZodRawShape,
SuperSchemaUnknownKeys extends z.UnknownKeysParam,
SuperSchemaCatchall extends z.ZodTypeAny,
SuperValues extends {},
SuperDefaultValues extends Partial<SuperValues>,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends SuperValues,
DefaultValues extends Partial<Values>,
>(
this: Super | ZodSchemaAbstractClass<SuperInstance, SuperSchemaT, SuperSchemaUnknownKeys, SuperSchemaCatchall, SuperValues, SuperDefaultValues>,
props: {
schema: (props: {
schema: Super["schema"]
shape: Super["schema"]["shape"]
}) => z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>
defaultValues: (defaultValues: SuperDefaultValues) => DefaultValues
},
): (
AbstractClass<
Extend<[SuperInstance, Values]>,
[values: Values]
> &
Extend<[
StaticMembers<Super>,
{
readonly schema: z.ZodObject<SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, Values>,
readonly defaultValues: DefaultValues,
},
]>
) {
const schema = props.schema({ schema: this.schema, shape: this.schema.shape })
const defaultValues = props.defaultValues(this.defaultValues)
return class extends this {
static readonly schema = schema
static readonly defaultValues = defaultValues
} as any
}
})
.build()

View File

@@ -0,0 +1,104 @@
import { trait } from "@thilawyn/traitify-ts"
import { Effect, pipe } from "effect"
import { HasRequiredKeys } from "type-fest"
import { z } from "zod"
import { ZodSchemaClass } from "../shapes/ZodSchemaClass"
import { parseZodTypeEffect } from "../util"
type NewZodSchemaInstanceInput<
Values extends {},
DefaultValues extends Partial<Values>,
> = {
[Key in Exclude<keyof Values, keyof DefaultValues>]: Values[Key]
} & {
[Key in keyof DefaultValues]?: Key extends keyof Values
? Values[Key]
: never
}
type ParseParamsArgs = [] | [params: Partial<z.ParseParams>]
type NewZodSchemaInstanceArgs<Input extends object> = (
HasRequiredKeys<Input> extends true
? [values: Input, ...args: ParseParamsArgs]
: [] | [values: Input, ...args: ParseParamsArgs]
)
export const InstantiableZodSchemaObject = trait
.implement(Super => class InstantiableZodSchemaObject extends Super {
static create<
Instance extends Values,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
this: ZodSchemaClass<Instance, SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, DefaultValues>,
...[values, params]: NewZodSchemaInstanceArgs<
NewZodSchemaInstanceInput<Values, DefaultValues>
>
) {
return new this(
this.schema.parse({ ...this.defaultValues, ...values }, params)
)
}
static async createPromise<
Instance extends Values,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
this: ZodSchemaClass<Instance, SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, DefaultValues>,
...[values, params]: NewZodSchemaInstanceArgs<
NewZodSchemaInstanceInput<Values, DefaultValues>
>
) {
return new this(
await this.schema.parseAsync({ ...this.defaultValues, ...values }, params)
)
}
static createEffect<
Instance extends Values,
SchemaT extends z.ZodRawShape,
SchemaUnknownKeys extends z.UnknownKeysParam,
SchemaCatchall extends z.ZodTypeAny,
Values extends {},
DefaultValues extends Partial<Values>,
>(
this: ZodSchemaClass<Instance, SchemaT, SchemaUnknownKeys, SchemaCatchall, Values, DefaultValues>,
...[values, params]: NewZodSchemaInstanceArgs<
NewZodSchemaInstanceInput<Values, DefaultValues>
>
) {
return pipe(
parseZodTypeEffect(
this.schema,
{ ...this.defaultValues, ...values },
params,
),
Effect.map(values => new this(values)),
)
}
protected static initialize() {
}
})
.build()

View File

@@ -0,0 +1,10 @@
import { trait } from "@thilawyn/traitify-ts"
export const ObservableZodSchemaObject = trait
.implement(Super => class ObservableZodSchemaObject extends Super {
constructor(...args: any[]) {
super(...args)
}
})
.build()

101
src/util/class.ts Normal file
View File

@@ -0,0 +1,101 @@
import { AbstractClass, Class as ConcreteClass } from "type-fest"
/**
* Represents the possible types of a class.
*/
export type ClassType = "AbstractClass" | "Class"
/**
* Represents a class based on the specified type.
* @template Type - The type of the class ("AbstractClass" or "Class").
* @template T - The type parameter of the class.
* @template Arguments - The type of arguments the class constructor takes.
*/
export type Class<
Type extends ClassType,
T,
Arguments extends unknown[] = any[],
> = (
Type extends "AbstractClass"
? AbstractClass<T, Arguments>
: Type extends "Class"
? ConcreteClass<T, Arguments>
: never
)
/**
* Gets the type of a class (either "Class" or "AbstractClass").
* @template C - The class type to determine.
*/
export type GetClassType<C> = (
C extends ConcreteClass<any>
? "Class"
: C extends AbstractClass<any>
? "AbstractClass"
: never
)
/**
* Represents an array of instances corresponding to the provided classes.
* @template Classes - An array of classes extending AbstractClass.
*/
export type ClassesInstances<Classes extends readonly AbstractClass<any>[]> = (
Classes extends [infer Class, ...infer Rest]
? Class extends AbstractClass<any>
? Rest extends AbstractClass<any>[]
? [InstanceType<Class>, ...ClassesInstances<Rest>]
: never
: never
: []
)
/**
* Represents an intersection of instances of the provided classes.
* @template Classes - An array of classes extending AbstractClass.
*/
export type ClassesInstancesIntersection<Classes extends readonly AbstractClass<any>[]> = (
Classes extends [infer Class, ...infer Rest]
? Class extends AbstractClass<any>
? Rest extends AbstractClass<any>[]
? InstanceType<Class> & ClassesInstancesIntersection<Rest>
: never
: never
: {}
)
/**
* Represents the static members of a class.
* @template Class - A class extending AbstractClass.
*/
export type StaticMembers<Class extends AbstractClass<any>> = (
Omit<Class, "prototype">
)
/**
* Represents an array of static members corresponding to the provided classes.
* @template Classes - An array of classes extending AbstractClass.
*/
export type ClassesStaticMembers<Classes extends readonly AbstractClass<any>[]> = (
Classes extends [infer Class, ...infer Rest]
? Class extends AbstractClass<any>
? Rest extends AbstractClass<any>[]
? [StaticMembers<Class>, ...ClassesStaticMembers<Rest>]
: never
: never
: []
)
/**
* Represents an intersection of static members of the provided classes.
* @template Classes - An array of classes extending AbstractClass.
*/
export type ClassesStaticMembersIntersection<Classes extends readonly AbstractClass<any>[]> = (
Classes extends [infer Class, ...infer Rest]
? Class extends AbstractClass<any>
? Rest extends AbstractClass<any>[]
? StaticMembers<Class> & ClassesStaticMembersIntersection<Rest>
: never
: never
: {}
)

View File

@@ -1,37 +1,7 @@
import { Effect, pipe } from "effect" import { Effect, pipe } from "effect"
import { AbstractClass, Class as ConcreteClass } from "type-fest"
import { z } from "zod" import { z } from "zod"
export function identity<T>(value: T) {
return value
}
export type ClassType = "AbstractClass" | "Class"
export type Class<
Type extends ClassType,
T,
Arguments extends unknown[] = any[],
> = (
Type extends "AbstractClass"
? AbstractClass<T, Arguments>
: Type extends "Class"
? ConcreteClass<T, Arguments>
: never
)
/**
* Represents the static members of a class.
* @template C - The class type.
*/
export type StaticMembers<C> = {
[Key in keyof C as Key extends "prototype" ? never : Key]: C[Key]
}
/** /**
* Parses a value using a ZodType schema wrapped in an Effect monad. * Parses a value using a ZodType schema wrapped in an Effect monad.
* *

40
src/util/extend.ts Normal file
View File

@@ -0,0 +1,40 @@
/**
* Represents the common keys between two types.
* @template A - The first type.
* @template B - The second type.
*/
export type CommonKeys<A, B> = Extract<keyof A, keyof B>
export type Extend<T extends readonly object[]> = (
T extends [
infer Super,
infer Self,
...infer Rest extends object[],
]
? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>>
? Extend<[
Omit<Super, CommonKeys<Self, Super>> & Self,
...Rest,
]>
: never
: T extends [infer Self]
? Self
: {}
)
/**
* Merges an inheritance tree defined by an array of types without allowing overrides.
* @template T - An array of types representing the inheritance tree.
*/
export type ExtendWithoutOverriding<T extends readonly any[]> = (
T extends [infer Super, infer Self, ...infer Rest]
? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>>
? ExtendWithoutOverriding<[
Super & Self,
...Rest,
]>
: never
: T extends [infer Self]
? Self
: void
)

4
src/util/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export * from "./class"
export * from "./effect"
export * from "./extend"
export * from "./misc"

3
src/util/misc.ts Normal file
View File

@@ -0,0 +1,3 @@
export function identity<T>(value: T) {
return value
}