From be2871cbc7e796f0ac68dbace6fbb843e88d711e Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Sat, 28 Jan 2023 00:02:00 +0900 Subject: [PATCH] Complement #209 - documentation by comments --- README.md | 2 +- package.json | 2 +- packages/core/package.json | 2 +- packages/core/src/decorators/DynamicModule.ts | 23 +++++++++++++++-- packages/core/src/decorators/EncryptedBody.ts | 20 +++++++++------ .../core/src/decorators/EncryptedRoute.ts | 21 ++++++++-------- packages/core/src/decorators/TypedBody.ts | 15 ++++++----- packages/core/src/decorators/TypedParam.ts | 12 ++++----- packages/core/src/decorators/TypedQuery.ts | 25 ++++++++++++++++--- packages/core/src/decorators/TypedRoute.ts | 11 ++++---- .../src/decorators/internal/TransformError.ts | 8 ++++++ .../internal/get_path_and_stringify.ts | 7 +++--- .../internal/validate_request_body.ts | 7 +++--- src/NestiaSetupWizard.ts | 3 ++- 14 files changed, 105 insertions(+), 53 deletions(-) create mode 100644 packages/core/src/decorators/internal/TransformError.ts diff --git a/README.md b/README.md index 919ecd4a1..166f38487 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ All functions in `typia` require **only one line**. You don't need any extra ded Also, as `typia` performs AOT (Ahead of Time) compilation skill, its performance is much faster than other competitive libaries. For an example, when comparing validate function `is()` with other competitive libraries, `typia` is maximum **15,000x times faster** than `class-validator`. -## Reactia +### Reactia > https://github.com/samchon/reactia > > Not published yet, but soon diff --git a/package.json b/package.json index 1d784ef4f..d18e60f52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestia", - "version": "4.0.4", + "version": "4.0.5", "description": "Nestia CLI", "main": "bin/index.js", "bin": { diff --git a/packages/core/package.json b/packages/core/package.json index f6f727da1..fe0b6cec1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@nestia/core", - "version": "1.0.9", + "version": "1.0.10", "description": "Super-fast validation decorators of NestJS", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/packages/core/src/decorators/DynamicModule.ts b/packages/core/src/decorators/DynamicModule.ts index d1b5ea15d..493ce3e58 100644 --- a/packages/core/src/decorators/DynamicModule.ts +++ b/packages/core/src/decorators/DynamicModule.ts @@ -4,16 +4,35 @@ import { ModuleMetadata } from "@nestjs/common/interfaces"; import { Creator } from "../typings/Creator"; import { load_controllers } from "./internal/load_controller"; +/** + * Dynamic module. + * + * `DynamicModule` is a namespace wrapping a convenient function, which can load + * controller classes dynamically just by specifying their directory path. + * + * @author Jeongho Nam - https://github.com/samchon + */ export namespace DynamicModule { + /** + * Mount dynamic module. + * + * Constructs a module instance with directory path of controller classes. + * + * Every controller classes in the target directory would be dynamically mounted. + * + * @param path Path of controllers + * @param metadata Addtional metadata except controllers + * @returns module instance + */ export async function mount( path: string, - options: Omit = {}, + metadata: Omit = {}, ): Promise { // LOAD CONTROLLERS const controllers: Creator[] = await load_controllers(path); // RETURN WITH DECORATING - @Module({ ...options, controllers }) + @Module({ ...metadata, controllers }) class NestiaModule {} return NestiaModule; } diff --git a/packages/core/src/decorators/EncryptedBody.ts b/packages/core/src/decorators/EncryptedBody.ts index 8885c3a18..83ea29fb6 100644 --- a/packages/core/src/decorators/EncryptedBody.ts +++ b/packages/core/src/decorators/EncryptedBody.ts @@ -6,6 +6,7 @@ import { } from "@nestjs/common"; import type express from "express"; import raw from "raw-body"; + import { assert, is, validate } from "typia"; import { IRequestBodyValidator } from "../options/IRequestBodyValidator"; @@ -17,14 +18,15 @@ import { validate_request_body } from "./internal/validate_request_body"; /** * Encrypted body decorator. * - * `EncryptedBody` is a decorator function getting JSON data from HTTP request who've - * been encrypted by AES-128/256 algorithm. Also, `EncyrptedBody` validates the JSON - * data type through - * [`typia.assert()`](https://github.com/samchon/typia#runtime-type-checkers) - * function and throws `BadRequestException` error (status code: 400), if the JSON - * data is not following the promised type. + * `EncryptedBody` is a decorator function getting `application/json` typed data from + * requeset body which has been encrypted by AES-128/256 algorithm. Also, + * `EncyrptedBody` validates the request body data type through + * [typia](https://github.com/samchon/typia) ad the validation speed is + * maximum 15,000x times faster than `class-validator`. * - * For reference, `EncryptedRoute` decrypts request body usnig those options. + * For reference, when the request body data is not following the promised type `T`, + * `BadRequestException` error (status code: 400) would be thrown. Also, + * `EncryptedRoute` decrypts request body usnig those options. * * - AES-128/256 * - CBC mode @@ -34,7 +36,9 @@ import { validate_request_body } from "./internal/validate_request_body"; * @return Parameter decorator * @author Jeongho Nam - https://github.com/samchon */ -export function EncryptedBody(validator?: IRequestBodyValidator) { +export function EncryptedBody( + validator?: IRequestBodyValidator, +): ParameterDecorator { const checker = validate_request_body("EncryptedBody")(validator); return createParamDecorator(async function EncryptedBody( _unknown: any, diff --git a/packages/core/src/decorators/EncryptedRoute.ts b/packages/core/src/decorators/EncryptedRoute.ts index df7bad86c..89f929e0e 100644 --- a/packages/core/src/decorators/EncryptedRoute.ts +++ b/packages/core/src/decorators/EncryptedRoute.ts @@ -14,6 +14,7 @@ import { import { HttpArgumentsHost } from "@nestjs/common/interfaces"; import express from "express"; import { Observable, catchError, map } from "rxjs"; + import { assertStringify, isStringify, @@ -24,6 +25,7 @@ import { import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier"; import { Singleton } from "../utils/Singleton"; import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant"; +import { TransformError } from "./internal/TransformError"; import { get_path_and_stringify } from "./internal/get_path_and_stringify"; import { headers_to_object } from "./internal/headers_to_object"; import { route_error } from "./internal/route_error"; @@ -32,21 +34,20 @@ import { route_error } from "./internal/route_error"; * Encrypted router decorator functions. * * `EncryptedRoute` is a module containing router decorator functions which encrypts - * response body data through AES-128/250 encryption. Also, those decorator functions - * can boost up JSON string conversion speed about 5x times faster, through - * [`typia.stringify()`](https://github.com/samchon/typia#fastest-json-string-conversion). + * response body data through AES-128/250 encryption. Furthermore, they can boost + * up JSON string conversion speed about 10x times faster, even type safe through + * [typia](https://github.com/samchon/typia). * - * For reference, `EncryptedRoute` encrypts response body usnig those options. + * For reference, router functions of `EncryptedRoute` can convert custom error classes + * to regular {@link nest.HttpException} class automatically, through + * {@link ExceptionManager}. Also, `EncryptedRoute` encrypts response body usnig those + * options. * * - AES-128/256 * - CBC mode * - PKCS #5 Padding * - Base64 Encoding * - * Also, router functions in `EncryptedRoute` can convert custom error classes to the - * regular {@link nest.HttpException} class automatically, through - * {@link ExceptionManager}. - * * @author Jeongho Nam - https://github.com/samchon */ export namespace EncryptedRoute { @@ -155,9 +156,7 @@ class EncryptedRouteInterceptor implements NestInterceptor { context.getClass(), ); if (!param) - throw new Error( - `Error on nestia.core.EncryptedRoute.${this.method}(): no encryption password is given.`, - ); + throw TransformError(`EncryptedRoute.${this.method}`); const headers: Singleton> = new Singleton(() => { diff --git a/packages/core/src/decorators/TypedBody.ts b/packages/core/src/decorators/TypedBody.ts index 753d8b3e2..74ec59bb1 100644 --- a/packages/core/src/decorators/TypedBody.ts +++ b/packages/core/src/decorators/TypedBody.ts @@ -5,19 +5,22 @@ import { } from "@nestjs/common"; import type express from "express"; import raw from "raw-body"; + import { assert, is, validate } from "typia"; import { IRequestBodyValidator } from "../options/IRequestBodyValidator"; import { validate_request_body } from "./internal/validate_request_body"; /** - * Safe body decorator. + * Type safe body decorator. + * + * `TypedBody` is a decoratur function getting `application/json` typed data from + * request body. Also, it validates the request body data type through + * [typia](https://github.com/samchon/typia) and the validation speed is + * maximum 15,000x times faster than `class-validator`. * - * `TypedBody` is a decorator function getting JSON data from HTTP request. Also, - * it validates the JSON data type through - * [`typia.assert()`](https://github.com/samchon/typia#runtime-type-checkers) - * function and throws `BadRequestException` error (status code: 400), if the JSON - * data is not following the promised type. + * For reference, when the request body data is not following the promised type `T`, + * `BadRequestException` error (status code: 400) would be thrown. * * @param validator Custom validator if required. Default is `typia.assert()` * @author Jeongho Nam - https://github.com/samchon diff --git a/packages/core/src/decorators/TypedParam.ts b/packages/core/src/decorators/TypedParam.ts index 3953ffa63..54ab36f5e 100644 --- a/packages/core/src/decorators/TypedParam.ts +++ b/packages/core/src/decorators/TypedParam.ts @@ -6,12 +6,12 @@ import { import type express from "express"; /** - * URL parameter decorator with type. + * Type safe URL parameter decorator. * - * `TypedParam` is a decorator function getting specific typed parameter from the HTTP - * request URL. It's almost same with the {@link nest.Param}, but `TypedParam` can specify - * the parameter type manually. Beside, the {@link nest.Param} always parses all of the - * parameters as string type. + * `TypedParam` is a decorator function getting specific typed parameter from the + * HTTP request URL. It's almost same with the {@link nest.Param}, but `TypedParam` + * can specify the parameter type manually. Beside, the {@link nest.Param} always + * parses all of the parameters as string type. * * ```typescript * \@TypedRoute.Get("shopping/sales/:section/:id/:paused") @@ -33,7 +33,7 @@ export function TypedParam( name: string, type: "boolean" | "number" | "string" | "uuid" = "string", nullable: boolean = false, -) { +): ParameterDecorator { return createParamDecorator(function TypedParam( {}: any, ctx: ExecutionContext, diff --git a/packages/core/src/decorators/TypedQuery.ts b/packages/core/src/decorators/TypedQuery.ts index 690df2c2e..36aa9a4f2 100644 --- a/packages/core/src/decorators/TypedQuery.ts +++ b/packages/core/src/decorators/TypedQuery.ts @@ -3,9 +3,25 @@ import express from "express"; import { assert } from "typia"; -export function TypedQuery(decoder?: (params: URLSearchParams) => any) { - if (decoder === undefined) - throw new Error("Error on TypedQuery(): no decoder function provided."); +import { TransformError } from "./internal/TransformError"; + +/** + * Type safe URL query decorator. + * + * `TypedQuery` is a decorator function that can parse URL query string. It is almost + * same with {@link nest.Query}, but it can automatically cast property type following + * its DTO definition. Also, `TypedQuery` performs type validation. + * + * For referecen, when URL query parameters are different with their promised + * type `T`, `BadRequestException` error (status code: 400) would be thrown. + * + * @returns Parameter decorator + * @author Jeongho Nam - https://github.com/samchon + */ +export function TypedQuery( + decoder?: (params: URLSearchParams) => T, +): ParameterDecorator { + if (decoder === undefined) throw TransformError("TypedQuery"); return createParamDecorator(async function TypedQuery( _unknown: any, @@ -36,6 +52,9 @@ export namespace TypedQuery { } Object.assign(TypedQuery, assert); +/** + * @internal + */ function tail(url: string): string { const index: number = url.indexOf("?"); return index === -1 ? "" : url.substring(index + 1); diff --git a/packages/core/src/decorators/TypedRoute.ts b/packages/core/src/decorators/TypedRoute.ts index 22c0372d0..4c6b5fe83 100644 --- a/packages/core/src/decorators/TypedRoute.ts +++ b/packages/core/src/decorators/TypedRoute.ts @@ -13,6 +13,7 @@ import { import { HttpArgumentsHost } from "@nestjs/common/interfaces"; import express from "express"; import { Observable, catchError, map } from "rxjs"; + import { assertStringify, isStringify, @@ -25,14 +26,14 @@ import { get_path_and_stringify } from "./internal/get_path_and_stringify"; import { route_error } from "./internal/route_error"; /** - * Safe router decorator functions. + * Type safe router decorator functions. * * `TypedRoute` is a module containing router decorator functions which can boost up - * JSON string conversion speed about 5x times faster, through - * [`typia.stringify()`](https://github.com/samchon/typia#fastest-json-string-conversion). + * JSON string conversion speed about 10x times faster. Furthermore, such JSON string + * conversion is even type safe through [typia](https://github.com/samchon/typia). * - * Also, router functions in `TypedRoute` can convert custom error classes to the - * regular {@link nest.HttpException} class automatically, through + * For reference, router functions of `TypedRoute` can convert custom error classes to + * the regular {@link nest.HttpException} class automatically, through * {@link ExceptionManager}. * * @author Jeongho Nam - https://github.com/samchon diff --git a/packages/core/src/decorators/internal/TransformError.ts b/packages/core/src/decorators/internal/TransformError.ts new file mode 100644 index 000000000..9e004de87 --- /dev/null +++ b/packages/core/src/decorators/internal/TransformError.ts @@ -0,0 +1,8 @@ +/** + * @internal + */ +export function TransformError(method: string): Error { + return new Error( + `Error on nestia.core.${method}(): no transform has been configured. Configure "tsconfig.json" file following [Guide Documents](https://github.com/samchon/nestia/wiki/Setup#tsconfigjson).`, + ); +} diff --git a/packages/core/src/decorators/internal/get_path_and_stringify.ts b/packages/core/src/decorators/internal/get_path_and_stringify.ts index 441a8114c..8f09d234c 100644 --- a/packages/core/src/decorators/internal/get_path_and_stringify.ts +++ b/packages/core/src/decorators/internal/get_path_and_stringify.ts @@ -1,7 +1,9 @@ import { InternalServerErrorException } from "@nestjs/common"; + import { IValidation, TypeGuardError } from "typia"; import { IResponseBodyStringifier } from "../../options/IResponseBodyStringifier"; +import { TransformError } from "./TransformError"; export const get_path_and_stringify = (method: string) => @@ -22,10 +24,7 @@ export const get_path_and_stringify = const take = (method: string) => (functor?: IResponseBodyStringifier | null) => { - if (functor === undefined) - throw new Error( - `Error on nestia.core.${method}(): no stringify function provided.`, - ); + if (functor === undefined) throw TransformError(method); else if (functor === null) return JSON.stringify; else if (functor.type === "stringify") return functor.stringify; else if (functor.type === "assert") return assert(functor.assert); diff --git a/packages/core/src/decorators/internal/validate_request_body.ts b/packages/core/src/decorators/internal/validate_request_body.ts index aeef2d9d9..eee77ffca 100644 --- a/packages/core/src/decorators/internal/validate_request_body.ts +++ b/packages/core/src/decorators/internal/validate_request_body.ts @@ -1,15 +1,14 @@ import { BadRequestException } from "@nestjs/common"; + import { IValidation, TypeGuardError } from "typia"; import { IRequestBodyValidator } from "../../options/IRequestBodyValidator"; +import { TransformError } from "./TransformError"; export const validate_request_body = (method: string) => (validator?: IRequestBodyValidator) => { - if (!validator) - throw new Error( - `Error on nestia.core.${method}(): no transformer.`, - ); + if (!validator) throw TransformError(method); else if (validator.type === "assert") return assert(validator.assert); else if (validator.type === "is") return is(validator.is); else if (validator.type === "validate") diff --git a/src/NestiaSetupWizard.ts b/src/NestiaSetupWizard.ts index f26c95ba5..320a9aef0 100644 --- a/src/NestiaSetupWizard.ts +++ b/src/NestiaSetupWizard.ts @@ -25,7 +25,8 @@ export namespace NestiaSetupWizard { await fs.promises.readFile("package.json", "utf8"), ); add(args.manager)(pack)("@nestia/core", false); - add(args.manager)(pack)("@nestia/sdk", false); + add(args.manager)(pack)("@nestia/sdk", true); + add(args.manager)(pack)("nestia", true); const modulo: typeof import("@nestia/core/lib/executable/internal/CoreSetupWizard") = await import(