diff --git a/README.md b/README.md index adb9b58..5005fab 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# schemable-class +# zod-schema-class Create TypeScript classes out of Zod schemas diff --git a/bun.lockb b/bun.lockb index a8be37e..6409dc5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 2ab619a..fbd80fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@thilawyn/schemable-class", - "version": "0.1.1", + "name": "@thilawyn/zod-schema-class", + "version": "0.1.2", "type": "module", "publishConfig": { "registry": "https://git.jvalver.de/api/packages/thilawyn/npm/" @@ -11,32 +11,22 @@ "exports": { ".": { "import": { - "types": "./dist/schemable.d.mts", - "default": "./dist/schemable.mjs" + "types": "./dist/lib.d.mts", + "default": "./dist/lib.mjs" }, "require": { - "types": "./dist/schemable.d.cts", - "default": "./dist/schemable.cjs" + "types": "./dist/lib.d.cts", + "default": "./dist/lib.cjs" } }, - "./jsonifiable": { + "./schema": { "import": { - "types": "./dist/jsonifiable.d.mts", - "default": "./dist/jsonifiable.mjs" + "types": "./dist/schema.d.mts", + "default": "./dist/schema.mjs" }, "require": { - "types": "./dist/jsonifiable.d.cts", - "default": "./dist/jsonifiable.cjs" - } - }, - "./observable": { - "import": { - "types": "./dist/observable.d.mts", - "default": "./dist/observable.mjs" - }, - "require": { - "types": "./dist/observable.d.cts", - "default": "./dist/observable.cjs" + "types": "./dist/schema.d.cts", + "default": "./dist/schema.cjs" } } }, @@ -48,24 +38,25 @@ "clean:node": "rm -rf node_modules" }, "dependencies": { + "@thilawyn/traitify-ts": "^0.1.15", "decimal.js": "^10.4.3", - "effect": "^2.1.1", + "effect": "^2.4.3", "lodash-es": "^4.17.21", "mobx": "^6.12.0", - "type-fest": "^4.9.0", + "type-fest": "^4.12.0", "zod": "^3.22.4" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", "@types/lodash-es": "^4.17.12", "bun-types": "latest", - "npm-check-updates": "^16.14.12", + "npm-check-updates": "^16.14.15", "npm-sort": "^0.0.4", - "rollup": "^4.9.5", + "rollup": "^4.12.1", "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-ts": "^3.4.5", "ts-functional-pipe": "^3.1.2", - "tsx": "^4.7.0", - "typescript": "^5.3.3" + "tsx": "^4.7.1", + "typescript": "^5.4.2" } } diff --git a/rollup.config.ts b/rollup.config.ts index 292a90c..566206a 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -38,7 +38,6 @@ export const createBundleConfig = ( export default [ - createBundleConfig("src/index.ts", "."), - createBundleConfig("src/jsonifiable/index.ts", "./jsonifiable"), - createBundleConfig("src/observable/index.ts", "./observable"), + createBundleConfig("src/lib.ts", "."), + createBundleConfig("src/schema/lib.ts", "./schema"), ] diff --git a/src/SchemableClass.ts b/src/SchemableClass.ts deleted file mode 100644 index f54a32f..0000000 --- a/src/SchemableClass.ts +++ /dev/null @@ -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, - - 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, -> = { - [Key in Exclude]: Values[Key] -} & { - [Key in keyof DefaultValues]?: Key extends keyof Values - ? Values[Key] - : never -} diff --git a/src/builders/ZodSchemaClassBuilder.ts b/src/builders/ZodSchemaClassBuilder.ts new file mode 100644 index 0000000..a16ed6f --- /dev/null +++ b/src/builders/ZodSchemaClassBuilder.ts @@ -0,0 +1,133 @@ +import { Trait, TraitExpressionBuilder, expression } from "@thilawyn/traitify-ts" +import { AbstractClass } from "type-fest" +import { EmptyObject } from "type-fest/source/empty-object" +import { JsonifiableObject } from "type-fest/source/jsonifiable" +import { z } from "zod" +import { JsonifiableZodSchemaObject } from "../traits/JsonifiableZodSchemaObject" +import { ZodSchemaObject } from "../traits/ZodSchemaObject" + + +export class ZodSchemaClassBuilder< + Superclass extends AbstractClass, + const Traits extends readonly Trait[], + Schemas extends object, +> { + declare ["constructor"]: typeof ZodSchemaClassBuilder + + constructor( + protected readonly expression: TraitExpressionBuilder, + protected readonly schemas: Schemas, + ) {} + + + schema< + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, + >( + this: ZodSchemaClassBuilder, + + props: { + schema: z.ZodObject + + schemaWithDefaultValues: ( + schema: z.ZodObject + ) => z.ZodObject + }, + ) { + const schema = props.schema + const schemaWithDefaultValues = props.schemaWithDefaultValues(props.schema) + + abstract class ZodSchemaObjectConstructor { + constructor(values: Values) { + Object.assign(this, values) + } + } + + return new this.constructor( + this.expression + .extends(ZodSchemaObjectConstructor as AbstractClass) + .expresses(ZodSchemaObject(schema, schemaWithDefaultValues)), + + { schema, schemaWithDefaultValues } as const, + ) + } + + jsonifiable< + S extends { + readonly schema: z.ZodObject, + readonly schemaWithDefaultValues: z.ZodObject, + jsonifySchema?: never + dejsonifySchema?: never + }, + + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, + + 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, + >( + this: ZodSchemaClassBuilder, + readonly schemaWithDefaultValues: z.ZodObject, + jsonifySchema?: never + dejsonifySchema?: never + }>, + + props: { + jsonifySchema: ( + schema: z.ZodObject + ) => z.ZodObject + + dejsonifySchema: ( + schema: z.ZodObject + ) => z.ZodObject + }, + ) { + const jsonifySchema = props.jsonifySchema(this.schemas.schema) + const dejsonifySchema = props.dejsonifySchema(this.schemas.schema) + + return new this.constructor( + this.expression.expresses( + JsonifiableZodSchemaObject( + this.schemas.schema, + this.schemas.schemaWithDefaultValues, + jsonifySchema, + dejsonifySchema, + ) + ), + + { ...this.schemas as S, jsonifySchema, dejsonifySchema } as const, + ) + } + + + toExpression() { + return this.expression + } +} + + +export const zodSchemaClass = new ZodSchemaClassBuilder(expression, {}) diff --git a/src/builders/ZodSchemaClassExtender.ts b/src/builders/ZodSchemaClassExtender.ts new file mode 100644 index 0000000..d78a3c4 --- /dev/null +++ b/src/builders/ZodSchemaClassExtender.ts @@ -0,0 +1,196 @@ +// import { expression } from "@thilawyn/traitify-ts" +// import { AbstractClass, Simplify } from "type-fest" +// import { JsonifiableObject } from "type-fest/source/jsonifiable" +// import { z } from "zod" +// import { JsonifiableZodSchemaAbstractClass } from "../shapes/JsonifiableZodSchemaClass" +// import { ZodSchemaAbstractClass } from "../shapes/ZodSchemaClass" +// import { Extend, Override, StaticMembers } from "../util" + + +// export class ZodSchemaClassExtender< +// Superclass extends AbstractClass, +// Subclass extends AbstractClass, +// > { +// declare ["constructor"]: typeof ZodSchemaClassExtender + +// constructor( +// readonly superclass: Superclass, +// readonly subclass: Subclass, +// ) {} + + +// schema< +// Super extends ZodSchemaAbstractClass, + +// SuperSchemaT extends z.ZodRawShape, +// SuperSchemaUnknownKeys extends z.UnknownKeysParam, +// SuperSchemaCatchall extends z.ZodTypeAny, + +// SuperValues extends object, +// SuperDefaultValues extends Partial, + +// SchemaT extends z.ZodRawShape, +// SchemaUnknownKeys extends z.UnknownKeysParam, +// SchemaCatchall extends z.ZodTypeAny, + +// Values extends SuperValues, +// DefaultValues extends Partial, +// >( +// this: ZodSchemaClassExtender< +// Super | ZodSchemaAbstractClass, +// any +// >, + +// props: { +// schema: (schema: Super["schema"]) => z.ZodObject +// defaultValues: (defaultValues: SuperDefaultValues) => DefaultValues +// }, +// ) { +// const schema = props.schema(this.superclass.schema) +// const defaultValues = props.defaultValues(this.superclass.defaultValues) + +// class Schemas extends (this.superclass as AbstractClass) { +// static readonly schema = schema +// static readonly defaultValues = defaultValues +// } + +// return new this.constructor( +// this.superclass as Super, + +// Schemas as unknown as AbstractClass< +// Simplify< +// Extend<[InstanceType, Values]> +// >, + +// [values: Values] +// > & +// Simplify< +// Override<[ +// StaticMembers, +// StaticMembers, +// ]> +// > +// ) +// } + +// jsonifiable< +// /** Superclass jsonifiable schemas */ +// Super extends JsonifiableZodSchemaAbstractClass< +// any, + +// SuperJsonifySchemaT, +// SuperJsonifySchemaUnknownKeys, +// SuperJsonifySchemaCatchall, + +// SuperDejsonifySchemaT, +// SuperDejsonifySchemaUnknownKeys, +// SuperDejsonifySchemaCatchall, + +// SuperJsonifiedValues, +// SuperValues +// >, + +// SuperJsonifySchemaT extends z.ZodRawShape, +// SuperJsonifySchemaUnknownKeys extends z.UnknownKeysParam, +// SuperJsonifySchemaCatchall extends z.ZodTypeAny, + +// SuperDejsonifySchemaT extends z.ZodRawShape, +// SuperDejsonifySchemaUnknownKeys extends z.UnknownKeysParam, +// SuperDejsonifySchemaCatchall extends z.ZodTypeAny, + +// SuperJsonifiedValues extends JsonifiableObject, +// SuperValues extends object, + +// /** New schemas */ +// Self extends ZodSchemaAbstractClass, + +// SelfSchemaT extends z.ZodRawShape, +// SelfSchemaUnknownKeys extends z.UnknownKeysParam, +// SelfSchemaCatchall extends z.ZodTypeAny, + +// SelfValues extends object, +// SelfDefaultValues extends Partial, + +// /* New jsonifiable schemas */ +// 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 SuperJsonifiedValues, +// Values extends SelfValues, +// >( +// this: ZodSchemaClassExtender< +// Super | JsonifiableZodSchemaAbstractClass< +// any, + +// SuperJsonifySchemaT, +// SuperJsonifySchemaUnknownKeys, +// SuperJsonifySchemaCatchall, + +// SuperDejsonifySchemaT, +// SuperDejsonifySchemaUnknownKeys, +// SuperDejsonifySchemaCatchall, + +// SuperJsonifiedValues, +// SuperValues +// >, + +// Self | ZodSchemaAbstractClass +// >, + +// props: { +// jsonifySchema: ( +// schema: Self["schema"], +// jsonifySchema: Super["jsonifySchema"], +// ) => z.ZodObject + +// dejsonifySchema: ( +// schema: Self["schema"], +// dejsonifySchema: Super["dejsonifySchema"], +// ) => z.ZodObject +// }, +// ) { +// const jsonifySchema = props.jsonifySchema(this.subclass.schema, this.superclass.jsonifySchema) +// const dejsonifySchema = props.dejsonifySchema(this.subclass.schema, this.superclass.dejsonifySchema) + +// class JsonifiableSchemas extends (this.subclass as AbstractClass) { +// static readonly jsonifySchema = jsonifySchema +// readonly jsonifySchema = jsonifySchema +// static readonly dejsonifySchema = dejsonifySchema +// readonly dejsonifySchema = dejsonifySchema +// } + +// return new this.constructor( +// this.superclass as Super, + +// JsonifiableSchemas as unknown as AbstractClass< +// Simplify< +// Override<[InstanceType, JsonifiableSchemas]> +// >, + +// ConstructorParameters< +// ZodSchemaAbstractClass +// > +// > & +// Simplify< +// Override<[ +// StaticMembers, +// StaticMembers, +// ]> +// >, +// ) +// } + + +// toClass() { +// return this.subclass +// } + +// toExpressionBuilder() { +// return expression.extends(this.subclass) +// } +// } diff --git a/src/defineDefaultValues.ts b/src/defineDefaultValues.ts deleted file mode 100644 index 634d83a..0000000 --- a/src/defineDefaultValues.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Opaque } from "type-fest" - - -export type DefinedDefaultValuesTag = "@thilawyn/schemable-class/DefinedDefaultValues" - -export function defineDefaultValues(values: T) { - return values as Opaque -} diff --git a/src/extendSchemableClass.ts b/src/extendSchemableClass.ts deleted file mode 100644 index bb392e1..0000000 --- a/src/extendSchemableClass.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest" -import { z } from "zod" -import { DefinedDefaultValuesTag, SchemableClass } from "." -import { StaticMembers } from "./util" - - -export function extendSchemableClass< - C extends SchemableClass< - ExtendSchemaT, - ExtendSchemaUnknownKeys, - ExtendSchemaCatchall, - ExtendSchemaValues, - ExtendDefaultValues - >, - - ExtendSchemaT extends z.ZodRawShape, - ExtendSchemaUnknownKeys extends z.UnknownKeysParam, - ExtendSchemaCatchall extends z.ZodTypeAny, - ExtendSchemaValues extends {}, - ExtendDefaultValues extends Partial, - - SchemaT extends z.ZodRawShape, - SchemaUnknownKeys extends z.UnknownKeysParam, - SchemaCatchall extends z.ZodTypeAny, - SchemaValues extends ExtendSchemaValues, - - DefaultValues extends Partial, ->( - extend: C | SchemableClass< - ExtendSchemaT, - ExtendSchemaUnknownKeys, - ExtendSchemaCatchall, - ExtendSchemaValues, - ExtendDefaultValues - >, - - props: { - schema: (props: { - schema: z.ZodObject< - ExtendSchemaT, - ExtendSchemaUnknownKeys, - ExtendSchemaCatchall, - ExtendSchemaValues, - ExtendSchemaValues - > - - shape: ExtendSchemaT - }) => z.ZodObject< - SchemaT, - SchemaUnknownKeys, - SchemaCatchall, - SchemaValues, - SchemaValues - > - - defaultValues: (defaultValues: ExtendDefaultValues) => Opaque - }, -) { - type Class = ( - C extends ConcreteClass - ? ConcreteClass - : AbstractClass - ) - - const schema = props.schema({ - schema: extend.schema, - shape: extend.schema.shape, - }) - const defaultValues = props.defaultValues(extend.defaultValues) - - return class extends extend { - static readonly schema = schema - readonly schema = schema - - static readonly defaultValues = defaultValues - readonly defaultValues = defaultValues - } as unknown as ( - Class< - Omit, "schema" | "defaultValues" | keyof ExtendSchemaValues> & - { - readonly schema: z.ZodObject, - readonly defaultValues: DefaultValues, - } & - SchemaValues, - - Parameters<(values: SchemaValues) => void> - > & - - Omit, "schema" | "defaultValues"> & - { - readonly schema: z.ZodObject, - readonly defaultValues: DefaultValues, - } - ) -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 4b4c248..0000000 --- a/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./SchemableClass" -export * from "./defineDefaultValues" -export * from "./extendSchemableClass" -export * from "./makeSchemableClass" -export * from "./newSchemable" diff --git a/src/jsonifiable/JsonifiableSchemableClass.ts b/src/jsonifiable/JsonifiableSchemableClass.ts deleted file mode 100644 index da145d6..0000000 --- a/src/jsonifiable/JsonifiableSchemableClass.ts +++ /dev/null @@ -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, - - 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 - jsonifyEffect(): Effect.Effect, JsonifiedValues> - }, - - any[] - > & { - readonly jsonifySchema: z.ZodObject< - JsonifySchemaT, - JsonifySchemaUnknownKeys, - JsonifySchemaCatchall, - JsonifiedValues, - Values - > - - readonly dejsonifySchema: z.ZodObject< - DejsonifySchemaT, - DejsonifySchemaUnknownKeys, - DejsonifySchemaCatchall, - Values, - JsonifiedValues - > - } -) diff --git a/src/jsonifiable/dejsonifySchemable.ts b/src/jsonifiable/dejsonifySchemable.ts deleted file mode 100644 index b8e7f80..0000000 --- a/src/jsonifiable/dejsonifySchemable.ts +++ /dev/null @@ -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, - - 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, -) { - return new class_( - class_.dejsonifySchema.parse(values, params) - ) as InstanceType -} - - -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, - - 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, -) { - return new class_( - await class_.dejsonifySchema.parseAsync(values, params) - ) as InstanceType -} - - -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, - - 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, -) { - return pipe( - parseZodTypeEffect(class_.dejsonifySchema, values, params), - Effect.map(values => new class_(values) as InstanceType), - ) -} diff --git a/src/jsonifiable/index.ts b/src/jsonifiable/index.ts deleted file mode 100644 index 74e7d23..0000000 --- a/src/jsonifiable/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./JsonifiableSchemableClass" -export * from "./dejsonifySchemable" -export * from "./makeJsonifiableSchemableClass" -export * from "./schema" diff --git a/src/jsonifiable/makeJsonifiableSchemableClass.ts b/src/jsonifiable/makeJsonifiableSchemableClass.ts deleted file mode 100644 index 691a3f2..0000000 --- a/src/jsonifiable/makeJsonifiableSchemableClass.ts +++ /dev/null @@ -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, - - 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 = ( - C extends ConcreteClass - ? ConcreteClass - : AbstractClass - ) - - 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 & { - readonly jsonifySchema: z.ZodObject, - readonly dejsonifySchema: z.ZodObject, - - jsonify(): JsonifiedValues - jsonifyPromise(): Promise - jsonifyEffect(): Effect.Effect, JsonifiedValues> - }, - - ConstructorParameters - > & - - StaticMembers & { - readonly jsonifySchema: z.ZodObject, - readonly dejsonifySchema: z.ZodObject, - } - ) -} diff --git a/src/jsonifiable/schema/index.ts b/src/jsonifiable/schema/index.ts deleted file mode 100644 index 08ecef8..0000000 --- a/src/jsonifiable/schema/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./bigint" -export * from "./date" -export * from "./decimal" -export * from "./schemable" diff --git a/src/jsonifiable/schema/schemable.ts b/src/jsonifiable/schema/schemable.ts deleted file mode 100644 index b0a72bc..0000000 --- a/src/jsonifiable/schema/schemable.ts +++ /dev/null @@ -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, - - 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, z.ZodTypeDef, InstanceType>, ->( - 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, - - 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, z.ZodTypeDef, InstanceType>, ->( - 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) -} diff --git a/src/legacy/SchemableClass.ts b/src/legacy/SchemableClass.ts deleted file mode 100644 index f85216c..0000000 --- a/src/legacy/SchemableClass.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Class } from "type-fest" -import { z } from "zod" - - -/** - * Configuration for creating a schemable object with validation schemas. - * @template Values - The type representing the expected values. - * @template Input - The type representing the input values. - * @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, - SchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, - SchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny, - - SchemaWithDefaultValuesT extends z.ZodRawShape = z.ZodRawShape, - SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, - SchemaWithDefaultValuesCatchall extends z.ZodTypeAny = z.ZodTypeAny, -> = { - readonly values: Values - readonly input: Input - - readonly schema: z.ZodObject< - SchemaT, - SchemaUnknownKeys, - SchemaCatchall, - Values, - Values - > - - readonly schemaWithDefaultValues: z.ZodObject< - SchemaWithDefaultValuesT, - SchemaWithDefaultValuesUnknownKeys, - SchemaWithDefaultValuesCatchall, - Values, - Input - > -} - - -/** - * 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: $Config["schema"] - readonly schemaWithDefaultValues: $Config["schemaWithDefaultValues"] - } -) - -/** - * 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 - > -) - -/** - * Represents an object with validation schemas. - * @template $Config - The configuration type for the schemable object. - */ -export type SchemableObject< - $Config extends SchemableConfig -> = ( - { - readonly $schemableConfig: $Config - readonly schema: $Config["schema"] - readonly schemaWithDefaultValues: $Config["schemaWithDefaultValues"] - } & $Config["values"] -) diff --git a/src/legacy/index.ts b/src/legacy/index.ts deleted file mode 100644 index 17d8b56..0000000 --- a/src/legacy/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./SchemableClass" -export * from "./makeSchemableClass" -export * from "./newSchemable" diff --git a/src/legacy/jsonifiable/JsonifiableSchemableClass.ts b/src/legacy/jsonifiable/JsonifiableSchemableClass.ts deleted file mode 100644 index c0dc3c0..0000000 --- a/src/legacy/jsonifiable/JsonifiableSchemableClass.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Effect } from "effect" -import { Class } from "type-fest" -import { JsonifiableObject } from "type-fest/source/jsonifiable" -import { z } from "zod" -import { SchemableClassConstructorParams, SchemableConfig } from ".." - - -export type JsonifiableSchemableConfig< - $SchemableConfig extends SchemableConfig = SchemableConfig, - - JsonifiedValues extends JsonifiableObject = {}, - - JsonifySchemaT extends z.ZodRawShape = z.ZodRawShape, - JsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, - JsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny, - - DejsonifySchemaT extends z.ZodRawShape = z.ZodRawShape, - DejsonifySchemaUnknownKeys extends z.UnknownKeysParam = z.UnknownKeysParam, - DejsonifySchemaCatchall extends z.ZodTypeAny = z.ZodTypeAny, -> = { - readonly $schemableConfig: $SchemableConfig - - readonly jsonifiedValues: JsonifiedValues - - readonly jsonifySchema: z.ZodObject< - JsonifySchemaT, - JsonifySchemaUnknownKeys, - JsonifySchemaCatchall, - JsonifiedValues, - $SchemableConfig["values"] - > - - readonly dejsonifySchema: z.ZodObject< - DejsonifySchemaT, - DejsonifySchemaUnknownKeys, - DejsonifySchemaCatchall, - $SchemableConfig["values"], - 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, $Config["jsonifiedValues"]> -} diff --git a/src/legacy/jsonifiable/dejsonifySchemable.ts b/src/legacy/jsonifiable/dejsonifySchemable.ts deleted file mode 100644 index 35ceafb..0000000 --- a/src/legacy/jsonifiable/dejsonifySchemable.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Effect, pipe } from "effect" -import { z } from "zod" -import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from "." -import { parseZodTypeEffect } from "../util" - - -export const dejsonifySchemable = < - C extends JsonifiableSchemableClass<$Config>, - $Config extends JsonifiableSchemableConfig, ->( - class_: C | JsonifiableSchemableClass<$Config>, - values: $Config["jsonifiedValues"], - params?: Partial, -) => - new class_(class_.dejsonifySchema.parse(values, params)) as InstanceType - - -export const dejsonifySchemablePromise = async < - C extends JsonifiableSchemableClass<$Config>, - $Config extends JsonifiableSchemableConfig, ->( - class_: C | JsonifiableSchemableClass<$Config>, - values: $Config["jsonifiedValues"], - params?: Partial, -) => - new class_(await class_.dejsonifySchema.parseAsync(values, params)) as InstanceType - - -export const dejsonifySchemableEffect = < - C extends JsonifiableSchemableClass<$Config>, - $Config extends JsonifiableSchemableConfig, ->( - class_: C | JsonifiableSchemableClass<$Config>, - values: $Config["jsonifiedValues"], - params?: Partial, -) => pipe( - parseZodTypeEffect< - z.output, - z.input - >( - class_.dejsonifySchema, - values, - params, - ), - - Effect.map(values => new class_(values) as InstanceType), -) diff --git a/src/legacy/jsonifiable/index.ts b/src/legacy/jsonifiable/index.ts deleted file mode 100644 index 74e7d23..0000000 --- a/src/legacy/jsonifiable/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./JsonifiableSchemableClass" -export * from "./dejsonifySchemable" -export * from "./makeJsonifiableSchemableClass" -export * from "./schema" diff --git a/src/legacy/jsonifiable/makeJsonifiableSchemableClass.ts b/src/legacy/jsonifiable/makeJsonifiableSchemableClass.ts deleted file mode 100644 index a956b0b..0000000 --- a/src/legacy/jsonifiable/makeJsonifiableSchemableClass.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Class } from "type-fest" -import { JsonifiableObject } from "type-fest/source/jsonifiable" -import { z } from "zod" -import { JsonifiableSchemableClass, JsonifiableSchemableConfig, JsonifiableSchemableObject } from "." -import { SchemableClass, SchemableConfig } from ".." -import { StaticMembers, parseZodTypeEffect } from "../util" - - -export function makeJsonifiableSchemableClass< - C extends SchemableClass<$SchemableConfig>, - $SchemableConfig extends SchemableConfig, - - JsonifiedValues extends JsonifiableObject, - - JsonifySchemaT extends z.ZodRawShape, - JsonifySchemaUnknownKeys extends z.UnknownKeysParam, - JsonifySchemaCatchall extends z.ZodTypeAny, - - DejsonifySchemaT extends z.ZodRawShape, - DejsonifySchemaUnknownKeys extends z.UnknownKeysParam, - DejsonifySchemaCatchall extends z.ZodTypeAny, ->( - class_: C | SchemableClass<$SchemableConfig>, - - props: { - jsonifySchema: (props: { - schema: $SchemableConfig["schema"] - s: $SchemableConfig["schema"]["shape"] - }) => z.ZodObject< - JsonifySchemaT, - JsonifySchemaUnknownKeys, - JsonifySchemaCatchall, - JsonifiedValues, - $SchemableConfig["values"] - > - - dejsonifySchema: (props: { - schema: $SchemableConfig["schema"] - s: $SchemableConfig["schema"]["shape"] - }) => z.ZodObject< - DejsonifySchemaT, - DejsonifySchemaUnknownKeys, - DejsonifySchemaCatchall, - $SchemableConfig["values"], - JsonifiedValues - > - }, -) { - - const jsonifySchema = props.jsonifySchema({ - schema: class_.schema, - s: class_.schema.shape, - }) - - const dejsonifySchema = props.dejsonifySchema({ - schema: class_.schema, - s: class_.schema.shape, - }) - - const $jsonifiableSchemableConfig = { - $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 dejsonifySchema = dejsonifySchema - - readonly $jsonifiableSchemableConfig = $jsonifiableSchemableConfig - readonly jsonifySchema = jsonifySchema - readonly dejsonifySchema = dejsonifySchema - - jsonify() { - return this.jsonifySchema.parse(this) - } - - jsonifyPromise() { - return this.jsonifySchema.parseAsync(this) - } - - jsonifyEffect() { - return parseZodTypeEffect(this.jsonifySchema, this) - } - } satisfies JsonifiableSchemableClass - - return jsonifiableClass as unknown as ( - Class< - InstanceType & JsonifiableSchemableObject, - ConstructorParameters - > & - StaticMembers & - StaticMembers> - ) - -} diff --git a/src/legacy/jsonifiable/schema/bigint.ts b/src/legacy/jsonifiable/schema/bigint.ts deleted file mode 100644 index b0f0093..0000000 --- a/src/legacy/jsonifiable/schema/bigint.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from "zod" - - -export const jsonifyBigIntSchema = (schema: S) => - schema.transform(v => v.toString()) - -export const dejsonifyBigIntSchema = (schema: S) => - z - .string() - .transform(v => { - try { - return BigInt(v) - } - catch (e) { - return v - } - }) - .pipe(schema) diff --git a/src/legacy/jsonifiable/schema/date.ts b/src/legacy/jsonifiable/schema/date.ts deleted file mode 100644 index b5ac677..0000000 --- a/src/legacy/jsonifiable/schema/date.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from "zod" - - -export const jsonifyDateSchema = (schema: S) => - schema.transform(v => v.toString()) - -export const dejsonifyDateSchema = (schema: S) => - z - .string() - .transform(v => { - try { - return new Date(v) - } - catch (e) { - return v - } - }) - .pipe(schema) diff --git a/src/legacy/jsonifiable/schema/decimal.ts b/src/legacy/jsonifiable/schema/decimal.ts deleted file mode 100644 index 58c492d..0000000 --- a/src/legacy/jsonifiable/schema/decimal.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Decimal } from "decimal.js" -import { z } from "zod" - - -export const jsonifyDecimalSchema = >(schema: S) => - schema.transform(v => v.toJSON()) - -export const dejsonifyDecimalSchema = >(schema: S) => - z - .string() - .transform(v => { - try { - return new Decimal(v) - } - catch (e) { - return v - } - }) - .pipe(schema) diff --git a/src/legacy/jsonifiable/schema/index.ts b/src/legacy/jsonifiable/schema/index.ts deleted file mode 100644 index 08ecef8..0000000 --- a/src/legacy/jsonifiable/schema/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./bigint" -export * from "./date" -export * from "./decimal" -export * from "./schemable" diff --git a/src/legacy/jsonifiable/schema/schemable.ts b/src/legacy/jsonifiable/schema/schemable.ts deleted file mode 100644 index c6e2a2d..0000000 --- a/src/legacy/jsonifiable/schema/schemable.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from "zod" -import { JsonifiableSchemableClass, JsonifiableSchemableConfig } from ".." - - -// TODO: try to find a way to get rid of the 'class_' arg -export const jsonifySchemableSchema = < - C extends JsonifiableSchemableClass<$Config>, - $Config extends JsonifiableSchemableConfig, - S extends z.ZodType, z.ZodTypeDef, InstanceType>, ->( - class_: C | JsonifiableSchemableClass<$Config>, - schema: S, -) => - schema.pipe(class_.jsonifySchema) - -// 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, z.ZodTypeDef, InstanceType>, ->( - class_: C | JsonifiableSchemableClass<$Config>, - schema: S, -) => - class_.dejsonifySchema.transform(v => new class_(v)).pipe(schema) diff --git a/src/legacy/makeSchemableClass.ts b/src/legacy/makeSchemableClass.ts deleted file mode 100644 index 88bcf72..0000000 --- a/src/legacy/makeSchemableClass.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { z } from "zod" -import { SchemableClass, SchemableConfig } from "." -import { zodObjectRemoveDefaults } from "./util" - - -export function makeSchemableClass< - SchemaWithDefaultValuesT extends z.ZodRawShape, - SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, - SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, - SchemaWithDefaultValuesOutput extends SchemaWithDefaultValuesInput, // TODO: apply "StripSchemaInputDefaults"? - SchemaWithDefaultValuesInput extends {}, ->( - { - schema: schemaWithDefaultValues - }: { - schema: z.ZodObject< - SchemaWithDefaultValuesT, - SchemaWithDefaultValuesUnknownKeys, - SchemaWithDefaultValuesCatchall, - SchemaWithDefaultValuesOutput, - SchemaWithDefaultValuesInput - > - } -) { - - const schema = zodObjectRemoveDefaults(schemaWithDefaultValues) - - const $schemableConfig = { - values: undefined as unknown as z.output, - input: undefined as unknown as z.input, - 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) { - Object.assign(this, data) - } - } as SchemableClass - -} diff --git a/src/legacy/newSchemable.ts b/src/legacy/newSchemable.ts deleted file mode 100644 index da0be36..0000000 --- a/src/legacy/newSchemable.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Effect, pipe } from "effect" -import { HasRequiredKeys } from "type-fest" -import { z } from "zod" -import { SchemableClass, SchemableConfig } from "." -import { parseZodTypeEffect } from "./util" - - -type ParamsArgs = [] | [Partial] - -type NewSchemableArgs = - HasRequiredKeys extends true - ? [Input, ...ParamsArgs] - : [] | [Input, ...ParamsArgs] - - -/** - * Creates a new instance of a SchemableClass with default values. - * - * @param class_ - The SchemableClass. - * @param values - The values to be parsed and used to create the instance. - * @param params - Optional parameters for parsing. - * @returns A new instance of the specified SchemableClass. - */ -export const newSchemable = < - C extends SchemableClass<$Config>, - $Config extends SchemableConfig, ->( - class_: C | SchemableClass<$Config>, - ...[values, params]: NewSchemableArgs<$Config["input"]> -) => - new class_(class_.schemaWithDefaultValues.parse(values || {}, params)) as InstanceType - - -/** - * Creates a new instance of a SchemableClass with default values asynchronously. - * - * @param class_ - The SchemableClass. - * @param values - The values to be parsed and used to create the instance. - * @param params - Optional parameters for parsing. - * @returns A Promise resolving to a new instance of the specified SchemableClass. - */ -export const newSchemablePromise = async < - C extends SchemableClass<$Config>, - $Config extends SchemableConfig, ->( - class_: C | SchemableClass<$Config>, - ...[values, params]: NewSchemableArgs<$Config["input"]> -) => - new class_(await class_.schemaWithDefaultValues.parseAsync(values || {}, params)) as InstanceType - - -/** - * Creates a new instance of a SchemableClass with default values as an Effect. - * - * @param class_ - The SchemableClass. - * @param values - The values to be parsed and used to create the instance. - * @param params - Optional parameters for parsing. - * @returns An Effect producing a new instance of the specified SchemableClass. - */ -export const newSchemableEffect = < - C extends SchemableClass<$Config>, - $Config extends SchemableConfig, ->( - class_: C | SchemableClass<$Config>, - ...[values, params]: NewSchemableArgs<$Config["input"]> -) => pipe( - parseZodTypeEffect< - z.output, - z.input - >( - class_.schemaWithDefaultValues, - values || {}, - params, - ), - - Effect.map(values => new class_(values) as InstanceType), -) diff --git a/src/legacy/tests.ts b/src/legacy/tests.ts deleted file mode 100644 index c19daf7..0000000 --- a/src/legacy/tests.ts +++ /dev/null @@ -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) diff --git a/src/legacy/util.ts b/src/legacy/util.ts deleted file mode 100644 index 2cf7b08..0000000 --- a/src/legacy/util.ts +++ /dev/null @@ -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 = { - [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 - ? 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, - ...args: Parameters -) => pipe( - Effect.promise(() => schema.safeParseAsync(...args)), - - Effect.flatMap(response => - response.success - ? Effect.succeed(response.data) - : Effect.fail(response.error) - ), -) diff --git a/src/lib.ts b/src/lib.ts new file mode 100644 index 0000000..ef4a60b --- /dev/null +++ b/src/lib.ts @@ -0,0 +1,4 @@ +export { ZodSchemaClassBuilder, zodSchemaClass } from "./builders/ZodSchemaClassBuilder" +export { JsonifiableZodSchemaObject } from "./traits/JsonifiableZodSchemaObject" +export { MobXObservableZodSchemaObject } from "./traits/MobXObservableZodSchemaObject" +export { ZodSchemaObject, ZodSchemaObjectTrait } from "./traits/ZodSchemaObject" diff --git a/src/makeSchemableClass.ts b/src/makeSchemableClass.ts deleted file mode 100644 index 0345eb7..0000000 --- a/src/makeSchemableClass.ts +++ /dev/null @@ -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, ->( - extend: C, - - { schema, defaultValues }: { - schema: z.ZodObject - defaultValues: Opaque - }, -) { - type Class = ( - C extends ConcreteClass - ? ConcreteClass - : AbstractClass - ) - - return class extends (extend as unknown as ConcreteClass) { - 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 & - { - readonly schema: z.ZodObject, - readonly defaultValues: DefaultValues, - } & - Values, - - Parameters<(values: Values) => void> - > & - - StaticMembers & - { - readonly schema: z.ZodObject, - readonly defaultValues: DefaultValues, - } - ) -} - - -export function makeSchemableClass< - SchemaT extends z.ZodRawShape, - SchemaUnknownKeys extends z.UnknownKeysParam, - SchemaCatchall extends z.ZodTypeAny, - - Values extends {}, - DefaultValues extends Partial, ->( - props: { - schema: z.ZodObject - defaultValues: Opaque - } -) { - return makeSchemableClassFrom(Object, props) -} diff --git a/src/newSchemable.ts b/src/newSchemable.ts deleted file mode 100644 index 98a5498..0000000 --- a/src/newSchemable.ts +++ /dev/null @@ -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] - -type NewSchemableArgs = - HasRequiredKeys 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, ->( - class_: C | SchemableClass< - SchemaT, - SchemaUnknownKeys, - SchemaCatchall, - Values, - DefaultValues, - "Class" - >, - - ...[values, params]: NewSchemableArgs< - SchemableClassInput - > -) { - return new class_( - class_.schema.parse({ ...class_.defaultValues, ...values }, params) - ) as InstanceType -} - - -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, ->( - class_: C | SchemableClass< - SchemaT, - SchemaUnknownKeys, - SchemaCatchall, - Values, - DefaultValues, - "Class" - >, - - ...[values, params]: NewSchemableArgs< - SchemableClassInput - > -) { - return new class_( - await class_.schema.parseAsync({ ...class_.defaultValues, ...values }, params) - ) as InstanceType -} - - -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, ->( - class_: C | SchemableClass< - SchemaT, - SchemaUnknownKeys, - SchemaCatchall, - Values, - DefaultValues, - "Class" - >, - - ...[values, params]: NewSchemableArgs< - SchemableClassInput - > -) { - return pipe( - parseZodTypeEffect( - class_.schema, - { ...class_.defaultValues, ...values }, - params, - ), - - Effect.map(values => new class_(values) as InstanceType), - ) -} diff --git a/src/observable/index.ts b/src/observable/index.ts deleted file mode 100644 index 6f219a5..0000000 --- a/src/observable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./makeSchemableClassObservable" diff --git a/src/observable/makeSchemableClassObservable.ts b/src/observable/makeSchemableClassObservable.ts deleted file mode 100644 index 7b5fcb7..0000000 --- a/src/observable/makeSchemableClassObservable.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { mapValues } from "lodash-es" -import { makeObservable, observable } from "mobx" -import { AbstractConstructor } from "type-fest" -import { z } from "zod" -import { SchemableClass } from ".." - - -export function makeSchemableClassObservable< - C extends SchemableClass, - - SchemaT extends z.ZodRawShape, - SchemaUnknownKeys extends z.UnknownKeysParam, - SchemaCatchall extends z.ZodTypeAny, - - Values extends {}, - DefaultValues extends Partial, ->( - extend: C | SchemableClass -) { - return class extends (extend as AbstractConstructor) { - constructor(...args: any[]) { - super(...args) - - makeObservable(this, - mapValues(this.schema.shape, () => observable) - ) - } - } as unknown as C -} diff --git a/src/schema/effect/index.ts b/src/schema/effect/index.ts new file mode 100644 index 0000000..904b057 --- /dev/null +++ b/src/schema/effect/index.ts @@ -0,0 +1,6 @@ +import { option } from "./option" + + +export const effect = { + option, +} as const diff --git a/src/schema/effect/option.ts b/src/schema/effect/option.ts new file mode 100644 index 0000000..53b6abf --- /dev/null +++ b/src/schema/effect/option.ts @@ -0,0 +1,21 @@ +import { Option } from "effect" +import { identity } from "lodash-es" +import { z } from "zod" + + +export const option = { + option: (schema: S) => + z.union([option.some(schema), option.none(schema)]), + + some: (schema: S) => z + .custom>>(v => Option.isOption(v) && Option.isSome(v), "Not an Option") + .pipe(z.object({ value: schema }).passthrough()) + .transform>>(identity), + + none: (_schema?: S) => + z.custom + : unknown + >>(v => Option.isOption(v) && Option.isNone(v), "Not an Option"), +} as const diff --git a/src/jsonifiable/schema/bigint.ts b/src/schema/jsonifiable/bigint.ts similarity index 82% rename from src/jsonifiable/schema/bigint.ts rename to src/schema/jsonifiable/bigint.ts index 76a605d..b6d02d0 100644 --- a/src/jsonifiable/schema/bigint.ts +++ b/src/schema/jsonifiable/bigint.ts @@ -1,9 +1,9 @@ +import { identity } from "lodash-es" import { Opaque } from "type-fest" import { z } from "zod" -import { identity } from "../../util" -export type JsonifiedBigInt = Opaque +export type JsonifiedBigInt = Opaque export function jsonifyBigIntSchema(schema: S) { diff --git a/src/jsonifiable/schema/date.ts b/src/schema/jsonifiable/date.ts similarity index 82% rename from src/jsonifiable/schema/date.ts rename to src/schema/jsonifiable/date.ts index c70b2ed..e147a5d 100644 --- a/src/jsonifiable/schema/date.ts +++ b/src/schema/jsonifiable/date.ts @@ -1,9 +1,9 @@ +import { identity } from "lodash-es" import { Opaque } from "type-fest" import { z } from "zod" -import { identity } from "../../util" -export type JsonifiedDate = Opaque +export type JsonifiedDate = Opaque export function jsonifyDateSchema(schema: S) { diff --git a/src/jsonifiable/schema/decimal.ts b/src/schema/jsonifiable/decimal.ts similarity index 84% rename from src/jsonifiable/schema/decimal.ts rename to src/schema/jsonifiable/decimal.ts index be387ee..ca87662 100644 --- a/src/jsonifiable/schema/decimal.ts +++ b/src/schema/jsonifiable/decimal.ts @@ -1,10 +1,10 @@ import { Decimal } from "decimal.js" +import { identity } from "lodash-es" import { Opaque } from "type-fest" import { z } from "zod" -import { identity } from "../../util" -export type JsonifiedDecimal = Opaque +export type JsonifiedDecimal = Opaque export function jsonifyDecimalSchema< diff --git a/src/schema/jsonifiable/index.ts b/src/schema/jsonifiable/index.ts new file mode 100644 index 0000000..6bff7ae --- /dev/null +++ b/src/schema/jsonifiable/index.ts @@ -0,0 +1,16 @@ +import { dejsonifyBigIntSchema, jsonifyBigIntSchema } from "./bigint" +import { dejsonifyDateSchema, jsonifyDateSchema } from "./date" +import { dejsonifyDecimalSchema, jsonifyDecimalSchema } from "./decimal" + + +export const jsonify = { + bigint: jsonifyBigIntSchema, + date: jsonifyDateSchema, + decimal: jsonifyDecimalSchema, +} as const + +export const dejsonify = { + bigint: dejsonifyBigIntSchema, + date: dejsonifyDateSchema, + decimal: dejsonifyDecimalSchema, +} as const diff --git a/src/schema/lib.ts b/src/schema/lib.ts new file mode 100644 index 0000000..9339106 --- /dev/null +++ b/src/schema/lib.ts @@ -0,0 +1,2 @@ +export * from "./effect" +export * from "./jsonifiable" diff --git a/src/shapes/JsonifiableZodSchemaClass.ts b/src/shapes/JsonifiableZodSchemaClass.ts new file mode 100644 index 0000000..2f35971 --- /dev/null +++ b/src/shapes/JsonifiableZodSchemaClass.ts @@ -0,0 +1,78 @@ +import { AbstractClass, Class } from "type-fest" +import { JsonifiableObject } from "type-fest/source/jsonifiable" +import { z } from "zod" + + +export type JsonifiableZodSchemaClass< + Instance extends 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, + Values extends object, +> = ( + Class & + JsonifiableZodSchemas< + JsonifySchemaT, + JsonifySchemaUnknownKeys, + JsonifySchemaCatchall, + + DejsonifySchemaT, + DejsonifySchemaUnknownKeys, + DejsonifySchemaCatchall, + + JsonifiedValues, + Values + > +) + +export type JsonifiableZodSchemaAbstractClass< + Instance extends 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, + Values extends object, +> = ( + AbstractClass & + JsonifiableZodSchemas< + JsonifySchemaT, + JsonifySchemaUnknownKeys, + JsonifySchemaCatchall, + + DejsonifySchemaT, + DejsonifySchemaUnknownKeys, + DejsonifySchemaCatchall, + + JsonifiedValues, + Values + > +) + +export type JsonifiableZodSchemas< + 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, + Values extends object, +> = { + readonly jsonifySchema: z.ZodObject + readonly dejsonifySchema: z.ZodObject +} diff --git a/src/shapes/ZodSchemaClass.ts b/src/shapes/ZodSchemaClass.ts new file mode 100644 index 0000000..680c59a --- /dev/null +++ b/src/shapes/ZodSchemaClass.ts @@ -0,0 +1,55 @@ +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, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, +> = ( + Class & + ZodSchemas +) + +export type ZodSchemaAbstractClass< + Instance extends Values, + + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, +> = ( + AbstractClass & + ZodSchemas +) + +export type ZodSchemas< + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, +> = { + readonly schema: z.ZodObject + readonly schemaWithDefaultValues: z.ZodObject +} diff --git a/src/tests.ts b/src/tests.ts index 6015710..dff7e44 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -1,63 +1,64 @@ -import { pipeInto } from "ts-functional-pipe" +import { Implements } from "@thilawyn/traitify-ts" import { z } from "zod" -import { defineDefaultValues, extendSchemableClass, makeSchemableClass, newSchemable } from "." -import { dejsonifyBigIntSchema, dejsonifySchemable, jsonifyBigIntSchema, makeJsonifiableSchemableClass } from "./jsonifiable" -import { makeSchemableClassObservable } from "./observable" +import { zodSchemaClass } from "./builders/ZodSchemaClassBuilder" +import { dejsonify, jsonify } from "./schema/jsonifiable" +import { MobXObservableZodSchemaObject } from "./traits/MobXObservableZodSchemaObject" -const UserLevel = z.enum(["User", "Admin"]) - - -class User extends pipeInto( - makeSchemableClass({ +const exp = zodSchemaClass + .schema({ schema: z.object({ - id: z.bigint(), - name: z.string(), - level: UserLevel, + /** User ID */ + id: z.bigint(), + + /** Username */ + name: z.string(), }), - defaultValues: defineDefaultValues({ - level: "User" as const + schemaWithDefaultValues: s => s.extend({ + id: s.shape.id.default(-1n), }), - }), - - v => makeSchemableClassObservable(v), - - v => makeJsonifiableSchemableClass(v, { - jsonifySchema: ({ schema, shape }) => schema.extend({ - id: jsonifyBigIntSchema(shape.id) + }) + .jsonifiable({ + jsonifySchema: s => s.extend({ + id: jsonify.bigint(s.shape.id) }), - dejsonifySchema: ({ schema, shape }) => schema.extend({ - id: dejsonifyBigIntSchema(shape.id) + dejsonifySchema: s => s.extend({ + id: dejsonify.bigint(s.shape.id) }), - }), -) {} - -User.schema + }) + .toExpression() + .expresses(MobXObservableZodSchemaObject) + .build() -const user1 = newSchemable(User, { id: 1n, name: "User" }) -user1.schema +@exp.staticImplements +class User extends exp.extends implements Implements {} -const jsonifiedUser1 = user1.jsonify() -console.log(jsonifiedUser1) -console.log(dejsonifySchemable(User, jsonifiedUser1)) +const inst = User.create({ id: 1n, name: "User" }) +// console.log(inst.name) +const instEffect = User.createEffect({ id: 1n, name: "User" }) + +const jsonifiedUser = await inst.jsonifyPromise() +const dejsonifiedInst = await User.dejsonifyPromise(jsonifiedUser) -const UserWithPhone = extendSchemableClass(User, { - schema: ({ schema }) => schema.extend({ - phone: z.string() - }), - - defaultValues: defaultValues => defineDefaultValues({ - ...defaultValues, - phone: "+33600000000", - }), -}) - -UserWithPhone.defaultValues +// const AdminUserProto = User.extend() +// .schema({ +// schema: s => s.extend({ +// name: z.literal("Admin"), +// prout: z.string(), +// }), +// defaultValues: v => ({ ...v, name: "Admin" as const }), +// }) +// .jsonifiable({ +// jsonifySchema: (s, json) => json.extend({ +// prout: s.shape.prout +// }) +// }) -// const user2 = newSchemable(UserWithPhone, { id: 1n, name: "User" }) -// console.log(user2.jsonify()) +// class AdminUser extends AdminUserProto.toClass() {} +// const subInst = await AdminUser.createPromise({ id: 2n, prout: "" }) +// console.log(subInst) diff --git a/src/traits/ExtendableZodSchemaObject.ts b/src/traits/ExtendableZodSchemaObject.ts new file mode 100644 index 0000000..0fc0891 --- /dev/null +++ b/src/traits/ExtendableZodSchemaObject.ts @@ -0,0 +1,16 @@ +// import { trait } from "@thilawyn/traitify-ts" +// import { ZodSchemaClassExtender } from "../builders/ZodSchemaClassExtender" +// import { ZodSchemaClass } from "../shapes/ZodSchemaClass" + + +// export const ExtendableZodSchemaObject = trait +// .implement(Super => class ExtendableZodSchemaObject extends Super { +// static extend< +// Self extends ZodSchemaClass, +// >( +// this: Self +// ) { +// return new ZodSchemaClassExtender(this, this) +// } +// }) +// .build() diff --git a/src/traits/JsonifiableZodSchemaObject.ts b/src/traits/JsonifiableZodSchemaObject.ts new file mode 100644 index 0000000..c747a8b --- /dev/null +++ b/src/traits/JsonifiableZodSchemaObject.ts @@ -0,0 +1,110 @@ +import { ImplStatic, expression } from "@thilawyn/traitify-ts" +import { Class } from "type-fest" +import { JsonifiableObject } from "type-fest/source/jsonifiable" +import { z } from "zod" +import { parseZodSchemaEffect } from "../util" +import { ZodSchemaObject } from "./ZodSchemaObject" + + +export const JsonifiableZodSchemaObject = < + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, + + 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, +>( + schema: z.ZodObject, + schemaWithDefaultValues: z.ZodObject, + jsonifySchema: z.ZodObject, + dejsonifySchema: z.ZodObject, +) => expression + .expresses(ZodSchemaObject(schema, schemaWithDefaultValues)) + .build() + .subtrait() + .implement(Super => class JsonifiableZodSchemaObject extends Super { + declare ["constructor"]: typeof JsonifiableZodSchemaObject + + static readonly jsonifySchema = jsonifySchema + static readonly dejsonifySchema = dejsonifySchema + + + jsonify(params?: Partial) { + return this.constructor.jsonifySchema.parse(this, params) + } + + jsonifyPromise(params?: Partial) { + return this.constructor.jsonifySchema.parseAsync(this, params) + } + + jsonifyEffect(params?: Partial) { + return parseZodSchemaEffect( + this.constructor.jsonifySchema, + this, + params, + ) + } + + + static dejsonify< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + values: JsonifiedValues, + params?: Partial, + ) { + return this + .transform(this.dejsonifySchema) + .parse(values, params) + } + + static dejsonifyPromise< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + values: JsonifiedValues, + params?: Partial, + ) { + return this + .transform(this.dejsonifySchema) + .parseAsync(values, params) + } + + static dejsonifyEffect< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + values: JsonifiedValues, + params?: Partial, + ) { + return parseZodSchemaEffect( + this.transform(this.dejsonifySchema), + values, + params, + ) + } + }) + .build() diff --git a/src/traits/MobXObservableZodSchemaObject.ts b/src/traits/MobXObservableZodSchemaObject.ts new file mode 100644 index 0000000..c9913da --- /dev/null +++ b/src/traits/MobXObservableZodSchemaObject.ts @@ -0,0 +1,23 @@ +import { trait } from "@thilawyn/traitify-ts" +import { mapValues } from "lodash-es" +import { makeObservable, observable } from "mobx" +import { z } from "zod" + + +export const MobXObservableZodSchemaObject = trait + .staticAbstract(Super => class extends Super { + declare readonly schema: z.ZodObject + }) + .implement(Super => class ObservableZodSchemaObject extends Super { + constructor(...args: any[]) { + super(...args) + + makeObservable(this, + mapValues( + (this.constructor as typeof ObservableZodSchemaObject).schema.shape, + () => observable, + ) + ) + } + }) + .build() diff --git a/src/traits/ZodSchemaObject.ts b/src/traits/ZodSchemaObject.ts new file mode 100644 index 0000000..e866fdf --- /dev/null +++ b/src/traits/ZodSchemaObject.ts @@ -0,0 +1,122 @@ +import { ImplStatic, trait } from "@thilawyn/traitify-ts" +import { Class, HasRequiredKeys } from "type-fest" +import { z } from "zod" +import { parseZodSchemaEffect } from "../util" + + +type CreateArgs = ( + HasRequiredKeys extends true + ? [values: Input, params?: Partial] + : [] | [values: Input, params?: Partial] +) + + +export const ZodSchemaObject = < + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, +>( + schema: z.ZodObject, + schemaWithDefaultValues: z.ZodObject, +) => trait + .implement(Super => class ZodSchemaObject extends Super { + static readonly schema = schema + static readonly schemaWithDefaultValues = schemaWithDefaultValues + + static transform< + Instance extends Values, + + T extends z.ZodRawShape, + UnknownKeys extends z.UnknownKeysParam, + Catchall extends z.ZodTypeAny, + Output extends Values, + Input, + >( + this: Class, + schema: z.ZodObject, + ) { + return schema.transform(values => new this(values)) + } + + + static create< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + ...[values, params]: CreateArgs + ) { + return this + .transform(this.schemaWithDefaultValues) + .parse(values, params) + } + + static createPromise< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + ...[values, params]: CreateArgs + ) { + return this + .transform(this.schemaWithDefaultValues) + .parseAsync(values, params) + } + + static createEffect< + Instance extends Values + >( + this: ( + Class & + ImplStatic + ), + ...[values, params]: CreateArgs + ) { + return parseZodSchemaEffect( + this.transform(this.schemaWithDefaultValues), + values, + params, + ) + } + }) + .build() + + +export type ZodSchemaObjectTrait< + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + SchemaWithDefaultValuesT extends z.ZodRawShape, + SchemaWithDefaultValuesUnknownKeys extends z.UnknownKeysParam, + SchemaWithDefaultValuesCatchall extends z.ZodTypeAny, + + Values extends object, + PartialValues extends Partial, +> = ( + ReturnType< + typeof ZodSchemaObject< + SchemaT, + SchemaUnknownKeys, + SchemaCatchall, + + SchemaWithDefaultValuesT, + SchemaWithDefaultValuesUnknownKeys, + SchemaWithDefaultValuesCatchall, + + Values, + PartialValues + > + > +) diff --git a/src/util.ts b/src/util.ts deleted file mode 100644 index a1c11d4..0000000 --- a/src/util.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Effect, pipe } from "effect" -import { AbstractClass, Class as ConcreteClass } from "type-fest" -import { z } from "zod" - - -export function identity(value: T) { - return value -} - - -export type ClassType = "AbstractClass" | "Class" - -export type Class< - Type extends ClassType, - T, - Arguments extends unknown[] = any[], -> = ( - Type extends "AbstractClass" - ? AbstractClass - : Type extends "Class" - ? ConcreteClass - : never -) - - -/** - * Represents the static members of a class. - * @template C - The class type. - */ -export type StaticMembers = { - [Key in keyof C as Key extends "prototype" ? never : Key]: C[Key] -} - - -/** - * 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, - ...args: Parameters -) => pipe( - Effect.promise(() => schema.safeParseAsync(...args)), - - Effect.flatMap(response => - response.success - ? Effect.succeed(response.data) - : Effect.fail(response.error) - ), -) diff --git a/src/util/class.ts b/src/util/class.ts new file mode 100644 index 0000000..616f709 --- /dev/null +++ b/src/util/class.ts @@ -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 + : Type extends "Class" + ? ConcreteClass + : never +) + +/** + * Gets the type of a class (either "Class" or "AbstractClass"). + * @template C - The class type to determine. + */ +export type GetClassType = ( + C extends ConcreteClass + ? "Class" + : C extends AbstractClass + ? "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 [infer Class, ...infer Rest] + ? Class extends AbstractClass + ? Rest extends AbstractClass[] + ? [InstanceType, ...ClassesInstances] + : never + : never + : [] +) + +/** + * Represents an intersection of instances of the provided classes. + * @template Classes - An array of classes extending AbstractClass. + */ +export type ClassesInstancesIntersection[]> = ( + Classes extends [infer Class, ...infer Rest] + ? Class extends AbstractClass + ? Rest extends AbstractClass[] + ? InstanceType & ClassesInstancesIntersection + : never + : never + : {} +) + +/** + * Represents the static members of a class. + * @template Class - A class extending AbstractClass. + */ +export type StaticMembers> = ( + Omit +) + +/** + * Represents an array of static members corresponding to the provided classes. + * @template Classes - An array of classes extending AbstractClass. + */ +export type ClassesStaticMembers[]> = ( + Classes extends [infer Class, ...infer Rest] + ? Class extends AbstractClass + ? Rest extends AbstractClass[] + ? [StaticMembers, ...ClassesStaticMembers] + : 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 [infer Class, ...infer Rest] + ? Class extends AbstractClass + ? Rest extends AbstractClass[] + ? StaticMembers & ClassesStaticMembersIntersection + : never + : never + : {} +) diff --git a/src/util/effect.ts b/src/util/effect.ts new file mode 100644 index 0000000..b4da92b --- /dev/null +++ b/src/util/effect.ts @@ -0,0 +1,23 @@ +import { Effect, pipe } from "effect" +import { z } from "zod" + + +/** + * Parses a value using a Zod schema wrapped in an Effect monad. + * + * @param schema - The Zod 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 parseZodSchemaEffect = ( + schema: z.ZodType, + ...args: Parameters +) => pipe( + Effect.promise(() => schema.safeParseAsync(...args)), + + Effect.flatMap(response => + response.success + ? Effect.succeed(response.data) + : Effect.fail(response.error) + ), +) diff --git a/src/util/extend.ts b/src/util/extend.ts new file mode 100644 index 0000000..fb28207 --- /dev/null +++ b/src/util/extend.ts @@ -0,0 +1,55 @@ +/** + * Represents the common keys between two types. + * @template A - The first type. + * @template B - The second type. + */ +export type CommonKeys = Extract + +export type Extend = ( + T extends readonly [ + infer Super, + infer Self, + ...infer Rest extends readonly object[], + ] + ? Pick> extends Pick> + ? Extend> & Self, + ...Rest, + ]> + : never + : T extends readonly [infer Self] + ? Self + : {} +) + +export type Override = ( + T extends readonly [ + infer Super, + infer Self, + ...infer Rest extends readonly object[], + ] + ? Override> & Self, + ...Rest, + ]> + : T extends readonly [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 [infer Super, infer Self, ...infer Rest] + ? Pick> extends Pick> + ? ExtendWithoutOverriding<[ + Super & Self, + ...Rest, + ]> + : never + : T extends [infer Self] + ? Self + : void +) diff --git a/src/util/index.ts b/src/util/index.ts new file mode 100644 index 0000000..7bc5968 --- /dev/null +++ b/src/util/index.ts @@ -0,0 +1,4 @@ +export * from "./class" +export * from "./effect" +export * from "./extend" +export * from "./misc" diff --git a/src/util/misc.ts b/src/util/misc.ts new file mode 100644 index 0000000..f381be2 --- /dev/null +++ b/src/util/misc.ts @@ -0,0 +1,3 @@ +export function identity(value: T) { + return value +}