@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.
Files changed (49) hide show
  1. package/lib/cjs/decorators/responseFilter.js +23 -0
  2. package/lib/cjs/decorators/responseFilter.js.map +1 -0
  3. package/lib/cjs/domain/ResponseFiltersContainer.js +16 -0
  4. package/lib/cjs/domain/ResponseFiltersContainer.js.map +1 -0
  5. package/lib/cjs/errors/TemplateRenderError.js +23 -0
  6. package/lib/cjs/errors/TemplateRenderError.js.map +1 -0
  7. package/lib/cjs/index.js +14 -0
  8. package/lib/cjs/index.js.map +1 -0
  9. package/lib/cjs/interfaces/ResponseFilterMethods.js +3 -0
  10. package/lib/cjs/interfaces/ResponseFilterMethods.js.map +1 -0
  11. package/lib/cjs/package.json +3 -0
  12. package/lib/cjs/services/PlatformResponseFilter.js +94 -0
  13. package/lib/cjs/services/PlatformResponseFilter.js.map +1 -0
  14. package/lib/cjs/utils/getContentType.js +28 -0
  15. package/lib/cjs/utils/getContentType.js.map +1 -0
  16. package/lib/cjs/utils/renderView.js +17 -0
  17. package/lib/cjs/utils/renderView.js.map +1 -0
  18. package/lib/esm/decorators/responseFilter.js +19 -0
  19. package/lib/esm/decorators/responseFilter.js.map +1 -0
  20. package/lib/esm/domain/ResponseFiltersContainer.js +12 -0
  21. package/lib/esm/domain/ResponseFiltersContainer.js.map +1 -0
  22. package/lib/esm/errors/TemplateRenderError.js +19 -0
  23. package/lib/esm/errors/TemplateRenderError.js.map +1 -0
  24. package/lib/esm/index.js +11 -0
  25. package/lib/esm/index.js.map +1 -0
  26. package/lib/esm/interfaces/ResponseFilterMethods.js +2 -0
  27. package/lib/esm/interfaces/ResponseFilterMethods.js.map +1 -0
  28. package/lib/esm/package.json +3 -0
  29. package/lib/esm/services/PlatformResponseFilter.js +91 -0
  30. package/lib/esm/services/PlatformResponseFilter.js.map +1 -0
  31. package/lib/esm/utils/getContentType.js +24 -0
  32. package/lib/esm/utils/getContentType.js.map +1 -0
  33. package/lib/esm/utils/renderView.js +13 -0
  34. package/lib/esm/utils/renderView.js.map +1 -0
  35. package/lib/{decorators → types/decorators}/responseFilter.d.ts +0 -0
  36. package/lib/{domain → types/domain}/ResponseFiltersContainer.d.ts +0 -0
  37. package/lib/types/errors/TemplateRenderError.d.ts +14 -0
  38. package/lib/{index.d.ts → types/index.d.ts} +5 -0
  39. package/lib/{interfaces → types/interfaces}/ResponseFilterMethods.d.ts +0 -0
  40. package/lib/{services → types/services}/PlatformResponseFilter.d.ts +15 -3
  41. package/lib/{utils → types/utils}/getContentType.d.ts +0 -0
  42. package/lib/types/utils/renderView.d.ts +2 -0
  43. package/package.json +41 -16
  44. package/readme.md +123 -7
  45. package/tsconfig.compile.esm.json +12 -0
  46. package/lib/index.js +0 -132
  47. package/lib/index.js.map +0 -1
  48. package/lib/index.modern.js +0 -128
  49. 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"]}
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ResponseFilterMethods.js.map
@@ -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,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -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"]}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ResponseFilterMethods.js.map
@@ -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,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -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":"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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,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"]}
@@ -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";
@@ -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
- transform(data: unknown, ctx: BaseContext): any;
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
@@ -0,0 +1,2 @@
1
+ import { BaseContext } from "@tsed/di";
2
+ export declare function renderView(data: any, $ctx: BaseContext): Promise<any>;
package/package.json CHANGED
@@ -1,38 +1,63 @@
1
1
  {
2
2
  "name": "@tsed/platform-response-filter",
3
- "version": "7.0.0-alpha.1",
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
- "typings": "./lib/index.d.ts",
7
+ "main": "./lib/cjs/index.js",
8
+ "module": "./lib/esm/index.js",
9
+ "typings": "./lib/types/index.d.ts",
9
10
  "exports": {
10
- "require": "./lib/index.js",
11
- "default": "./lib/index.modern.js"
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": "microbundle --target node --no-compress --format modern,cjs --tsconfig ./tsconfig.compile.json"
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.2.0"
23
+ "tslib": "2.3.1"
18
24
  },
19
25
  "devDependencies": {
20
- "@tsed/core": "7.0.0-alpha.1",
21
- "@tsed/di": "7.0.0-alpha.1",
22
- "@tsed/exceptions": "7.0.0-alpha.1",
23
- "@tsed/schema": "7.0.0-alpha.1"
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-alpha.1",
27
- "@tsed/di": "^7.0.0-alpha.1",
28
- "@tsed/exceptions": "^7.0.0-alpha.1",
29
- "@tsed/schema": "^7.0.0-alpha.1"
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/alpha/packages/platform/platform-response-filter",
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 website. [[Become a sponsor](https://opencollective.com/tsed#sponsor)]
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 documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
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 Software.
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 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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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"}
@@ -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
@@ -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":"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"}