@tsed/platform-response-filter 8.11.1 → 8.12.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/constants/ContentTypes.js +0 -1
- package/lib/esm/decorators/responseFilter.js +0 -1
- package/lib/esm/domain/ResponseFiltersContainer.js +0 -1
- package/lib/esm/errors/TemplateRenderError.js +0 -1
- package/lib/esm/index.js +0 -1
- package/lib/esm/interfaces/ResponseFilterMethods.js +0 -1
- package/lib/esm/services/PlatformContentTypeResolver.js +0 -1
- package/lib/esm/services/PlatformContentTypesContainer.js +0 -1
- package/lib/esm/services/PlatformResponseFilter.js +0 -1
- package/package.json +12 -9
- package/lib/esm/constants/ContentTypes.js.map +0 -1
- package/lib/esm/decorators/responseFilter.js.map +0 -1
- package/lib/esm/domain/ResponseFiltersContainer.js.map +0 -1
- package/lib/esm/errors/TemplateRenderError.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/interfaces/ResponseFilterMethods.js.map +0 -1
- package/lib/esm/services/PlatformContentTypeResolver.js.map +0 -1
- package/lib/esm/services/PlatformContentTypesContainer.js.map +0 -1
- package/lib/esm/services/PlatformResponseFilter.js.map +0 -1
- package/src/constants/ContentTypes.ts +0 -5
- package/src/decorators/responseFilter.ts +0 -17
- package/src/domain/ResponseFiltersContainer.ts +0 -18
- package/src/errors/TemplateRenderError.spec.ts +0 -9
- package/src/errors/TemplateRenderError.ts +0 -21
- package/src/index.ts +0 -11
- package/src/interfaces/ResponseFilterMethods.ts +0 -17
- package/src/services/PlatformContentTypeResolver.spec.ts +0 -184
- package/src/services/PlatformContentTypeResolver.ts +0 -49
- package/src/services/PlatformContentTypesContainer.ts +0 -32
- package/src/services/PlatformResponseFilter.spec.ts +0 -384
- package/src/services/PlatformResponseFilter.ts +0 -105
- package/vitest.config.mts +0 -21
package/lib/esm/index.js
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tsed/platform-response-filter",
|
|
3
3
|
"description": "Platform response filter module for Ts.ED Framework",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.
|
|
5
|
+
"version": "8.12.0-rc.1",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./lib/esm/index.js",
|
|
8
8
|
"module": "./lib/esm/index.js",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"tslib": "2.7.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@tsed/barrels": "8.
|
|
30
|
-
"@tsed/core": "8.
|
|
31
|
-
"@tsed/di": "8.
|
|
32
|
-
"@tsed/exceptions": "8.
|
|
33
|
-
"@tsed/json-mapper": "8.
|
|
34
|
-
"@tsed/schema": "8.
|
|
35
|
-
"@tsed/typescript": "8.
|
|
29
|
+
"@tsed/barrels": "8.12.0-rc.1",
|
|
30
|
+
"@tsed/core": "8.12.0-rc.1",
|
|
31
|
+
"@tsed/di": "8.12.0-rc.1",
|
|
32
|
+
"@tsed/exceptions": "8.12.0-rc.1",
|
|
33
|
+
"@tsed/json-mapper": "8.12.0-rc.1",
|
|
34
|
+
"@tsed/schema": "8.12.0-rc.1",
|
|
35
|
+
"@tsed/typescript": "8.12.0-rc.1",
|
|
36
36
|
"eslint": "9.12.0",
|
|
37
37
|
"typescript": "5.4.5",
|
|
38
38
|
"vitest": "3.1.4"
|
|
@@ -67,5 +67,8 @@
|
|
|
67
67
|
},
|
|
68
68
|
"homepage": "https://github.com/tsedio/tsed/tree/production/packages/platform/platform-response-filter",
|
|
69
69
|
"author": "Romain Lenzotti",
|
|
70
|
-
"license": "MIT"
|
|
70
|
+
"license": "MIT",
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"tag": "rc"
|
|
73
|
+
}
|
|
71
74
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ContentTypes.js","sourceRoot":"","sources":["../../../src/constants/ContentTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,2BAAW,CAAA;IACX,yCAAyB,CAAA;IACzB,kCAAkB,CAAA;AACpB,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"responseFilter.js","sourceRoot":"","sources":["../../../src/decorators/responseFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAC,sBAAsB,EAAoB,MAAM,uCAAuC,CAAC;AAEhG;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAG,YAAiC;IACjE,OAAO,CAAC,MAAW,EAAE,EAAE;QACrB,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACnC,sBAAsB,CAAC,WAAW,EAAE,MAAa,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseFiltersContainer.js","sourceRoot":"","sources":["../../../src/domain/ResponseFiltersContainer.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,yCAAyC;AACzC,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAkD,CAAC;AAClG;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAuB,EAAE,KAAkC;IAChG,wBAAwB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateRenderError.js","sourceRoot":"","sources":["../../../src/errors/TemplateRenderError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAO,MAAM,YAAY,CAAC;AACxC,OAAO,EAAC,mBAAmB,EAAC,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,mBAAmB;IAG1D,YAAY,MAA0B,EAAE,MAAuB,EAAE,GAAU;QACzE,KAAK,CAAC,mBAAmB,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;QAH/D,SAAI,GAAG,uBAAuB,CAAC;IAI/B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,MAA0B,EAAE,MAAuB,EAAE,GAAU;QACjF,OAAO,6BAA6B,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;IACnF,CAAC;CACF"}
|
package/lib/esm/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,sCAAsC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseFilterMethods.js","sourceRoot":"","sources":["../../../src/interfaces/ResponseFilterMethods.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformContentTypeResolver.js","sourceRoot":"","sources":["../../../src/services/PlatformContentTypeResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAC,MAAM,YAAY,CAAC;AACnE,OAAO,EAA8C,MAAM,EAAE,UAAU,EAAC,MAAM,UAAU,CAAC;AAEzF,OAAO,EAAC,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAC,gCAAgC,EAAC,MAAM,oCAAoC,CAAC;AAEpF,MAAM,UAAU,GAAG,CAAC,IAAa,EAAE,EAAE;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5G,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,GAAgB;IAC5D,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,GAAG,CAAC;IACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,EAAE,IAAI,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAE1G,IAAI,WAAW,IAAI,WAAW,KAAK,YAAY,CAAC,GAAG,EAAE,CAAC;QACpD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;AAChG,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;KACnG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAS,EAAE,GAAgB,EAAU,EAAE;IACrD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE9C,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,MAAM,EAAC,YAAY,EAAC,GAAG,MAAM,CAAC,gCAAgC,CAAC,CAAC;QAEhE,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAEhG,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC,MAAM,CAAC,eAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;KACD,KAAK,EAAE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformContentTypesContainer.js","sourceRoot":"","sources":["../../../src/services/PlatformContentTypesContainer.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAqB,MAAM,UAAU,CAAC;AAE1E,OAAO,EAAC,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAoB,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAGlG,MAAM,CAAC,MAAM,gCAAgC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;KACvG,OAAO,CAAC,GAAG,EAAE;IACZ,MAAM,eAAe,GAAG,QAAQ,CAAgC,iBAAiB,EAAE,EAAE,CAAC,CAAC;IACvF,MAAM,UAAU,GAA0C,IAAI,GAAG,EAAE,CAAC;IAEpE,wBAAwB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC/C,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,YAAY,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;QACpC,OAAO,CAAC,eAAuB;YAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YAElF,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,MAAM,CAAwB,KAAK,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;KACD,KAAK,EAAE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformResponseFilter.js","sourceRoot":"","sources":["../../../src/services/PlatformResponseFilter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {injectable} from "@tsed/di";
|
|
2
|
-
|
|
3
|
-
import {registerResponseFilter, ResponseFilterKey} from "../domain/ResponseFiltersContainer.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Register a response filter service.
|
|
7
|
-
* @param contentTypes
|
|
8
|
-
* @decorator
|
|
9
|
-
*/
|
|
10
|
-
export function ResponseFilter(...contentTypes: ResponseFilterKey[]): ClassDecorator {
|
|
11
|
-
return (target: any) => {
|
|
12
|
-
contentTypes.forEach((contentType) => {
|
|
13
|
-
registerResponseFilter(contentType, target as any);
|
|
14
|
-
});
|
|
15
|
-
injectable(target).class(target);
|
|
16
|
-
};
|
|
17
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {Type} from "@tsed/core";
|
|
2
|
-
|
|
3
|
-
import {ResponseFilterMethods} from "../interfaces/ResponseFilterMethods.js";
|
|
4
|
-
/**
|
|
5
|
-
* @ignore
|
|
6
|
-
*/
|
|
7
|
-
export type ResponseFilterKey = "*/*" | "application/json" | "text/html" | "plain/text" | string;
|
|
8
|
-
/**
|
|
9
|
-
* @ignore
|
|
10
|
-
*/
|
|
11
|
-
// tslint:disable-next-line:variable-name
|
|
12
|
-
export const ResponseFiltersContainer = new Map<ResponseFilterKey, Type<ResponseFilterMethods>>();
|
|
13
|
-
/**
|
|
14
|
-
* @ignore
|
|
15
|
-
*/
|
|
16
|
-
export function registerResponseFilter(type: ResponseFilterKey, token: Type<ResponseFilterMethods>) {
|
|
17
|
-
ResponseFiltersContainer.set(type, token);
|
|
18
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import {TemplateRenderError} from "./TemplateRenderError.js";
|
|
2
|
-
|
|
3
|
-
describe("TemplateRenderingError", () => {
|
|
4
|
-
it("should have a message", () => {
|
|
5
|
-
const errorInstance = new TemplateRenderError(class Target {}, "method", new Error("test"));
|
|
6
|
-
expect(errorInstance.message).toEqual("Template rendering error: Target.method()\nError: test");
|
|
7
|
-
expect(errorInstance.name).toEqual("TEMPLATE_RENDER_ERROR");
|
|
8
|
-
});
|
|
9
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {nameOf, Type} from "@tsed/core";
|
|
2
|
-
import {InternalServerError} from "@tsed/exceptions";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @private
|
|
6
|
-
*/
|
|
7
|
-
export class TemplateRenderError extends InternalServerError {
|
|
8
|
-
name = "TEMPLATE_RENDER_ERROR";
|
|
9
|
-
|
|
10
|
-
constructor(target: Type<any> | string, method: string | symbol, err: Error) {
|
|
11
|
-
super(TemplateRenderError.buildMessage(target, method, err));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
* @returns {string}
|
|
17
|
-
*/
|
|
18
|
-
static buildMessage(target: Type<any> | string, method: string | symbol, err: Error) {
|
|
19
|
-
return `Template rendering error: ${nameOf(target)}.${String(method)}()\n` + err;
|
|
20
|
-
}
|
|
21
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Automatically generated by @tsed/barrels.
|
|
3
|
-
*/
|
|
4
|
-
export * from "./constants/ContentTypes.js";
|
|
5
|
-
export * from "./decorators/responseFilter.js";
|
|
6
|
-
export * from "./domain/ResponseFiltersContainer.js";
|
|
7
|
-
export * from "./errors/TemplateRenderError.js";
|
|
8
|
-
export * from "./interfaces/ResponseFilterMethods.js";
|
|
9
|
-
export * from "./services/PlatformContentTypeResolver.js";
|
|
10
|
-
export * from "./services/PlatformContentTypesContainer.js";
|
|
11
|
-
export * from "./services/PlatformResponseFilter.js";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {Type} from "@tsed/core";
|
|
2
|
-
import type {BaseContext} from "@tsed/di";
|
|
3
|
-
|
|
4
|
-
declare global {
|
|
5
|
-
namespace TsED {
|
|
6
|
-
interface Configuration {
|
|
7
|
-
/**
|
|
8
|
-
* A list of response filters must be called before returning a response to the consumer. See more on [Response filters](/docs/response-filter.md).
|
|
9
|
-
*/
|
|
10
|
-
responseFilters: Type<ResponseFilterMethods>[];
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ResponseFilterMethods<T = unknown> {
|
|
16
|
-
transform(data: T, ctx: BaseContext): any;
|
|
17
|
-
}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
2
|
-
import {EndpointMetadata, Get, Returns, View} from "@tsed/schema";
|
|
3
|
-
import {createReadStream} from "fs";
|
|
4
|
-
|
|
5
|
-
import {ContentTypes} from "../constants/ContentTypes.js";
|
|
6
|
-
import {PLATFORM_CONTENT_TYPE_RESOLVER} from "./PlatformContentTypeResolver.js";
|
|
7
|
-
import {PLATFORM_CONTENT_TYPES_CONTAINER} from "./PlatformContentTypesContainer.js";
|
|
8
|
-
|
|
9
|
-
async function getTestFixture(contentTypes = [ContentTypes.JSON, ContentTypes.HTML]) {
|
|
10
|
-
const contentTypeResolver = await PlatformTest.invoke<PLATFORM_CONTENT_TYPE_RESOLVER>(PLATFORM_CONTENT_TYPE_RESOLVER, [
|
|
11
|
-
{
|
|
12
|
-
token: PLATFORM_CONTENT_TYPES_CONTAINER,
|
|
13
|
-
use: {
|
|
14
|
-
contentTypes
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
|
-
const data = {
|
|
20
|
-
test: "test"
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const ctx = PlatformTest.createRequestContext();
|
|
24
|
-
return {
|
|
25
|
-
data,
|
|
26
|
-
ctx,
|
|
27
|
-
contentTypeResolver
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe("PlatformContentTypeResolver", () => {
|
|
32
|
-
beforeEach(() => PlatformTest.create());
|
|
33
|
-
afterEach(() => PlatformTest.reset());
|
|
34
|
-
|
|
35
|
-
it("should return the content type (undefined | Buffer)", async () => {
|
|
36
|
-
class TestController {
|
|
37
|
-
@Get("/")
|
|
38
|
-
get() {}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
42
|
-
|
|
43
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
44
|
-
|
|
45
|
-
const result = await contentTypeResolver(Buffer.from("data"), ctx);
|
|
46
|
-
|
|
47
|
-
expect(result).toEqual(undefined);
|
|
48
|
-
});
|
|
49
|
-
it("should return the content type (undefined | Stream)", async () => {
|
|
50
|
-
class TestController {
|
|
51
|
-
@Get("/")
|
|
52
|
-
get() {}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const stream = createReadStream(`${import.meta.dirname}/__mock__/response.txt`);
|
|
56
|
-
|
|
57
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
58
|
-
|
|
59
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
60
|
-
|
|
61
|
-
const result = await contentTypeResolver(stream, ctx);
|
|
62
|
-
|
|
63
|
-
expect(result).toEqual(undefined);
|
|
64
|
-
});
|
|
65
|
-
it("should return the content type (object - empty resolve content type - application/json)", async () => {
|
|
66
|
-
class TestController {
|
|
67
|
-
@Get("/")
|
|
68
|
-
get() {}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
72
|
-
|
|
73
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
74
|
-
|
|
75
|
-
const result = await contentTypeResolver(data, ctx);
|
|
76
|
-
|
|
77
|
-
expect(result).toEqual("application/json");
|
|
78
|
-
});
|
|
79
|
-
it("should return the content type (object - application/json)", async () => {
|
|
80
|
-
class TestController {
|
|
81
|
-
@Get("/")
|
|
82
|
-
@(Returns(200).ContentType(ContentTypes.JSON))
|
|
83
|
-
get() {}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
87
|
-
|
|
88
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
89
|
-
ctx.response.getRes().statusCode = 200;
|
|
90
|
-
|
|
91
|
-
vi.spyOn(ctx.response, "getContentType").mockReturnValue(ContentTypes.JSON);
|
|
92
|
-
|
|
93
|
-
const result = contentTypeResolver(data, ctx);
|
|
94
|
-
|
|
95
|
-
expect(result).toEqual(ContentTypes.JSON);
|
|
96
|
-
});
|
|
97
|
-
it("should return the content type (object - custom content-type)", async () => {
|
|
98
|
-
class TestController {
|
|
99
|
-
@Get("/")
|
|
100
|
-
@(Returns(200).ContentType("application/vnd.custom+json"))
|
|
101
|
-
get() {}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
105
|
-
|
|
106
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
107
|
-
ctx.response.getRes().statusCode = 200;
|
|
108
|
-
|
|
109
|
-
vi.spyOn(ctx.response, "getContentType").mockReturnValue("application/vnd.custom+json");
|
|
110
|
-
|
|
111
|
-
const result = contentTypeResolver(data, ctx);
|
|
112
|
-
|
|
113
|
-
expect(result).toEqual("application/vnd.custom+json");
|
|
114
|
-
});
|
|
115
|
-
it("should return the content type (string - application/json)", async () => {
|
|
116
|
-
class TestController {
|
|
117
|
-
@Get("/")
|
|
118
|
-
@(Returns(200).ContentType("application/json"))
|
|
119
|
-
get() {}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
123
|
-
|
|
124
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
125
|
-
ctx.response.getRes().statusCode = 200;
|
|
126
|
-
vi.spyOn(ctx.response, "getContentType").mockReturnValue("application/json");
|
|
127
|
-
|
|
128
|
-
const result = contentTypeResolver(data, ctx);
|
|
129
|
-
|
|
130
|
-
expect(result).toEqual("application/json");
|
|
131
|
-
});
|
|
132
|
-
it("should return the content type (boolean - application/json)", async () => {
|
|
133
|
-
class TestController {
|
|
134
|
-
@Get("/")
|
|
135
|
-
@Returns(200)
|
|
136
|
-
get() {}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
140
|
-
|
|
141
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
142
|
-
ctx.response.getRes().statusCode = 200;
|
|
143
|
-
vi.spyOn(ctx.response, "getContentType").mockReturnValue("application/json");
|
|
144
|
-
|
|
145
|
-
const result = contentTypeResolver(true, ctx);
|
|
146
|
-
|
|
147
|
-
expect(result).toEqual("application/json");
|
|
148
|
-
});
|
|
149
|
-
it("should return the content type (string - text/html)", async () => {
|
|
150
|
-
class TestController {
|
|
151
|
-
@Get("/")
|
|
152
|
-
@(Returns(200).ContentType(ContentTypes.HTML))
|
|
153
|
-
get() {}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
157
|
-
|
|
158
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
159
|
-
ctx.response.getRes().statusCode = 200;
|
|
160
|
-
vi.spyOn(ctx.response, "getContentType").mockReturnValue(ContentTypes.HTML);
|
|
161
|
-
|
|
162
|
-
const result = contentTypeResolver(data, ctx);
|
|
163
|
-
|
|
164
|
-
expect(result).toEqual(ContentTypes.HTML);
|
|
165
|
-
});
|
|
166
|
-
it("should return the content type (string - view)", async () => {
|
|
167
|
-
class TestController {
|
|
168
|
-
@Get("/")
|
|
169
|
-
@Returns(200)
|
|
170
|
-
@View("view.html")
|
|
171
|
-
get() {}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const {contentTypeResolver, ctx, data} = await getTestFixture();
|
|
175
|
-
|
|
176
|
-
ctx.endpoint = EndpointMetadata.get(TestController, "get");
|
|
177
|
-
ctx.response.getRes().statusCode = 200;
|
|
178
|
-
ctx.view = "true";
|
|
179
|
-
|
|
180
|
-
const result = contentTypeResolver(data, ctx);
|
|
181
|
-
|
|
182
|
-
expect(result).toEqual(ContentTypes.HTML);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import {isBoolean, isNumber, isObject, isStream} from "@tsed/core";
|
|
2
|
-
import {type BaseContext, type FactoryTokenProvider, inject, injectable} from "@tsed/di";
|
|
3
|
-
|
|
4
|
-
import {ContentTypes} from "../constants/ContentTypes.js";
|
|
5
|
-
import {PLATFORM_CONTENT_TYPES_CONTAINER} from "./PlatformContentTypesContainer.js";
|
|
6
|
-
|
|
7
|
-
const isJsonData = (data: unknown) => {
|
|
8
|
-
return (isObject(data) || isNumber(data) || isBoolean(data)) && !isStream(data) && !Buffer.isBuffer(data);
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Determine the content type of the response based on the data and the context.
|
|
13
|
-
* @param {unknown} data
|
|
14
|
-
* @param {BaseContext} ctx
|
|
15
|
-
* @ignore
|
|
16
|
-
*/
|
|
17
|
-
export function getContentType(data: unknown, ctx: BaseContext) {
|
|
18
|
-
const {endpoint, response} = ctx;
|
|
19
|
-
const contentType = response.getContentType() || endpoint.operation.getContentTypeOf(response.statusCode);
|
|
20
|
-
|
|
21
|
-
if (contentType && contentType !== ContentTypes.ANY) {
|
|
22
|
-
return contentType;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return endpoint.view ? ContentTypes.HTML : isJsonData(data) ? ContentTypes.JSON : contentType;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @ignore
|
|
30
|
-
*/
|
|
31
|
-
export const PLATFORM_CONTENT_TYPE_RESOLVER = injectable(Symbol.for("PLATFORM_CONTENT_TYPE_RESOLVER"))
|
|
32
|
-
.factory(() => (data: any, ctx: BaseContext): string => {
|
|
33
|
-
const contentType = getContentType(data, ctx);
|
|
34
|
-
|
|
35
|
-
if (ctx.request.get("Accept")) {
|
|
36
|
-
const {contentTypes} = inject(PLATFORM_CONTENT_TYPES_CONTAINER);
|
|
37
|
-
|
|
38
|
-
const bestContentType = ctx.request.accepts([contentType].concat(contentTypes).filter(Boolean));
|
|
39
|
-
|
|
40
|
-
if (bestContentType) {
|
|
41
|
-
return [].concat(bestContentType as any).filter((type) => type !== ContentTypes.ANY)[0];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return contentType;
|
|
46
|
-
})
|
|
47
|
-
.token();
|
|
48
|
-
|
|
49
|
-
export type PLATFORM_CONTENT_TYPE_RESOLVER = typeof PLATFORM_CONTENT_TYPE_RESOLVER;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type {Type} from "@tsed/core";
|
|
2
|
-
import {constant, inject, injectable, type TokenProvider} from "@tsed/di";
|
|
3
|
-
|
|
4
|
-
import {ContentTypes} from "../constants/ContentTypes.js";
|
|
5
|
-
import {ResponseFilterKey, ResponseFiltersContainer} from "../domain/ResponseFiltersContainer.js";
|
|
6
|
-
import type {ResponseFilterMethods} from "../interfaces/ResponseFilterMethods.js";
|
|
7
|
-
|
|
8
|
-
export const PLATFORM_CONTENT_TYPES_CONTAINER = injectable(Symbol.for("PLATFORM_CONTENT_TYPES_CONTAINER"))
|
|
9
|
-
.factory(() => {
|
|
10
|
-
const responseFilters = constant<Type<ResponseFilterMethods>[]>("responseFilters", []);
|
|
11
|
-
const containers: Map<ResponseFilterKey, TokenProvider> = new Map();
|
|
12
|
-
|
|
13
|
-
ResponseFiltersContainer.forEach((token, type) => {
|
|
14
|
-
if (responseFilters.includes(token)) {
|
|
15
|
-
containers.set(type, token);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
contentTypes: [...containers.keys()],
|
|
21
|
-
resolve(bestContentType: string) {
|
|
22
|
-
const token = containers.get(bestContentType) || containers.get(ContentTypes.ANY);
|
|
23
|
-
|
|
24
|
-
if (token) {
|
|
25
|
-
return inject<ResponseFilterMethods>(token);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
})
|
|
30
|
-
.token();
|
|
31
|
-
|
|
32
|
-
export type PLATFORM_CONTENT_TYPES_CONTAINER = typeof PLATFORM_CONTENT_TYPES_CONTAINER;
|
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
import {catchAsyncError} from "@tsed/core";
|
|
2
|
-
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
3
|
-
import {Context} from "@tsed/platform-params";
|
|
4
|
-
import {EndpointMetadata, Get, Ignore, Property, Returns, View} from "@tsed/schema";
|
|
5
|
-
|
|
6
|
-
import {ResponseFilter} from "../decorators/responseFilter.js";
|
|
7
|
-
import {ResponseFilterMethods} from "../interfaces/ResponseFilterMethods.js";
|
|
8
|
-
import {PlatformResponseFilter} from "./PlatformResponseFilter.js";
|
|
9
|
-
|
|
10
|
-
@ResponseFilter("custom/json")
|
|
11
|
-
class CustomJsonFilter implements ResponseFilterMethods {
|
|
12
|
-
transform(data: unknown, ctx: Context) {
|
|
13
|
-
return {data};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@ResponseFilter("application/json")
|
|
18
|
-
class ApplicationJsonFilter implements ResponseFilterMethods {
|
|
19
|
-
transform(data: unknown, ctx: Context) {
|
|
20
|
-
return {data, "content-type": "application/json"};
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
@ResponseFilter("*/*")
|
|
25
|
-
class AllFilter implements ResponseFilterMethods {
|
|
26
|
-
transform(data: unknown, ctx: Context) {
|
|
27
|
-
return {data, "content-type": "*/*"};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe("PlatformResponseFilter", () => {
|
|
32
|
-
describe("transform() with registered filters", () => {
|
|
33
|
-
describe("when filter list is given", () => {
|
|
34
|
-
beforeEach(() =>
|
|
35
|
-
PlatformTest.create({
|
|
36
|
-
responseFilters: [CustomJsonFilter, AllFilter, ApplicationJsonFilter]
|
|
37
|
-
})
|
|
38
|
-
);
|
|
39
|
-
afterEach(() => PlatformTest.reset());
|
|
40
|
-
|
|
41
|
-
it("should transform data for custom/json", async () => {
|
|
42
|
-
class Test {
|
|
43
|
-
@Get("/")
|
|
44
|
-
test() {}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
48
|
-
|
|
49
|
-
const ctx = PlatformTest.createRequestContext();
|
|
50
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
51
|
-
const data = {text: "test"};
|
|
52
|
-
|
|
53
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
54
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
55
|
-
vi.spyOn(ctx.request, "get").mockReturnValue("custom/json");
|
|
56
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(["custom/json"]);
|
|
57
|
-
|
|
58
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
59
|
-
|
|
60
|
-
expect(result).toEqual({
|
|
61
|
-
data: {
|
|
62
|
-
text: "test"
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
it("should transform data for application/json", async () => {
|
|
67
|
-
class Test {
|
|
68
|
-
@Get("/")
|
|
69
|
-
test() {}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
73
|
-
|
|
74
|
-
const ctx = PlatformTest.createRequestContext();
|
|
75
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
76
|
-
const data = {text: "test"};
|
|
77
|
-
|
|
78
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
79
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
80
|
-
vi.spyOn(ctx.request, "get").mockReturnValue("application/json");
|
|
81
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(["application/json"]);
|
|
82
|
-
|
|
83
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
84
|
-
|
|
85
|
-
expect(result).toEqual({
|
|
86
|
-
"content-type": "application/json",
|
|
87
|
-
data: {
|
|
88
|
-
text: "test"
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
it("should return data without transformation", async () => {
|
|
93
|
-
class Test {
|
|
94
|
-
@Get("/")
|
|
95
|
-
test() {}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
99
|
-
|
|
100
|
-
const ctx = PlatformTest.createRequestContext();
|
|
101
|
-
const data = {text: "test"};
|
|
102
|
-
|
|
103
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
104
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
105
|
-
vi.spyOn(ctx.request, "get").mockReturnValue("application/json");
|
|
106
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(["application/json"]);
|
|
107
|
-
|
|
108
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
109
|
-
|
|
110
|
-
expect(result).toEqual({
|
|
111
|
-
text: "test"
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
it("should get content-type set from response", async () => {
|
|
115
|
-
class Test {
|
|
116
|
-
@Get("/")
|
|
117
|
-
test() {}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
121
|
-
|
|
122
|
-
const ctx = PlatformTest.createRequestContext();
|
|
123
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
124
|
-
const data = {text: "test"};
|
|
125
|
-
|
|
126
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
127
|
-
vi.spyOn(ctx.response, "get").mockReturnValue("text/json; charset: utf-8");
|
|
128
|
-
vi.spyOn(ctx.request, "get").mockReturnValue("application/json");
|
|
129
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(["application/json"]);
|
|
130
|
-
|
|
131
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
132
|
-
|
|
133
|
-
expect(result).toEqual({
|
|
134
|
-
"content-type": "application/json",
|
|
135
|
-
data: {
|
|
136
|
-
text: "test"
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
it("should transform data for any content type", async () => {
|
|
141
|
-
class Test {
|
|
142
|
-
@Get("/")
|
|
143
|
-
test() {}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
147
|
-
|
|
148
|
-
const ctx = PlatformTest.createRequestContext();
|
|
149
|
-
const data = {text: "test"};
|
|
150
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
151
|
-
|
|
152
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
153
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
154
|
-
vi.spyOn(ctx.request, "get").mockReturnValue("*/*");
|
|
155
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(["application/json"]);
|
|
156
|
-
|
|
157
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
158
|
-
|
|
159
|
-
expect(result).toEqual({
|
|
160
|
-
"content-type": "application/json",
|
|
161
|
-
data: {
|
|
162
|
-
text: "test"
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
describe("when filter list is not given", () => {
|
|
168
|
-
beforeEach(() =>
|
|
169
|
-
PlatformTest.create({
|
|
170
|
-
responseFilters: [AllFilter]
|
|
171
|
-
})
|
|
172
|
-
);
|
|
173
|
-
afterEach(() => PlatformTest.reset());
|
|
174
|
-
it("should transform data for default content-type from metadata", async () => {
|
|
175
|
-
class Test {
|
|
176
|
-
@Get("/")
|
|
177
|
-
@(Returns(200).ContentType("application/json"))
|
|
178
|
-
test() {}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
182
|
-
|
|
183
|
-
const ctx = PlatformTest.createRequestContext();
|
|
184
|
-
const data = {text: "test"};
|
|
185
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
186
|
-
|
|
187
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
188
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
189
|
-
vi.spyOn(ctx.request, "get").mockReturnValue(undefined);
|
|
190
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(false);
|
|
191
|
-
|
|
192
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
193
|
-
|
|
194
|
-
expect(result).toEqual({
|
|
195
|
-
"content-type": "*/*",
|
|
196
|
-
data: {
|
|
197
|
-
text: "test"
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
it("should transform data for default content-type from metadata with any response filter", async () => {
|
|
202
|
-
class Test {
|
|
203
|
-
@Get("/")
|
|
204
|
-
@(Returns(200).ContentType("application/json"))
|
|
205
|
-
test() {}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
209
|
-
|
|
210
|
-
const ctx = PlatformTest.createRequestContext();
|
|
211
|
-
const data = {text: "test"};
|
|
212
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
213
|
-
|
|
214
|
-
vi.spyOn(ctx.response, "contentType").mockReturnThis();
|
|
215
|
-
vi.spyOn(ctx.response, "get").mockReturnValue(undefined);
|
|
216
|
-
vi.spyOn(ctx.request, "get").mockReturnValue(undefined);
|
|
217
|
-
vi.spyOn(ctx.request, "accepts").mockReturnValue(false);
|
|
218
|
-
|
|
219
|
-
const result = await platformResponseFilter.transform(data, ctx);
|
|
220
|
-
|
|
221
|
-
expect(result).toEqual({
|
|
222
|
-
"content-type": "*/*",
|
|
223
|
-
data: {
|
|
224
|
-
text: "test"
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
describe("transform() without registered filters", () => {
|
|
231
|
-
beforeEach(() => PlatformTest.create());
|
|
232
|
-
afterEach(() => PlatformTest.reset());
|
|
233
|
-
it("should transform value", async () => {
|
|
234
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
235
|
-
const ctx = PlatformTest.createRequestContext();
|
|
236
|
-
|
|
237
|
-
const result = await platformResponseFilter.transform({test: "test"}, ctx);
|
|
238
|
-
|
|
239
|
-
expect(result).toEqual({test: "test"});
|
|
240
|
-
});
|
|
241
|
-
it("should transform value (endpoint)", async () => {
|
|
242
|
-
class Test {
|
|
243
|
-
@Get("/")
|
|
244
|
-
test() {}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
248
|
-
const ctx = PlatformTest.createRequestContext();
|
|
249
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
250
|
-
|
|
251
|
-
vi.spyOn(ctx.endpoint, "getResponseOptions");
|
|
252
|
-
|
|
253
|
-
const result = await platformResponseFilter.transform({test: "test"}, ctx);
|
|
254
|
-
|
|
255
|
-
expect(result).toEqual({test: "test"});
|
|
256
|
-
expect(ctx.endpoint.getResponseOptions).toHaveBeenCalledWith(200, {includes: undefined});
|
|
257
|
-
});
|
|
258
|
-
it("should transform value (endpoint + includes)", async () => {
|
|
259
|
-
class Test {
|
|
260
|
-
@Get("/")
|
|
261
|
-
test() {}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
265
|
-
const ctx = PlatformTest.createRequestContext();
|
|
266
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
267
|
-
|
|
268
|
-
vi.spyOn(ctx.endpoint, "getResponseOptions");
|
|
269
|
-
|
|
270
|
-
ctx.request.query.includes = [];
|
|
271
|
-
|
|
272
|
-
const result = await platformResponseFilter.transform({test: "test"}, ctx);
|
|
273
|
-
|
|
274
|
-
expect(result).toEqual({test: "test"});
|
|
275
|
-
expect(ctx.endpoint.getResponseOptions).toHaveBeenCalledWith(200, {includes: []});
|
|
276
|
-
});
|
|
277
|
-
it("should transform value (endpoint + includes with ,)", async () => {
|
|
278
|
-
class Test {
|
|
279
|
-
@Get("/")
|
|
280
|
-
test() {}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
284
|
-
const ctx = PlatformTest.createRequestContext();
|
|
285
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
286
|
-
|
|
287
|
-
vi.spyOn(ctx.endpoint, "getResponseOptions");
|
|
288
|
-
|
|
289
|
-
ctx.request.query.includes = ["test,test2"];
|
|
290
|
-
|
|
291
|
-
const result = await platformResponseFilter.transform({test: "test"}, ctx);
|
|
292
|
-
|
|
293
|
-
expect(result).toEqual({test: "test"});
|
|
294
|
-
expect(ctx.endpoint.getResponseOptions).toHaveBeenCalledWith(200, {
|
|
295
|
-
includes: ["test", "test2"]
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
it("should transform value (endpoint - view)", async () => {
|
|
299
|
-
class Test {
|
|
300
|
-
@Get("/")
|
|
301
|
-
@View("test.pug")
|
|
302
|
-
test() {}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
306
|
-
const ctx = PlatformTest.createRequestContext();
|
|
307
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
308
|
-
vi.spyOn(ctx.response, "render").mockResolvedValue("template");
|
|
309
|
-
|
|
310
|
-
const result = await platformResponseFilter.transform({test: "test"}, ctx);
|
|
311
|
-
|
|
312
|
-
expect(result).toEqual("template");
|
|
313
|
-
});
|
|
314
|
-
it("should transform value (endpoint - view - error)", async () => {
|
|
315
|
-
class Test {
|
|
316
|
-
@Get("/")
|
|
317
|
-
@View("test.pug")
|
|
318
|
-
test() {}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
322
|
-
const ctx = PlatformTest.createRequestContext();
|
|
323
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
324
|
-
vi.spyOn(ctx.response, "render").mockRejectedValue(new Error("parsing error"));
|
|
325
|
-
|
|
326
|
-
const result = await catchAsyncError(() => platformResponseFilter.transform({test: "test"}, ctx));
|
|
327
|
-
|
|
328
|
-
expect(result?.message).toEqual("Template rendering error: Test.test()\nError: parsing error");
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it("should render content", async () => {
|
|
332
|
-
class Model {
|
|
333
|
-
@Property()
|
|
334
|
-
data: string;
|
|
335
|
-
|
|
336
|
-
@Ignore()
|
|
337
|
-
test: string;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
class Test {
|
|
341
|
-
@Get("/")
|
|
342
|
-
@View("view", {options: "options"})
|
|
343
|
-
@Returns(200, Model)
|
|
344
|
-
test() {}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
348
|
-
const ctx = PlatformTest.createRequestContext();
|
|
349
|
-
|
|
350
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
351
|
-
|
|
352
|
-
vi.spyOn(ctx.response, "render").mockResolvedValue("HTML");
|
|
353
|
-
|
|
354
|
-
ctx.data = {data: "data"};
|
|
355
|
-
|
|
356
|
-
await platformResponseFilter.transform(ctx.data, ctx);
|
|
357
|
-
|
|
358
|
-
expect(ctx.response.render).toHaveBeenCalledWith("view", {
|
|
359
|
-
$ctx: ctx,
|
|
360
|
-
data: "data",
|
|
361
|
-
options: "options"
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
it("should render content and throw an error", async () => {
|
|
365
|
-
class Test {
|
|
366
|
-
@Get("/")
|
|
367
|
-
@View("view", {options: "options"})
|
|
368
|
-
test() {}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const platformResponseFilter = PlatformTest.get<PlatformResponseFilter>(PlatformResponseFilter);
|
|
372
|
-
const ctx = PlatformTest.createRequestContext();
|
|
373
|
-
ctx.endpoint = EndpointMetadata.get(Test, "test");
|
|
374
|
-
|
|
375
|
-
vi.spyOn(ctx.response, "render").mockRejectedValue(new Error("parser error"));
|
|
376
|
-
|
|
377
|
-
ctx.data = {data: "data"};
|
|
378
|
-
|
|
379
|
-
let actualError: any = await catchAsyncError(() => platformResponseFilter.transform(ctx.data, ctx));
|
|
380
|
-
|
|
381
|
-
expect(actualError.message).toEqual("Template rendering error: Test.test()\nError: parser error");
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
});
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import {isSerializable} from "@tsed/core";
|
|
2
|
-
import {BaseContext, constant, inject, injectable} from "@tsed/di";
|
|
3
|
-
import {serialize} from "@tsed/json-mapper";
|
|
4
|
-
|
|
5
|
-
import {TemplateRenderError} from "../errors/TemplateRenderError.js";
|
|
6
|
-
import {PLATFORM_CONTENT_TYPE_RESOLVER} from "./PlatformContentTypeResolver.js";
|
|
7
|
-
import {PLATFORM_CONTENT_TYPES_CONTAINER} from "./PlatformContentTypesContainer.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* PlatformResponseFilter is responsible for transforming the response data
|
|
11
|
-
* to the appropriate format based on the endpoint metadata and context.
|
|
12
|
-
*
|
|
13
|
-
* @platform
|
|
14
|
-
*/
|
|
15
|
-
export class PlatformResponseFilter {
|
|
16
|
-
protected additionalProperties = constant<boolean>("additionalProperties");
|
|
17
|
-
protected container = inject(PLATFORM_CONTENT_TYPES_CONTAINER);
|
|
18
|
-
protected contentTypeResolver = inject(PLATFORM_CONTENT_TYPE_RESOLVER);
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Transform the data to the right format.
|
|
22
|
-
* @param data The data to transform.
|
|
23
|
-
* @param $ctx The context.
|
|
24
|
-
*/
|
|
25
|
-
async transform(data: unknown, $ctx: BaseContext): Promise<unknown> {
|
|
26
|
-
const {endpoint} = $ctx;
|
|
27
|
-
|
|
28
|
-
if (endpoint) {
|
|
29
|
-
if (endpoint.view) {
|
|
30
|
-
data = await this.renderView(data, $ctx);
|
|
31
|
-
} else if (isSerializable(data)) {
|
|
32
|
-
data = await this.serialize(data, $ctx);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return this.resolve(data, $ctx);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Render the view with the given data.
|
|
41
|
-
* @param data The data to render.
|
|
42
|
-
* @param $ctx The context.
|
|
43
|
-
* @protected
|
|
44
|
-
*/
|
|
45
|
-
protected async renderView(data: unknown, $ctx: BaseContext) {
|
|
46
|
-
const {response, endpoint} = $ctx;
|
|
47
|
-
try {
|
|
48
|
-
const {path, options} = endpoint.view;
|
|
49
|
-
|
|
50
|
-
return await response.render(path, {...options, ...(data as object), $ctx});
|
|
51
|
-
} catch (err) {
|
|
52
|
-
throw new TemplateRenderError(endpoint.targetName, endpoint.propertyKey, err);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Serialize data before calling filters
|
|
58
|
-
* @param data
|
|
59
|
-
* @param ctx
|
|
60
|
-
*/
|
|
61
|
-
protected async serialize(data: unknown, ctx: BaseContext) {
|
|
62
|
-
const {response, endpoint} = ctx;
|
|
63
|
-
|
|
64
|
-
const responseOpts = endpoint.getResponseOptions(response.statusCode, {
|
|
65
|
-
includes: this.getIncludes(ctx)
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
data = serialize(data, {
|
|
69
|
-
useAlias: true,
|
|
70
|
-
additionalProperties: this.additionalProperties,
|
|
71
|
-
...responseOpts,
|
|
72
|
-
endpoint: true
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
return data;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
protected resolve(data: any, ctx: BaseContext) {
|
|
79
|
-
const {response} = ctx;
|
|
80
|
-
|
|
81
|
-
if (ctx.endpoint?.operation) {
|
|
82
|
-
const bestContentType = this.contentTypeResolver(data, ctx);
|
|
83
|
-
|
|
84
|
-
bestContentType && response.contentType(bestContentType);
|
|
85
|
-
|
|
86
|
-
const resolved = this.container.resolve(bestContentType);
|
|
87
|
-
|
|
88
|
-
if (resolved) {
|
|
89
|
-
return resolved.transform(data, ctx);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return data;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
protected getIncludes(ctx: BaseContext) {
|
|
97
|
-
if (ctx.request.query.includes) {
|
|
98
|
-
return [].concat(ctx.request.query.includes).flatMap((include: string) => include.split(","));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return undefined;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
injectable(PlatformResponseFilter);
|
package/vitest.config.mts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import {presets} from "@tsed/vitest/presets";
|
|
3
|
-
import {defineConfig} from "vitest/config";
|
|
4
|
-
|
|
5
|
-
export default defineConfig(
|
|
6
|
-
{
|
|
7
|
-
...presets,
|
|
8
|
-
test: {
|
|
9
|
-
...presets.test,
|
|
10
|
-
coverage: {
|
|
11
|
-
...presets.test.coverage,
|
|
12
|
-
thresholds: {
|
|
13
|
-
statements: 0,
|
|
14
|
-
branches: 0,
|
|
15
|
-
functions: 0,
|
|
16
|
-
lines: 0
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
);
|