mythix 2.9.0 → 2.10.0

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.
@@ -2,9 +2,8 @@
2
2
 
3
3
  /* global Buffer, Utils, globalScope */
4
4
 
5
- const Nife = require('nife');
6
- const ControllerUtils = require('./controller-utils');
7
- const HTTPUtils = require('../utils/http-utils');
5
+ const Nife = require('nife');
6
+ const HTTPUtils = require('../utils/http-utils');
8
7
 
9
8
  function tabIn(str, amount) {
10
9
  var padding = ''.padStart((amount || 1) * 2, ' ');
@@ -20,11 +19,6 @@ function tabIn(str, amount) {
20
19
  });
21
20
  }
22
21
 
23
- function buildRoutes(httpServer, routes) {
24
- var customParserTypes = this.getCustomRouteParserTypes(httpServer, routes);
25
- return ControllerUtils.buildRoutes(routes, customParserTypes);
26
- }
27
-
28
22
  function nodeRequestHandler(routeName, requestOptions) {
29
23
  return new Promise((function(resolve, reject) {
30
24
  if (!requestOptions || Utils.isEmpty(requestOptions.url)) {
@@ -163,15 +157,22 @@ function browserRequestHandler(routeName, requestOptions) {
163
157
  var data = requestOptions.data;
164
158
  var extraConfig = {};
165
159
  var headers = Object.assign(Utils.keysToLowerCase(this.defaultHeaders || {}), Utils.keysToLowerCase(requestOptions.headers || {}));
160
+ var isFormData = (data && (data instanceof FormData || data.constructor.name === 'FormData'));
166
161
 
167
162
  if (data) {
168
163
  if (!method.match(/^(GET|HEAD)$/i)) {
169
- if ((headers['content-type'] || '').match(/application\/json/i))
170
- data = JSON.stringify(data);
164
+ if (isFormData) {
165
+ extraConfig = {
166
+ body: data,
167
+ };
168
+ } else {
169
+ if ((headers['content-type'] || '').match(/application\/json/i))
170
+ data = JSON.stringify(data);
171
171
 
172
- extraConfig = {
173
- body: data,
174
- };
172
+ extraConfig = {
173
+ body: data,
174
+ };
175
+ }
175
176
  } else {
176
177
  var queryString = Utils.dataToQueryString(data);
177
178
  if (queryString)
@@ -193,6 +194,8 @@ function browserRequestHandler(routeName, requestOptions) {
193
194
  );
194
195
 
195
196
  delete options.data;
197
+ if (isFormData && options.headers)
198
+ delete options.headers['content-type'];
196
199
 
197
200
  globalScope.fetch(url, Utils.cleanObjectProperties(options)).then(
198
201
  async function(response) {
@@ -298,45 +301,31 @@ function generateUtils() {
298
301
  `;
299
302
  }
300
303
 
301
- function generateRoutes(_routes, _options) {
302
- var options = _options || {};
303
- var methods = {};
304
- var domain = options.domain;
305
- var routes = _routes;
306
-
307
- if (options.routeFilter) {
308
- var routeFilter = options.routeFilter;
309
-
310
- if (typeof routeFilter === 'function') {
311
- routes = routes.filter(routeFilter);
312
- } else if (routeFilter instanceof RegExp) {
313
- routes = routes.filter((route) => {
314
- return routeFilter.test(route.path);
315
- });
316
- } else if (Nife.instanceOf(routeFilter, 'string')) {
317
- routes = routes.filter((route) => {
318
- return (route.path.indexOf(routeFilter) >= 0);
319
- });
320
- }
321
- }
304
+ function generateRoutes(applicationRoutes, _options) {
305
+ let options = _options || {};
306
+ let methods = {};
307
+ let domain = options.domain;
308
+ let routeFilter = options.routeFilter;
322
309
 
323
310
  if (Nife.isEmpty(domain))
324
311
  domain = '';
325
312
  else
326
313
  domain = ('' + domain).replace(/\/+$/, '');
327
314
 
328
- for (var i = 0, il = routes.length; i < il; i++) {
329
- var route = routes[i];
330
- var methodName = route.name;
331
- if (Nife.isEmpty(methodName))
332
- continue;
315
+ applicationRoutes.walkRoutes((context) => {
316
+ if (typeof routeFilter === 'function') {
317
+ if (!routeFilter(context))
318
+ return;
319
+ }
333
320
 
334
- var pathMatcher = route.pathMatcher;
335
- var clientOptions = route.clientOptions;
336
- var sanitizedPath = pathMatcher.sanitizedPath;
321
+ let { endpoint } = context;
322
+ let methodName = endpoint.name;
323
+ if (Nife.isEmpty(methodName))
324
+ return;
337
325
 
326
+ let clientOptions = endpoint.clientOptions;
338
327
  if (clientOptions == null) {
339
- var contentType = route.accept;
328
+ let contentType = endpoint.contentType;
340
329
  if (Nife.isEmpty(contentType))
341
330
  contentType = 'application/json';
342
331
  else if (Array.isArray(contentType))
@@ -361,15 +350,13 @@ function generateRoutes(_routes, _options) {
361
350
  return value;
362
351
  });
363
352
 
364
- var defaultMethod = Nife.toArray(route.methods).filter(Boolean);
365
- if (Nife.isEmpty(defaultMethod))
366
- defaultMethod = 'GET';
367
- else if (Array.isArray(defaultMethod))
368
- defaultMethod = defaultMethod[0];
369
-
370
- var url = `${domain}${sanitizedPath}`;
371
- methods[methodName] = { method: `function ${methodName}(_options) { var clientOptions = ${clientOptions}; var options = Object.assign({ url: '${url}', method: '${defaultMethod}' }, defaultRouteOptions, clientOptions, Object.assign({}, _options || {}, { headers: Object.assign({}, defaultRouteOptions.headers || {}, clientOptions.headers || {}, ((_options || {}).headers) || {}) })); options.url = Utils.injectURLParams('${methodName}', options); delete options.params; return makeRequest.call(this, '${methodName}', options); }`, route };
372
- }
353
+ let defaultMethod = endpoint.methods[0];
354
+ let url = `${domain}/${endpoint.path.replace(/^\/+/, '')}`;
355
+ methods[methodName] = {
356
+ method: `function ${methodName}(_options) { var clientOptions = ${clientOptions}; var options = Object.assign({ url: '${url}', method: '${defaultMethod}' }, defaultRouteOptions, clientOptions, Object.assign({}, _options || {}, { headers: Object.assign({}, defaultRouteOptions.headers || {}, clientOptions.headers || {}, ((_options || {}).headers) || {}) })); options.url = Utils.injectURLParams('${methodName}', options); delete options.params; return makeRequest.call(this, '${methodName}', options); }`,
357
+ endpoint,
358
+ };
359
+ });
373
360
 
374
361
  return methods;
375
362
  }
@@ -498,10 +485,10 @@ function generateAPIInterface(routes, _options) {
498
485
  var routeMethods = generateRoutes(routes, options);
499
486
  var routeMethodNames = Object.keys(routeMethods).sort();
500
487
  var injectMethodsStr = routeMethodNames.map((methodName) => {
501
- var info = routeMethods[methodName];
502
- var method = info.method;
503
- var route = info.route;
504
- var help = route.help;
488
+ var info = routeMethods[methodName];
489
+ var method = info.method;
490
+ var endpoint = info.endpoint;
491
+ var help = endpoint.help;
505
492
 
506
493
  if (!help || options.mode !== 'development')
507
494
  help = '{}';
@@ -647,8 +634,7 @@ function generateAPIInterface(routes, _options) {
647
634
 
648
635
  function generateClientAPIInterface(application, _options) {
649
636
  var options = _options || {};
650
- var httpServer = application.getHTTPServer() || null;
651
- var routes = buildRoutes.call(application, httpServer, application.getRoutes());
637
+ var routes = application._getRoutes();
652
638
  var globalName = (Object.prototype.hasOwnProperty.call(options, 'globalName')) ? options.globalName : '';
653
639
 
654
640
  if (Nife.isNotEmpty(globalName))
@@ -1,4 +1,5 @@
1
1
  export * from './controller-base';
2
+ export * as Routes from './routes';
2
3
  export * as ControllerUtils from './controller-utils';
3
4
  export { defineController } from './controller-utils';
4
5
  export * from './generate-client-api-interface';
@@ -5,22 +5,15 @@ const { ControllerModule } = require('./controller-module');
5
5
  const { generateClientAPIInterface } = require('./generate-client-api-interface');
6
6
 
7
7
  const {
8
- buildPatternMatcher,
9
- buildMethodMatcher,
10
- buildContentTypeMatcher,
11
- buildPathMatcher,
12
- buildRoutes,
13
8
  defineController,
14
9
  } = require('./controller-utils');
15
10
 
11
+ const Routes = require('./routes');
12
+
16
13
  module.exports = {
17
14
  ControllerBase,
18
15
  ControllerModule,
19
- buildPatternMatcher,
20
- buildMethodMatcher,
21
- buildContentTypeMatcher,
22
- buildPathMatcher,
23
- buildRoutes,
16
+ Routes,
24
17
  defineController,
25
18
  generateClientAPIInterface,
26
19
  };
@@ -0,0 +1,4 @@
1
+ export * from './route-capture';
2
+ export * from './route-endpoint';
3
+ export * from './route-scope-base';
4
+ export * from './route-scope';
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ RouteScopeBase,
5
+ } = require('./route-scope-base');
6
+
7
+ const {
8
+ RouteScope,
9
+ } = require('./route-scope');
10
+
11
+ const {
12
+ RouteCapture,
13
+ } = require('./route-capture');
14
+
15
+ const {
16
+ RouteEndpoint,
17
+ } = require('./route-endpoint');
18
+
19
+ module.exports = {
20
+ // Route scope base
21
+ RouteScopeBase,
22
+
23
+ // Route scope
24
+ RouteScope,
25
+
26
+ // Route capture
27
+ RouteCapture,
28
+
29
+ // Route endpoint
30
+ RouteEndpoint,
31
+ };
@@ -0,0 +1,32 @@
1
+ import { GenericObject } from '../../interfaces/common';
2
+ import { RouteScopeBase } from './route-scope-base';
3
+
4
+ export declare interface RouteCaptureOptions {
5
+ type?: string;
6
+ optional?: boolean;
7
+ }
8
+
9
+ export declare interface RouteCaptureHelperContext {
10
+ value: string;
11
+ request: Request;
12
+ method: string;
13
+ path: string;
14
+ contentType: string | undefined;
15
+ params: GenericObject;
16
+ }
17
+
18
+ export declare type RouteCaptureHelper = ((context: RouteCaptureHelperContext) => any) | RegExp;
19
+
20
+ export declare class RouteCapture {
21
+ declare _parentScope: RouteScopeBase;
22
+ declare _paramName: string;
23
+ declare _helper: RouteCaptureHelper | null;
24
+ declare _options: RouteCaptureOptions;
25
+
26
+ public constructor(parentScope: RouteScopeBase, paramName: string, _helperOrOptions?: RouteCaptureHelper | GenericObject, _options?: RouteCaptureOptions);
27
+ public getParentScope(): RouteScopeBase;
28
+ public getName(): string;
29
+ public isOptional(): boolean;
30
+ public clone(newOptions?: RouteCaptureOptions): RouteCapture;
31
+ public matches(context: RouteCaptureHelperContext): any;
32
+ }
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+
3
+ const Nife = require('nife');
4
+
5
+ class RouteCapture {
6
+ constructor(parentScope, paramName, _helperOrOptions, _options) {
7
+ let helper;
8
+ let options;
9
+
10
+ if (!Nife.instanceOf(paramName, 'string'))
11
+ throw new TypeError('RouteCapture::constructor: "paramName" is required to be a string.');
12
+
13
+ if (typeof _helperOrOptions === 'function' || _helperOrOptions instanceof RegExp) {
14
+ helper = _helperOrOptions;
15
+ options = _options || {};
16
+ } else {
17
+ options = _helperOrOptions || {};
18
+ }
19
+
20
+ Object.defineProperties(this, {
21
+ '_parentScope': {
22
+ writable: false,
23
+ enumerable: false,
24
+ configurable: false,
25
+ value: parentScope || null,
26
+ },
27
+ '_paramName': {
28
+ writable: false,
29
+ enumerable: false,
30
+ configurable: false,
31
+ value: paramName,
32
+ },
33
+ '_helper': {
34
+ writable: false,
35
+ enumerable: false,
36
+ configurable: false,
37
+ value: helper || null,
38
+ },
39
+ '_options': {
40
+ writable: false,
41
+ enumerable: false,
42
+ configurable: false,
43
+ value: options,
44
+ },
45
+ });
46
+ }
47
+
48
+ getParentScope = () => {
49
+ return this._parentScope;
50
+ };
51
+
52
+ getName() {
53
+ return this._paramName;
54
+ }
55
+
56
+ isOptional() {
57
+ return !!this._options.optional;
58
+ }
59
+
60
+ clone(newOptions) {
61
+ let options = Object.assign({}, this._options, newOptions || {});
62
+
63
+ if (this._helper)
64
+ return new this.constructor(this._parentScope, this._paramName, this._helper, options);
65
+ else
66
+ return new this.constructor(this._parentScope, this._paramName, options);
67
+ }
68
+
69
+ matches(context) {
70
+ let helper = this._helper;
71
+ if (typeof helper === 'function') {
72
+ return helper(context);
73
+ } else if (helper instanceof RegExp) {
74
+ let result = context.value.match(helper);
75
+ if (!result)
76
+ return;
77
+
78
+ return (result && result.groups) ? result.groups : result[0];
79
+ } else {
80
+ if (!this.isOptional() && Nife.isEmpty(context.value))
81
+ return;
82
+
83
+ let options = this._options || {};
84
+ let type = options.type || 'string';
85
+ return Nife.coerceValue(context.value, type);
86
+ }
87
+ }
88
+
89
+ toString() {
90
+ let paramName = this.getName();
91
+ let optional = this.isOptional();
92
+
93
+ return `<<${paramName}${(optional) ? '?' : ''}>>`;
94
+ }
95
+ }
96
+
97
+ module.exports = {
98
+ RouteCapture,
99
+ };
@@ -0,0 +1,26 @@
1
+ import { GenericObject } from '../../interfaces/common';
2
+ import { RouteScopeBase } from './route-scope-base';
3
+
4
+ export declare type EndpointMethods = 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | '*';
5
+
6
+ export declare interface EndpointOptions {
7
+ name?: string;
8
+ methods?: Array<EndpointMethods> | EndpointMethods;
9
+ contentType?: Array<string | RegExp> | string | RegExp;
10
+ controller: string;
11
+ path?: string;
12
+ help?: GenericObject;
13
+ queryParams?: GenericObject;
14
+ middleware?: Array<Function>;
15
+ [key: string | symbol]: any;
16
+ }
17
+
18
+ export declare class RouteEndpoint implements EndpointOptions {
19
+ declare _parentScope: RouteScopeBase;
20
+ declare isDynamic: boolean;
21
+ declare controller: string;
22
+ declare methods: Array<EndpointMethods>;
23
+
24
+ public constructor(parentScope: RouteScopeBase, attributes: EndpointOptions);
25
+ public getParentScope(): RouteScopeBase;
26
+ }
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ const Nife = require('nife');
4
+
5
+ class RouteEndpoint {
6
+ constructor(parentScope, attributes) {
7
+ Object.defineProperties(this, {
8
+ '_parentScope': {
9
+ writable: false,
10
+ enumerable: false,
11
+ configurable: false,
12
+ value: parentScope || null,
13
+ },
14
+ 'isDynamic': {
15
+ writable: true,
16
+ enumerable: false,
17
+ configurable: true,
18
+ value: false,
19
+ },
20
+ });
21
+
22
+ Object.assign(
23
+ this,
24
+ {
25
+ methods: [ 'GET' ],
26
+ contentType: [ 'application/json', 'multipart/form-data' ],
27
+ },
28
+ attributes,
29
+ );
30
+
31
+ this.methods = Nife.arrayFlatten(Nife.toArray(this.methods || []).filter(Boolean).map((method) => {
32
+ if (method === '*')
33
+ return [ 'GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS' ];
34
+
35
+ return ('' + method).toUpperCase();
36
+ }));
37
+
38
+ this.contentType = Nife.arrayFlatten(Nife.toArray(this.contentType || []).filter(Boolean).map((contentType) => {
39
+ if (contentType === '*')
40
+ return [];
41
+
42
+ if (contentType instanceof RegExp)
43
+ return contentType;
44
+
45
+ return ('' + contentType).split(';')[0].trim().toLowerCase();
46
+ }));
47
+
48
+ if (Nife.isEmpty(this.contentType))
49
+ this.contentType = null;
50
+ }
51
+
52
+ getParentScope = () => {
53
+ return this._parentScope;
54
+ };
55
+ }
56
+
57
+ module.exports = {
58
+ RouteEndpoint,
59
+ };
@@ -0,0 +1,29 @@
1
+ import { GenericObject } from '../../interfaces/common';
2
+ import { RouteCapture } from './route-capture';
3
+ import { RouteEndpoint } from './route-endpoint';
4
+
5
+ export declare type PathPart = string | RouteCapture;
6
+ export declare type RoutePart = RouteScopeBase | RouteEndpoint;
7
+
8
+ export declare interface RouteCallbackContext {
9
+ endpoint: RouteEndpoint;
10
+ pathParts: Array<PathPart>;
11
+ stop: (result: any) => void;
12
+ scope: RouteScopeBase;
13
+ }
14
+
15
+ export declare type RouteCallback = (context: RouteCallbackContext) => void;
16
+
17
+ export declare class RouteScopeBase {
18
+ declare _parentScope: RouteScopeBase | null;
19
+ declare _pathParts: Array<PathPart>;
20
+ declare _routes: Map<PathPart, RoutePart>;
21
+ declare isDynamic: boolean;
22
+
23
+ public constructor(parentScope?: RouteScopeBase | null, pathParts?: Array<PathPart> | null);
24
+ public getParentScope(): RouteScopeBase | null;
25
+ public addRoute(pathPart: PathPart, scope: RoutePart): void;
26
+ public isDynamicPathPart(pathPart: PathPart): boolean;
27
+ public walkRoutes(callback: RouteCallback): any;
28
+ public findFirstMatchingRoute(request: Request): { endpoint?: RouteEndpoint, params?: GenericObject, error?: string };
29
+ }
@@ -0,0 +1,196 @@
1
+ 'use strict';
2
+
3
+ const Nife = require('nife');
4
+ const { RouteCapture } = require('./route-capture');
5
+ const { RouteEndpoint } = require('./route-endpoint');
6
+
7
+ class RouteScopeBase {
8
+ constructor(parentScope, pathParts) {
9
+ Object.defineProperties(this, {
10
+ '_parentScope': {
11
+ writable: false,
12
+ enumerable: false,
13
+ configurable: false,
14
+ value: parentScope || null,
15
+ },
16
+ '_pathParts': {
17
+ writable: false,
18
+ enumerable: false,
19
+ configurable: false,
20
+ value: pathParts || [],
21
+ },
22
+ '_routes': {
23
+ writable: true,
24
+ enumerable: false,
25
+ configurable: true,
26
+ value: new Map(),
27
+ },
28
+ '_routeMatchCache': {
29
+ writable: true,
30
+ enumerable: false,
31
+ configurable: true,
32
+ value: new Map(),
33
+ },
34
+ 'isDynamic': {
35
+ writable: true,
36
+ enumerable: false,
37
+ configurable: true,
38
+ value: false,
39
+ },
40
+ });
41
+ }
42
+
43
+ getParentScope = () => {
44
+ return this._parentScope;
45
+ };
46
+
47
+ addRoute(pathPart, scope) {
48
+ let set = this._routes.get(pathPart);
49
+ if (!set) {
50
+ set = new Set();
51
+ this._routes.set(pathPart, set);
52
+ }
53
+
54
+ set.add(scope);
55
+ }
56
+
57
+ isDynamicPathPart(pathPart) {
58
+ if (pathPart instanceof RouteCapture)
59
+ return true;
60
+
61
+ return false;
62
+ }
63
+
64
+ walkRoutes(callback) {
65
+ const walk = (routeScope, pathParts) => {
66
+ for (let [ pathPart, children ] of routeScope._routes) {
67
+ if (isStopped)
68
+ break;
69
+
70
+ let newPathParts = pathParts.concat(pathPart);
71
+ for (let child of children) {
72
+ if (child instanceof RouteEndpoint)
73
+ callback({ endpoint: child, pathParts: newPathParts, stop, scope: routeScope });
74
+ else
75
+ walk(child, newPathParts);
76
+ }
77
+ }
78
+ };
79
+
80
+ let finalResult;
81
+ let isStopped = false;
82
+ let stop = (result) => {
83
+ isStopped = true;
84
+ finalResult = result;
85
+ };
86
+
87
+ walk(this, []);
88
+
89
+ return finalResult;
90
+ }
91
+
92
+ findFirstMatchingRoute(request) {
93
+ let method = request.method.toUpperCase();
94
+ let contentType = Nife.get(request, 'headers.content-type');
95
+ let path = decodeURIComponent(request.path);
96
+
97
+ if (contentType) {
98
+ contentType = contentType.split(';')[0];
99
+ if (contentType)
100
+ contentType = contentType.trim().toLowerCase();
101
+ }
102
+
103
+ let cacheKey = `${method}:${contentType}:${path}`;
104
+ let routeMatch = this._routeMatchCache.get(cacheKey);
105
+ if (routeMatch)
106
+ return routeMatch;
107
+
108
+ const matchesPathParts = (pathParts) => {
109
+ let params = {};
110
+
111
+ for (let i = 0, il = pathParts.length; i < il; i++) {
112
+ let pathPart = pathParts[i];
113
+ let incomingPathPart = incomingPathParts[i] || '';
114
+
115
+ if (pathPart instanceof RouteCapture) {
116
+ let result = pathPart.matches({ value: incomingPathPart, request, method, path, contentType, params });
117
+ if (result == null) {
118
+ if (pathPart.isOptional())
119
+ continue;
120
+
121
+ return;
122
+ }
123
+
124
+ params[pathPart.getName()] = result;
125
+ } else {
126
+ if (pathPart !== incomingPathPart)
127
+ return;
128
+ }
129
+ }
130
+
131
+ return params;
132
+ };
133
+
134
+ const contentTypeMatches = (endpointContentTypes) => {
135
+ if (!endpointContentTypes || !contentType)
136
+ return true;
137
+
138
+ for (let i = 0, il = endpointContentTypes.length; i < il; i++) {
139
+ let thisContentType = endpointContentTypes[i];
140
+ if ((thisContentType instanceof RegExp) && thisContentType.test(contentType))
141
+ return true;
142
+ else if (thisContentType === contentType)
143
+ return true;
144
+ }
145
+
146
+ return false;
147
+ };
148
+
149
+ let incomingPathParts = path.trim().replace(/^\/+/, '').split('/');
150
+ let possibleMatch;
151
+
152
+ let result = this.walkRoutes(({ endpoint, pathParts, stop }) => {
153
+ // Does method match route?
154
+ if (endpoint.methods.indexOf(method) < 0)
155
+ return;
156
+
157
+ // Because of optional capture groups, it is possible
158
+ // that the length could deviate by one.
159
+ if (pathParts.length !== incomingPathParts.length) {
160
+ if (Math.abs(pathParts.length - incomingPathParts.length) > 1)
161
+ return;
162
+
163
+ let lastPathPart = pathParts[pathParts.length - 1];
164
+ if (!((lastPathPart instanceof RouteCapture) && lastPathPart.isOptional()))
165
+ return;
166
+ }
167
+
168
+ let params = matchesPathParts(pathParts);
169
+ if (params) {
170
+ // Does the contentType match?
171
+ if ((method !== 'GET' && method !== 'HEAD') && !contentTypeMatches(endpoint.contentType)) {
172
+ possibleMatch = endpoint;
173
+ return;
174
+ }
175
+
176
+ return stop({ endpoint, params });
177
+ }
178
+ });
179
+
180
+ if (!result) {
181
+ if (possibleMatch)
182
+ return { endpoint: possibleMatch, error: 'BadContentType' };
183
+
184
+ return {};
185
+ }
186
+
187
+ if (!result.endpoint.isDynamic)
188
+ this._routeMatchCache.set(cacheKey, result);
189
+
190
+ return result;
191
+ }
192
+ }
193
+
194
+ module.exports = {
195
+ RouteScopeBase,
196
+ };