diff --git a/docs/docs/filters.md b/docs/docs/filters.md index 72b1a725103..26e62f175f2 100644 --- a/docs/docs/filters.md +++ b/docs/docs/filters.md @@ -29,11 +29,11 @@ export class BodyParamsFilter implements IFilter { Then create the decorator. This decorator will be used on a controller method. ```typescript -import {ParamRegistry} from "@tsed/common"; +import {UseFilter} from "@tsed/common"; import {BodyParamsFilter} from "../filters" export function BodyParams(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(BodyParamsFilter, {expression, useType}); + return UseFilter(BodyParamsFilter, {expression, useType}); } ``` diff --git a/packages/common/src/filters/decorators/bodyParams.ts b/packages/common/src/filters/decorators/bodyParams.ts index d7b4c555d0c..64b7855c09b 100644 --- a/packages/common/src/filters/decorators/bodyParams.ts +++ b/packages/common/src/filters/decorators/bodyParams.ts @@ -1,6 +1,6 @@ import {BodyParamsFilter} from "../components/BodyParamsFilter"; import {ParamTypes} from "../interfaces/ParamTypes"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; /** * BodyParams return the value from [request.body](http://expressjs.com/en/4x/api.html#req.body) object. @@ -39,7 +39,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function BodyParams(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(BodyParamsFilter, { + return UseFilter(BodyParamsFilter, { expression, useType, useConverter: true, diff --git a/packages/common/src/filters/decorators/cookies.ts b/packages/common/src/filters/decorators/cookies.ts index 8330e70d677..86f602f9cca 100644 --- a/packages/common/src/filters/decorators/cookies.ts +++ b/packages/common/src/filters/decorators/cookies.ts @@ -1,6 +1,6 @@ -import {ParamTypes} from "../interfaces/ParamTypes"; import {CookiesFilter} from "../components/CookiesFilter"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {ParamTypes} from "../interfaces/ParamTypes"; +import {UseFilter} from "./useFilter"; /** * Cookies or CookiesParams return the value from [request.cookies](http://expressjs.com/en/4x/api.html#req.cookies) object. @@ -34,7 +34,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function CookiesParams(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(CookiesFilter, { + return UseFilter(CookiesFilter, { expression, useType, paramType: ParamTypes.COOKIES diff --git a/packages/common/src/filters/decorators/endpointInfo.ts b/packages/common/src/filters/decorators/endpointInfo.ts index cb07cdf91d1..f17d6acae99 100644 --- a/packages/common/src/filters/decorators/endpointInfo.ts +++ b/packages/common/src/filters/decorators/endpointInfo.ts @@ -1,6 +1,6 @@ import {EndpointMetadata} from "../../mvc/class/EndpointMetadata"; import {ENDPOINT_INFO} from "../constants"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; export type EndpointInfo = EndpointMetadata; @@ -10,5 +10,5 @@ export type EndpointInfo = EndpointMetadata; * @decorator */ export function EndpointInfo(): Function { - return ParamRegistry.decorate(ENDPOINT_INFO); + return UseFilter(ENDPOINT_INFO); } diff --git a/packages/common/src/filters/decorators/error.ts b/packages/common/src/filters/decorators/error.ts index 7ecdc6a752f..547d9d42978 100644 --- a/packages/common/src/filters/decorators/error.ts +++ b/packages/common/src/filters/decorators/error.ts @@ -1,5 +1,5 @@ -import {ParamRegistry} from "../registries/ParamRegistry"; import {EXPRESS_ERR} from "../constants"; +import {UseFilter} from "./useFilter"; /** * @@ -7,5 +7,5 @@ import {EXPRESS_ERR} from "../constants"; * @decorators */ export function Err(): Function { - return ParamRegistry.decorate(EXPRESS_ERR); + return UseFilter(EXPRESS_ERR); } diff --git a/packages/common/src/filters/decorators/headerParams.ts b/packages/common/src/filters/decorators/headerParams.ts index 4936651756a..fc7bc81d3f2 100644 --- a/packages/common/src/filters/decorators/headerParams.ts +++ b/packages/common/src/filters/decorators/headerParams.ts @@ -1,6 +1,6 @@ -import {ParamTypes} from "../interfaces/ParamTypes"; import {HeaderParamsFilter} from "../components/HeaderParamsFilter"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {ParamTypes} from "../interfaces/ParamTypes"; +import {UseFilter} from "./useFilter"; /** * HeaderParams return the value from [request.params](http://expressjs.com/en/4x/api.html#req.params) object. @@ -28,7 +28,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function HeaderParams(expression: string): Function { - return ParamRegistry.decorate(HeaderParamsFilter, { + return UseFilter(HeaderParamsFilter, { expression, paramType: ParamTypes.HEADER }); diff --git a/packages/common/src/filters/decorators/locals.ts b/packages/common/src/filters/decorators/locals.ts index 1ff6354388f..086b5b8fe00 100644 --- a/packages/common/src/filters/decorators/locals.ts +++ b/packages/common/src/filters/decorators/locals.ts @@ -1,6 +1,6 @@ -import {ParamTypes} from "../interfaces/ParamTypes"; import {LocalsFilter} from "../components/LocalsFilter"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {ParamTypes} from "../interfaces/ParamTypes"; +import {UseFilter} from "./useFilter"; /** * Locals return the value from [response.locals](http://expressjs.com/en/4x/api.html#res.locals) object. @@ -28,7 +28,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function Locals(expression?: string | any): Function { - return ParamRegistry.decorate(LocalsFilter, { + return UseFilter(LocalsFilter, { expression, useConverter: false, paramType: ParamTypes.LOCALS diff --git a/packages/common/src/filters/decorators/next.ts b/packages/common/src/filters/decorators/next.ts index b0efb3769e5..da315a3122b 100644 --- a/packages/common/src/filters/decorators/next.ts +++ b/packages/common/src/filters/decorators/next.ts @@ -1,6 +1,6 @@ import * as Express from "express"; import {EXPRESS_NEXT_FN} from "../constants"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; export type Next = Express.NextFunction; @@ -10,5 +10,5 @@ export type Next = Express.NextFunction; * @decorator */ export function Next(): Function { - return ParamRegistry.decorate(EXPRESS_NEXT_FN); + return UseFilter(EXPRESS_NEXT_FN); } diff --git a/packages/common/src/filters/decorators/pathParams.ts b/packages/common/src/filters/decorators/pathParams.ts index 899df944368..78824a68a1a 100644 --- a/packages/common/src/filters/decorators/pathParams.ts +++ b/packages/common/src/filters/decorators/pathParams.ts @@ -1,6 +1,6 @@ -import {ParamTypes} from "../interfaces/ParamTypes"; import {PathParamsFilter} from "../components/PathParamsFilter"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {ParamTypes} from "../interfaces/ParamTypes"; +import {UseFilter} from "./useFilter"; /** * PathParams return the value from [request.params](http://expressjs.com/en/4x/api.html#req.params) object. @@ -29,7 +29,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function PathParams(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(PathParamsFilter, { + return UseFilter(PathParamsFilter, { expression, useType, paramType: ParamTypes.PATH diff --git a/packages/common/src/filters/decorators/queryParams.ts b/packages/common/src/filters/decorators/queryParams.ts index bc90d1f92e0..75e15c523d8 100644 --- a/packages/common/src/filters/decorators/queryParams.ts +++ b/packages/common/src/filters/decorators/queryParams.ts @@ -1,6 +1,6 @@ import {QueryParamsFilter} from "../components/QueryParamsFilter"; import {ParamTypes} from "../interfaces/ParamTypes"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; /** * QueryParams return the value from [request.query](http://expressjs.com/en/4x/api.html#req.query) object. @@ -39,7 +39,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function QueryParams(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(QueryParamsFilter, { + return UseFilter(QueryParamsFilter, { expression, useType, useConverter: true, diff --git a/packages/common/src/filters/decorators/request.ts b/packages/common/src/filters/decorators/request.ts index 7f187c68a72..eb42c93e115 100644 --- a/packages/common/src/filters/decorators/request.ts +++ b/packages/common/src/filters/decorators/request.ts @@ -1,3 +1,4 @@ +import {UseFilter} from "./useFilter"; import * as Express from "express"; import {EXPRESS_REQUEST} from "../constants"; import {ParamRegistry} from "../registries/ParamRegistry"; @@ -21,5 +22,5 @@ export function Request(): Function { * @alias Request */ export function Req() { - return ParamRegistry.decorate(EXPRESS_REQUEST); + return UseFilter(EXPRESS_REQUEST); } diff --git a/packages/common/src/filters/decorators/response.ts b/packages/common/src/filters/decorators/response.ts index b04f1c8c96a..0ad1466472f 100644 --- a/packages/common/src/filters/decorators/response.ts +++ b/packages/common/src/filters/decorators/response.ts @@ -1,6 +1,6 @@ import * as Express from "express"; import {EXPRESS_RESPONSE} from "../constants"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; export type Response = Express.Response; export type Res = Express.Response; @@ -21,5 +21,5 @@ export function Response(): Function { * @alias Request */ export function Res() { - return ParamRegistry.decorate(EXPRESS_RESPONSE); + return UseFilter(EXPRESS_RESPONSE); } diff --git a/packages/common/src/filters/decorators/responseData.ts b/packages/common/src/filters/decorators/responseData.ts index ad2d1fb2352..ece7ad3e32c 100644 --- a/packages/common/src/filters/decorators/responseData.ts +++ b/packages/common/src/filters/decorators/responseData.ts @@ -1,5 +1,5 @@ import {RESPONSE_DATA} from "../constants"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {UseFilter} from "./useFilter"; /** * @@ -7,5 +7,5 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @decorator */ export function ResponseData(): Function { - return ParamRegistry.decorate(RESPONSE_DATA); + return UseFilter(RESPONSE_DATA); } diff --git a/packages/common/src/filters/decorators/session.ts b/packages/common/src/filters/decorators/session.ts index db01e6c7ebe..54ea37e0ac4 100644 --- a/packages/common/src/filters/decorators/session.ts +++ b/packages/common/src/filters/decorators/session.ts @@ -1,6 +1,6 @@ -import {ParamTypes} from "../interfaces/ParamTypes"; import {SessionFilter} from "../components/SessionFilter"; -import {ParamRegistry} from "../registries/ParamRegistry"; +import {ParamTypes} from "../interfaces/ParamTypes"; +import {UseFilter} from "./useFilter"; /** * Session return the value from [request.session](http://expressjs.com/en/4x/api.html#req.session) object. @@ -29,7 +29,7 @@ import {ParamRegistry} from "../registries/ParamRegistry"; * @returns {Function} */ export function Session(expression?: string | any, useType?: any): Function { - return ParamRegistry.decorate(SessionFilter, { + return UseFilter(SessionFilter, { expression, useType, paramType: ParamTypes.SESSION diff --git a/packages/common/src/filters/decorators/useFilter.ts b/packages/common/src/filters/decorators/useFilter.ts new file mode 100644 index 00000000000..bfc563203af --- /dev/null +++ b/packages/common/src/filters/decorators/useFilter.ts @@ -0,0 +1,22 @@ +import {StoreMerge, Type} from "@tsed/core"; +import {IInjectableParamSettings} from "../interfaces/IInjectableParamSettings"; +import {ParamRegistry} from "../registries/ParamRegistry"; + +export function UseFilter(token: Type | symbol, options: Partial> = {}): ParameterDecorator { + return (target: Type, propertyKey: string | symbol, parameterIndex: number): any => { + const settings = Object.assign( + { + target, + propertyKey, + parameterIndex + }, + options + ); + + if (typeof token === "symbol") { + ParamRegistry.usePreHandler(token, settings); + } else { + ParamRegistry.useFilter(token, settings); + } + }; +} diff --git a/packages/common/src/filters/index.ts b/packages/common/src/filters/index.ts index dff56aa5bc3..22e302033cd 100644 --- a/packages/common/src/filters/index.ts +++ b/packages/common/src/filters/index.ts @@ -6,6 +6,7 @@ export * from "./errors/ParseExpressionError"; export * from "./errors/RequiredParamError"; export * from "./errors/UnknowFilterError"; +export * from "./decorators/useFilter"; export * from "./decorators/bodyParams"; export * from "./decorators/cookies"; export * from "./decorators/filter"; diff --git a/packages/common/src/filters/registries/ParamRegistry.ts b/packages/common/src/filters/registries/ParamRegistry.ts index 5ceff4b360b..d0f62cb1390 100644 --- a/packages/common/src/filters/registries/ParamRegistry.ts +++ b/packages/common/src/filters/registries/ParamRegistry.ts @@ -26,39 +26,39 @@ export class ParamRegistry { /** * * @param target - * @param targetKey + * @param propertyKey * @returns {Array} */ - static getParams = (target: Type, targetKey?: string | symbol): ParamMetadata[] => - Metadata.has(PARAM_METADATA, target, targetKey) ? Metadata.get(PARAM_METADATA, target, targetKey) : []; + static getParams(target: Type, propertyKey: string | symbol): ParamMetadata[] { + return Metadata.has(PARAM_METADATA, target, propertyKey) ? Metadata.get(PARAM_METADATA, target, propertyKey) : []; + } /** * * @param target - * @param targetKey + * @param propertyKey * @param index * @param paramMetadata */ - static set(target: Type, targetKey: string | symbol, index: number, paramMetadata: ParamMetadata): void { - const params = Metadata.has(PARAM_METADATA, target, targetKey) ? Metadata.get(PARAM_METADATA, target, targetKey) : []; + static set(target: Type, propertyKey: string | symbol, index: number, paramMetadata: ParamMetadata): void { + const params = this.getParams(target, propertyKey); params[index] = paramMetadata; - Metadata.set(PARAM_METADATA, params, target, targetKey); + Metadata.set(PARAM_METADATA, params, target, propertyKey); } /** * * @param service * @param settings + * @deprecated */ static usePreHandler(service: symbol, settings: IParamArgs) { const param = ParamRegistry.get(settings.target, settings.propertyKey, settings.parameterIndex); param.service = service; param.useConverter = false; - ParamRegistry.set(settings.target, settings.propertyKey, settings.parameterIndex, param); - return this; } @@ -68,6 +68,7 @@ export class ParamRegistry { * @param propertyKey * @param parameterIndex * @param allowedRequiredValues + * @deprecated */ static required(target: Type, propertyKey: string | symbol, parameterIndex: number, allowedRequiredValues: any[] = []) { const param = ParamRegistry.get(target, propertyKey, parameterIndex); @@ -75,8 +76,6 @@ export class ParamRegistry { param.required = true; param.allowedRequiredValues = allowedRequiredValues; - ParamRegistry.set(target, propertyKey, parameterIndex, param); - param.store.merge("responses", { "400": { description: "BadRequest" @@ -91,6 +90,7 @@ export class ParamRegistry { * @param token * @param {Partial>} options * @returns {Function} + * @deprecated */ static decorate(token: Type | symbol, options: Partial> = {}): ParameterDecorator { return (target: Type, propertyKey: string | symbol, parameterIndex: number): any => { @@ -117,6 +117,7 @@ export class ParamRegistry { * * @param service * @param options + * @deprecated */ static useFilter(service: Type, options: IInjectableParamSettings): ParamMetadata { const {propertyKey, parameterIndex, target, useConverter, useValidation, paramType} = options; @@ -146,8 +147,6 @@ export class ParamRegistry { param.useConverter = useConverter; } - ParamRegistry.set(target, propertyKey, parameterIndex, param); - return param; } } diff --git a/packages/common/test/filters/decorators/bodyParams.spec.ts b/packages/common/test/filters/decorators/bodyParams.spec.ts index 83ab5cadc16..b92a6fb327a 100644 --- a/packages/common/test/filters/decorators/bodyParams.spec.ts +++ b/packages/common/test/filters/decorators/bodyParams.spec.ts @@ -1,26 +1,34 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {BodyParams, ParamRegistry, ParamTypes} from "../../../src/filters"; import {BodyParamsFilter} from "../../../src/filters/components/BodyParamsFilter"; -class Test { -} - -describe("BodyParams", () => { +const sandbox = Sinon.createSandbox(); +describe("@BodyParams", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - BodyParams("test", Test); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(BodyParamsFilter, { - expression: "test", + class Ctrl { + test(@BodyParams("expression", Test) body: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(BodyParamsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useType: Test, useConverter: true, useValidation: true, paramType: ParamTypes.BODY - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/cookies.spec.ts b/packages/common/test/filters/decorators/cookies.spec.ts index d56e71edf66..e4fe5c7671d 100644 --- a/packages/common/test/filters/decorators/cookies.spec.ts +++ b/packages/common/test/filters/decorators/cookies.spec.ts @@ -1,24 +1,33 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {Cookies, ParamRegistry, ParamTypes} from "../../../src/filters"; import {CookiesFilter} from "../../../src/filters/components/CookiesFilter"; -class Test { -} - -describe("Cookies", () => { +const sandbox = Sinon.createSandbox(); +describe("@Cookies", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Cookies("test", Test); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(CookiesFilter, { - expression: "test", + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } + + class Ctrl { + test(@Cookies("expression", Test) body: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(CookiesFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useType: Test, paramType: ParamTypes.COOKIES - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/endpointInfo.spec.ts b/packages/common/test/filters/decorators/endpointInfo.spec.ts index 06d331d21b7..48d3a4f1717 100644 --- a/packages/common/test/filters/decorators/endpointInfo.spec.ts +++ b/packages/common/test/filters/decorators/endpointInfo.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {EndpointInfo, ParamRegistry} from "../../../src/filters"; import {ENDPOINT_INFO} from "../../../src/filters/constants"; -describe("EndpointInfo", () => { +const sandbox = Sinon.createSandbox(); +describe("@EndpointInfo", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - EndpointInfo(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(ENDPOINT_INFO)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@EndpointInfo() arg: EndpointInfo) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(ENDPOINT_INFO, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/error.spec.ts b/packages/common/test/filters/decorators/error.spec.ts index 45965db317f..8db56da0e34 100644 --- a/packages/common/test/filters/decorators/error.spec.ts +++ b/packages/common/test/filters/decorators/error.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {Err, ParamRegistry} from "../../../src/filters"; +import {EndpointInfo, Err, ParamRegistry} from "../../../src/filters"; import {EXPRESS_ERR} from "../../../src/filters/constants"; -describe("Err", () => { +const sandbox = Sinon.createSandbox(); +describe("@Err", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Err(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_ERR)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@Err() arg: EndpointInfo) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_ERR, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/headerParams.spec.ts b/packages/common/test/filters/decorators/headerParams.spec.ts index 8b1984abac2..7622e861ad0 100644 --- a/packages/common/test/filters/decorators/headerParams.spec.ts +++ b/packages/common/test/filters/decorators/headerParams.spec.ts @@ -1,21 +1,28 @@ -import {ParamTypes} from "@tsed/common"; +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {HeaderParams, ParamRegistry} from "../../../src/filters"; +import {HeaderParams, ParamRegistry, ParamTypes} from "../../../src/filters"; import {HeaderParamsFilter} from "../../../src/filters/components/HeaderParamsFilter"; -describe("HeaderParams", () => { +const sandbox = Sinon.createSandbox(); +describe("@HeaderParams", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - HeaderParams("test"); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Ctrl { + test(@HeaderParams("expression") header: string) { + } + } - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(HeaderParamsFilter, { - expression: "test", + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(HeaderParamsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", paramType: ParamTypes.HEADER - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/locals.spec.ts b/packages/common/test/filters/decorators/locals.spec.ts index 34853d3842f..384e60a4f3f 100644 --- a/packages/common/test/filters/decorators/locals.spec.ts +++ b/packages/common/test/filters/decorators/locals.spec.ts @@ -1,22 +1,32 @@ -import {ParamTypes} from "@tsed/common"; +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {Locals, ParamRegistry} from "../../../src/filters"; +import {Locals, ParamRegistry, ParamTypes} from "../../../src/filters"; import {LocalsFilter} from "../../../src/filters/components/LocalsFilter"; -describe("Locals", () => { +const sandbox = Sinon.createSandbox(); +describe("@Locals", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Locals("test"); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } + + class Ctrl { + test(@Locals("expression") test: any) { + } + } - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(LocalsFilter, { - expression: "test", + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(LocalsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useConverter: false, paramType: ParamTypes.LOCALS - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/next.spec.ts b/packages/common/test/filters/decorators/next.spec.ts index 44d255c0f02..eaf70ec053f 100644 --- a/packages/common/test/filters/decorators/next.spec.ts +++ b/packages/common/test/filters/decorators/next.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {Next, ParamRegistry} from "../../../src/filters"; +import {EndpointInfo, Next, ParamRegistry} from "../../../src/filters"; import {EXPRESS_NEXT_FN} from "../../../src/filters/constants"; -describe("Next", () => { +const sandbox = Sinon.createSandbox(); +describe("@Next", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Next(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_NEXT_FN)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@Next() arg: EndpointInfo) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_NEXT_FN, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/pathParams.spec.ts b/packages/common/test/filters/decorators/pathParams.spec.ts index 0251f283a4c..d6b3a47b0f0 100644 --- a/packages/common/test/filters/decorators/pathParams.spec.ts +++ b/packages/common/test/filters/decorators/pathParams.spec.ts @@ -1,24 +1,32 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {ParamRegistry, PathParams,ParamTypes} from "../../../src/filters"; +import {ParamRegistry, ParamTypes, PathParams} from "../../../src/filters"; import {PathParamsFilter} from "../../../src/filters/components/PathParamsFilter"; -class Test { -} - -describe("PathParams", () => { +const sandbox = Sinon.createSandbox(); +describe("@PathParams", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - PathParams("test", Test); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(PathParamsFilter, { - expression: "test", + class Ctrl { + test(@PathParams("expression", Test) header: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(PathParamsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useType: Test, paramType: ParamTypes.PATH - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/queryParams.spec.ts b/packages/common/test/filters/decorators/queryParams.spec.ts index 857c3d425cb..f93ae271c61 100644 --- a/packages/common/test/filters/decorators/queryParams.spec.ts +++ b/packages/common/test/filters/decorators/queryParams.spec.ts @@ -1,26 +1,34 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {ParamRegistry, QueryParams, ParamTypes} from "../../../src/filters"; +import {ParamRegistry, ParamTypes, QueryParams} from "../../../src/filters"; import {QueryParamsFilter} from "../../../src/filters/components/QueryParamsFilter"; -class Test { -} - -describe("QueryParams", () => { +const sandbox = Sinon.createSandbox(); +describe("@QueryParams", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - QueryParams("test", Test); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(QueryParamsFilter, { - expression: "test", + class Ctrl { + test(@QueryParams("expression", Test) header: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(QueryParamsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useType: Test, + paramType: ParamTypes.QUERY, useConverter: true, - useValidation: true, - paramType: ParamTypes.QUERY - })); + useValidation: true + }); + }); }); diff --git a/packages/common/test/filters/decorators/request.spec.ts b/packages/common/test/filters/decorators/request.spec.ts index 35d6ee87c87..13f27b9e267 100644 --- a/packages/common/test/filters/decorators/request.spec.ts +++ b/packages/common/test/filters/decorators/request.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {ParamRegistry, Req} from "../../../src/filters"; import {EXPRESS_REQUEST} from "../../../src/filters/constants"; -describe("Request", () => { +const sandbox = Sinon.createSandbox(); +describe("@Req", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Req(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_REQUEST)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@Req() arg: Req) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_REQUEST, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/response.spec.ts b/packages/common/test/filters/decorators/response.spec.ts index 15c7b0429db..fd0758b8483 100644 --- a/packages/common/test/filters/decorators/response.spec.ts +++ b/packages/common/test/filters/decorators/response.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {ParamRegistry, Res} from "../../../src/filters"; import {EXPRESS_RESPONSE} from "../../../src/filters/constants"; -describe("Response", () => { +const sandbox = Sinon.createSandbox(); +describe("@Res", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Res(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_RESPONSE)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@Res() arg: Res) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(EXPRESS_RESPONSE, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/responseData.spec.ts b/packages/common/test/filters/decorators/responseData.spec.ts index 7713696cc51..4a4f4c6cfa7 100644 --- a/packages/common/test/filters/decorators/responseData.spec.ts +++ b/packages/common/test/filters/decorators/responseData.spec.ts @@ -1,17 +1,27 @@ +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; import {ParamRegistry, ResponseData} from "../../../src/filters"; import {RESPONSE_DATA} from "../../../src/filters/constants"; -describe("ResponseData", () => { +const sandbox = Sinon.createSandbox(); +describe("@ResponseData", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - ResponseData(); + sandbox.stub(ParamRegistry, "usePreHandler"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(RESPONSE_DATA)); + it("should call ParamFilter.usePrehandler method with the correct parameters", () => { + class Ctrl { + test(@ResponseData() arg: any) { + } + } + + ParamRegistry.usePreHandler.should.have.been.calledOnce.and.calledWithExactly(RESPONSE_DATA, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0 + }); + }); }); diff --git a/packages/common/test/filters/decorators/session.spec.ts b/packages/common/test/filters/decorators/session.spec.ts index e576b251cf3..a2b6c76d09c 100644 --- a/packages/common/test/filters/decorators/session.spec.ts +++ b/packages/common/test/filters/decorators/session.spec.ts @@ -1,25 +1,33 @@ -import {ParamTypes} from "@tsed/common"; +import {prototypeOf} from "@tsed/core"; import * as Sinon from "sinon"; -import {ParamRegistry, Session} from "../../../src/filters"; +import {ParamRegistry, ParamTypes, Session} from "../../../src/filters"; import {SessionFilter} from "../../../src/filters/components/SessionFilter"; -class Test { -} - -describe("Session", () => { +const sandbox = Sinon.createSandbox(); +describe("@Session", () => { before(() => { - this.decorateStub = Sinon.stub(ParamRegistry, "decorate"); - Session("test", Test); + sandbox.stub(ParamRegistry, "useFilter"); }); - after(() => { - this.decorateStub.restore(); + sandbox.restore(); }); - it("should have been called ParamFilter.decorate method with the correct parameters", () => - this.decorateStub.should.have.been.calledOnce.and.calledWithExactly(SessionFilter, { - expression: "test", + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } + + class Ctrl { + test(@Session("expression", Test) body: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(SessionFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", useType: Test, paramType: ParamTypes.SESSION - })); + }); + }); }); diff --git a/packages/common/test/filters/decorators/useFilter.spec.ts b/packages/common/test/filters/decorators/useFilter.spec.ts new file mode 100644 index 00000000000..e804e3189fe --- /dev/null +++ b/packages/common/test/filters/decorators/useFilter.spec.ts @@ -0,0 +1,42 @@ +import {prototypeOf} from "@tsed/core"; +import * as Sinon from "sinon"; +import {ParamRegistry, ParamTypes, UseFilter} from "../../../src/filters"; +import {BodyParamsFilter} from "../../../src/filters/components/BodyParamsFilter"; + +const sandbox = Sinon.createSandbox(); +describe("@UseFilter", () => { + describe("when filter is a class", () => { + before(() => { + sandbox.stub(ParamRegistry, "useFilter"); + }); + after(() => { + sandbox.restore(); + }); + it("should call ParamFilter.useFilter method with the correct parameters", () => { + class Test { + } + + class Ctrl { + test(@UseFilter(BodyParamsFilter, { + expression: "expression", + useConverter: true, + useValidation: true, + paramType: ParamTypes.BODY, + useType: Test + }) body: Test) { + } + } + + ParamRegistry.useFilter.should.have.been.calledOnce.and.calledWithExactly(BodyParamsFilter, { + target: prototypeOf(Ctrl), + propertyKey: "test", + parameterIndex: 0, + expression: "expression", + useType: Test, + useConverter: true, + useValidation: true, + paramType: ParamTypes.BODY + }); + }); + }); +}); diff --git a/packages/common/test/filters/services/ParamsRegistry.spec.ts b/packages/common/test/filters/services/ParamsRegistry.spec.ts index 118cc706277..27366651730 100644 --- a/packages/common/test/filters/services/ParamsRegistry.spec.ts +++ b/packages/common/test/filters/services/ParamsRegistry.spec.ts @@ -1,109 +1,26 @@ -import {Metadata} from "@tsed/core"; -import {expect} from "chai"; -import * as Sinon from "sinon"; -import {ParamMetadata, ParamRegistry} from "../../../src/filters"; -import {EXPRESS_NEXT_FN} from "../../../src/filters/constants"; +import {prototypeOf} from "@tsed/core"; +import {ParamMetadata, ParamRegistry, Req} from "../../../src/filters"; +import {EXPRESS_REQUEST} from "../../../src/filters/constants"; -class Test { -} describe("ParamRegistry", () => { - describe("decorate()", () => { - describe("when it used with filter", () => { - before(() => { - this.useServiceStub = Sinon.stub(ParamRegistry, "usePreHandler"); - this.useFilterStub = Sinon.stub(ParamRegistry, "useFilter"); - - this.classT = class T { - }; - this.classO = class O { - }; - - this.decorator = ParamRegistry.decorate(this.classT, {expression: "options"}); - this.decorator(this.classO, "test", 0); - }); - after(() => { - this.useServiceStub.restore(); - this.useFilterStub.restore(); - }); - it("should return a function", () => { - expect(this.decorator).to.be.a("function"); - }); - it("should call the useFilter with the correct parameters", () => { - this.useFilterStub.should.have.been.calledOnce.and.calledWithExactly(this.classT, { - expression: "options", - target: this.classO, - propertyKey: "test", - parameterIndex: 0 - }); - }); - it("should not call the usePreHandler", () => { - return this.useServiceStub.should.not.be.called; - }); - }); - describe("when it used with service", () => { - before(() => { - this.useServiceStub = Sinon.stub(ParamRegistry, "usePreHandler"); - this.useFilterStub = Sinon.stub(ParamRegistry, "useFilter"); - - this.symbolT = Symbol("serviceT"); - this.classO = class O { - }; - - this.decorator = ParamRegistry.decorate(this.symbolT, {expression: "options"}); - this.decorator(this.classO, "test", 0); - }); - after(() => { - this.useServiceStub.restore(); - this.useFilterStub.restore(); - }); - it("should return a function", () => { - expect(this.decorator).to.be.a("function"); - }); - it("should call the usePreHandler with the correct parameters", () => { - this.useServiceStub.should.have.been.calledOnce.and.calledWithExactly(this.symbolT, { - expression: "options", - target: this.classO, - propertyKey: "test", - parameterIndex: 0 - }); - }); - it("should not call the useFilter", () => { - return this.useFilterStub.should.not.be.called; - }); - }); - }); - - // describe("hasNextFunction()", () => { - // before(() => { - // this.getStub = Sinon.stub(Metadata, "get"); - // this.getStub.returns([{service: EXPRESS_NEXT_FN}]); - // this.hasStub = Sinon.stub(Metadata, "has"); - // this.hasStub.returns(true); - // }); - // after(() => { - // this.getStub.restore(); - // this.hasStub.restore(); - // }); - // it("should return true", () => { - // expect(ParamRegistry.hasNextFunction(Test, "test")).to.eq(true); - // }); - // }); - - describe("required()", () => { - before(() => { - ParamRegistry.required(Test, "test", 0, [null, ""]); - this.paramMetadata = ParamRegistry.get(Test, "test", 0); - }); - - it("should return the paramMetadata", () => { - expect(this.paramMetadata).to.be.an.instanceof(ParamMetadata); - }); - it("should be required", () => { - expect(this.paramMetadata.required).to.eq(true); - }); - it("should be allowedRequiredValues", () => { - expect(this.paramMetadata.allowedRequiredValues).to.deep.eq([null, ""]); + describe("getParams", () => { + it("should returns params", () => { + // GIVEN + class Test { + test(@Req() req: any) { + } + } + + // WHEN + const result = ParamRegistry.getParams(prototypeOf(Test), "test"); + + // THEN + const param1 = new ParamMetadata(prototypeOf(Test), "test", 0); + param1.service = EXPRESS_REQUEST; + param1.useConverter = false; + + result.should.deep.eq([param1]); }); }); }); diff --git a/packages/core/src/utils/DecoratorUtils.ts b/packages/core/src/utils/DecoratorUtils.ts index 6bff4d65ccd..ce221c0779a 100644 --- a/packages/core/src/utils/DecoratorUtils.ts +++ b/packages/core/src/utils/DecoratorUtils.ts @@ -81,10 +81,12 @@ export function decorateMethodsOf(klass: any, decorator: any) { }); } -export function applyDecorators(...decorators: Function[]): Function { +export function applyDecorators(...decorators: any | Function[]): Function { return (...args: DecoratorParameters) => { - decorators.forEach(decorator => { - decorator(...args); - }); + decorators + // .filter((o: any) => !!o) + .forEach((decorator: Function) => { + decorator(...args); + }); }; } diff --git a/packages/multipartfiles/src/decorators/multipartFile.ts b/packages/multipartfiles/src/decorators/multipartFile.ts index ecffcb87053..a1e6b50e6d6 100644 --- a/packages/multipartfiles/src/decorators/multipartFile.ts +++ b/packages/multipartfiles/src/decorators/multipartFile.ts @@ -1,4 +1,4 @@ -import {ParamRegistry, ParamTypes, UseBefore} from "@tsed/common"; +import {ParamTypes, UseBefore, UseFilter} from "@tsed/common"; import {descriptorOf, getDecoratorType, Metadata, Store} from "@tsed/core"; import * as multer from "multer"; import {MultipartFileFilter} from "../components/MultipartFileFilter"; @@ -87,13 +87,13 @@ export function MultipartFile(name?: string | multer.Options, maxCount?: number) any: true }); - ParamRegistry.useFilter(multiple ? MultipartFilesFilter : MultipartFileFilter, { + UseFilter(multiple ? MultipartFilesFilter : MultipartFileFilter, { propertyKey, parameterIndex, target, useConverter: false, paramType: ParamTypes.FORM_DATA - }); + })(target, propertyKey, parameterIndex); } else { const expression = multiple ? (name as string) : name + ".0"; @@ -107,14 +107,14 @@ export function MultipartFile(name?: string | multer.Options, maxCount?: number) options }); - ParamRegistry.useFilter(MultipartFilesFilter, { + UseFilter(MultipartFilesFilter, { expression, propertyKey, parameterIndex, target, useConverter: false, paramType: ParamTypes.FORM_DATA - }); + })(target, propertyKey, parameterIndex); } break;