Moved current version to legacy
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Julien Valverdé
2024-01-20 22:02:14 +01:00
parent 019066bb9c
commit fc95a5d53a
32 changed files with 782 additions and 1509 deletions

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/"

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
}

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)
),
)

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

@@ -1,63 +0,0 @@
import { pipeInto } from "ts-functional-pipe"
import { z } from "zod"
import { defineDefaultValues, extendSchemableClass, makeSchemableClass, newSchemable } from "."
import { dejsonifyBigIntSchema, dejsonifySchemable, jsonifyBigIntSchema, makeJsonifiableSchemableClass } from "./jsonifiable"
import { makeSchemableClassObservable } from "./observable"
const UserLevel = z.enum(["User", "Admin"])
class User extends pipeInto(
makeSchemableClass({
schema: z.object({
id: z.bigint(),
name: z.string(),
level: UserLevel,
}),
defaultValues: defineDefaultValues({
level: "User" as const
}),
}),
v => makeSchemableClassObservable(v),
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
// const user2 = newSchemable(UserWithPhone, { id: 1n, name: "User" })
// console.log(user2.jsonify())