@tsed/platform-response-filter 7.0.0-alpha.1 → 7.0.0-beta.10
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/cjs/decorators/responseFilter.js +23 -0
- package/lib/cjs/decorators/responseFilter.js.map +1 -0
- package/lib/cjs/domain/ResponseFiltersContainer.js +16 -0
- package/lib/cjs/domain/ResponseFiltersContainer.js.map +1 -0
- package/lib/cjs/errors/TemplateRenderError.js +23 -0
- package/lib/cjs/errors/TemplateRenderError.js.map +1 -0
- package/lib/cjs/index.js +14 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/interfaces/ResponseFilterMethods.js +3 -0
- package/lib/cjs/interfaces/ResponseFilterMethods.js.map +1 -0
- package/lib/cjs/package.json +3 -0
- package/lib/cjs/services/PlatformResponseFilter.js +94 -0
- package/lib/cjs/services/PlatformResponseFilter.js.map +1 -0
- package/lib/cjs/utils/getContentType.js +28 -0
- package/lib/cjs/utils/getContentType.js.map +1 -0
- package/lib/cjs/utils/renderView.js +17 -0
- package/lib/cjs/utils/renderView.js.map +1 -0
- package/lib/esm/decorators/responseFilter.js +19 -0
- package/lib/esm/decorators/responseFilter.js.map +1 -0
- package/lib/esm/domain/ResponseFiltersContainer.js +12 -0
- package/lib/esm/domain/ResponseFiltersContainer.js.map +1 -0
- package/lib/esm/errors/TemplateRenderError.js +19 -0
- package/lib/esm/errors/TemplateRenderError.js.map +1 -0
- package/lib/esm/index.js +11 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/interfaces/ResponseFilterMethods.js +2 -0
- package/lib/esm/interfaces/ResponseFilterMethods.js.map +1 -0
- package/lib/esm/package.json +3 -0
- package/lib/esm/services/PlatformResponseFilter.js +91 -0
- package/lib/esm/services/PlatformResponseFilter.js.map +1 -0
- package/lib/esm/utils/getContentType.js +24 -0
- package/lib/esm/utils/getContentType.js.map +1 -0
- package/lib/esm/utils/renderView.js +13 -0
- package/lib/esm/utils/renderView.js.map +1 -0
- package/lib/{decorators → types/decorators}/responseFilter.d.ts +0 -0
- package/lib/{domain → types/domain}/ResponseFiltersContainer.d.ts +0 -0
- package/lib/types/errors/TemplateRenderError.d.ts +14 -0
- package/lib/{index.d.ts → types/index.d.ts} +5 -0
- package/lib/{interfaces → types/interfaces}/ResponseFilterMethods.d.ts +0 -0
- package/lib/{services → types/services}/PlatformResponseFilter.d.ts +15 -3
- package/lib/{utils → types/utils}/getContentType.d.ts +0 -0
- package/lib/types/utils/renderView.d.ts +2 -0
- package/package.json +41 -16
- package/readme.md +123 -7
- package/tsconfig.compile.esm.json +12 -0
- package/lib/index.js +0 -132
- package/lib/index.js.map +0 -1
- package/lib/index.modern.js +0 -128
- package/lib/index.modern.js.map +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseFilter = void 0;
|
|
4
|
+
const di_1 = require("@tsed/di");
|
|
5
|
+
const ResponseFiltersContainer_1 = require("../domain/ResponseFiltersContainer");
|
|
6
|
+
/**
|
|
7
|
+
* Register a response filter service.
|
|
8
|
+
* @param contentTypes
|
|
9
|
+
* @decorator
|
|
10
|
+
*/
|
|
11
|
+
function ResponseFilter(...contentTypes) {
|
|
12
|
+
return (target) => {
|
|
13
|
+
contentTypes.forEach((contentType) => {
|
|
14
|
+
(0, ResponseFiltersContainer_1.registerResponseFilter)(contentType, target);
|
|
15
|
+
});
|
|
16
|
+
(0, di_1.registerProvider)({
|
|
17
|
+
provide: target,
|
|
18
|
+
useClass: target
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
exports.ResponseFilter = ResponseFilter;
|
|
23
|
+
//# sourceMappingURL=responseFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseFilter.js","sourceRoot":"","sources":["../../../src/decorators/responseFilter.ts"],"names":[],"mappings":";;;AACA,iCAA0C;AAC1C,iFAA6F;AAE7F;;;;GAIG;AACH,SAAgB,cAAc,CAAC,GAAG,YAAiC;IACjE,OAAO,CAAU,MAAS,EAAY,EAAE;QACtC,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACnC,IAAA,iDAAsB,EAAC,WAAW,EAAE,MAAa,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,IAAA,qBAAgB,EAAC;YACf,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,MAA8B;SACzC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAVD,wCAUC","sourcesContent":["import {Type} from \"@tsed/core\";\nimport {registerProvider} from \"@tsed/di\";\nimport {registerResponseFilter, ResponseFilterKey} from \"../domain/ResponseFiltersContainer\";\n\n/**\n * Register a response filter service.\n * @param contentTypes\n * @decorator\n */\nexport function ResponseFilter(...contentTypes: ResponseFilterKey[]): ClassDecorator {\n return <T = any>(target: T): void | T => {\n contentTypes.forEach((contentType) => {\n registerResponseFilter(contentType, target as any);\n });\n registerProvider({\n provide: target,\n useClass: target as unknown as Type<any>\n });\n };\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerResponseFilter = exports.ResponseFiltersContainer = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @ignore
|
|
6
|
+
*/
|
|
7
|
+
// tslint:disable-next-line:variable-name
|
|
8
|
+
exports.ResponseFiltersContainer = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* @ignore
|
|
11
|
+
*/
|
|
12
|
+
function registerResponseFilter(type, token) {
|
|
13
|
+
exports.ResponseFiltersContainer.set(type, token);
|
|
14
|
+
}
|
|
15
|
+
exports.registerResponseFilter = registerResponseFilter;
|
|
16
|
+
//# sourceMappingURL=ResponseFiltersContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponseFiltersContainer.js","sourceRoot":"","sources":["../../../src/domain/ResponseFiltersContainer.ts"],"names":[],"mappings":";;;AAMA;;GAEG;AACH,yCAAyC;AAC5B,QAAA,wBAAwB,GAAG,IAAI,GAAG,EAAkD,CAAC;AAClG;;GAEG;AACH,SAAgB,sBAAsB,CAAC,IAAuB,EAAE,KAAkC;IAChG,gCAAwB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC;AAFD,wDAEC","sourcesContent":["import {Type} from \"@tsed/core\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\n/**\n * @ignore\n */\nexport type ResponseFilterKey = \"*/*\" | \"application/json\" | \"text/html\" | \"plain/text\" | string;\n/**\n * @ignore\n */\n// tslint:disable-next-line:variable-name\nexport const ResponseFiltersContainer = new Map<ResponseFilterKey, Type<ResponseFilterMethods>>();\n/**\n * @ignore\n */\nexport function registerResponseFilter(type: ResponseFilterKey, token: Type<ResponseFilterMethods>) {\n ResponseFiltersContainer.set(type, token);\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TemplateRenderError = void 0;
|
|
4
|
+
const core_1 = require("@tsed/core");
|
|
5
|
+
const exceptions_1 = require("@tsed/exceptions");
|
|
6
|
+
/**
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
class TemplateRenderError extends exceptions_1.InternalServerError {
|
|
10
|
+
constructor(target, method, err) {
|
|
11
|
+
super(TemplateRenderError.buildMessage(target, method, err));
|
|
12
|
+
this.name = "TEMPLATE_RENDER_ERROR";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
static buildMessage(target, method, err) {
|
|
19
|
+
return `Template rendering error: ${(0, core_1.nameOf)(target)}.${String(method)}()\n` + err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.TemplateRenderError = TemplateRenderError;
|
|
23
|
+
//# sourceMappingURL=TemplateRenderError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateRenderError.js","sourceRoot":"","sources":["../../../src/errors/TemplateRenderError.ts"],"names":[],"mappings":";;;AAAA,qCAAwC;AACxC,iDAAqD;AAErD;;GAEG;AACH,MAAa,mBAAoB,SAAQ,gCAAmB;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,IAAA,aAAM,EAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;IACnF,CAAC;CACF;AAdD,kDAcC","sourcesContent":["import {nameOf, Type} from \"@tsed/core\";\nimport {InternalServerError} from \"@tsed/exceptions\";\n\n/**\n * @private\n */\nexport class TemplateRenderError extends InternalServerError {\n name = \"TEMPLATE_RENDER_ERROR\";\n\n constructor(target: Type<any> | string, method: string | symbol, err: Error) {\n super(TemplateRenderError.buildMessage(target, method, err));\n }\n\n /**\n *\n * @returns {string}\n */\n static buildMessage(target: Type<any> | string, method: string | symbol, err: Error) {\n return `Template rendering error: ${nameOf(target)}.${String(method)}()\\n` + err;\n }\n}\n"]}
|
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Automatically generated by barrelsby.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
tslib_1.__exportStar(require("./decorators/responseFilter"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./domain/ResponseFiltersContainer"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./errors/TemplateRenderError"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./interfaces/ResponseFilterMethods"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./services/PlatformResponseFilter"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./utils/getContentType"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./utils/renderView"), exports);
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,sEAA4C;AAC5C,4EAAkD;AAClD,uEAA6C;AAC7C,6EAAmD;AACnD,4EAAkD;AAClD,iEAAuC;AACvC,6DAAmC","sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from \"./decorators/responseFilter\";\nexport * from \"./domain/ResponseFiltersContainer\";\nexport * from \"./errors/TemplateRenderError\";\nexport * from \"./interfaces/ResponseFilterMethods\";\nexport * from \"./services/PlatformResponseFilter\";\nexport * from \"./utils/getContentType\";\nexport * from \"./utils/renderView\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponseFilterMethods.js","sourceRoot":"","sources":["../../../src/interfaces/ResponseFilterMethods.ts"],"names":[],"mappings":"","sourcesContent":["import {Type} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\n\ndeclare global {\n namespace TsED {\n interface Configuration {\n /**\n * A list of response filters must be called before returning a response to the consumer. See more on [Response filters](/docs/response-filter.md).\n */\n responseFilters: Type<ResponseFilterMethods>[];\n }\n }\n}\n\nexport interface ResponseFilterMethods<T = unknown> {\n transform(data: T, ctx: BaseContext): any;\n}\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PlatformResponseFilter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@tsed/core");
|
|
6
|
+
const json_mapper_1 = require("@tsed/json-mapper");
|
|
7
|
+
const di_1 = require("@tsed/di");
|
|
8
|
+
const ResponseFiltersContainer_1 = require("../domain/ResponseFiltersContainer");
|
|
9
|
+
const getContentType_1 = require("../utils/getContentType");
|
|
10
|
+
const renderView_1 = require("../utils/renderView");
|
|
11
|
+
/**
|
|
12
|
+
* @platform
|
|
13
|
+
*/
|
|
14
|
+
let PlatformResponseFilter = class PlatformResponseFilter {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.types = new Map();
|
|
17
|
+
}
|
|
18
|
+
get contentTypes() {
|
|
19
|
+
return [...this.types.keys()];
|
|
20
|
+
}
|
|
21
|
+
$onInit() {
|
|
22
|
+
ResponseFiltersContainer_1.ResponseFiltersContainer.forEach((token, type) => {
|
|
23
|
+
if (this.responseFilters.includes(token)) {
|
|
24
|
+
this.types.set(type, this.injector.get(token));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
getBestContentType(data, ctx) {
|
|
29
|
+
const contentType = (0, getContentType_1.getContentType)(data, ctx);
|
|
30
|
+
if (ctx.request.get("Accept")) {
|
|
31
|
+
const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));
|
|
32
|
+
if (bestContentType) {
|
|
33
|
+
return [].concat(bestContentType).filter((type) => type !== "*/*")[0];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return contentType;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Call filters to transform data
|
|
40
|
+
* @param data
|
|
41
|
+
* @param ctx
|
|
42
|
+
*/
|
|
43
|
+
async transform(data, ctx) {
|
|
44
|
+
const { response } = ctx;
|
|
45
|
+
const bestContentType = this.getBestContentType(data, ctx);
|
|
46
|
+
bestContentType && response.contentType(bestContentType);
|
|
47
|
+
if (this.types.has(bestContentType)) {
|
|
48
|
+
return this.types.get(bestContentType).transform(data, ctx);
|
|
49
|
+
}
|
|
50
|
+
if (this.types.has(getContentType_1.ANY_CONTENT_TYPE)) {
|
|
51
|
+
return this.types.get(getContentType_1.ANY_CONTENT_TYPE).transform(data, ctx);
|
|
52
|
+
}
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Serialize data before calling filters
|
|
57
|
+
* @param data
|
|
58
|
+
* @param ctx
|
|
59
|
+
*/
|
|
60
|
+
async serialize(data, ctx) {
|
|
61
|
+
const { response, endpoint } = ctx;
|
|
62
|
+
if (endpoint) {
|
|
63
|
+
if (endpoint.view) {
|
|
64
|
+
data = await (0, renderView_1.renderView)(data, ctx);
|
|
65
|
+
}
|
|
66
|
+
else if ((0, core_1.isSerializable)(data)) {
|
|
67
|
+
data = (0, json_mapper_1.serialize)(data, {
|
|
68
|
+
useAlias: true,
|
|
69
|
+
additionalProperties: this.additionalProperties,
|
|
70
|
+
...endpoint.getResponseOptions(response.statusCode),
|
|
71
|
+
endpoint: true
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
tslib_1.__decorate([
|
|
79
|
+
(0, di_1.Inject)(),
|
|
80
|
+
tslib_1.__metadata("design:type", di_1.InjectorService)
|
|
81
|
+
], PlatformResponseFilter.prototype, "injector", void 0);
|
|
82
|
+
tslib_1.__decorate([
|
|
83
|
+
(0, di_1.Constant)("responseFilters", []),
|
|
84
|
+
tslib_1.__metadata("design:type", Array)
|
|
85
|
+
], PlatformResponseFilter.prototype, "responseFilters", void 0);
|
|
86
|
+
tslib_1.__decorate([
|
|
87
|
+
(0, di_1.Constant)("additionalProperties"),
|
|
88
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
89
|
+
], PlatformResponseFilter.prototype, "additionalProperties", void 0);
|
|
90
|
+
PlatformResponseFilter = tslib_1.__decorate([
|
|
91
|
+
(0, di_1.Injectable)()
|
|
92
|
+
], PlatformResponseFilter);
|
|
93
|
+
exports.PlatformResponseFilter = PlatformResponseFilter;
|
|
94
|
+
//# sourceMappingURL=PlatformResponseFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlatformResponseFilter.js","sourceRoot":"","sources":["../../../src/services/PlatformResponseFilter.ts"],"names":[],"mappings":"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","sourcesContent":["import {isSerializable, Type} from \"@tsed/core\";\nimport {serialize} from \"@tsed/json-mapper\";\nimport {BaseContext, Constant, Inject, Injectable, InjectorService} from \"@tsed/di\";\nimport {ResponseFilterKey, ResponseFiltersContainer} from \"../domain/ResponseFiltersContainer\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\nimport {ANY_CONTENT_TYPE, getContentType} from \"../utils/getContentType\";\nimport {renderView} from \"../utils/renderView\";\n\n/**\n * @platform\n */\n@Injectable()\nexport class PlatformResponseFilter {\n protected types: Map<ResponseFilterKey, ResponseFilterMethods> = new Map();\n\n @Inject()\n protected injector: InjectorService;\n\n @Constant(\"responseFilters\", [])\n protected responseFilters: Type<ResponseFilterMethods>[];\n\n @Constant(\"additionalProperties\")\n protected additionalProperties: boolean;\n\n get contentTypes(): ResponseFilterKey[] {\n return [...this.types.keys()];\n }\n\n $onInit() {\n ResponseFiltersContainer.forEach((token, type) => {\n if (this.responseFilters.includes(token)) {\n this.types.set(type, this.injector.get(token)!);\n }\n });\n }\n\n getBestContentType(data: any, ctx: BaseContext) {\n const contentType = getContentType(data, ctx);\n\n if (ctx.request.get(\"Accept\")) {\n const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));\n\n if (bestContentType) {\n return [].concat(bestContentType as any).filter((type) => type !== \"*/*\")[0];\n }\n }\n\n return contentType;\n }\n\n /**\n * Call filters to transform data\n * @param data\n * @param ctx\n */\n async transform(data: unknown, ctx: BaseContext) {\n const {response} = ctx;\n const bestContentType = this.getBestContentType(data, ctx);\n\n bestContentType && response.contentType(bestContentType);\n\n if (this.types.has(bestContentType)) {\n return this.types.get(bestContentType)!.transform(data, ctx);\n }\n\n if (this.types.has(ANY_CONTENT_TYPE)) {\n return this.types.get(ANY_CONTENT_TYPE)!.transform(data, ctx);\n }\n\n return data;\n }\n\n /**\n * Serialize data before calling filters\n * @param data\n * @param ctx\n */\n async serialize(data: unknown, ctx: BaseContext) {\n const {response, endpoint} = ctx;\n\n if (endpoint) {\n if (endpoint.view) {\n data = await renderView(data, ctx);\n } else if (isSerializable(data)) {\n data = serialize(data, {\n useAlias: true,\n additionalProperties: this.additionalProperties,\n ...endpoint.getResponseOptions(response.statusCode),\n endpoint: true\n });\n }\n }\n\n return data;\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getContentType = exports.ANY_CONTENT_TYPE = void 0;
|
|
4
|
+
const core_1 = require("@tsed/core");
|
|
5
|
+
exports.ANY_CONTENT_TYPE = "*/*";
|
|
6
|
+
/**
|
|
7
|
+
* @ignore
|
|
8
|
+
*/
|
|
9
|
+
function getContentType(data, ctx) {
|
|
10
|
+
const { endpoint, response } = ctx;
|
|
11
|
+
const { operation } = endpoint;
|
|
12
|
+
const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || "";
|
|
13
|
+
if (contentType && contentType !== exports.ANY_CONTENT_TYPE) {
|
|
14
|
+
if (contentType === "application/json") {
|
|
15
|
+
if ((0, core_1.isObject)(data)) {
|
|
16
|
+
return contentType;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return contentType;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (typeof data === "string" && endpoint.view) {
|
|
24
|
+
return "text/html";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.getContentType = getContentType;
|
|
28
|
+
//# sourceMappingURL=getContentType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getContentType.js","sourceRoot":"","sources":["../../../src/utils/getContentType.ts"],"names":[],"mappings":";;;AAAA,qCAAoC;AAEvB,QAAA,gBAAgB,GAAG,KAAK,CAAC;AACtC;;GAEG;AACH,SAAgB,cAAc,CAAC,IAAS,EAAE,GAAgB;IACxD,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,GAAG,CAAC;IACjC,MAAM,EAAC,SAAS,EAAC,GAAG,QAAQ,CAAC;IAE7B,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,EAAE,IAAI,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAEvG,IAAI,WAAW,IAAI,WAAW,KAAK,wBAAgB,EAAE;QACnD,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,IAAI,IAAA,eAAQ,EAAC,IAAI,CAAC,EAAE;gBAClB,OAAO,WAAW,CAAC;aACpB;SACF;aAAM;YACL,OAAO,WAAW,CAAC;SACpB;KACF;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE;QAC7C,OAAO,WAAW,CAAC;KACpB;AACH,CAAC;AAnBD,wCAmBC","sourcesContent":["import {isObject} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\nexport const ANY_CONTENT_TYPE = \"*/*\";\n/**\n * @ignore\n */\nexport function getContentType(data: any, ctx: BaseContext) {\n const {endpoint, response} = ctx;\n const {operation} = endpoint;\n\n const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || \"\";\n\n if (contentType && contentType !== ANY_CONTENT_TYPE) {\n if (contentType === \"application/json\") {\n if (isObject(data)) {\n return contentType;\n }\n } else {\n return contentType;\n }\n }\n\n if (typeof data === \"string\" && endpoint.view) {\n return \"text/html\";\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderView = void 0;
|
|
4
|
+
const TemplateRenderError_1 = require("../errors/TemplateRenderError");
|
|
5
|
+
async function renderView(data, $ctx) {
|
|
6
|
+
const { response, endpoint } = $ctx;
|
|
7
|
+
try {
|
|
8
|
+
const { data } = $ctx;
|
|
9
|
+
const { path, options } = endpoint.view;
|
|
10
|
+
return await response.render(path, { ...options, ...data, $ctx });
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
throw new TemplateRenderError_1.TemplateRenderError(endpoint.targetName, endpoint.propertyKey, err);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.renderView = renderView;
|
|
17
|
+
//# sourceMappingURL=renderView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderView.js","sourceRoot":"","sources":["../../../src/utils/renderView.ts"],"names":[],"mappings":";;;AACA,uEAAkE;AAE3D,KAAK,UAAU,UAAU,CAAC,IAAS,EAAE,IAAiB;IAC3D,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,IAAI,CAAC;IAClC,IAAI;QACF,MAAM,EAAC,IAAI,EAAC,GAAG,IAAI,CAAC;QACpB,MAAM,EAAC,IAAI,EAAE,OAAO,EAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;QAEtC,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAC,GAAG,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;KACjE;IAAC,OAAO,GAAG,EAAE;QACZ,MAAM,IAAI,yCAAmB,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;KAC/E;AACH,CAAC;AAVD,gCAUC","sourcesContent":["import {BaseContext} from \"@tsed/di\";\nimport {TemplateRenderError} from \"../errors/TemplateRenderError\";\n\nexport async function renderView(data: any, $ctx: BaseContext) {\n const {response, endpoint} = $ctx;\n try {\n const {data} = $ctx;\n const {path, options} = endpoint.view;\n\n return await response.render(path, {...options, ...data, $ctx});\n } catch (err) {\n throw new TemplateRenderError(endpoint.targetName, endpoint.propertyKey, err);\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { registerProvider } from "@tsed/di";
|
|
2
|
+
import { registerResponseFilter } from "../domain/ResponseFiltersContainer.js";
|
|
3
|
+
/**
|
|
4
|
+
* Register a response filter service.
|
|
5
|
+
* @param contentTypes
|
|
6
|
+
* @decorator
|
|
7
|
+
*/
|
|
8
|
+
export function ResponseFilter(...contentTypes) {
|
|
9
|
+
return (target) => {
|
|
10
|
+
contentTypes.forEach((contentType) => {
|
|
11
|
+
registerResponseFilter(contentType, target);
|
|
12
|
+
});
|
|
13
|
+
registerProvider({
|
|
14
|
+
provide: target,
|
|
15
|
+
useClass: target
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=responseFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseFilter.js","sourceRoot":"","sources":["../../../src/decorators/responseFilter.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAC,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAC,sBAAsB,EAAoB,MAAM,oCAAoC,CAAC;AAE7F;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAG,YAAiC;IACjE,OAAO,CAAU,MAAS,EAAY,EAAE;QACtC,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACnC,sBAAsB,CAAC,WAAW,EAAE,MAAa,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,gBAAgB,CAAC;YACf,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,MAA8B;SACzC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {Type} from \"@tsed/core\";\nimport {registerProvider} from \"@tsed/di\";\nimport {registerResponseFilter, ResponseFilterKey} from \"../domain/ResponseFiltersContainer\";\n\n/**\n * Register a response filter service.\n * @param contentTypes\n * @decorator\n */\nexport function ResponseFilter(...contentTypes: ResponseFilterKey[]): ClassDecorator {\n return <T = any>(target: T): void | T => {\n contentTypes.forEach((contentType) => {\n registerResponseFilter(contentType, target as any);\n });\n registerProvider({\n provide: target,\n useClass: target as unknown as Type<any>\n });\n };\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ignore
|
|
3
|
+
*/
|
|
4
|
+
// tslint:disable-next-line:variable-name
|
|
5
|
+
export const ResponseFiltersContainer = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* @ignore
|
|
8
|
+
*/
|
|
9
|
+
export function registerResponseFilter(type, token) {
|
|
10
|
+
ResponseFiltersContainer.set(type, token);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=ResponseFiltersContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponseFiltersContainer.js","sourceRoot":"","sources":["../../../src/domain/ResponseFiltersContainer.ts"],"names":[],"mappings":"AAMA;;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","sourcesContent":["import {Type} from \"@tsed/core\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\n/**\n * @ignore\n */\nexport type ResponseFilterKey = \"*/*\" | \"application/json\" | \"text/html\" | \"plain/text\" | string;\n/**\n * @ignore\n */\n// tslint:disable-next-line:variable-name\nexport const ResponseFiltersContainer = new Map<ResponseFilterKey, Type<ResponseFilterMethods>>();\n/**\n * @ignore\n */\nexport function registerResponseFilter(type: ResponseFilterKey, token: Type<ResponseFilterMethods>) {\n ResponseFiltersContainer.set(type, token);\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { nameOf } from "@tsed/core";
|
|
2
|
+
import { InternalServerError } from "@tsed/exceptions";
|
|
3
|
+
/**
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
export class TemplateRenderError extends InternalServerError {
|
|
7
|
+
constructor(target, method, err) {
|
|
8
|
+
super(TemplateRenderError.buildMessage(target, method, err));
|
|
9
|
+
this.name = "TEMPLATE_RENDER_ERROR";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
static buildMessage(target, method, err) {
|
|
16
|
+
return `Template rendering error: ${nameOf(target)}.${String(method)}()\n` + err;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=TemplateRenderError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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","sourcesContent":["import {nameOf, Type} from \"@tsed/core\";\nimport {InternalServerError} from \"@tsed/exceptions\";\n\n/**\n * @private\n */\nexport class TemplateRenderError extends InternalServerError {\n name = \"TEMPLATE_RENDER_ERROR\";\n\n constructor(target: Type<any> | string, method: string | symbol, err: Error) {\n super(TemplateRenderError.buildMessage(target, method, err));\n }\n\n /**\n *\n * @returns {string}\n */\n static buildMessage(target: Type<any> | string, method: string | symbol, err: Error) {\n return `Template rendering error: ${nameOf(target)}.${String(method)}()\\n` + err;\n }\n}\n"]}
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by barrelsby.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./decorators/responseFilter.js";
|
|
5
|
+
export * from "./domain/ResponseFiltersContainer.js";
|
|
6
|
+
export * from "./errors/TemplateRenderError.js";
|
|
7
|
+
export * from "./interfaces/ResponseFilterMethods.js";
|
|
8
|
+
export * from "./services/PlatformResponseFilter.js";
|
|
9
|
+
export * from "./utils/getContentType.js";
|
|
10
|
+
export * from "./utils/renderView.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC","sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from \"./decorators/responseFilter\";\nexport * from \"./domain/ResponseFiltersContainer\";\nexport * from \"./errors/TemplateRenderError\";\nexport * from \"./interfaces/ResponseFilterMethods\";\nexport * from \"./services/PlatformResponseFilter\";\nexport * from \"./utils/getContentType\";\nexport * from \"./utils/renderView\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponseFilterMethods.js","sourceRoot":"","sources":["../../../src/interfaces/ResponseFilterMethods.ts"],"names":[],"mappings":"","sourcesContent":["import {Type} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\n\ndeclare global {\n namespace TsED {\n interface Configuration {\n /**\n * A list of response filters must be called before returning a response to the consumer. See more on [Response filters](/docs/response-filter.md).\n */\n responseFilters: Type<ResponseFilterMethods>[];\n }\n }\n}\n\nexport interface ResponseFilterMethods<T = unknown> {\n transform(data: T, ctx: BaseContext): any;\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { isSerializable } from "@tsed/core";
|
|
3
|
+
import { serialize } from "@tsed/json-mapper";
|
|
4
|
+
import { Constant, Inject, Injectable, InjectorService } from "@tsed/di";
|
|
5
|
+
import { ResponseFiltersContainer } from "../domain/ResponseFiltersContainer.js";
|
|
6
|
+
import { ANY_CONTENT_TYPE, getContentType } from "../utils/getContentType.js";
|
|
7
|
+
import { renderView } from "../utils/renderView.js";
|
|
8
|
+
/**
|
|
9
|
+
* @platform
|
|
10
|
+
*/
|
|
11
|
+
let PlatformResponseFilter = class PlatformResponseFilter {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.types = new Map();
|
|
14
|
+
}
|
|
15
|
+
get contentTypes() {
|
|
16
|
+
return [...this.types.keys()];
|
|
17
|
+
}
|
|
18
|
+
$onInit() {
|
|
19
|
+
ResponseFiltersContainer.forEach((token, type) => {
|
|
20
|
+
if (this.responseFilters.includes(token)) {
|
|
21
|
+
this.types.set(type, this.injector.get(token));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
getBestContentType(data, ctx) {
|
|
26
|
+
const contentType = getContentType(data, ctx);
|
|
27
|
+
if (ctx.request.get("Accept")) {
|
|
28
|
+
const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));
|
|
29
|
+
if (bestContentType) {
|
|
30
|
+
return [].concat(bestContentType).filter((type) => type !== "*/*")[0];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return contentType;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Call filters to transform data
|
|
37
|
+
* @param data
|
|
38
|
+
* @param ctx
|
|
39
|
+
*/
|
|
40
|
+
async transform(data, ctx) {
|
|
41
|
+
const { response } = ctx;
|
|
42
|
+
const bestContentType = this.getBestContentType(data, ctx);
|
|
43
|
+
bestContentType && response.contentType(bestContentType);
|
|
44
|
+
if (this.types.has(bestContentType)) {
|
|
45
|
+
return this.types.get(bestContentType).transform(data, ctx);
|
|
46
|
+
}
|
|
47
|
+
if (this.types.has(ANY_CONTENT_TYPE)) {
|
|
48
|
+
return this.types.get(ANY_CONTENT_TYPE).transform(data, ctx);
|
|
49
|
+
}
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Serialize data before calling filters
|
|
54
|
+
* @param data
|
|
55
|
+
* @param ctx
|
|
56
|
+
*/
|
|
57
|
+
async serialize(data, ctx) {
|
|
58
|
+
const { response, endpoint } = ctx;
|
|
59
|
+
if (endpoint) {
|
|
60
|
+
if (endpoint.view) {
|
|
61
|
+
data = await renderView(data, ctx);
|
|
62
|
+
}
|
|
63
|
+
else if (isSerializable(data)) {
|
|
64
|
+
data = serialize(data, {
|
|
65
|
+
useAlias: true,
|
|
66
|
+
additionalProperties: this.additionalProperties,
|
|
67
|
+
...endpoint.getResponseOptions(response.statusCode),
|
|
68
|
+
endpoint: true
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return data;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
__decorate([
|
|
76
|
+
Inject(),
|
|
77
|
+
__metadata("design:type", InjectorService)
|
|
78
|
+
], PlatformResponseFilter.prototype, "injector", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
Constant("responseFilters", []),
|
|
81
|
+
__metadata("design:type", Array)
|
|
82
|
+
], PlatformResponseFilter.prototype, "responseFilters", void 0);
|
|
83
|
+
__decorate([
|
|
84
|
+
Constant("additionalProperties"),
|
|
85
|
+
__metadata("design:type", Boolean)
|
|
86
|
+
], PlatformResponseFilter.prototype, "additionalProperties", void 0);
|
|
87
|
+
PlatformResponseFilter = __decorate([
|
|
88
|
+
Injectable()
|
|
89
|
+
], PlatformResponseFilter);
|
|
90
|
+
export { PlatformResponseFilter };
|
|
91
|
+
//# sourceMappingURL=PlatformResponseFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlatformResponseFilter.js","sourceRoot":"","sources":["../../../src/services/PlatformResponseFilter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,cAAc,EAAO,MAAM,YAAY,CAAC;AAChD,OAAO,EAAC,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAc,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,UAAU,CAAC;AACpF,OAAO,EAAoB,wBAAwB,EAAC,MAAM,oCAAoC,CAAC;AAE/F,OAAO,EAAC,gBAAgB,EAAE,cAAc,EAAC,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAE/C;;GAEG;AAEH,IAAa,sBAAsB,GAAnC,MAAa,sBAAsB;IAAnC;QACY,UAAK,GAAkD,IAAI,GAAG,EAAE,CAAC;IAkF7E,CAAC;IAvEC,IAAI,YAAY;QACd,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,OAAO;QACL,wBAAwB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC/C,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;gBACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,CAAC;aACjD;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,IAAS,EAAE,GAAgB;QAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAE9C,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC7B,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAErG,IAAI,eAAe,EAAE;gBACnB,OAAO,EAAE,CAAC,MAAM,CAAC,eAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;aAC9E;SACF;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,IAAa,EAAE,GAAgB;QAC7C,MAAM,EAAC,QAAQ,EAAC,GAAG,GAAG,CAAC;QACvB,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAE3D,eAAe,IAAI,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAEzD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE;YACnC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;SAC9D;QAED,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE;YACpC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;SAC/D;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,IAAa,EAAE,GAAgB;QAC7C,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,GAAG,CAAC;QAEjC,IAAI,QAAQ,EAAE;YACZ,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACjB,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;aACpC;iBAAM,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE;gBAC/B,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE;oBACrB,QAAQ,EAAE,IAAI;oBACd,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;oBAC/C,GAAG,QAAQ,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC;oBACnD,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC;aACJ;SACF;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA/EC;IADC,MAAM,EAAE;8BACW,eAAe;wDAAC;AAGpC;IADC,QAAQ,CAAC,iBAAiB,EAAE,EAAE,CAAC;;+DACyB;AAGzD;IADC,QAAQ,CAAC,sBAAsB,CAAC;;oEACO;AAV7B,sBAAsB;IADlC,UAAU,EAAE;GACA,sBAAsB,CAmFlC;SAnFY,sBAAsB","sourcesContent":["import {isSerializable, Type} from \"@tsed/core\";\nimport {serialize} from \"@tsed/json-mapper\";\nimport {BaseContext, Constant, Inject, Injectable, InjectorService} from \"@tsed/di\";\nimport {ResponseFilterKey, ResponseFiltersContainer} from \"../domain/ResponseFiltersContainer\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\nimport {ANY_CONTENT_TYPE, getContentType} from \"../utils/getContentType\";\nimport {renderView} from \"../utils/renderView\";\n\n/**\n * @platform\n */\n@Injectable()\nexport class PlatformResponseFilter {\n protected types: Map<ResponseFilterKey, ResponseFilterMethods> = new Map();\n\n @Inject()\n protected injector: InjectorService;\n\n @Constant(\"responseFilters\", [])\n protected responseFilters: Type<ResponseFilterMethods>[];\n\n @Constant(\"additionalProperties\")\n protected additionalProperties: boolean;\n\n get contentTypes(): ResponseFilterKey[] {\n return [...this.types.keys()];\n }\n\n $onInit() {\n ResponseFiltersContainer.forEach((token, type) => {\n if (this.responseFilters.includes(token)) {\n this.types.set(type, this.injector.get(token)!);\n }\n });\n }\n\n getBestContentType(data: any, ctx: BaseContext) {\n const contentType = getContentType(data, ctx);\n\n if (ctx.request.get(\"Accept\")) {\n const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));\n\n if (bestContentType) {\n return [].concat(bestContentType as any).filter((type) => type !== \"*/*\")[0];\n }\n }\n\n return contentType;\n }\n\n /**\n * Call filters to transform data\n * @param data\n * @param ctx\n */\n async transform(data: unknown, ctx: BaseContext) {\n const {response} = ctx;\n const bestContentType = this.getBestContentType(data, ctx);\n\n bestContentType && response.contentType(bestContentType);\n\n if (this.types.has(bestContentType)) {\n return this.types.get(bestContentType)!.transform(data, ctx);\n }\n\n if (this.types.has(ANY_CONTENT_TYPE)) {\n return this.types.get(ANY_CONTENT_TYPE)!.transform(data, ctx);\n }\n\n return data;\n }\n\n /**\n * Serialize data before calling filters\n * @param data\n * @param ctx\n */\n async serialize(data: unknown, ctx: BaseContext) {\n const {response, endpoint} = ctx;\n\n if (endpoint) {\n if (endpoint.view) {\n data = await renderView(data, ctx);\n } else if (isSerializable(data)) {\n data = serialize(data, {\n useAlias: true,\n additionalProperties: this.additionalProperties,\n ...endpoint.getResponseOptions(response.statusCode),\n endpoint: true\n });\n }\n }\n\n return data;\n }\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isObject } from "@tsed/core";
|
|
2
|
+
export const ANY_CONTENT_TYPE = "*/*";
|
|
3
|
+
/**
|
|
4
|
+
* @ignore
|
|
5
|
+
*/
|
|
6
|
+
export function getContentType(data, ctx) {
|
|
7
|
+
const { endpoint, response } = ctx;
|
|
8
|
+
const { operation } = endpoint;
|
|
9
|
+
const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || "";
|
|
10
|
+
if (contentType && contentType !== ANY_CONTENT_TYPE) {
|
|
11
|
+
if (contentType === "application/json") {
|
|
12
|
+
if (isObject(data)) {
|
|
13
|
+
return contentType;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return contentType;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (typeof data === "string" && endpoint.view) {
|
|
21
|
+
return "text/html";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=getContentType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getContentType.js","sourceRoot":"","sources":["../../../src/utils/getContentType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AAEpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AACtC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAS,EAAE,GAAgB;IACxD,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,GAAG,CAAC;IACjC,MAAM,EAAC,SAAS,EAAC,GAAG,QAAQ,CAAC;IAE7B,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,EAAE,IAAI,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAEvG,IAAI,WAAW,IAAI,WAAW,KAAK,gBAAgB,EAAE;QACnD,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE;gBAClB,OAAO,WAAW,CAAC;aACpB;SACF;aAAM;YACL,OAAO,WAAW,CAAC;SACpB;KACF;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE;QAC7C,OAAO,WAAW,CAAC;KACpB;AACH,CAAC","sourcesContent":["import {isObject} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\nexport const ANY_CONTENT_TYPE = \"*/*\";\n/**\n * @ignore\n */\nexport function getContentType(data: any, ctx: BaseContext) {\n const {endpoint, response} = ctx;\n const {operation} = endpoint;\n\n const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || \"\";\n\n if (contentType && contentType !== ANY_CONTENT_TYPE) {\n if (contentType === \"application/json\") {\n if (isObject(data)) {\n return contentType;\n }\n } else {\n return contentType;\n }\n }\n\n if (typeof data === \"string\" && endpoint.view) {\n return \"text/html\";\n }\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TemplateRenderError } from "../errors/TemplateRenderError.js";
|
|
2
|
+
export async function renderView(data, $ctx) {
|
|
3
|
+
const { response, endpoint } = $ctx;
|
|
4
|
+
try {
|
|
5
|
+
const { data } = $ctx;
|
|
6
|
+
const { path, options } = endpoint.view;
|
|
7
|
+
return await response.render(path, { ...options, ...data, $ctx });
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
throw new TemplateRenderError(endpoint.targetName, endpoint.propertyKey, err);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=renderView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderView.js","sourceRoot":"","sources":["../../../src/utils/renderView.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,mBAAmB,EAAC,MAAM,+BAA+B,CAAC;AAElE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAS,EAAE,IAAiB;IAC3D,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAC,GAAG,IAAI,CAAC;IAClC,IAAI;QACF,MAAM,EAAC,IAAI,EAAC,GAAG,IAAI,CAAC;QACpB,MAAM,EAAC,IAAI,EAAE,OAAO,EAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;QAEtC,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAC,GAAG,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;KACjE;IAAC,OAAO,GAAG,EAAE;QACZ,MAAM,IAAI,mBAAmB,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;KAC/E;AACH,CAAC","sourcesContent":["import {BaseContext} from \"@tsed/di\";\nimport {TemplateRenderError} from \"../errors/TemplateRenderError\";\n\nexport async function renderView(data: any, $ctx: BaseContext) {\n const {response, endpoint} = $ctx;\n try {\n const {data} = $ctx;\n const {path, options} = endpoint.view;\n\n return await response.render(path, {...options, ...data, $ctx});\n } catch (err) {\n throw new TemplateRenderError(endpoint.targetName, endpoint.propertyKey, err);\n }\n}\n"]}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Type } from "@tsed/core";
|
|
2
|
+
import { InternalServerError } from "@tsed/exceptions";
|
|
3
|
+
/**
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
export declare class TemplateRenderError extends InternalServerError {
|
|
7
|
+
name: string;
|
|
8
|
+
constructor(target: Type<any> | string, method: string | symbol, err: Error);
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
static buildMessage(target: Type<any> | string, method: string | symbol, err: Error): string;
|
|
14
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by barrelsby.
|
|
3
|
+
*/
|
|
1
4
|
export * from "./decorators/responseFilter";
|
|
2
5
|
export * from "./domain/ResponseFiltersContainer";
|
|
6
|
+
export * from "./errors/TemplateRenderError";
|
|
3
7
|
export * from "./interfaces/ResponseFilterMethods";
|
|
4
8
|
export * from "./services/PlatformResponseFilter";
|
|
5
9
|
export * from "./utils/getContentType";
|
|
10
|
+
export * from "./utils/renderView";
|
|
File without changes
|
|
@@ -6,11 +6,23 @@ import { ResponseFilterMethods } from "../interfaces/ResponseFilterMethods";
|
|
|
6
6
|
* @platform
|
|
7
7
|
*/
|
|
8
8
|
export declare class PlatformResponseFilter {
|
|
9
|
-
types: Map<ResponseFilterKey, ResponseFilterMethods>;
|
|
10
|
-
injector: InjectorService;
|
|
9
|
+
protected types: Map<ResponseFilterKey, ResponseFilterMethods>;
|
|
10
|
+
protected injector: InjectorService;
|
|
11
11
|
protected responseFilters: Type<ResponseFilterMethods>[];
|
|
12
|
+
protected additionalProperties: boolean;
|
|
12
13
|
get contentTypes(): ResponseFilterKey[];
|
|
13
14
|
$onInit(): void;
|
|
14
15
|
getBestContentType(data: any, ctx: BaseContext): any;
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Call filters to transform data
|
|
18
|
+
* @param data
|
|
19
|
+
* @param ctx
|
|
20
|
+
*/
|
|
21
|
+
transform(data: unknown, ctx: BaseContext): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Serialize data before calling filters
|
|
24
|
+
* @param data
|
|
25
|
+
* @param ctx
|
|
26
|
+
*/
|
|
27
|
+
serialize(data: unknown, ctx: BaseContext): Promise<unknown>;
|
|
16
28
|
}
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,38 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsed/platform-response-filter",
|
|
3
|
-
"version": "7.0.0-
|
|
3
|
+
"version": "7.0.0-beta.10",
|
|
4
4
|
"description": "Platform response filter module for Ts.ED Framework",
|
|
5
5
|
"private": false,
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
|
-
"main": "./lib/index.js",
|
|
8
|
-
"
|
|
7
|
+
"main": "./lib/cjs/index.js",
|
|
8
|
+
"module": "./lib/esm/index.js",
|
|
9
|
+
"typings": "./lib/types/index.d.ts",
|
|
9
10
|
"exports": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
11
|
+
"types": "./lib/types/index.d.ts",
|
|
12
|
+
"import": "./lib/esm/index.js",
|
|
13
|
+
"require": "./lib/cjs/index.js",
|
|
14
|
+
"default": "./lib/esm/index.js"
|
|
12
15
|
},
|
|
13
16
|
"scripts": {
|
|
14
|
-
"build": "
|
|
17
|
+
"build": "yarn barrels && yarn run build:esm && yarn run build:cjs",
|
|
18
|
+
"build:cjs": "tsc --build tsconfig.compile.json",
|
|
19
|
+
"build:esm": "tsc --build tsconfig.compile.esm.json",
|
|
20
|
+
"barrels": "yarn barrelsby --delete -d ./src -e \"\\.spec\\.ts\" -e \"__mock__\" -e \".benchmark.ts\""
|
|
15
21
|
},
|
|
16
22
|
"dependencies": {
|
|
17
|
-
"tslib": "2.
|
|
23
|
+
"tslib": "2.3.1"
|
|
18
24
|
},
|
|
19
25
|
"devDependencies": {
|
|
20
|
-
"@tsed/core": "7.0.0-
|
|
21
|
-
"@tsed/di": "7.0.0-
|
|
22
|
-
"@tsed/exceptions": "7.0.0-
|
|
23
|
-
"@tsed/
|
|
26
|
+
"@tsed/core": "7.0.0-beta.10",
|
|
27
|
+
"@tsed/di": "7.0.0-beta.10",
|
|
28
|
+
"@tsed/exceptions": "7.0.0-beta.10",
|
|
29
|
+
"@tsed/json-mapper": "7.0.0-beta.10",
|
|
30
|
+
"@tsed/schema": "7.0.0-beta.10"
|
|
24
31
|
},
|
|
25
32
|
"peerDependencies": {
|
|
26
|
-
"@tsed/core": "^7.0.0-
|
|
27
|
-
"@tsed/di": "^7.0.0-
|
|
28
|
-
"@tsed/exceptions": "^7.0.0-
|
|
29
|
-
"@tsed/
|
|
33
|
+
"@tsed/core": "^7.0.0-beta.10",
|
|
34
|
+
"@tsed/di": "^7.0.0-beta.10",
|
|
35
|
+
"@tsed/exceptions": "^7.0.0-beta.10",
|
|
36
|
+
"@tsed/json-mapper": "^7.0.0-beta.10",
|
|
37
|
+
"@tsed/schema": "^7.0.0-beta.10"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"@tsed/core": {
|
|
41
|
+
"optional": false
|
|
42
|
+
},
|
|
43
|
+
"@tsed/di": {
|
|
44
|
+
"optional": false
|
|
45
|
+
},
|
|
46
|
+
"@tsed/exceptions": {
|
|
47
|
+
"optional": false
|
|
48
|
+
},
|
|
49
|
+
"@tsed/json-mapper": {
|
|
50
|
+
"optional": false
|
|
51
|
+
},
|
|
52
|
+
"@tsed/schema": {
|
|
53
|
+
"optional": false
|
|
54
|
+
}
|
|
30
55
|
},
|
|
31
56
|
"repository": "https://github.com/tsedio/tsed",
|
|
32
57
|
"bugs": {
|
|
33
58
|
"url": "https://github.com/tsedio/tsed/issues"
|
|
34
59
|
},
|
|
35
|
-
"homepage": "https://github.com/tsedio/tsed/tree/
|
|
60
|
+
"homepage": "https://github.com/tsedio/tsed/tree/beta/packages/platform/platform-response-filter",
|
|
36
61
|
"author": "Romain Lenzotti",
|
|
37
62
|
"license": "MIT"
|
|
38
63
|
}
|
package/readme.md
CHANGED
|
@@ -29,28 +29,137 @@
|
|
|
29
29
|
|
|
30
30
|
A package of Ts.ED framework. See website: https://tsed.io/
|
|
31
31
|
|
|
32
|
+
# Features
|
|
33
|
+
|
|
34
|
+
Transform data returned by a method to a formatted response based on the stored metadata.
|
|
35
|
+
|
|
32
36
|
# Installation
|
|
33
37
|
|
|
34
38
|
```bash
|
|
35
|
-
npm install --save @tsed/platform-response-filter
|
|
39
|
+
npm install --save @tsed/di @tsed/platform-views @tsed/schema @tsed/json-schema @tsed/platform-response-filter
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
Define a class that return data:
|
|
45
|
+
```typescript
|
|
46
|
+
import {Injectable} from "@tsed/di";
|
|
47
|
+
import {Returns} from "@tsed/schema";
|
|
48
|
+
import {MyModel} from "../models/MyModel";
|
|
49
|
+
|
|
50
|
+
@Injectable()
|
|
51
|
+
class MyService {
|
|
52
|
+
@Returns(200, MyModel)
|
|
53
|
+
async getData() {
|
|
54
|
+
return new MyModel({ id: "id", test: "test" })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Returns(200, MyModel)
|
|
58
|
+
@View("myview.ejs")
|
|
59
|
+
async getDataView() {
|
|
60
|
+
return new MyModel({ id: "id", test: "test" })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Add a response filter for a specific content-type:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import {ResponseFilter, Context, ResponseFilterMethods} from "@tsed/common";
|
|
69
|
+
|
|
70
|
+
@ResponseFilter("application/json")
|
|
71
|
+
export class WrapperResponseFilter implements ResponseFilterMethods {
|
|
72
|
+
transform(data: any, ctx: Context) {
|
|
73
|
+
return {data, errors: [], links: {}};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Then call the service in you module:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import {Module, DIContext} from "@tsed/di";
|
|
82
|
+
import {ResponseFilter} from "@tsed/platform-response-filter";
|
|
83
|
+
import "./filters/WrapperResponseFilter"
|
|
84
|
+
|
|
85
|
+
@Module()
|
|
86
|
+
class MyModule {
|
|
87
|
+
@Inject()
|
|
88
|
+
injector: InjectorService;
|
|
89
|
+
|
|
90
|
+
@Inject()
|
|
91
|
+
responseFilter: ResponseFilter;
|
|
92
|
+
|
|
93
|
+
async onRequest(req: any, res: any) {
|
|
94
|
+
const context = new DIContext({
|
|
95
|
+
id: uuid.v4(),
|
|
96
|
+
injector: this.injector,
|
|
97
|
+
logger: this.injector.logger
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// must implement these methods
|
|
101
|
+
context.request = {
|
|
102
|
+
accepts(...args: any[]) {
|
|
103
|
+
return req.accepts(...args)
|
|
104
|
+
},
|
|
105
|
+
get(key: string) {
|
|
106
|
+
return req.get(key)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
context.response = {
|
|
110
|
+
contentType(contentType: string) {
|
|
111
|
+
res.contentType(contentType)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const service = this.injector.get<MyService>(MyService);
|
|
116
|
+
let data = await service.getData()
|
|
117
|
+
|
|
118
|
+
// serialize data (map Model to Plain object)
|
|
119
|
+
data = await this.responseFilter.serialize(data, context);
|
|
120
|
+
|
|
121
|
+
// call filter based on the right content type
|
|
122
|
+
data = await this.responseFilter.transform(data, context)
|
|
123
|
+
|
|
124
|
+
if (isObject(data)) {
|
|
125
|
+
res.json(data)
|
|
126
|
+
} else {
|
|
127
|
+
res.send(data)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This example will call the getData() method, serialize the instance MyModel to a plain object then call the WrapperResponseFilter,
|
|
134
|
+
to produce the following response:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
{
|
|
138
|
+
"data": {
|
|
139
|
+
"id": "id",
|
|
140
|
+
"test": "test"
|
|
141
|
+
},
|
|
142
|
+
"error": [],
|
|
143
|
+
"links": {}
|
|
144
|
+
}
|
|
36
145
|
```
|
|
37
146
|
|
|
38
147
|
## Contributors
|
|
148
|
+
|
|
39
149
|
Please read [contributing guidelines here](https://tsed.io/CONTRIBUTING.html).
|
|
40
150
|
|
|
41
151
|
<a href="https://github.com/tsedio/ts-express-decorators/graphs/contributors"><img src="https://opencollective.com/tsed/contributors.svg?width=890" /></a>
|
|
42
152
|
|
|
43
|
-
|
|
44
153
|
## Backers
|
|
45
154
|
|
|
46
155
|
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/tsed#backer)]
|
|
47
156
|
|
|
48
157
|
<a href="https://opencollective.com/tsed#backers" target="_blank"><img src="https://opencollective.com/tsed/tiers/backer.svg?width=890"></a>
|
|
49
158
|
|
|
50
|
-
|
|
51
159
|
## Sponsors
|
|
52
160
|
|
|
53
|
-
Support this project by becoming a sponsor. Your logo will show up here with a link to your
|
|
161
|
+
Support this project by becoming a sponsor. Your logo will show up here with a link to your
|
|
162
|
+
website. [[Become a sponsor](https://opencollective.com/tsed#sponsor)]
|
|
54
163
|
|
|
55
164
|
## License
|
|
56
165
|
|
|
@@ -58,8 +167,15 @@ The MIT License (MIT)
|
|
|
58
167
|
|
|
59
168
|
Copyright (c) 2016 - 2018 Romain Lenzotti
|
|
60
169
|
|
|
61
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
170
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
171
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
172
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
173
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
62
174
|
|
|
63
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
175
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
176
|
+
Software.
|
|
64
177
|
|
|
65
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
178
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
179
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
180
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
181
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.compile.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"module": "ES2020",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "./lib/esm",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"declarationDir": "./lib/types"
|
|
10
|
+
},
|
|
11
|
+
"exclude": ["node_modules", "test", "lib", "benchmark", "coverage", "spec", "**/*.benchmark.ts", "**/*.spec.ts", "keys", "jest.config.js"]
|
|
12
|
+
}
|
package/lib/index.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
var di = require('@tsed/di');
|
|
2
|
-
var tslib = require('tslib');
|
|
3
|
-
var core = require('@tsed/core');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @ignore
|
|
7
|
-
*/
|
|
8
|
-
// tslint:disable-next-line:variable-name
|
|
9
|
-
const ResponseFiltersContainer = new Map();
|
|
10
|
-
/**
|
|
11
|
-
* @ignore
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
function registerResponseFilter(type, token) {
|
|
15
|
-
ResponseFiltersContainer.set(type, token);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Register a response filter service.
|
|
20
|
-
* @param contentTypes
|
|
21
|
-
* @decorator
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
function ResponseFilter(...contentTypes) {
|
|
25
|
-
return target => {
|
|
26
|
-
contentTypes.forEach(contentType => {
|
|
27
|
-
registerResponseFilter(contentType, target);
|
|
28
|
-
});
|
|
29
|
-
di.registerProvider({
|
|
30
|
-
provide: target,
|
|
31
|
-
useClass: target
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const ANY_CONTENT_TYPE = "*/*";
|
|
37
|
-
/**
|
|
38
|
-
* @ignore
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
function getContentType(data, ctx) {
|
|
42
|
-
const {
|
|
43
|
-
endpoint,
|
|
44
|
-
response
|
|
45
|
-
} = ctx;
|
|
46
|
-
const {
|
|
47
|
-
operation
|
|
48
|
-
} = endpoint;
|
|
49
|
-
const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || "";
|
|
50
|
-
|
|
51
|
-
if (contentType && contentType !== ANY_CONTENT_TYPE) {
|
|
52
|
-
if (contentType === "application/json") {
|
|
53
|
-
if (core.isObject(data)) {
|
|
54
|
-
return contentType;
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
return contentType;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (typeof data === "string" && endpoint.view) {
|
|
62
|
-
return "text/html";
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @platform
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
exports.PlatformResponseFilter = class PlatformResponseFilter {
|
|
71
|
-
constructor() {
|
|
72
|
-
this.types = new Map();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get contentTypes() {
|
|
76
|
-
return [...this.types.keys()];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
$onInit() {
|
|
80
|
-
ResponseFiltersContainer.forEach((token, type) => {
|
|
81
|
-
if (this.responseFilters.includes(token)) {
|
|
82
|
-
this.types.set(type, this.injector.get(token));
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
getBestContentType(data, ctx) {
|
|
88
|
-
const contentType = getContentType(data, ctx);
|
|
89
|
-
|
|
90
|
-
if (ctx.request.get("Accept")) {
|
|
91
|
-
const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));
|
|
92
|
-
|
|
93
|
-
if (bestContentType) {
|
|
94
|
-
return [].concat(bestContentType).filter(type => type !== "*/*")[0];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return contentType;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
transform(data, ctx) {
|
|
102
|
-
const {
|
|
103
|
-
response
|
|
104
|
-
} = ctx;
|
|
105
|
-
const bestContentType = this.getBestContentType(data, ctx);
|
|
106
|
-
bestContentType && response.contentType(bestContentType);
|
|
107
|
-
|
|
108
|
-
if (this.types.has(bestContentType)) {
|
|
109
|
-
return this.types.get(bestContentType).transform(data, ctx);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (this.types.has(ANY_CONTENT_TYPE)) {
|
|
113
|
-
return this.types.get(ANY_CONTENT_TYPE).transform(data, ctx);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return data;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
tslib.__decorate([di.Inject(), tslib.__metadata("design:type", di.InjectorService)], exports.PlatformResponseFilter.prototype, "injector", void 0);
|
|
122
|
-
|
|
123
|
-
tslib.__decorate([di.Constant("responseFilters", []), tslib.__metadata("design:type", Array)], exports.PlatformResponseFilter.prototype, "responseFilters", void 0);
|
|
124
|
-
|
|
125
|
-
exports.PlatformResponseFilter = tslib.__decorate([di.Injectable()], exports.PlatformResponseFilter);
|
|
126
|
-
|
|
127
|
-
exports.ANY_CONTENT_TYPE = ANY_CONTENT_TYPE;
|
|
128
|
-
exports.ResponseFilter = ResponseFilter;
|
|
129
|
-
exports.ResponseFiltersContainer = ResponseFiltersContainer;
|
|
130
|
-
exports.getContentType = getContentType;
|
|
131
|
-
exports.registerResponseFilter = registerResponseFilter;
|
|
132
|
-
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/domain/ResponseFiltersContainer.ts","../src/decorators/responseFilter.ts","../src/utils/getContentType.ts","../src/services/PlatformResponseFilter.ts"],"sourcesContent":["import {Type} from \"@tsed/core\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\n/**\n * @ignore\n */\nexport type ResponseFilterKey = \"*/*\" | \"application/json\" | \"text/html\" | \"plain/text\" | string;\n/**\n * @ignore\n */\n// tslint:disable-next-line:variable-name\nexport const ResponseFiltersContainer = new Map<ResponseFilterKey, Type<ResponseFilterMethods>>();\n/**\n * @ignore\n */\nexport function registerResponseFilter(type: ResponseFilterKey, token: Type<ResponseFilterMethods>) {\n ResponseFiltersContainer.set(type, token);\n}\n","import {Type} from \"@tsed/core\";\nimport {registerProvider} from \"@tsed/di\";\nimport {registerResponseFilter, ResponseFilterKey} from \"../domain/ResponseFiltersContainer\";\n\n/**\n * Register a response filter service.\n * @param contentTypes\n * @decorator\n */\nexport function ResponseFilter(...contentTypes: ResponseFilterKey[]): ClassDecorator {\n return <T = any>(target: T): void | T => {\n contentTypes.forEach((contentType) => {\n registerResponseFilter(contentType, target as any);\n });\n registerProvider({\n provide: target,\n useClass: (target as unknown) as Type<any>\n });\n };\n}\n","import {isObject} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\nexport const ANY_CONTENT_TYPE = \"*/*\";\n/**\n * @ignore\n */\nexport function getContentType(data: any, ctx: BaseContext) {\n const {endpoint, response} = ctx;\n const {operation} = endpoint;\n\n const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || \"\";\n\n if (contentType && contentType !== ANY_CONTENT_TYPE) {\n if (contentType === \"application/json\") {\n if (isObject(data)) {\n return contentType;\n }\n } else {\n return contentType;\n }\n }\n\n if (typeof data === \"string\" && endpoint.view) {\n return \"text/html\";\n }\n}\n","import {Type} from \"@tsed/core\";\nimport {BaseContext, Constant, Inject, Injectable, InjectorService} from \"@tsed/di\";\nimport {ResponseFilterKey, ResponseFiltersContainer} from \"../domain/ResponseFiltersContainer\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\nimport {ANY_CONTENT_TYPE, getContentType} from \"../utils/getContentType\";\n\n/**\n * @platform\n */\n@Injectable()\nexport class PlatformResponseFilter {\n types: Map<ResponseFilterKey, ResponseFilterMethods> = new Map();\n\n @Inject()\n injector: InjectorService;\n\n @Constant(\"responseFilters\", [])\n protected responseFilters: Type<ResponseFilterMethods>[];\n\n get contentTypes(): ResponseFilterKey[] {\n return [...this.types.keys()];\n }\n\n $onInit() {\n ResponseFiltersContainer.forEach((token, type) => {\n if (this.responseFilters.includes(token)) {\n this.types.set(type, this.injector.get(token)!);\n }\n });\n }\n\n getBestContentType(data: any, ctx: BaseContext) {\n const contentType = getContentType(data, ctx);\n\n if (ctx.request.get(\"Accept\")) {\n const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));\n\n if (bestContentType) {\n return [].concat(bestContentType as any).filter((type) => type !== \"*/*\")[0];\n }\n }\n\n return contentType;\n }\n\n transform(data: unknown, ctx: BaseContext) {\n const {response} = ctx;\n const bestContentType = this.getBestContentType(data, ctx);\n\n bestContentType && response.contentType(bestContentType);\n\n if (this.types.has(bestContentType)) {\n return this.types.get(bestContentType)!.transform(data, ctx);\n }\n\n if (this.types.has(ANY_CONTENT_TYPE)) {\n return this.types.get(ANY_CONTENT_TYPE)!.transform(data, ctx);\n }\n\n return data;\n }\n}\n"],"names":["ResponseFiltersContainer","Map","registerResponseFilter","type","token","set","ResponseFilter","contentTypes","target","forEach","contentType","registerProvider","provide","useClass","ANY_CONTENT_TYPE","getContentType","data","ctx","endpoint","response","operation","getContentTypeOf","statusCode","isObject","view","PlatformResponseFilter","constructor","types","keys","$onInit","responseFilters","includes","injector","get","getBestContentType","request","bestContentType","accepts","concat","filter","Boolean","transform","has","__decorate","Inject","InjectorService","Constant","Injectable"],"mappings":"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"}
|
package/lib/index.modern.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { registerProvider, Inject, InjectorService, Constant, Injectable } from '@tsed/di';
|
|
2
|
-
import { __decorate, __metadata } from 'tslib';
|
|
3
|
-
import { isObject } from '@tsed/core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @ignore
|
|
7
|
-
*/
|
|
8
|
-
// tslint:disable-next-line:variable-name
|
|
9
|
-
const ResponseFiltersContainer = new Map();
|
|
10
|
-
/**
|
|
11
|
-
* @ignore
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
function registerResponseFilter(type, token) {
|
|
15
|
-
ResponseFiltersContainer.set(type, token);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Register a response filter service.
|
|
20
|
-
* @param contentTypes
|
|
21
|
-
* @decorator
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
function ResponseFilter(...contentTypes) {
|
|
25
|
-
return target => {
|
|
26
|
-
contentTypes.forEach(contentType => {
|
|
27
|
-
registerResponseFilter(contentType, target);
|
|
28
|
-
});
|
|
29
|
-
registerProvider({
|
|
30
|
-
provide: target,
|
|
31
|
-
useClass: target
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const ANY_CONTENT_TYPE = "*/*";
|
|
37
|
-
/**
|
|
38
|
-
* @ignore
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
function getContentType(data, ctx) {
|
|
42
|
-
const {
|
|
43
|
-
endpoint,
|
|
44
|
-
response
|
|
45
|
-
} = ctx;
|
|
46
|
-
const {
|
|
47
|
-
operation
|
|
48
|
-
} = endpoint;
|
|
49
|
-
const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || "";
|
|
50
|
-
|
|
51
|
-
if (contentType && contentType !== ANY_CONTENT_TYPE) {
|
|
52
|
-
if (contentType === "application/json") {
|
|
53
|
-
if (isObject(data)) {
|
|
54
|
-
return contentType;
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
return contentType;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (typeof data === "string" && endpoint.view) {
|
|
62
|
-
return "text/html";
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @platform
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
let PlatformResponseFilter = class PlatformResponseFilter {
|
|
71
|
-
constructor() {
|
|
72
|
-
this.types = new Map();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get contentTypes() {
|
|
76
|
-
return [...this.types.keys()];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
$onInit() {
|
|
80
|
-
ResponseFiltersContainer.forEach((token, type) => {
|
|
81
|
-
if (this.responseFilters.includes(token)) {
|
|
82
|
-
this.types.set(type, this.injector.get(token));
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
getBestContentType(data, ctx) {
|
|
88
|
-
const contentType = getContentType(data, ctx);
|
|
89
|
-
|
|
90
|
-
if (ctx.request.get("Accept")) {
|
|
91
|
-
const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));
|
|
92
|
-
|
|
93
|
-
if (bestContentType) {
|
|
94
|
-
return [].concat(bestContentType).filter(type => type !== "*/*")[0];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return contentType;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
transform(data, ctx) {
|
|
102
|
-
const {
|
|
103
|
-
response
|
|
104
|
-
} = ctx;
|
|
105
|
-
const bestContentType = this.getBestContentType(data, ctx);
|
|
106
|
-
bestContentType && response.contentType(bestContentType);
|
|
107
|
-
|
|
108
|
-
if (this.types.has(bestContentType)) {
|
|
109
|
-
return this.types.get(bestContentType).transform(data, ctx);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (this.types.has(ANY_CONTENT_TYPE)) {
|
|
113
|
-
return this.types.get(ANY_CONTENT_TYPE).transform(data, ctx);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return data;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
__decorate([Inject(), __metadata("design:type", InjectorService)], PlatformResponseFilter.prototype, "injector", void 0);
|
|
122
|
-
|
|
123
|
-
__decorate([Constant("responseFilters", []), __metadata("design:type", Array)], PlatformResponseFilter.prototype, "responseFilters", void 0);
|
|
124
|
-
|
|
125
|
-
PlatformResponseFilter = __decorate([Injectable()], PlatformResponseFilter);
|
|
126
|
-
|
|
127
|
-
export { ANY_CONTENT_TYPE, PlatformResponseFilter, ResponseFilter, ResponseFiltersContainer, getContentType, registerResponseFilter };
|
|
128
|
-
//# sourceMappingURL=index.modern.js.map
|
package/lib/index.modern.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.modern.js","sources":["../src/domain/ResponseFiltersContainer.ts","../src/decorators/responseFilter.ts","../src/utils/getContentType.ts","../src/services/PlatformResponseFilter.ts"],"sourcesContent":["import {Type} from \"@tsed/core\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\n/**\n * @ignore\n */\nexport type ResponseFilterKey = \"*/*\" | \"application/json\" | \"text/html\" | \"plain/text\" | string;\n/**\n * @ignore\n */\n// tslint:disable-next-line:variable-name\nexport const ResponseFiltersContainer = new Map<ResponseFilterKey, Type<ResponseFilterMethods>>();\n/**\n * @ignore\n */\nexport function registerResponseFilter(type: ResponseFilterKey, token: Type<ResponseFilterMethods>) {\n ResponseFiltersContainer.set(type, token);\n}\n","import {Type} from \"@tsed/core\";\nimport {registerProvider} from \"@tsed/di\";\nimport {registerResponseFilter, ResponseFilterKey} from \"../domain/ResponseFiltersContainer\";\n\n/**\n * Register a response filter service.\n * @param contentTypes\n * @decorator\n */\nexport function ResponseFilter(...contentTypes: ResponseFilterKey[]): ClassDecorator {\n return <T = any>(target: T): void | T => {\n contentTypes.forEach((contentType) => {\n registerResponseFilter(contentType, target as any);\n });\n registerProvider({\n provide: target,\n useClass: (target as unknown) as Type<any>\n });\n };\n}\n","import {isObject} from \"@tsed/core\";\nimport type {BaseContext} from \"@tsed/di\";\nexport const ANY_CONTENT_TYPE = \"*/*\";\n/**\n * @ignore\n */\nexport function getContentType(data: any, ctx: BaseContext) {\n const {endpoint, response} = ctx;\n const {operation} = endpoint;\n\n const contentType = response.getContentType() || operation.getContentTypeOf(response.statusCode) || \"\";\n\n if (contentType && contentType !== ANY_CONTENT_TYPE) {\n if (contentType === \"application/json\") {\n if (isObject(data)) {\n return contentType;\n }\n } else {\n return contentType;\n }\n }\n\n if (typeof data === \"string\" && endpoint.view) {\n return \"text/html\";\n }\n}\n","import {Type} from \"@tsed/core\";\nimport {BaseContext, Constant, Inject, Injectable, InjectorService} from \"@tsed/di\";\nimport {ResponseFilterKey, ResponseFiltersContainer} from \"../domain/ResponseFiltersContainer\";\nimport {ResponseFilterMethods} from \"../interfaces/ResponseFilterMethods\";\nimport {ANY_CONTENT_TYPE, getContentType} from \"../utils/getContentType\";\n\n/**\n * @platform\n */\n@Injectable()\nexport class PlatformResponseFilter {\n types: Map<ResponseFilterKey, ResponseFilterMethods> = new Map();\n\n @Inject()\n injector: InjectorService;\n\n @Constant(\"responseFilters\", [])\n protected responseFilters: Type<ResponseFilterMethods>[];\n\n get contentTypes(): ResponseFilterKey[] {\n return [...this.types.keys()];\n }\n\n $onInit() {\n ResponseFiltersContainer.forEach((token, type) => {\n if (this.responseFilters.includes(token)) {\n this.types.set(type, this.injector.get(token)!);\n }\n });\n }\n\n getBestContentType(data: any, ctx: BaseContext) {\n const contentType = getContentType(data, ctx);\n\n if (ctx.request.get(\"Accept\")) {\n const bestContentType = ctx.request.accepts([contentType].concat(this.contentTypes).filter(Boolean));\n\n if (bestContentType) {\n return [].concat(bestContentType as any).filter((type) => type !== \"*/*\")[0];\n }\n }\n\n return contentType;\n }\n\n transform(data: unknown, ctx: BaseContext) {\n const {response} = ctx;\n const bestContentType = this.getBestContentType(data, ctx);\n\n bestContentType && response.contentType(bestContentType);\n\n if (this.types.has(bestContentType)) {\n return this.types.get(bestContentType)!.transform(data, ctx);\n }\n\n if (this.types.has(ANY_CONTENT_TYPE)) {\n return this.types.get(ANY_CONTENT_TYPE)!.transform(data, ctx);\n }\n\n return data;\n }\n}\n"],"names":["ResponseFiltersContainer","Map","registerResponseFilter","type","token","set","ResponseFilter","contentTypes","target","forEach","contentType","registerProvider","provide","useClass","ANY_CONTENT_TYPE","getContentType","data","ctx","endpoint","response","operation","getContentTypeOf","statusCode","isObject","view","PlatformResponseFilter","constructor","types","keys","$onInit","responseFilters","includes","injector","get","getBestContentType","request","bestContentType","accepts","concat","filter","Boolean","transform","has","__decorate","Inject","InjectorService","Constant","Injectable"],"mappings":";;;;AAMA;;;AAGA;MACaA,wBAAwB,GAAG,IAAIC,GAAJ;AACxC;;;;SAGgBC,uBAAuBC,MAAyBC;AAC9DJ,EAAAA,wBAAwB,CAACK,GAAzB,CAA6BF,IAA7B,EAAmCC,KAAnC;AACD;;ACZD;;;;;;SAKgBE,eAAe,GAAGC;AAChC,SAAiBC,MAAV;AACLD,IAAAA,YAAY,CAACE,OAAb,CAAsBC,WAAD;AACnBR,MAAAA,sBAAsB,CAACQ,WAAD,EAAcF,MAAd,CAAtB;AACD,KAFD;AAGAG,IAAAA,gBAAgB,CAAC;AACfC,MAAAA,OAAO,EAAEJ,MADM;AAEfK,MAAAA,QAAQ,EAAGL;AAFI,KAAD,CAAhB;AAID,GARD;AASD;;MCjBYM,gBAAgB,GAAG;AAChC;;;;SAGgBC,eAAeC,MAAWC;AACxC,QAAM;AAACC,IAAAA,QAAD;AAAWC,IAAAA;AAAX,MAAuBF,GAA7B;AACA,QAAM;AAACG,IAAAA;AAAD,MAAcF,QAApB;AAEA,QAAMR,WAAW,GAAGS,QAAQ,CAACJ,cAAT,MAA6BK,SAAS,CAACC,gBAAV,CAA2BF,QAAQ,CAACG,UAApC,CAA7B,IAAgF,EAApG;;AAEA,MAAIZ,WAAW,IAAIA,WAAW,KAAKI,gBAAnC,EAAqD;AACnD,QAAIJ,WAAW,KAAK,kBAApB,EAAwC;AACtC,UAAIa,QAAQ,CAACP,IAAD,CAAZ,EAAoB;AAClB,eAAON,WAAP;AACD;AACF,KAJD,MAIO;AACL,aAAOA,WAAP;AACD;AACF;;AAED,MAAI,OAAOM,IAAP,KAAgB,QAAhB,IAA4BE,QAAQ,CAACM,IAAzC,EAA+C;AAC7C,WAAO,WAAP;AACD;AACF;;ACnBD;;;;IAIaC,sBAAsB,GAAnC,MAAaA,sBAAb;AAAAC,EAAAA;AACE,cAAA,GAAuD,IAAIzB,GAAJ,EAAvD;AAkDD;;AA1CiB,MAAZM,YAAY;AACd,WAAO,CAAC,GAAG,KAAKoB,KAAL,CAAWC,IAAX,EAAJ,CAAP;AACD;;AAEDC,EAAAA,OAAO;AACL7B,IAAAA,wBAAwB,CAACS,OAAzB,CAAiC,CAACL,KAAD,EAAQD,IAAR;AAC/B,UAAI,KAAK2B,eAAL,CAAqBC,QAArB,CAA8B3B,KAA9B,CAAJ,EAA0C;AACxC,aAAKuB,KAAL,CAAWtB,GAAX,CAAeF,IAAf,EAAqB,KAAK6B,QAAL,CAAcC,GAAd,CAAkB7B,KAAlB,CAArB;AACD;AACF,KAJD;AAKD;;AAED8B,EAAAA,kBAAkB,CAAClB,IAAD,EAAYC,GAAZ;AAChB,UAAMP,WAAW,GAAGK,cAAc,CAACC,IAAD,EAAOC,GAAP,CAAlC;;AAEA,QAAIA,GAAG,CAACkB,OAAJ,CAAYF,GAAZ,CAAgB,QAAhB,CAAJ,EAA+B;AAC7B,YAAMG,eAAe,GAAGnB,GAAG,CAACkB,OAAJ,CAAYE,OAAZ,CAAoB,CAAC3B,WAAD,EAAc4B,MAAd,CAAqB,KAAK/B,YAA1B,EAAwCgC,MAAxC,CAA+CC,OAA/C,CAApB,CAAxB;;AAEA,UAAIJ,eAAJ,EAAqB;AACnB,eAAO,GAAGE,MAAH,CAAUF,eAAV,EAAkCG,MAAlC,CAA0CpC,IAAD,IAAUA,IAAI,KAAK,KAA5D,EAAmE,CAAnE,CAAP;AACD;AACF;;AAED,WAAOO,WAAP;AACD;;AAED+B,EAAAA,SAAS,CAACzB,IAAD,EAAgBC,GAAhB;AACP,UAAM;AAACE,MAAAA;AAAD,QAAaF,GAAnB;AACA,UAAMmB,eAAe,GAAG,KAAKF,kBAAL,CAAwBlB,IAAxB,EAA8BC,GAA9B,CAAxB;AAEAmB,IAAAA,eAAe,IAAIjB,QAAQ,CAACT,WAAT,CAAqB0B,eAArB,CAAnB;;AAEA,QAAI,KAAKT,KAAL,CAAWe,GAAX,CAAeN,eAAf,CAAJ,EAAqC;AACnC,aAAO,KAAKT,KAAL,CAAWM,GAAX,CAAeG,eAAf,EAAiCK,SAAjC,CAA2CzB,IAA3C,EAAiDC,GAAjD,CAAP;AACD;;AAED,QAAI,KAAKU,KAAL,CAAWe,GAAX,CAAe5B,gBAAf,CAAJ,EAAsC;AACpC,aAAO,KAAKa,KAAL,CAAWM,GAAX,CAAenB,gBAAf,EAAkC2B,SAAlC,CAA4CzB,IAA5C,EAAkDC,GAAlD,CAAP;AACD;;AAED,WAAOD,IAAP;AACD;;;;AA9CD2B,YADCC,MAAM,8BACGC,wEAAV;;AAGAF,YADCG,QAAQ,CAAC,iBAAD,EAAoB,EAApB,kGACT;;AAPWrB,sBAAsB,eADlCsB,UAAU,KACEtB,uBAAA;;;;"}
|