@e22m4u/ts-rest-router 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +6 -0
  6. package/.mocharc.json +5 -0
  7. package/.prettierrc +7 -0
  8. package/LICENSE +21 -0
  9. package/README-ru.md +41 -0
  10. package/README.md +41 -0
  11. package/build-cjs.js +16 -0
  12. package/dist/cjs/index.cjs +692 -0
  13. package/dist/esm/controller-registry.d.ts +65 -0
  14. package/dist/esm/controller-registry.js +281 -0
  15. package/dist/esm/controller-registry.spec.d.ts +1 -0
  16. package/dist/esm/controller-registry.spec.js +719 -0
  17. package/dist/esm/debuggable-service.d.ts +18 -0
  18. package/dist/esm/debuggable-service.js +23 -0
  19. package/dist/esm/debuggable-service.spec.d.ts +1 -0
  20. package/dist/esm/debuggable-service.spec.js +16 -0
  21. package/dist/esm/decorators/action/action-decorator.d.ts +53 -0
  22. package/dist/esm/decorators/action/action-decorator.js +66 -0
  23. package/dist/esm/decorators/action/action-decorator.spec.d.ts +1 -0
  24. package/dist/esm/decorators/action/action-decorator.spec.js +59 -0
  25. package/dist/esm/decorators/action/action-metadata.d.ts +23 -0
  26. package/dist/esm/decorators/action/action-metadata.js +5 -0
  27. package/dist/esm/decorators/action/action-reflector.d.ts +22 -0
  28. package/dist/esm/decorators/action/action-reflector.js +29 -0
  29. package/dist/esm/decorators/action/action-reflector.spec.d.ts +1 -0
  30. package/dist/esm/decorators/action/action-reflector.spec.js +84 -0
  31. package/dist/esm/decorators/action/index.d.ts +3 -0
  32. package/dist/esm/decorators/action/index.js +3 -0
  33. package/dist/esm/decorators/controller/controller-decorator.d.ts +13 -0
  34. package/dist/esm/decorators/controller/controller-decorator.js +20 -0
  35. package/dist/esm/decorators/controller/controller-decorator.spec.d.ts +1 -0
  36. package/dist/esm/decorators/controller/controller-decorator.spec.js +53 -0
  37. package/dist/esm/decorators/controller/controller-metadata.d.ts +17 -0
  38. package/dist/esm/decorators/controller/controller-metadata.js +5 -0
  39. package/dist/esm/decorators/controller/controller-reflector.d.ts +20 -0
  40. package/dist/esm/decorators/controller/controller-reflector.js +24 -0
  41. package/dist/esm/decorators/controller/controller-reflector.spec.d.ts +1 -0
  42. package/dist/esm/decorators/controller/controller-reflector.spec.js +45 -0
  43. package/dist/esm/decorators/controller/index.d.ts +3 -0
  44. package/dist/esm/decorators/controller/index.js +3 -0
  45. package/dist/esm/decorators/index.d.ts +4 -0
  46. package/dist/esm/decorators/index.js +4 -0
  47. package/dist/esm/decorators/request-context/index.d.ts +3 -0
  48. package/dist/esm/decorators/request-context/index.js +3 -0
  49. package/dist/esm/decorators/request-context/request-context-decorator.d.ts +17 -0
  50. package/dist/esm/decorators/request-context/request-context-decorator.js +32 -0
  51. package/dist/esm/decorators/request-context/request-context-decorator.spec.d.ts +1 -0
  52. package/dist/esm/decorators/request-context/request-context-decorator.spec.js +59 -0
  53. package/dist/esm/decorators/request-context/request-context-metadata.d.ts +17 -0
  54. package/dist/esm/decorators/request-context/request-context-metadata.js +5 -0
  55. package/dist/esm/decorators/request-context/request-context-reflector.d.ts +24 -0
  56. package/dist/esm/decorators/request-context/request-context-reflector.js +31 -0
  57. package/dist/esm/decorators/request-context/request-context-reflector.spec.d.ts +1 -0
  58. package/dist/esm/decorators/request-context/request-context-reflector.spec.js +59 -0
  59. package/dist/esm/decorators/request-data/index.d.ts +3 -0
  60. package/dist/esm/decorators/request-data/index.js +3 -0
  61. package/dist/esm/decorators/request-data/request-data-decorator.d.ts +28 -0
  62. package/dist/esm/decorators/request-data/request-data-decorator.js +84 -0
  63. package/dist/esm/decorators/request-data/request-data-decorator.spec.d.ts +1 -0
  64. package/dist/esm/decorators/request-data/request-data-decorator.spec.js +534 -0
  65. package/dist/esm/decorators/request-data/request-data-metadata.d.ts +29 -0
  66. package/dist/esm/decorators/request-data/request-data-metadata.js +16 -0
  67. package/dist/esm/decorators/request-data/request-data-reflector.d.ts +24 -0
  68. package/dist/esm/decorators/request-data/request-data-reflector.js +31 -0
  69. package/dist/esm/decorators/request-data/request-data-reflector.spec.d.ts +1 -0
  70. package/dist/esm/decorators/request-data/request-data-reflector.spec.js +60 -0
  71. package/dist/esm/errors/index.d.ts +1 -0
  72. package/dist/esm/errors/index.js +1 -0
  73. package/dist/esm/errors/not-a-controller-error.d.ts +12 -0
  74. package/dist/esm/errors/not-a-controller-error.js +14 -0
  75. package/dist/esm/index.d.ts +5 -0
  76. package/dist/esm/index.js +5 -0
  77. package/dist/esm/rest-router.d.ts +19 -0
  78. package/dist/esm/rest-router.js +24 -0
  79. package/dist/esm/types.d.ts +57 -0
  80. package/dist/esm/types.js +2 -0
  81. package/dist/esm/utils/capitalize.d.ts +6 -0
  82. package/dist/esm/utils/capitalize.js +8 -0
  83. package/dist/esm/utils/capitalize.spec.d.ts +1 -0
  84. package/dist/esm/utils/capitalize.spec.js +8 -0
  85. package/dist/esm/utils/create-debugger.d.ts +11 -0
  86. package/dist/esm/utils/create-debugger.js +15 -0
  87. package/dist/esm/utils/create-debugger.spec.d.ts +1 -0
  88. package/dist/esm/utils/create-debugger.spec.js +8 -0
  89. package/dist/esm/utils/create-error.d.ts +10 -0
  90. package/dist/esm/utils/create-error.js +13 -0
  91. package/dist/esm/utils/create-error.spec.d.ts +1 -0
  92. package/dist/esm/utils/create-error.spec.js +8 -0
  93. package/dist/esm/utils/index.d.ts +4 -0
  94. package/dist/esm/utils/index.js +4 -0
  95. package/dist/esm/utils/to-camel-case.d.ts +6 -0
  96. package/dist/esm/utils/to-camel-case.js +11 -0
  97. package/dist/esm/utils/to-camel-case.spec.d.ts +1 -0
  98. package/dist/esm/utils/to-camel-case.spec.js +10 -0
  99. package/dist/tsconfig.tsbuildinfo +1 -0
  100. package/eslint.config.js +43 -0
  101. package/package.json +74 -0
  102. package/src/controller-registry.spec.ts +592 -0
  103. package/src/controller-registry.ts +355 -0
  104. package/src/debuggable-service.spec.ts +18 -0
  105. package/src/debuggable-service.ts +27 -0
  106. package/src/decorators/action/action-decorator.spec.ts +42 -0
  107. package/src/decorators/action/action-decorator.ts +100 -0
  108. package/src/decorators/action/action-metadata.ts +28 -0
  109. package/src/decorators/action/action-reflector.spec.ts +84 -0
  110. package/src/decorators/action/action-reflector.ts +38 -0
  111. package/src/decorators/action/index.ts +3 -0
  112. package/src/decorators/controller/controller-decorator.spec.ts +41 -0
  113. package/src/decorators/controller/controller-decorator.ts +29 -0
  114. package/src/decorators/controller/controller-metadata.ts +21 -0
  115. package/src/decorators/controller/controller-reflector.spec.ts +45 -0
  116. package/src/decorators/controller/controller-reflector.ts +28 -0
  117. package/src/decorators/controller/index.ts +3 -0
  118. package/src/decorators/index.ts +4 -0
  119. package/src/decorators/request-context/index.ts +3 -0
  120. package/src/decorators/request-context/request-context-decorator.spec.ts +41 -0
  121. package/src/decorators/request-context/request-context-decorator.ts +57 -0
  122. package/src/decorators/request-context/request-context-metadata.ts +21 -0
  123. package/src/decorators/request-context/request-context-reflector.spec.ts +77 -0
  124. package/src/decorators/request-context/request-context-reflector.ts +57 -0
  125. package/src/decorators/request-data/index.ts +3 -0
  126. package/src/decorators/request-data/request-data-decorator.spec.ts +477 -0
  127. package/src/decorators/request-data/request-data-decorator.ts +106 -0
  128. package/src/decorators/request-data/request-data-metadata.ts +34 -0
  129. package/src/decorators/request-data/request-data-reflector.spec.ts +78 -0
  130. package/src/decorators/request-data/request-data-reflector.ts +57 -0
  131. package/src/errors/index.ts +1 -0
  132. package/src/errors/not-a-controller-error.ts +15 -0
  133. package/src/index.ts +5 -0
  134. package/src/rest-router.ts +31 -0
  135. package/src/types.ts +59 -0
  136. package/src/utils/capitalize.spec.ts +9 -0
  137. package/src/utils/capitalize.ts +8 -0
  138. package/src/utils/create-debugger.spec.ts +9 -0
  139. package/src/utils/create-debugger.ts +21 -0
  140. package/src/utils/create-error.spec.ts +9 -0
  141. package/src/utils/create-error.ts +19 -0
  142. package/src/utils/index.ts +4 -0
  143. package/src/utils/to-camel-case.spec.ts +11 -0
  144. package/src/utils/to-camel-case.ts +11 -0
  145. package/tsconfig.json +17 -0
