diff --git a/README.md b/README.md index 224bbf7..927ae65 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,10 @@ [![Github][github-follower-badge]][github-follower-link] [![Twitter][twitter-follower-badge]][twitter-follower-link] -| package | Version | Description | Changelog | -|---------------------------------------------|---------------------------------------------------------------------|----------------------------------------------------------------------------------------|-------------------------------------------| -| [`@nestjs-modular/inject`](packages/inject) | [![npm version][inject-npm-version-badge]][inject-npm-version-link] | This module provides the ability to inject features in bulk by specifying a directory. | [CHANGELOG](packages/inject/CHANGELOG.md) | +| package | Version | Description | Changelog | +|-------------------------------------------------|-------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------|---------------------------------------------| +| [`@nestjs-modular/inject`](packages/inject) | [![npm version][inject-npm-version-badge]][inject-npm-version-link] | This module provides the ability to inject features in bulk by specifying a directory. | [CHANGELOG](packages/inject/CHANGELOG.md) | +| [`@nestjs-modular/validate`](packages/validate) | [![npm version][validate-npm-version-badge]][validate-npm-version-link] | This module provides a pipe to validate incoming requests using schema validation such as Zod or Yup. | [CHANGELOG](packages/validate/CHANGELOG.md) | ## 🤝 Contributing @@ -31,3 +32,5 @@ This project is [```MIT```](https://github.com/Karibash/nestjs-modular/blob/main [twitter-follower-link]: https://twitter.com/intent/follow?screen_name=Karibash [inject-npm-version-badge]: https://badge.fury.io/js/@nestjs-modular%2Finject.svg [inject-npm-version-link]: https://www.npmjs.com/package/@nestjs-modular/inject +[validate-npm-version-badge]: https://badge.fury.io/js/@nestjs-modular%2Fvalidate.svg +[validate-npm-version-link]: https://www.npmjs.com/package/@nestjs-modular/validate diff --git a/examples/inject/README.md b/examples/inject/README.md index 1cb3734..dd32100 100644 --- a/examples/inject/README.md +++ b/examples/inject/README.md @@ -7,6 +7,6 @@ This is a example program describing the basic usage of @nestjs-modular/inject p The example program can be run by executing the following command. ```sh -npm install -npm run start +$ npm install +$ npm run start ``` diff --git a/examples/inject/tsconfig.json b/examples/inject/tsconfig.json index 3923786..9de25cd 100644 --- a/examples/inject/tsconfig.json +++ b/examples/inject/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "strict": true, "module": "commonjs", "declaration": true, "removeComments": true, @@ -13,9 +14,6 @@ "baseUrl": "./", "incremental": true, "skipLibCheck": true, - "strictNullChecks": false, - "noImplicitAny": false, - "strictBindCallApply": false, "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false } diff --git a/examples/validate/.gitignore b/examples/validate/.gitignore new file mode 100644 index 0000000..22f55ad --- /dev/null +++ b/examples/validate/.gitignore @@ -0,0 +1,35 @@ +# compiled output +/dist +/node_modules + +# Logs +logs +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json \ No newline at end of file diff --git a/examples/validate/README.md b/examples/validate/README.md new file mode 100644 index 0000000..d7b406b --- /dev/null +++ b/examples/validate/README.md @@ -0,0 +1,12 @@ +# nest-js-modular-validate + +This is a example program describing the basic usage of @nestjs-modular/validate package. + +## Usage + +The example program can be run by executing the following command. + +```sh +$ npm install +$ npm run start +``` diff --git a/examples/validate/nest-cli.json b/examples/validate/nest-cli.json new file mode 100644 index 0000000..2566481 --- /dev/null +++ b/examples/validate/nest-cli.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src" +} diff --git a/examples/validate/package.json b/examples/validate/package.json new file mode 100644 index 0000000..16cd8f9 --- /dev/null +++ b/examples/validate/package.json @@ -0,0 +1,47 @@ +{ + "name": "nest-js-modular-validate-example", + "version": "0.0.0", + "description": "", + "author": "", + "private": true, + "license": "MIT", + "scripts": { + "prebuild": "rimraf dist", + "build": "nest build", + "start": "nest start", + "start:mock": "APP_ENV=mock nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main" + }, + "dependencies": { + "@nestjs-modular/validate": "1.0.0", + "@nestjs/common": "9.2.1", + "@nestjs/core": "9.2.1", + "@nestjs/platform-express": "9.2.1", + "@valivali/myzod": "1.0.0", + "@valivali/runtypes": "1.0.0", + "@valivali/superstruct": "1.0.0", + "@valivali/yup": "1.0.0", + "@valivali/zod": "1.0.0", + "myzod": "1.10.0", + "reflect-metadata": "0.1.13", + "rimraf": "3.0.2", + "runtypes": "6.6.0", + "rxjs": "7.6.0", + "superstruct": "1.0.3", + "yup": "1.0.2", + "zod": "3.20.2" + }, + "devDependencies": { + "@nestjs/cli": "9.1.5", + "@nestjs/schematics": "9.0.3", + "@types/express": "4.17.14", + "@types/node": "16.18.8", + "source-map-support": "0.5.21", + "ts-loader": "9.4.2", + "ts-node": "10.9.1", + "tsconfig-paths": "4.1.1", + "typescript": "4.9.4" + } +} diff --git a/examples/validate/src/app.module.ts b/examples/validate/src/app.module.ts new file mode 100644 index 0000000..2fc9d13 --- /dev/null +++ b/examples/validate/src/app.module.ts @@ -0,0 +1,26 @@ +import { IncomingValidatePipe } from '@nestjs-modular/validate'; +import { Module } from '@nestjs/common'; +import { APP_PIPE } from '@nestjs/core'; + +import { MyzodModule } from './modules/myzod/myzod.module'; +import { RuntypesModule } from './modules/runtypes/runtypes.module'; +import { SuperstructModule } from './modules/superstruct/superstruct.module'; +import { YupModule } from './modules/yup/yup.module'; +import { ZodModule } from './modules/zod/zod.module'; + +@Module({ + imports: [ + MyzodModule, + RuntypesModule, + SuperstructModule, + YupModule, + ZodModule, + ], + providers: [ + { + provide: APP_PIPE, + useClass: IncomingValidatePipe, + }, + ], +}) +export class AppModule {} diff --git a/examples/validate/src/main.ts b/examples/validate/src/main.ts new file mode 100644 index 0000000..04ba487 --- /dev/null +++ b/examples/validate/src/main.ts @@ -0,0 +1,10 @@ +import { NestFactory } from '@nestjs/core'; + +import { AppModule } from './app.module'; + +const bootstrap = async () => { + const app = await NestFactory.create(AppModule); + await app.listen(3005); +}; + +bootstrap().then(); diff --git a/examples/validate/src/modules/myzod/myzod.controller.ts b/examples/validate/src/modules/myzod/myzod.controller.ts new file mode 100644 index 0000000..e364176 --- /dev/null +++ b/examples/validate/src/modules/myzod/myzod.controller.ts @@ -0,0 +1,24 @@ +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/myzod'; +import z from 'myzod'; + +class ParamDto extends createIncomingDto(resolver(z.object({ + id: z.string(), +}))) {} + +class BodyDto extends createIncomingDto(resolver(z.object({ + title: z.string(), + content: z.string(), +}))) {} + +@Controller('myzod') +export class MyzodController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} diff --git a/examples/validate/src/modules/myzod/myzod.module.ts b/examples/validate/src/modules/myzod/myzod.module.ts new file mode 100644 index 0000000..5742708 --- /dev/null +++ b/examples/validate/src/modules/myzod/myzod.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { MyzodController } from './myzod.controller'; + +@Module({ + controllers: [ + MyzodController, + ], +}) +export class MyzodModule {} diff --git a/examples/validate/src/modules/runtypes/runtypes.controller.ts b/examples/validate/src/modules/runtypes/runtypes.controller.ts new file mode 100644 index 0000000..8c41f60 --- /dev/null +++ b/examples/validate/src/modules/runtypes/runtypes.controller.ts @@ -0,0 +1,24 @@ +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/runtypes'; +import * as rt from 'runtypes'; + +class ParamDto extends createIncomingDto(resolver(rt.Record({ + id: rt.String, +}))) {} + +class BodyDto extends createIncomingDto(resolver(rt.Record({ + title: rt.String, + content: rt.String, +}))) {} + +@Controller('runtypes') +export class RuntypesController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} diff --git a/examples/validate/src/modules/runtypes/runtypes.module.ts b/examples/validate/src/modules/runtypes/runtypes.module.ts new file mode 100644 index 0000000..a48448f --- /dev/null +++ b/examples/validate/src/modules/runtypes/runtypes.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { RuntypesController } from './runtypes.controller'; + +@Module({ + controllers: [ + RuntypesController, + ], +}) +export class RuntypesModule {} diff --git a/examples/validate/src/modules/superstruct/superstruct.controller.ts b/examples/validate/src/modules/superstruct/superstruct.controller.ts new file mode 100644 index 0000000..6697781 --- /dev/null +++ b/examples/validate/src/modules/superstruct/superstruct.controller.ts @@ -0,0 +1,24 @@ +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/superstruct'; +import st from 'superstruct'; + +class ParamDto extends createIncomingDto(resolver(st.object({ + id: st.string(), +}))) {} + +class BodyDto extends createIncomingDto(resolver(st.object({ + title: st.string(), + content: st.string(), +}))) {} + +@Controller('superstruct') +export class SuperstructController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} diff --git a/examples/validate/src/modules/superstruct/superstruct.module.ts b/examples/validate/src/modules/superstruct/superstruct.module.ts new file mode 100644 index 0000000..81478ad --- /dev/null +++ b/examples/validate/src/modules/superstruct/superstruct.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { SuperstructController } from './superstruct.controller'; + +@Module({ + controllers: [ + SuperstructController, + ], +}) +export class SuperstructModule {} diff --git a/examples/validate/src/modules/yup/yup.controller.ts b/examples/validate/src/modules/yup/yup.controller.ts new file mode 100644 index 0000000..e868645 --- /dev/null +++ b/examples/validate/src/modules/yup/yup.controller.ts @@ -0,0 +1,24 @@ +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/yup'; +import * as yup from 'yup'; + +class ParamDto extends createIncomingDto(resolver(yup.object({ + id: yup.string().required(), +}))) {} + +class BodyDto extends createIncomingDto(resolver(yup.object({ + title: yup.string().required(), + content: yup.string().required(), +}))) {} + +@Controller('yup') +export class YupController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} diff --git a/examples/validate/src/modules/yup/yup.module.ts b/examples/validate/src/modules/yup/yup.module.ts new file mode 100644 index 0000000..83bdb63 --- /dev/null +++ b/examples/validate/src/modules/yup/yup.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { YupController } from './yup.controller'; + +@Module({ + controllers: [ + YupController, + ], +}) +export class YupModule {} diff --git a/examples/validate/src/modules/zod/zod.controller.ts b/examples/validate/src/modules/zod/zod.controller.ts new file mode 100644 index 0000000..62f6f2a --- /dev/null +++ b/examples/validate/src/modules/zod/zod.controller.ts @@ -0,0 +1,24 @@ +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/zod'; +import { z } from 'zod'; + +class ParamDto extends createIncomingDto(resolver(z.object({ + id: z.string(), +}))) {} + +class BodyDto extends createIncomingDto(resolver(z.object({ + title: z.string(), + content: z.string(), +}))) {} + +@Controller('zod') +export class ZodController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} diff --git a/examples/validate/src/modules/zod/zod.module.ts b/examples/validate/src/modules/zod/zod.module.ts new file mode 100644 index 0000000..5c8460f --- /dev/null +++ b/examples/validate/src/modules/zod/zod.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { ZodController } from './zod.controller'; + +@Module({ + controllers: [ + ZodController, + ], +}) +export class ZodModule {} diff --git a/examples/validate/tsconfig.build.json b/examples/validate/tsconfig.build.json new file mode 100644 index 0000000..64f86c6 --- /dev/null +++ b/examples/validate/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/examples/validate/tsconfig.json b/examples/validate/tsconfig.json new file mode 100644 index 0000000..9de25cd --- /dev/null +++ b/examples/validate/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "strict": true, + "module": "commonjs", + "declaration": true, + "removeComments": true, + "esModuleInterop": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "es2017", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false + } +} diff --git a/jest.config.js b/jest.config.js index 7d2edb8..7d450c9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,18 @@ module.exports = { transform: { - '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: true }], + '^.+\\.(t|j)sx?$': ['@swc/jest', { + sourceMaps: true, + jsc: { + parser: { + syntax: 'typescript', + decorators: true, + }, + transform: { + legacyDecorator: true, + decoratorMetadata: true, + }, + }, + }], }, watchPlugins: [ 'jest-watch-typeahead/filename', diff --git a/packages/validate/CHANGELOG.md b/packages/validate/CHANGELOG.md new file mode 100644 index 0000000..d38281b --- /dev/null +++ b/packages/validate/CHANGELOG.md @@ -0,0 +1,7 @@ +# @nestjs-modular/validate + +## 1.0.0 + +### Major Changes + +- First release. diff --git a/packages/validate/LICENSE b/packages/validate/LICENSE new file mode 100644 index 0000000..c99a556 --- /dev/null +++ b/packages/validate/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Karibash + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/validate/README.md b/packages/validate/README.md new file mode 100644 index 0000000..7b164de --- /dev/null +++ b/packages/validate/README.md @@ -0,0 +1,82 @@ +# @nestjs-modular/validate + +[![npm version][npm-version-badge]][npm-version-link] +[![codecov][coverage-badge]][coverage-link] +[![license][license-badge]][license-link] +[![Github][github-follower-badge]][github-follower-link] +[![Twitter][twitter-follower-badge]][twitter-follower-link] + +This module provides a pipe to validate incoming requests using schema validation such as Zod or Yup. + +This simplifies validation of incoming requests. + +## 🗒 Examples + +- [REST API Server](../../examples/validate) + +## 🚀 Installation + +``` +$ npm install @nestjs-modular/validate +``` + +Install the schema validation library of your choice. +The following is an example of using zod. + +``` +$ npm install @valivali/zod zod +``` + +## 👏 Getting Started + +The following is a simple example of using zod. + +```ts +import { createIncomingDto } from '@nestjs-modular/validate'; +import { Body, Controller, Param, Post } from '@nestjs/common'; +import { resolver } from '@valivali/zod'; +import { z } from 'zod'; + +class ParamDto extends createIncomingDto(resolver(z.object({ + id: z.string(), +}))) {} + +class BodyDto extends createIncomingDto(resolver(z.object({ + title: z.string(), + content: z.string(), +}))) {} + +@Controller('zod') +export class ZodController { + @Post(':id') + public endpoint( + @Param() param: ParamDto, + @Body() body: BodyDto, + ): void { + console.log({ param, body }); + } +} +``` + +## 🤝 Contributing + +Contributions, issues and feature requests are welcome. + +Feel free to check [issues page](https://github.com/Karibash/nestjs-modular/issues) if you want to contribute. + +## 📝 License + +Copyright © 2020 [@Karibash](https://twitter.com/karibash). + +This project is [```MIT```](https://github.com/Karibash/nestjs-modular/blob/main/packages/validate/LICENSE) licensed. + +[npm-version-badge]: https://badge.fury.io/js/@nestjs-modular%2Fvalidate.svg +[npm-version-link]: https://www.npmjs.com/package/@nestjs-modular/validate +[coverage-badge]: https://codecov.io/gh/Karibash/nestjs-modular/branch/master/graph/badge.svg?flag=validate +[coverage-link]: https://codecov.io/gh/Karibash/nestjs-modular/tree/master/packages/validate +[license-badge]: https://img.shields.io/npm/l/@nestjs-modular%2Fvalidate.svg +[license-link]: https://github.com/Karibash/nestjs-modular/blob/main/packages/validate/LICENSE +[github-follower-badge]: https://img.shields.io/github/followers/Karibash?label=Follow&logo=github&style=social +[github-follower-link]: https://github.com/Karibash?tab=followers +[twitter-follower-badge]: https://img.shields.io/twitter/follow/Karibash?label=Follow&style=social +[twitter-follower-link]: https://twitter.com/intent/follow?screen_name=Karibash diff --git a/packages/validate/package.json b/packages/validate/package.json new file mode 100644 index 0000000..b8b7f2f --- /dev/null +++ b/packages/validate/package.json @@ -0,0 +1,44 @@ +{ + "name": "@nestjs-modular/validate", + "version": "1.0.0", + "description": "NestJS pipe that makes it possible to validate incoming requests using schema validation such as Zod or Yup.", + "main": "dist/nestjs-modular-validate.cjs.js", + "module": "dist/nestjs-modular-validate.esm.js", + "types": "dist/nestjs-modular-validate.cjs.d.ts", + "files": [ + "src", + "dist", + "LICENSE", + "README.md" + ], + "keywords": [ + "typescript", + "nestjs", + "validation", + "pipe" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/Karibash/nestjs-modular.git" + }, + "author": "Karibash", + "license": "MIT", + "bugs": { + "url": "https://github.com/Karibash/nestjs-modular/issues" + }, + "homepage": "https://github.com/Karibash/nestjs-modular/tree/main/packages/validate", + "dependencies": { + "@babel/runtime": "7.20.6", + "@valivali/core": "1.0.0" + }, + "devDependencies": { + "@nestjs/common": "9.2.1", + "typescript": "4.9.4" + }, + "peerDependencies": { + "@nestjs/common": "^9.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/validate/src/index.ts b/packages/validate/src/index.ts new file mode 100644 index 0000000..b665039 --- /dev/null +++ b/packages/validate/src/index.ts @@ -0,0 +1,49 @@ +import { BadRequestException, Optional } from '@nestjs/common'; +import { valivali } from '@valivali/core'; + +import { resolverSymbol } from './internals'; + +import type { ArgumentMetadata, PipeTransform } from '@nestjs/common'; +import type { Resolver } from '@valivali/core'; + +export interface IncomingDto { + new (): T; +} + +export const createIncomingDto = (resolver: Resolver) => { + class Dto { + public static [resolverSymbol] = resolver; + } + return Dto as unknown as IncomingDto; +}; + +export interface IncomingValidatePipeOptions { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + exceptionFactory?: (error: unknown) => any; +} + +export class IncomingValidatePipe implements PipeTransform { + constructor( + @Optional() private readonly options?: IncomingValidatePipeOptions, + ) {} + + public transform(value: unknown, { metatype }: ArgumentMetadata) { + if (!metatype) return value; + if (!(resolverSymbol in metatype)) return value; + + const resolver = metatype[resolverSymbol] as Resolver; + try { + return valivali(resolver, value); + } catch (error) { + if (error instanceof Error) { + if (this.options?.exceptionFactory) { + throw this.options?.exceptionFactory?.(error); + } + + throw new BadRequestException('Bad Request', { cause: error }); + } + + throw error; + } + } +} diff --git a/packages/validate/src/internals.ts b/packages/validate/src/internals.ts new file mode 100644 index 0000000..e1446c2 --- /dev/null +++ b/packages/validate/src/internals.ts @@ -0,0 +1 @@ +export const resolverSymbol = Symbol(); diff --git a/packages/validate/test/index.test.ts b/packages/validate/test/index.test.ts new file mode 100644 index 0000000..a009561 --- /dev/null +++ b/packages/validate/test/index.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from '@jest/globals'; + +import { createIncomingDto, IncomingValidatePipe } from '../src'; +import { resolverSymbol } from '../src/internals'; + +import type { Resolver } from '@valivali/core'; + +const stringResolver: Resolver = value => { + if (typeof value === 'string') return value; + throw Error('invalid value'); +}; + +describe('createIncomingDto', () => { + it('A class holding the resolver is generated', () => { + const dto = createIncomingDto(stringResolver); + + expect(resolverSymbol in dto).toBe(true); + // @ts-ignore + expect(dto[resolverSymbol]).toBe(stringResolver); + }); +}); + +describe('IncomingValidatePipe', () => { + it('Pass valid value', () => { + const pipe = new IncomingValidatePipe(); + const dto = createIncomingDto(stringResolver); + + const value = pipe.transform('string', { type: 'custom', metatype: dto }); + expect(value).toBe('string'); + }); + + it('Pass invalid value', () => { + const pipe = new IncomingValidatePipe(); + const dto = createIncomingDto(stringResolver); + + expect(() => pipe.transform(0, { type: 'custom', metatype: dto })).toThrow(); + }); + + it('Override exceptionFactory', () => { + const pipe = new IncomingValidatePipe({ exceptionFactory: () => 'error' }); + const dto = createIncomingDto(stringResolver); + + expect(() => pipe.transform(0, { type: 'custom', metatype: dto })).toThrow('error'); + }); +}); diff --git a/yarn.lock b/yarn.lock index 5217375..6eec02b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1656,6 +1656,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:7.20.7": + version: 7.20.7 + resolution: "@babel/runtime@npm:7.20.7" + dependencies: + regenerator-runtime: ^0.13.11 + checksum: 4629ce5c46f06cca9cfb9b7fc00d48003335a809888e2b91ec2069a2dcfbfef738480cff32ba81e0b7c290f8918e5c22ddcf2b710001464ee84ba62c7e32a3a3 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.7, @babel/runtime@npm:^7.8.4": version: 7.18.3 resolution: "@babel/runtime@npm:7.18.3" @@ -2499,6 +2508,19 @@ __metadata: languageName: unknown linkType: soft +"@nestjs-modular/validate@1.0.0, @nestjs-modular/validate@workspace:packages/validate": + version: 0.0.0-use.local + resolution: "@nestjs-modular/validate@workspace:packages/validate" + dependencies: + "@babel/runtime": 7.20.6 + "@nestjs/common": 9.2.1 + "@valivali/core": 1.0.0 + typescript: 4.9.4 + peerDependencies: + "@nestjs/common": ^9.0.0 + languageName: unknown + linkType: soft + "@nestjs/cli@npm:9.1.5": version: 9.1.5 resolution: "@nestjs/cli@npm:9.1.5" @@ -3457,6 +3479,75 @@ __metadata: languageName: node linkType: hard +"@valivali/core@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/core@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + checksum: 6400bb8f76cd33d5f312700278a970aa09ba46fe7405101b51e3c4ed88ca1af9c4b6860d5f1db776f068723c9e6a14754f02c361290c0119e1cdf753a8494aa4 + languageName: node + linkType: hard + +"@valivali/myzod@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/myzod@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + "@valivali/core": 1.0.0 + peerDependencies: + myzod: ^1.0.0 + checksum: c1fe5b803af6d33b0fc8760c1f06457d5cf56ed1248747b65f2791c287e895e054025ca21bb1c9fb3f124eecd33d444397dcd0470ea45796d0270bfb5cf90875 + languageName: node + linkType: hard + +"@valivali/runtypes@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/runtypes@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + "@valivali/core": 1.0.0 + peerDependencies: + runtypes: ^6.0.0 + checksum: 357d515dbd2ee931f11b6947a9e3553aee0f3681df6188516279d4c12be805fc9c4cedfbffb9706501fc4be5e74ccaa5ae5ed707c70045b1f73d56562ae13575 + languageName: node + linkType: hard + +"@valivali/superstruct@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/superstruct@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + "@valivali/core": 1.0.0 + peerDependencies: + superstruct: ^1.0.0 + checksum: 13d27a3586f4783b4d6ee3f8b7d456941f0793192b367cf487c9ef6ae6456aa309f02fc7bd43d68778abc3eec3773cb2231db022e411bebf81bcac9716cc547f + languageName: node + linkType: hard + +"@valivali/yup@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/yup@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + "@valivali/core": 1.0.0 + peerDependencies: + yup: ^1.0.0 + checksum: f71389a18d41f033a00658d7f954b261f1ee87d7ce4384756a513a167f9407294be7455621bb38f72c877c21838f1857524756647d89faffc32bba41d4805606 + languageName: node + linkType: hard + +"@valivali/zod@npm:1.0.0": + version: 1.0.0 + resolution: "@valivali/zod@npm:1.0.0" + dependencies: + "@babel/runtime": 7.20.7 + "@valivali/core": 1.0.0 + peerDependencies: + zod: ^3.0.0 + checksum: 681883e3c2359d468e1f07d3161e09ddfedfd9169ea802c0d46802263ff832391b4080038a449932004781048e3e987a11b7d866ea4ee0c705fc4fde31f17c24 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.11.1": version: 1.11.1 resolution: "@webassemblyjs/ast@npm:1.11.1" @@ -8162,6 +8253,13 @@ __metadata: languageName: node linkType: hard +"myzod@npm:1.10.0": + version: 1.10.0 + resolution: "myzod@npm:1.10.0" + checksum: a5d4eee5fed4205683a2e6b4557f7537979f098bd2b6040051fbc5a30d2bd6dcdf8fa20b16703ff8c56c69763bc226505d0c3155ac0bc7969e36773901d9af04 + languageName: node + linkType: hard + "natural-compare-lite@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare-lite@npm:1.4.0" @@ -8213,6 +8311,39 @@ __metadata: languageName: unknown linkType: soft +"nest-js-modular-validate-example@workspace:examples/validate": + version: 0.0.0-use.local + resolution: "nest-js-modular-validate-example@workspace:examples/validate" + dependencies: + "@nestjs-modular/validate": 1.0.0 + "@nestjs/cli": 9.1.5 + "@nestjs/common": 9.2.1 + "@nestjs/core": 9.2.1 + "@nestjs/platform-express": 9.2.1 + "@nestjs/schematics": 9.0.3 + "@types/express": 4.17.14 + "@types/node": 16.18.8 + "@valivali/myzod": 1.0.0 + "@valivali/runtypes": 1.0.0 + "@valivali/superstruct": 1.0.0 + "@valivali/yup": 1.0.0 + "@valivali/zod": 1.0.0 + myzod: 1.10.0 + reflect-metadata: 0.1.13 + rimraf: 3.0.2 + runtypes: 6.6.0 + rxjs: 7.6.0 + source-map-support: 0.5.21 + superstruct: 1.0.3 + ts-loader: 9.4.2 + ts-node: 10.9.1 + tsconfig-paths: 4.1.1 + typescript: 4.9.4 + yup: 1.0.2 + zod: 3.20.2 + languageName: unknown + linkType: soft + "nestjs-modular-project@workspace:.": version: 0.0.0-use.local resolution: "nestjs-modular-project@workspace:." @@ -8856,6 +8987,13 @@ __metadata: languageName: node linkType: hard +"property-expr@npm:^2.0.5": + version: 2.0.5 + resolution: "property-expr@npm:2.0.5" + checksum: 4ebe82ce45aaf1527e96e2ab84d75d25217167ec3ff6378cf83a84fb4abc746e7c65768a79d275881602ae82f168f9a6dfaa7f5e331d0fcc83d692770bcce5f1 + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -9367,6 +9505,13 @@ __metadata: languageName: node linkType: hard +"runtypes@npm:6.6.0": + version: 6.6.0 + resolution: "runtypes@npm:6.6.0" + checksum: 86cb4705285385ce3e50f8dbe1650001da1c375407735296cf86c13f5af2da408ee7f6d22849d5f849f87cf6416d841dd618548be0509886a0236294b22c551d + languageName: node + linkType: hard + "rxjs@npm:6.6.7, rxjs@npm:^6.6.0": version: 6.6.7 resolution: "rxjs@npm:6.6.7" @@ -9991,6 +10136,13 @@ __metadata: languageName: node linkType: hard +"superstruct@npm:1.0.3": + version: 1.0.3 + resolution: "superstruct@npm:1.0.3" + checksum: 761790bb111e6e21ddd608299c252f3be35df543263a7ebbc004e840d01fcf8046794c274bcb351bdf3eae4600f79d317d085cdbb19ca05803a4361840cc9bb1 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -10131,6 +10283,13 @@ __metadata: languageName: node linkType: hard +"tiny-case@npm:^1.0.3": + version: 1.0.3 + resolution: "tiny-case@npm:1.0.3" + checksum: 3f7a30c39d5b0e1bc097b0b271bec14eb5b836093db034f35a0de26c14422380b50dc12bfd37498cf35b192f5df06f28a710712c87ead68872a9e37ad6f6049d + languageName: node + linkType: hard + "tiny-glob@npm:^0.2.9": version: 0.2.9 resolution: "tiny-glob@npm:0.2.9" @@ -10180,6 +10339,13 @@ __metadata: languageName: node linkType: hard +"toposort@npm:^2.0.2": + version: 2.0.2 + resolution: "toposort@npm:2.0.2" + checksum: d64c74b570391c9432873f48e231b439ee56bc49f7cb9780b505cfdf5cb832f808d0bae072515d93834dd6bceca5bb34448b5b4b408335e4d4716eaf68195dcb + languageName: node + linkType: hard + "tr46@npm:^1.0.1": version: 1.0.1 resolution: "tr46@npm:1.0.1" @@ -10410,6 +10576,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^2.19.0": + version: 2.19.0 + resolution: "type-fest@npm:2.19.0" + checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 + languageName: node + linkType: hard + "type-fest@npm:^3.0.0": version: 3.3.0 resolution: "type-fest@npm:3.3.0" @@ -11016,3 +11189,22 @@ __metadata: checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard + +"yup@npm:1.0.2": + version: 1.0.2 + resolution: "yup@npm:1.0.2" + dependencies: + property-expr: ^2.0.5 + tiny-case: ^1.0.3 + toposort: ^2.0.2 + type-fest: ^2.19.0 + checksum: 1cb9c490853739aa0c576c87a81008dd3612985dd2da5ff6127b77640465fa906bb47ed30a7c97824b4a3f525010b2d7f614ebbd442b02e16433675c4d66f0b8 + languageName: node + linkType: hard + +"zod@npm:3.20.2": + version: 3.20.2 + resolution: "zod@npm:3.20.2" + checksum: 04172f7e9350372684ccd298d4716908edc9113751295b6c4e1b3ea84e2af8997e504b33ba36f4741417bb2a5dc90bfd40501f6b0e7389df10e42a63d6d8366c + languageName: node + linkType: hard