@deepkit/http 1.0.1-alpha.100

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 (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/dist/.gitkeep +0 -0
  4. package/dist/cjs/index.d.ts +14 -0
  5. package/dist/cjs/index.js +31 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/src/controllers.d.ts +13 -0
  8. package/dist/cjs/src/controllers.js +17 -0
  9. package/dist/cjs/src/controllers.js.map +1 -0
  10. package/dist/cjs/src/decorator.d.ts +241 -0
  11. package/dist/cjs/src/decorator.js +422 -0
  12. package/dist/cjs/src/decorator.js.map +1 -0
  13. package/dist/cjs/src/filter.d.ts +49 -0
  14. package/dist/cjs/src/filter.js +215 -0
  15. package/dist/cjs/src/filter.js.map +1 -0
  16. package/dist/cjs/src/http-app.d.ts +8 -0
  17. package/dist/cjs/src/http-app.js +16 -0
  18. package/dist/cjs/src/http-app.js.map +1 -0
  19. package/dist/cjs/src/http.d.ts +278 -0
  20. package/dist/cjs/src/http.js +878 -0
  21. package/dist/cjs/src/http.js.map +1 -0
  22. package/dist/cjs/src/kernel.d.ts +16 -0
  23. package/dist/cjs/src/kernel.js +79 -0
  24. package/dist/cjs/src/kernel.js.map +1 -0
  25. package/dist/cjs/src/logger.d.ts +7 -0
  26. package/dist/cjs/src/logger.js +34 -0
  27. package/dist/cjs/src/logger.js.map +1 -0
  28. package/dist/cjs/src/middleware.d.ts +61 -0
  29. package/dist/cjs/src/middleware.js +95 -0
  30. package/dist/cjs/src/middleware.js.map +1 -0
  31. package/dist/cjs/src/model.d.ts +165 -0
  32. package/dist/cjs/src/model.js +398 -0
  33. package/dist/cjs/src/model.js.map +1 -0
  34. package/dist/cjs/src/module.config.d.ts +84 -0
  35. package/dist/cjs/src/module.config.js +14 -0
  36. package/dist/cjs/src/module.config.js.map +1 -0
  37. package/dist/cjs/src/module.d.ts +14 -0
  38. package/dist/cjs/src/module.js +124 -0
  39. package/dist/cjs/src/module.js.map +1 -0
  40. package/dist/cjs/src/request-parser.d.ts +36 -0
  41. package/dist/cjs/src/request-parser.js +305 -0
  42. package/dist/cjs/src/request-parser.js.map +1 -0
  43. package/dist/cjs/src/router.d.ts +230 -0
  44. package/dist/cjs/src/router.js +617 -0
  45. package/dist/cjs/src/router.js.map +1 -0
  46. package/dist/cjs/src/static-serving.d.ts +32 -0
  47. package/dist/cjs/src/static-serving.js +157 -0
  48. package/dist/cjs/src/static-serving.js.map +1 -0
  49. package/dist/cjs/src/utils.d.ts +1 -0
  50. package/dist/cjs/src/utils.js +13 -0
  51. package/dist/cjs/src/utils.js.map +1 -0
  52. package/dist/cjs/tsconfig.tsbuildinfo +1 -0
  53. package/dist/esm/index.d.ts +14 -0
  54. package/dist/esm/index.js +15 -0
  55. package/dist/esm/index.js.map +1 -0
  56. package/dist/esm/package.json +1 -0
  57. package/dist/esm/src/controllers.d.ts +13 -0
  58. package/dist/esm/src/controllers.js +13 -0
  59. package/dist/esm/src/controllers.js.map +1 -0
  60. package/dist/esm/src/decorator.d.ts +241 -0
  61. package/dist/esm/src/decorator.js +414 -0
  62. package/dist/esm/src/decorator.js.map +1 -0
  63. package/dist/esm/src/filter.d.ts +49 -0
  64. package/dist/esm/src/filter.js +209 -0
  65. package/dist/esm/src/filter.js.map +1 -0
  66. package/dist/esm/src/http-app.d.ts +8 -0
  67. package/dist/esm/src/http-app.js +12 -0
  68. package/dist/esm/src/http-app.js.map +1 -0
  69. package/dist/esm/src/http.d.ts +278 -0
  70. package/dist/esm/src/http.js +841 -0
  71. package/dist/esm/src/http.js.map +1 -0
  72. package/dist/esm/src/kernel.d.ts +16 -0
  73. package/dist/esm/src/kernel.js +75 -0
  74. package/dist/esm/src/kernel.js.map +1 -0
  75. package/dist/esm/src/logger.d.ts +7 -0
  76. package/dist/esm/src/logger.js +30 -0
  77. package/dist/esm/src/logger.js.map +1 -0
  78. package/dist/esm/src/middleware.d.ts +61 -0
  79. package/dist/esm/src/middleware.js +90 -0
  80. package/dist/esm/src/middleware.js.map +1 -0
  81. package/dist/esm/src/model.d.ts +165 -0
  82. package/dist/esm/src/model.js +363 -0
  83. package/dist/esm/src/model.js.map +1 -0
  84. package/dist/esm/src/module.config.d.ts +84 -0
  85. package/dist/esm/src/module.config.js +10 -0
  86. package/dist/esm/src/module.config.js.map +1 -0
  87. package/dist/esm/src/module.d.ts +14 -0
  88. package/dist/esm/src/module.js +120 -0
  89. package/dist/esm/src/module.js.map +1 -0
  90. package/dist/esm/src/request-parser.d.ts +36 -0
  91. package/dist/esm/src/request-parser.js +295 -0
  92. package/dist/esm/src/request-parser.js.map +1 -0
  93. package/dist/esm/src/router.d.ts +230 -0
  94. package/dist/esm/src/router.js +605 -0
  95. package/dist/esm/src/router.js.map +1 -0
  96. package/dist/esm/src/static-serving.d.ts +32 -0
  97. package/dist/esm/src/static-serving.js +149 -0
  98. package/dist/esm/src/static-serving.js.map +1 -0
  99. package/dist/esm/src/utils.d.ts +1 -0
  100. package/dist/esm/src/utils.js +9 -0
  101. package/dist/esm/src/utils.js.map +1 -0
  102. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
  103. package/index.ts +14 -0
  104. package/package.json +67 -0
  105. package/src/controllers.ts +11 -0
  106. package/src/decorator.ts +411 -0
  107. package/src/filter.ts +224 -0
  108. package/src/http-app.ts +11 -0
  109. package/src/http.ts +828 -0
  110. package/src/kernel.ts +79 -0
  111. package/src/logger.ts +20 -0
  112. package/src/middleware.ts +116 -0
  113. package/src/model.ts +392 -0
  114. package/src/module.config.ts +95 -0
  115. package/src/module.ts +116 -0
  116. package/src/request-parser.ts +346 -0
  117. package/src/router.ts +747 -0
  118. package/src/static-serving.ts +153 -0
  119. package/src/utils.ts +5 -0
  120. package/tsconfig.esm.json +36 -0
  121. package/tsconfig.json +53 -0
package/src/module.ts ADDED
@@ -0,0 +1,116 @@
1
+ import { HttpListener, HttpResultFormatter, httpWorkflow } from './http.js';
2
+ import { HttpConfig } from './module.config.js';
3
+ import { AddedListener, AppModule, ControllerConfig, createModule, stringifyListener } from '@deepkit/app';
4
+ import { HttpRouter, HttpRouterRegistry, RouteConfig } from './router.js';
5
+ import { HttpKernel } from './kernel.js';
6
+ import { HttpRouterFilterResolver } from './filter.js';
7
+ import { HttpControllers } from './controllers.js';
8
+ import { ConsoleTransport, Logger } from '@deepkit/logger';
9
+ import { HttpRequest, HttpResponse } from './model.js';
10
+ import '@deepkit/type';
11
+ import { httpClass } from './decorator.js';
12
+ import { EventToken } from '@deepkit/event';
13
+ import { metaAnnotation, ReflectionKind, ReflectionParameter, Type } from '@deepkit/type';
14
+ import { buildRequestParser } from './request-parser.js';
15
+ import { InjectorContext } from '@deepkit/injector';
16
+
17
+ function parameterRequiresRequest(parameter: ReflectionParameter): boolean {
18
+ return Boolean(metaAnnotation.getForName(parameter.type, 'httpQueries') || metaAnnotation.getForName(parameter.type, 'httpQuery')
19
+ || metaAnnotation.getForName(parameter.type, 'httpBody') || metaAnnotation.getForName(parameter.type, 'httpPath') || metaAnnotation.getForName(parameter.type, 'httpHeader'));
20
+ }
21
+
22
+ export class HttpModule extends createModule({
23
+ config: HttpConfig,
24
+ providers: [
25
+ HttpRouter,
26
+ HttpKernel,
27
+ HttpResultFormatter,
28
+ HttpRouterRegistry,
29
+ HttpRouterFilterResolver,
30
+ { provide: HttpResponse, scope: 'http' },
31
+ { provide: HttpRequest, scope: 'http' },
32
+ { provide: RouteConfig, useValue: undefined, scope: 'http' },
33
+ { provide: Logger, useValue: new Logger([new ConsoleTransport()]) },
34
+ ],
35
+ listeners: [
36
+ HttpListener,
37
+ ],
38
+ workflows: [
39
+ httpWorkflow
40
+ ],
41
+ exports: [
42
+ HttpRouter,
43
+ HttpRouterRegistry,
44
+ HttpKernel,
45
+ HttpResultFormatter,
46
+ HttpRouterFilterResolver,
47
+ HttpResponse,
48
+ HttpRequest,
49
+ HttpControllers,
50
+ RouteConfig,
51
+ Logger,
52
+ ]
53
+ }) {
54
+ protected httpControllers = new HttpControllers;
55
+
56
+ process() {
57
+ this.addProvider({ provide: HttpControllers, useValue: this.httpControllers });
58
+ }
59
+
60
+ protected patchEventsForHttpRequestAccess: EventToken<any>[] = [httpWorkflow.onRequest, httpWorkflow.onAuth, httpWorkflow.onController];
61
+
62
+ processListener(module: AppModule<any>, listener: AddedListener) {
63
+ if (!this.patchEventsForHttpRequestAccess.includes(listener.eventToken)) return;
64
+
65
+ let requiresHttpRequest = false;
66
+ let needsAsync = false;
67
+ const params = listener.reflection.getParameters().slice(1);
68
+
69
+ for (const parameter of params) {
70
+ if (metaAnnotation.getForName(parameter.type, 'httpBody')) needsAsync = true;
71
+ if (parameterRequiresRequest(parameter)) requiresHttpRequest = true;
72
+ }
73
+
74
+ if (needsAsync) {
75
+ //not yet supported since we have to patch the listener to be async and redirect the call (as the DI container is sync).
76
+ throw new Error(`Listener ${stringifyListener(listener)} requires async HttpBody. This is not yet supported. You have to parse the request manually by injecting HttpRequest.`);
77
+ }
78
+
79
+ for (let index = 0; index < params.length; index++) {
80
+ const parameter = params[index];
81
+ if (!parameterRequiresRequest(parameter)) continue;
82
+
83
+ //change the reflection type so that we create a unique injection token for that type.
84
+ const unique = Symbol('unique');
85
+ const uniqueType: Type = { kind: ReflectionKind.literal, literal: unique };
86
+ metaAnnotation.registerType(parameter.type, { name: 'inject', options: [uniqueType] });
87
+ let build: Function;
88
+ let i = index;
89
+
90
+ this.addProvider({
91
+ provide: uniqueType, useFactory: (httpConfig: HttpConfig, request: HttpRequest, injector: InjectorContext, config?: RouteConfig) => {
92
+ if (!build) {
93
+ const params = listener.reflection.getParameters().slice(1);
94
+ build = buildRequestParser(httpConfig.parser, params, config?.getFullPath());
95
+ }
96
+
97
+ const parser = build(request);
98
+ const params = parser(injector);
99
+ return params.arguments[i];
100
+ }, scope: 'http'
101
+ });
102
+ this.addExport(uniqueType);
103
+ }
104
+ }
105
+
106
+ processController(module: AppModule<any>, config: ControllerConfig) {
107
+ const controller = config.controller;
108
+ if (!controller) return;
109
+
110
+ const httpConfig = httpClass._fetch(controller);
111
+ if (!httpConfig) return;
112
+
113
+ if (!module.isProvided(controller)) module.addProvider({ provide: controller, scope: 'http' });
114
+ this.httpControllers.add(controller, module);
115
+ }
116
+ }
@@ -0,0 +1,346 @@
1
+ import { asyncOperation, ClassType, CompilerContext, getClassName, isObject } from '@deepkit/core';
2
+ import { InjectorModule } from '@deepkit/injector';
3
+ import {
4
+ assertType,
5
+ findMember,
6
+ getSerializeFunction,
7
+ getValidatorFunction,
8
+ metaAnnotation,
9
+ ReflectionKind,
10
+ ReflectionParameter,
11
+ resolveReceiveType,
12
+ serializer,
13
+ stringifyType,
14
+ Type,
15
+ typeToObject,
16
+ ValidationError
17
+ } from '@deepkit/type';
18
+ import { BodyValidationError, createRequestWithCachedBody, getRegExp, HttpRequest, ValidatedBody } from './model.js';
19
+ import { RouteConfig, UploadedFile, UploadedFileSymbol } from './router.js';
20
+
21
+ //@ts-ignore
22
+ import qs from 'qs';
23
+
24
+ // @ts-ignore
25
+ import formidable from 'formidable';
26
+ import { HttpParserOptions } from './module.config.js';
27
+
28
+
29
+ function parseBody(
30
+ options: HttpParserOptions,
31
+ req: HttpRequest, foundFiles: { [name: string]: UploadedFile }) {
32
+ const form = formidable(Object.assign(options, {
33
+ multiples: true,
34
+ }));
35
+ return asyncOperation((resolve, reject) => {
36
+ function parseData(err: any, fields: any, files: any) {
37
+ if (err) {
38
+ reject(err);
39
+ } else {
40
+ for (const [name, file] of Object.entries(files) as any) {
41
+ if (file.size === 0) continue;
42
+ foundFiles[name] = {
43
+ validator: UploadedFileSymbol,
44
+ size: file.size,
45
+ path: file.filepath,
46
+ name: file.originalFilename,
47
+ type: file.mimetype,
48
+ lastModifiedDate: file.lastModifiedDate,
49
+ };
50
+ }
51
+ const body = { ...fields, ...foundFiles };
52
+ resolve(body);
53
+ }
54
+ }
55
+
56
+ if (req.body) {
57
+ form.parse(createRequestWithCachedBody(req, req.body), parseData);
58
+ return;
59
+ }
60
+
61
+ const chunks: Buffer[] = [];
62
+
63
+ function read(chunk: Buffer) {
64
+ chunks.push(chunk);
65
+ }
66
+
67
+ req.on('data', read);
68
+ req.once('end', () => {
69
+ req.body = Buffer.concat(chunks);
70
+ req.off('data', read);
71
+ });
72
+ req.once('error', () => req.off('data', read));
73
+
74
+ form.parse(req, parseData);
75
+ });
76
+ }
77
+
78
+ export class ParameterForRequestParser {
79
+ regexPosition?: number;
80
+
81
+ constructor(
82
+ public parameter: ReflectionParameter,
83
+ ) {
84
+ }
85
+
86
+ get body() {
87
+ return metaAnnotation.getForName(this.parameter.type, 'httpBody') !== undefined;
88
+ }
89
+
90
+ get bodyValidation() {
91
+ return metaAnnotation.getForName(this.parameter.type, 'httpBodyValidation') !== undefined;
92
+ }
93
+
94
+ getType(): Type {
95
+ if (this.bodyValidation) {
96
+ assertType(this.parameter.type, ReflectionKind.class);
97
+ const valueType = findMember('value', this.parameter.type.types);
98
+ if (!valueType || valueType.kind !== ReflectionKind.property) throw new Error(`No property value found at ${stringifyType(this.parameter.type)}`);
99
+ return valueType.type as Type;
100
+ }
101
+ return this.parameter.type;
102
+ }
103
+
104
+ get header() {
105
+ return metaAnnotation.getForName(this.parameter.type, 'httpHeader') !== undefined;
106
+ }
107
+
108
+ get query() {
109
+ return metaAnnotation.getForName(this.parameter.type, 'httpQuery') !== undefined;
110
+ }
111
+
112
+ get queries() {
113
+ return metaAnnotation.getForName(this.parameter.type, 'httpQueries') !== undefined;
114
+ }
115
+
116
+ get typePath(): string | undefined {
117
+ const typeOptions = metaAnnotation.getForName(this.parameter.type, 'httpQueries') || metaAnnotation.getForName(this.parameter.type, 'httpQuery')
118
+ || metaAnnotation.getForName(this.parameter.type, 'httpPath') || metaAnnotation.getForName(this.parameter.type, 'httpHeader');
119
+ if (!typeOptions) return;
120
+ const options = typeToObject(typeOptions[0]);
121
+ if (isObject(options)) return options.name;
122
+ return;
123
+ }
124
+
125
+ getName() {
126
+ return this.parameter.name;
127
+ }
128
+
129
+ isPartOfPath(): boolean {
130
+ return metaAnnotation.getForName(this.parameter.type, 'httpPath') !== undefined || this.regexPosition !== undefined;
131
+ }
132
+ }
133
+
134
+ export function parseRoutePathToRegex(path: string, params: ReflectionParameter[]): { regex: string, parameterNames: { [name: string]: number } } {
135
+ const parameterNames: { [name: string]: number } = {};
136
+
137
+ let argumentIndex = 0;
138
+ path = path.replace(/:(\w+)/g, (a, name) => {
139
+ parameterNames[name] = argumentIndex;
140
+ argumentIndex++;
141
+ const parameter = params.find(v => v.name === name);
142
+ if (parameter) {
143
+ const regExp = getRegExp(parameter.type);
144
+ if (regExp instanceof RegExp) {
145
+ return '(' + regExp.source + ')';
146
+ } else if (regExp) {
147
+ return '(' + regExp + ')';
148
+ }
149
+ }
150
+ return String.raw`([^/]+)`;
151
+ });
152
+
153
+ return { regex: path, parameterNames };
154
+ }
155
+
156
+ export function buildRequestParser(parseOptions: HttpParserOptions, parameters: ReflectionParameter[], path?: string): (request: HttpRequest) => any[] {
157
+ const compiler = new CompilerContext();
158
+ const params = parameters.map(v => new ParameterForRequestParser(v));
159
+
160
+ //todo: parse path
161
+ let pathRegex = '';
162
+ if (path) {
163
+ const parsedPath = parseRoutePathToRegex(path, parameters);
164
+ pathRegex = parsedPath.regex;
165
+
166
+ for (const param of params) {
167
+ param.regexPosition = parsedPath.parameterNames[param.parameter.name];
168
+ }
169
+ }
170
+
171
+ const code = getRequestParserCodeForParameters(compiler, parseOptions, params, {});
172
+ compiler.context.set('ValidationError', ValidationError);
173
+ compiler.context.set('qs', qs);
174
+
175
+ let needsQueryString = !!params.find(v => v.query || v.queries);
176
+ const query = needsQueryString ? '_qPosition === -1 ? {} : qs.parse(_url.substr(_qPosition + 1))' : '{}';
177
+
178
+ const regexVar = compiler.reserveVariable('regex', new RegExp('^' + pathRegex + '$'));
179
+
180
+ return compiler.build(`
181
+ const _method = request.method || 'GET';
182
+ const _url = request.url || '/';
183
+ const _headers = request.headers || {};
184
+ const _qPosition = _url.indexOf('?');
185
+ let uploadedFiles = {};
186
+ const _path = _qPosition === -1 ? _url : _url.substr(0, _qPosition);
187
+ const _match = _path.match(${regexVar}) || [];
188
+ const _query = ${query};
189
+ return ${code}
190
+ `, 'request');
191
+ }
192
+
193
+ export function getRequestParserCodeForParameters(
194
+ compiler: CompilerContext,
195
+ parseOptions: HttpParserOptions,
196
+ parameters: ParameterForRequestParser[],
197
+ config: {
198
+ module?: InjectorModule<any>,
199
+ resolverForParameterName?: Map<string, ClassType>,
200
+ resolverForToken?: Map<any, ClassType>,
201
+ pathParameterNames?: { [name: string]: number },
202
+ routeConfig?: RouteConfig,
203
+ }
204
+ ) {
205
+ let enableParseBody = false;
206
+ let requiresAsyncParameters = false;
207
+ const setParameters: string[] = [];
208
+ const parameterNames: string[] = [];
209
+ const parameterValidator: string[] = [];
210
+ let setParametersFromPath = '';
211
+ let bodyValidationErrorHandling = `if (bodyErrors.length) throw ValidationError.from(bodyErrors);`;
212
+
213
+ for (const parameter of parameters) {
214
+ if (parameter.body || parameter.bodyValidation) {
215
+ const type = parameter.getType();
216
+ const validatorVar = compiler.reserveVariable('argumentValidator', getValidatorFunction(undefined, type));
217
+ const converterVar = compiler.reserveVariable('argumentConverter', getSerializeFunction(type, serializer.deserializeRegistry));
218
+
219
+ enableParseBody = true;
220
+ setParameters.push(`parameters.${parameter.parameter.name} = ${converterVar}(bodyFields, {loosely: true});`);
221
+ parameterValidator.push(`${validatorVar}(parameters.${parameter.parameter.name}, {errors: bodyErrors});`);
222
+ if (parameter.bodyValidation) {
223
+ compiler.context.set('BodyValidation', ValidatedBody);
224
+ compiler.context.set('BodyValidationError', BodyValidationError);
225
+ parameterNames.push(`new BodyValidation(new BodyValidationError(bodyErrors), bodyErrors.length === 0 ? parameters.${parameter.parameter.name} : undefined)`);
226
+ bodyValidationErrorHandling = '';
227
+ } else {
228
+ parameterNames.push(`parameters.${parameter.parameter.name}`);
229
+ }
230
+ } else if (parameter.query || parameter.queries || parameter.header) {
231
+ const converted = getSerializeFunction(parameter.parameter.parameter, serializer.deserializeRegistry, undefined, parameter.getName());
232
+ const validator = getValidatorFunction(undefined, parameter.parameter.parameter,);
233
+ const converterVar = compiler.reserveVariable('argumentConverter', converted);
234
+ const validatorVar = compiler.reserveVariable('argumentValidator', validator);
235
+
236
+ const queryPath = parameter.typePath === undefined && !parameter.queries ? parameter.parameter.name : parameter.typePath;
237
+ const accessor = queryPath ? `['` + (queryPath.replace(/\./g, `']['`)) + `']` : '';
238
+ const queryAccessor = parameter.header ? `_headers${accessor}` : queryPath ? `_query${accessor}` : '_query';
239
+
240
+ setParameters.push(`parameters.${parameter.parameter.name} = ${converterVar}(${queryAccessor}, {loosely: true});`);
241
+ parameterNames.push(`parameters.${parameter.parameter.name}`);
242
+ parameterValidator.push(`${validatorVar}(parameters.${parameter.parameter.name}, {errors: validationErrors}, ${JSON.stringify(parameter.typePath || parameter.getName())});`);
243
+ } else {
244
+ parameterNames.push(`parameters.${parameter.parameter.name}`);
245
+
246
+ if (parameter.isPartOfPath()) {
247
+ if (parameter.parameter.type.kind !== ReflectionKind.class) {
248
+ const converted = getSerializeFunction(parameter.parameter.parameter, serializer.deserializeRegistry, undefined, parameter.getName());
249
+ const converterVar = compiler.reserveVariable('argumentConverter', converted);
250
+ setParameters.push(`parameters.${parameter.parameter.name} = ${converterVar}(_match[${1 + (parameter.regexPosition || 0)}], {loosely: true});`);
251
+
252
+ const validator = getValidatorFunction(undefined, parameter.parameter.parameter);
253
+ const validatorVar = compiler.reserveVariable('argumentValidator', validator);
254
+ parameterValidator.push(`${validatorVar}(parameters.${parameter.parameter.name}, {errors: validationErrors}, ${JSON.stringify(parameter.getName())});`);
255
+ } else {
256
+ setParameters.push(`parameters.${parameter.parameter.name} = _match[${1 + (parameter.regexPosition || 0)}];`);
257
+ }
258
+ }
259
+
260
+ const injectorToken = parameter.parameter.type.kind === ReflectionKind.class ? parameter.parameter.type.classType : undefined;
261
+ const injectorTokenVar = compiler.reserveVariable('classType', injectorToken);
262
+ const parameterResolverFoundVar = compiler.reserveVariable('parameterResolverFound', false);
263
+
264
+ setParameters.push(`${parameterResolverFoundVar} = false;`);
265
+
266
+ const resolverType = config.resolverForParameterName?.get(parameter.getName()) || config.resolverForToken?.get(injectorToken);
267
+
268
+ //make sure all parameter values from the path are available, important for parameter resolver
269
+ if (resolverType && !setParametersFromPath && config.pathParameterNames) {
270
+ for (const i in config.pathParameterNames) {
271
+ setParametersFromPath += `parameters.${i} = _match[${1 + config.pathParameterNames[i]}];`;
272
+ }
273
+ }
274
+
275
+ let injector = '_injector';
276
+ const moduleVar = config.module ? ', ' + compiler.reserveConst(config.module, 'module') : '';
277
+
278
+ if (resolverType) {
279
+ requiresAsyncParameters = true;
280
+ let instanceFetcher = '';
281
+ if (config.module && config.module.injector) {
282
+ const resolverResolverVar = compiler.reserveVariable('resolverProvideToken', config.module.injector.createResolver(resolveReceiveType(resolverType)));
283
+ instanceFetcher = `${resolverResolverVar}(${injector}.scope)`;
284
+ } else {
285
+ const resolverProvideTokenVar = compiler.reserveVariable('resolverProvideToken', resolverType);
286
+ instanceFetcher = `${injector}.get(${resolverProvideTokenVar}${moduleVar})`;
287
+ }
288
+ const instance = compiler.reserveVariable('resolverInstance');
289
+
290
+ const routeConfigVar = compiler.reserveVariable('routeConfigVar', config.routeConfig);
291
+ setParameters.push(`
292
+ //resolver ${getClassName(resolverType)} for ${parameter.getName()}
293
+ ${instance} = ${instanceFetcher};
294
+ if (!${parameterResolverFoundVar}) {
295
+ ${parameterResolverFoundVar} = true;
296
+ parameters.${parameter.parameter.name} = await ${instance}.resolve({
297
+ token: ${injectorTokenVar},
298
+ route: ${routeConfigVar},
299
+ request: request,
300
+ name: ${JSON.stringify(parameter.parameter.name)},
301
+ value: parameters.${parameter.parameter.name},
302
+ query: _query,
303
+ parameters: parameters,
304
+ type: ${compiler.reserveVariable('parameterType', parameter.parameter)}
305
+ });
306
+ }`);
307
+ }
308
+
309
+ if (!parameter.isPartOfPath()) {
310
+ let injectorGet = `parameters.${parameter.parameter.name} = ${injector}.get(${injectorTokenVar});`;
311
+ if (parameter.parameter.isOptional()) {
312
+ injectorGet = `try {parameters.${parameter.parameter.name} = ${injector}.get(${injectorTokenVar}); } catch (e) {}`;
313
+ }
314
+ setParameters.push(`if (!${parameterResolverFoundVar}) ${injectorGet}`);
315
+ }
316
+ }
317
+ }
318
+
319
+
320
+ let parseBodyLoading = '';
321
+ if (enableParseBody) {
322
+ const parseOptionsVar = compiler.reserveVariable('parseOptions', parseOptions);
323
+ const parseBodyVar = compiler.reserveVariable('parseBody', parseBody);
324
+ parseBodyLoading = `
325
+ const bodyFields = (await ${parseBodyVar}(${parseOptionsVar}, request, uploadedFiles));`;
326
+ requiresAsyncParameters = true;
327
+ }
328
+
329
+ let parametersLoader = '() => {}';
330
+
331
+ if (setParameters.length) {
332
+ parametersLoader = `${requiresAsyncParameters ? 'async' : ''} function parse(_injector){
333
+ const validationErrors = [];
334
+ const bodyErrors = [];
335
+ const parameters = {};
336
+ ${setParametersFromPath}
337
+ ${parseBodyLoading}
338
+ ${setParameters.join('\n')}
339
+ ${parameterValidator.join('\n')}
340
+ ${bodyValidationErrorHandling}
341
+ if (validationErrors.length) throw new ValidationError(validationErrors);
342
+ return {arguments: [${parameterNames.join(',')}], parameters: parameters};
343
+ }`;
344
+ }
345
+ return parametersLoader;
346
+ }