From 5ffb91329e7c2d3dbf92ed77dc5d7dc2773d8fbb Mon Sep 17 00:00:00 2001 From: garrettmills Date: Fri, 14 Jan 2022 01:04:13 -0600 Subject: [PATCH] Start new validation system and zodified types with excc --- package.json | 3 ++- pnpm-lock.yaml | 6 ++++++ src/index.ts | 7 ++++++- src/util/support/types.ts | 7 +++++++ src/validation/ValidationUnit.ts | 23 +++++++++++++++++++++++ src/validation/Validator.ts | 31 +++++++++++++++++++++++++++++++ src/validation/ZodifyRecipient.ts | 4 ++++ src/validation/ZodifyRegistrar.ts | 31 +++++++++++++++++++++++++++++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/validation/ValidationUnit.ts create mode 100644 src/validation/Validator.ts create mode 100644 src/validation/ZodifyRecipient.ts create mode 100644 src/validation/ZodifyRegistrar.ts diff --git a/package.json b/package.json index 8a8f061..015c5fe 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "typedoc-plugin-pages-fork": "^0.0.1", "typedoc-plugin-sourcefile-url": "^1.0.6", "typescript": "^4.2.3", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "zod": "^3.11.6" }, "scripts": { "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register 'tests/**/*.ts'", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 252f461..28cf466 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,7 @@ specifiers: typedoc-plugin-sourcefile-url: ^1.0.6 typescript: ^4.2.3 uuid: ^8.3.2 + zod: ^3.11.6 dependencies: '@atao60/fse-cli': 0.1.6 @@ -88,6 +89,7 @@ dependencies: typedoc-plugin-sourcefile-url: 1.0.6_typedoc@0.20.36 typescript: 4.2.3 uuid: 8.3.2 + zod: 3.11.6 devDependencies: '@types/chai': 4.2.22 @@ -3081,3 +3083,7 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zod/3.11.6: + resolution: {integrity: sha512-daZ80A81I3/9lIydI44motWe6n59kRBfNzTuS2bfzVh1nAXi667TOTWWtatxyG+fwgNUiagSj/CWZwRRbevJIg==} + dev: false diff --git a/src/index.ts b/src/index.ts index 6dc3d69..30e2461 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,11 @@ export * from './lifecycle/Application' export * from './lifecycle/AppClass' export * from './lifecycle/Unit' +export * from './validation/ZodifyRecipient' +export * from './validation/ZodifyRegistrar' +export * from './validation/Validator' +export * from './validation/ValidationUnit' + export * from './http/HTTPError' export * from './http/kernel/module/InjectSessionHTTPModule' @@ -94,6 +99,6 @@ export * from './views/PugViewEngine' export * from './cli' export * from './i18n' -export * from './forms' +// export * from './forms' export * from './orm' export * from './auth' diff --git a/src/util/support/types.ts b/src/util/support/types.ts index 39533f2..4393da0 100644 --- a/src/util/support/types.ts +++ b/src/util/support/types.ts @@ -23,3 +23,10 @@ export function isKeyof(key: unknown, obj: T): key is keyof T { export function hasOwnProperty(obj: X, prop: Y): obj is X & Record { // eslint-disable-line @typescript-eslint/ban-types return Object.hasOwnProperty.call(obj, prop) } + +/** + * TypeScript helper for creating tagged-types. + */ +export interface TypeTag { + readonly __typeTag: S +} diff --git a/src/validation/ValidationUnit.ts b/src/validation/ValidationUnit.ts new file mode 100644 index 0000000..fdb06eb --- /dev/null +++ b/src/validation/ValidationUnit.ts @@ -0,0 +1,23 @@ +import { z } from 'zod' +import {Canonical, CanonicalDefinition} from '../service/Canonical' +import {InvalidCanonicalExportError} from '../service/CanonicalInstantiable' +import {Singleton} from '../di' + +@Singleton() +export class ValidationUnit extends Canonical> { + protected appPath = ['types'] + + protected canonicalItem = 'type' + + protected suffix = '.js' + + public async initCanonicalItem(definition: CanonicalDefinition): Promise> { + if ( !(definition.imported?.exZodifiedSchema) ) { + this.logging.debug('Type export is invalid: no exZodifiedSchema found') + this.logging.debug(definition.imported) + throw new InvalidCanonicalExportError(definition.originalName) + } + + return definition.imported.exZodifiedSchema + } +} diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts new file mode 100644 index 0000000..43b4716 --- /dev/null +++ b/src/validation/Validator.ts @@ -0,0 +1,31 @@ +import { z } from 'zod' +import {InjectionAware} from '../di' +import {ZodifyRecipient} from './ZodifyRecipient' +import {ZodifyRegistrar} from './ZodifyRegistrar' + +export class InvalidSchemaMappingError extends Error { + constructor(message = 'Unable to resolve schema for validator.') { + super(message) + } +} + +export class Validator extends InjectionAware implements ZodifyRecipient { + __exZodifiedSchemata: number[] = [] + + protected getZod(): z.ZodType { + // eslint-disable-next-line no-underscore-dangle + if ( this.__exZodifiedSchemata.length < 1 ) { + throw new InvalidSchemaMappingError() + } + + // eslint-disable-next-line no-underscore-dangle + const id = this.__exZodifiedSchemata[0] + + const type = this.make(ZodifyRegistrar).get(id) + if ( !type ) { + throw new InvalidSchemaMappingError() + } + + return type + } +} diff --git a/src/validation/ZodifyRecipient.ts b/src/validation/ZodifyRecipient.ts new file mode 100644 index 0000000..ed25bec --- /dev/null +++ b/src/validation/ZodifyRecipient.ts @@ -0,0 +1,4 @@ + +export interface ZodifyRecipient { + __exZodifiedSchemata: number[] +} diff --git a/src/validation/ZodifyRegistrar.ts b/src/validation/ZodifyRegistrar.ts new file mode 100644 index 0000000..9745ba6 --- /dev/null +++ b/src/validation/ZodifyRegistrar.ts @@ -0,0 +1,31 @@ +import { z } from 'zod' +import {Container, Singleton} from '../di' +import {Collection, Maybe} from '../util' + +type ZodifyRegistrant = { id: number, schema: z.ZodType } + +export function registerZodifiedSchema(id: number, schema: z.ZodType): z.ZodType { + Container.getContainer() + .make(ZodifyRegistrar) + .register(id, schema) + + return schema +} + +@Singleton() +export class ZodifyRegistrar { + protected registeredSchemata: Collection = new Collection() + + public register(id: number, schema: z.ZodType): this { + this.registeredSchemata.push({ + id, + schema, + }) + + return this + } + + public get(id: number): Maybe> { + return this.registeredSchemata.firstWhere('id', '=', id)?.schema + } +}