@@ -0,0 +1,65 @@
1
+ import { Constructor } from './types.js';
2
+ import { RouteHandler } from '@e22m4u/js-trie-router';
3
+ import { RoutePreHandler } from '@e22m4u/js-trie-router';
4
+ import { RoutePostHandler } from '@e22m4u/js-trie-router';
5
+ import { ControllerMetadata } from './decorators/index.js';
6
+ import { DebuggableService } from './debuggable-service.js';
7
+ /**
8
+ * Controller root options.
9
+ */
10
+ export type ControllerRootOptions = {
11
+ pathPrefix?: string;
12
+ before?: RoutePreHandler | RoutePreHandler[];
13
+ after?: RoutePostHandler | RoutePostHandler[];
14
+ };
15
+ /**
16
+ * Controller registry.
17
+ */
18
+ export declare class ControllerRegistry extends DebuggableService {
19
+ /**
20
+ * Controllers.
21
+ */
22
+ controllers: Set<unknown>;
23
+ /**
24
+ * Add controller.
25
+ *
26
+ * @param ctor
27
+ * @param options
28
+ */
29
+ addController<T extends object>(ctor: Constructor<T>, options?: ControllerRootOptions): this;
30
+ /**
31
+ * Has controller.
32
+ *
33
+ * @param ctor
34
+ */
35
+ hasController<T extends object>(ctor: Constructor<T>): boolean;
36
+ /**
37
+ * Get path prefix by controller metadata.
38
+ *
39
+ * @param controllerMd
40
+ * @param options
41
+ */
42
+ getPathPrefixByControllerMetadata(controllerMd: ControllerMetadata, options?: ControllerRootOptions): string;
43
+ /**
44
+ * Get pre-handlers by controller metadata.
45
+ *
46
+ * @param controllerMd
47
+ * @param options
48
+ */
49
+ getPreHandlersByControllerMetadata(controllerMd: ControllerMetadata, options?: ControllerRootOptions): RouteHandler[];
50
+ /**
51
+ * Get post-handlers by controller metadata.
52
+ *
53
+ * @param controllerMd
54
+ * @param options
55
+ */
56
+ getPostHandlersByControllerMetadata(controllerMd: ControllerMetadata, options?: ControllerRootOptions): RoutePostHandler[];
57
+ /**
58
+ * Create route handler.
59
+ *
60
+ * @param controllerCtor
61
+ * @param actionName
62
+ * @protected
63
+ */
64
+ createRouteHandler<T extends object>(controllerCtor: Constructor<T>, actionName: string): RouteHandler;
65
+ }
@@ -0,0 +1,281 @@
1
+ import { Errorf } from '@e22m4u/js-format';
2
+ import { TrieRouter } from '@e22m4u/js-trie-router';
3
+ import { DataValidator } from '@e22m4u/ts-data-schema';
4
+ import { DataTypeCaster } from '@e22m4u/ts-data-schema';
5
+ import { ActionReflector } from './decorators/index.js';
6
+ import { NotAControllerError } from './errors/index.js';
7
+ import { RequestDataSource } from './decorators/index.js';
8
+ import { DebuggableService } from './debuggable-service.js';
9
+ import { ControllerReflector } from './decorators/index.js';
10
+ import { RequestDataReflector } from './decorators/index.js';
11
+ import { RequestContextReflector } from './decorators/index.js';
12
+ /**
13
+ * Controller registry.
14
+ */
15
+ export class ControllerRegistry extends DebuggableService {
16
+ /**
17
+ * Controllers.
18
+ */
19
+ controllers = new Set();
20
+ /**
21
+ * Add controller.
22
+ *
23
+ * @param ctor
24
+ * @param options
25
+ */
26
+ addController(ctor, options) {
27
+ // проверка повторной регистрации помогает
28
+ // заметить ошибку в коде, который использует
29
+ // интерфейс данного сервиса
30
+ if (this.hasController(ctor))
31
+ throw new Errorf('The controller %v is already registered.');
32
+ // так как контроллером может быть любой
33
+ // класс, выполняется проверка на наличие
34
+ // метаданных применяемых декоратором
35
+ const controllerMd = ControllerReflector.getMetadata(ctor);
36
+ if (!controllerMd)
37
+ throw new NotAControllerError(ctor);
38
+ this.debug('Adding controller %s.', ctor.name);
39
+ // определение префикса применяемого
40
+ // к маршрутам контроллера
41
+ const pathPrefix = this.getPathPrefixByControllerMetadata(controllerMd, options);
42
+ this.debug('Path prefix is %v.', pathPrefix);
43
+ // подготовка pre-обработчиков
44
+ const preHandlers = this.getPreHandlersByControllerMetadata(controllerMd, options);
45
+ this.debug('%v total pre-handlers found.', preHandlers.length);
46
+ // подготовка post-обработчиков
47
+ const postHandlers = this.getPostHandlersByControllerMetadata(controllerMd, options);
48
+ this.debug('%v total post-handlers found.', postHandlers.length);
49
+ // обход всех операций контроллера
50
+ // для определения маршрутов
51
+ const actionsMd = ActionReflector.getMetadata(ctor);
52
+ this.debug('%v actions found.', actionsMd.size);
53
+ const router = this.getService(TrieRouter);
54
+ actionsMd.forEach((actionMd, actionName) => {
55
+ this.debug('Adding route for %s.%s.', ctor.name, actionName);
56
+ // подготовка пути маршрута с префиксом
57
+ this.debug('Route path is %v.', actionMd.path);
58
+ const prefixedRoutePath = `${pathPrefix}/${actionMd.path}`.replace(/\/\//g, '/');
59
+ this.debug('Prefixed route path is %v.', prefixedRoutePath);
60
+ // подготовка pre-обработчиков операции
61
+ const actionPreHandlers = Array.isArray(actionMd.before)
62
+ ? actionMd.before
63
+ : actionMd.before
64
+ ? [actionMd.before]
65
+ : [];
66
+ this.debug('%v action pre-handlers found.', actionPreHandlers.length);
67
+ const mergedPreHandlers = [...preHandlers, ...actionPreHandlers];
68
+ // подготовка post-обработчиков операции
69
+ const actionPostHandlers = Array.isArray(actionMd.after)
70
+ ? actionMd.after
71
+ : actionMd.after
72
+ ? [actionMd.after]
73
+ : [];
74
+ this.debug('%v action post-handlers found.', actionPostHandlers.length);
75
+ const mergedPostHandlers = [...postHandlers, ...actionPostHandlers];
76
+ // подготовка обработчика маршрута
77
+ const routeHandler = this.createRouteHandler(ctor, actionName);
78
+ router.defineRoute({
79
+ method: actionMd.method,
80
+ path: prefixedRoutePath,
81
+ preHandler: mergedPreHandlers,
82
+ handler: routeHandler,
83
+ postHandler: mergedPostHandlers,
84
+ });
85
+ this.debug('Route %s %v is added.', actionMd.method.toUpperCase(), prefixedRoutePath);
86
+ });
87
+ this.controllers.add(ctor);
88
+ return this;
89
+ }
90
+ /**
91
+ * Has controller.
92
+ *
93
+ * @param ctor
94
+ */
95
+ hasController(ctor) {
96
+ return this.controllers.has(ctor);
97
+ }
98
+ /**
99
+ * Get path prefix by controller metadata.
100
+ *
101
+ * @param controllerMd
102
+ * @param options
103
+ */
104
+ getPathPrefixByControllerMetadata(controllerMd, options) {
105
+ const rootPathPrefix = options?.pathPrefix || '';
106
+ this.debug('Root path prefix is %v.', rootPathPrefix);
107
+ const controllerPathPrefix = controllerMd.path || '';
108
+ this.debug('Controller path prefix is %v.', controllerPathPrefix);
109
+ const mergedPathPrefix = `/${rootPathPrefix}/${controllerPathPrefix}`
110
+ .replace(/\/\//g, '/')
111
+ .replace(/\/$/, '');
112
+ this.debug('Merged path prefix is %v.', mergedPathPrefix);
113
+ return mergedPathPrefix;
114
+ }
115
+ /**
116
+ * Get pre-handlers by controller metadata.
117
+ *
118
+ * @param controllerMd
119
+ * @param options
120
+ */
121
+ getPreHandlersByControllerMetadata(controllerMd, options) {
122
+ // подготовка дополнительных
123
+ // pre-обработчиков запроса
124
+ let rootPreHandlers = [];
125
+ if (options?.before)
126
+ rootPreHandlers = Array.isArray(options?.before)
127
+ ? options.before
128
+ : [options.before];
129
+ this.debug('%v root pre-handlers found.', rootPreHandlers.length);
130
+ // подготовка pre-обработчиков
131
+ // запроса контроллера
132
+ let ctlPreHandlers = [];
133
+ if (controllerMd.before)
134
+ ctlPreHandlers = Array.isArray(controllerMd.before)
135
+ ? controllerMd.before
136
+ : [controllerMd.before];
137
+ this.debug('%v controller pre-handlers found.', ctlPreHandlers.length);
138
+ // подготовка объединенного набора
139
+ // pre-обработчиков запроса
140
+ const mergedPreHandlers = [...rootPreHandlers, ...ctlPreHandlers];
141
+ this.debug('%v merged pre-handlers.', mergedPreHandlers.length);
142
+ return mergedPreHandlers;
143
+ }
144
+ /**
145
+ * Get post-handlers by controller metadata.
146
+ *
147
+ * @param controllerMd
148
+ * @param options
149
+ */
150
+ getPostHandlersByControllerMetadata(controllerMd, options) {
151
+ // подготовка дополнительных
152
+ // post-обработчиков запроса
153
+ let rootPostHandlers = [];
154
+ if (options?.after)
155
+ rootPostHandlers = Array.isArray(options.after)
156
+ ? options.after
157
+ : [options.after];
158
+ this.debug('%v root post-handlers found.', rootPostHandlers.length);
159
+ // подготовка post-обработчиков
160
+ // запроса контроллера
161
+ let ctlPostHandlers = [];
162
+ if (controllerMd.after)
163
+ ctlPostHandlers = Array.isArray(controllerMd.after)
164
+ ? controllerMd.after
165
+ : [controllerMd.after];
166
+ this.debug('%v controller post-handlers found.', ctlPostHandlers.length);
167
+ // подготовка объединенного набора
168
+ // post-обработчиков запроса
169
+ const mergedPostHandlers = [...rootPostHandlers, ...ctlPostHandlers];
170
+ this.debug('%v merged post-handlers.', mergedPostHandlers.length);
171
+ return mergedPostHandlers;
172
+ }
173
+ /**
174
+ * Create route handler.
175
+ *
176
+ * @param controllerCtor
177
+ * @param actionName
178
+ * @protected
179
+ */
180
+ createRouteHandler(controllerCtor, actionName) {
181
+ this.debug('Creating route handler for %s.%s.', controllerCtor.name, actionName);
182
+ const requestContextMetadataMap = RequestContextReflector.getMetadata(controllerCtor, actionName);
183
+ const requestDataMetadataMap = RequestDataReflector.getMetadata(controllerCtor, actionName);
184
+ const argsNumber = controllerCtor.prototype[actionName].length;
185
+ const dataTypeCaster = this.getService(DataTypeCaster);
186
+ const dataValidator = this.getService(DataValidator);
187
+ return (requestContext) => {
188
+ this.debug('Executing route handler for %s.%s.', controllerCtor.name, actionName);
189
+ const args = Array(argsNumber).map((value, index) => {
190
+ if (value != null)
191
+ return value;
192
+ // заполнение аргументов операции
193
+ // значениями из контекста запроса
194
+ const requestContextMd = requestContextMetadataMap.get(index);
195
+ if (requestContextMd != null) {
196
+ this.debug('Argument %v has request context metadata.', index);
197
+ // если свойство контекста не определено,
198
+ // то используем весь объект контекста
199
+ // в качестве значения текущего аргумента
200
+ if (requestContextMd.property == null) {
201
+ this.debug('Request context property is not specified.');
202
+ this.debug('Argument %v is set to %v.', index, requestContext);
203
+ return requestContext;
204
+ }
205
+ // если свойство контекста определено,
206
+ // то используем значение этого свойства
207
+ // в качестве текущего аргумента
208
+ const propName = requestContextMd.property;
209
+ const propValue = requestContext[propName];
210
+ this.debug('Request context property is %v.', propName);
211
+ this.debug('Argument %v is set to %v.', index, propValue);
212
+ return propValue;
213
+ }
214
+ else {
215
+ this.debug('No RequestContextMetadata specified for %v argument.', index);
216
+ }
217
+ // заполнение аргументов операции
218
+ // значениями из данных запроса
219
+ const requestDataMd = requestDataMetadataMap.get(index);
220
+ if (requestDataMd != null) {
221
+ this.debug('Argument %v has request data metadata.', index);
222
+ // получение данных
223
+ // согласно источнику
224
+ let data;
225
+ switch (requestDataMd.source) {
226
+ case RequestDataSource.PARAMS:
227
+ data = requestContext.params;
228
+ break;
229
+ case RequestDataSource.QUERY:
230
+ data = requestContext.query;
231
+ break;
232
+ case RequestDataSource.HEADERS:
233
+ data = requestContext.headers;
234
+ break;
235
+ case RequestDataSource.COOKIE:
236
+ data = requestContext.cookie;
237
+ break;
238
+ case RequestDataSource.BODY:
239
+ data = requestContext.body;
240
+ break;
241
+ }
242
+ this.debug('Request data source is %v.', requestDataMd.source);
243
+ // при наличии схемы данных выполняется
244
+ // их конвертация и валидация
245
+ if (requestDataMd.schema) {
246
+ data = dataTypeCaster.cast(data, requestDataMd.schema, {
247
+ noTypeCastError: true,
248
+ sourcePath: requestDataMd.source,
249
+ });
250
+ this.debug('Data type casting is passed.');
251
+ dataValidator.validate(data, requestDataMd.schema, requestDataMd.source);
252
+ this.debug('Data validation is passed.');
253
+ }
254
+ // если свойство данных не определено,
255
+ // то используем весь объекта данных
256
+ // в качестве значения текущего аргумента
257
+ if (requestDataMd.property == null) {
258
+ this.debug('Request data property is not specified.');
259
+ this.debug('Argument %v is set to %v.', index, data);
260
+ return data;
261
+ }
262
+ // если свойство данных определено,
263
+ // то используем значение этого свойства
264
+ // в качестве текущего аргумента
265
+ const dataAsObject = data;
266
+ const propName = requestDataMd.property;
267
+ const propValue = dataAsObject[propName];
268
+ this.debug('Request data property is %v.', propName);
269
+ this.debug('Argument %v is set to %v.', index, propValue);
270
+ return propValue;
271
+ }
272
+ else {
273
+ this.debug('No RequestDataMetadata specified for %v argument.', index);
274
+ }
275
+ });
276
+ // выполнение операции контроллера
277
+ const controller = this.getService(controllerCtor);
278
+ return controller[actionName](...args);
279
+ };
280
+ }
281
+ }
@@ -0,0 +1 @@
1
+ export {};