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.
- package/package.json +1 -1
- package/src/application.d.ts +3 -1
- package/src/application.js +7 -0
- package/src/cli/cli-utils.js +11 -0
- package/src/cli/deploy-command.js +4 -0
- package/src/cli/routes-command.js +10 -33
- package/src/controllers/controller-module.d.ts +0 -1
- package/src/controllers/controller-module.js +4 -13
- package/src/controllers/controller-utils.d.ts +0 -32
- package/src/controllers/controller-utils.js +1 -407
- package/src/controllers/generate-client-api-interface.js +44 -58
- package/src/controllers/index.d.ts +1 -0
- package/src/controllers/index.js +3 -10
- package/src/controllers/routes/index.d.ts +4 -0
- package/src/controllers/routes/index.js +31 -0
- package/src/controllers/routes/route-capture.d.ts +32 -0
- package/src/controllers/routes/route-capture.js +99 -0
- package/src/controllers/routes/route-endpoint.d.ts +26 -0
- package/src/controllers/routes/route-endpoint.js +59 -0
- package/src/controllers/routes/route-scope-base.d.ts +29 -0
- package/src/controllers/routes/route-scope-base.js +196 -0
- package/src/controllers/routes/route-scope.d.ts +10 -0
- package/src/controllers/routes/route-scope.js +48 -0
- package/src/http-server/http-errors.js +7 -7
- package/src/http-server/http-server.d.ts +3 -1
- package/src/http-server/http-server.js +24 -37
- package/src/models/model.js +1 -1
- package/src/http-server/stop.js +0 -528
package/package.json
CHANGED
package/src/application.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ConnectionBase, ModelClass, Models } from 'mythix-orm';
|
|
2
2
|
import { ControllerClass } from './controllers/controller-base';
|
|
3
|
+
import { RouteScope } from './controllers/routes/route-scope';
|
|
3
4
|
import { HTTPServer } from './http-server/http-server';
|
|
4
5
|
import { GenericObject } from './interfaces/common';
|
|
5
6
|
import { Logger, LoggerClass, LoggerOptions } from './logger';
|
|
@@ -54,7 +55,8 @@ export declare class Application {
|
|
|
54
55
|
public getConfig(): GenericObject;
|
|
55
56
|
public setConfig(options: GenericObject): Application;
|
|
56
57
|
public getApplicationName(): string;
|
|
57
|
-
public
|
|
58
|
+
public _getRoutes(): RouteScope;
|
|
59
|
+
public getRoutes(context: RouteScope): void;
|
|
58
60
|
public getCustomRouteParserTypes(): { [key: string]: (value: string, param: GenericObject, index?: number) => any };
|
|
59
61
|
public createLogger(loggerOptions: LoggerOptions, LoggerClass: LoggerClass): Logger;
|
|
60
62
|
public getLogger(): Logger;
|
package/src/application.js
CHANGED
|
@@ -15,6 +15,7 @@ const { ControllerModule } = require('./controllers/controller-module');
|
|
|
15
15
|
const { TaskModule } = require('./tasks/task-module');
|
|
16
16
|
const { FileWatcherModule } = require('./modules/file-watcher-module');
|
|
17
17
|
const { wrapConfig } = require('./utils');
|
|
18
|
+
const ControllerRoutes = require('./controllers/routes');
|
|
18
19
|
|
|
19
20
|
// Trace what is requesting the application exit
|
|
20
21
|
|
|
@@ -272,6 +273,12 @@ class Application extends EventEmitter {
|
|
|
272
273
|
return this;
|
|
273
274
|
}
|
|
274
275
|
|
|
276
|
+
_getRoutes() {
|
|
277
|
+
let routeScope = new ControllerRoutes.RouteScope();
|
|
278
|
+
this.getRoutes(routeScope);
|
|
279
|
+
return routeScope;
|
|
280
|
+
}
|
|
281
|
+
|
|
275
282
|
getRoutes() {
|
|
276
283
|
throw new Error('Error: child application expected to implement "getRoutes" method');
|
|
277
284
|
}
|
package/src/cli/cli-utils.js
CHANGED
|
@@ -78,6 +78,17 @@ class CommandBase {
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
childProcess.on('error', (error) => {
|
|
81
|
+
if (options && options.ignoreExitCode) {
|
|
82
|
+
resolve({
|
|
83
|
+
stdout: Buffer.concat(output).toString('utf8'),
|
|
84
|
+
stderr: Buffer.concat(errors).toString('utf8'),
|
|
85
|
+
code: 0,
|
|
86
|
+
error,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
81
92
|
reject({
|
|
82
93
|
stdout: Buffer.concat(output).toString('utf8'),
|
|
83
94
|
stderr: Buffer.concat(errors).toString('utf8'),
|
|
@@ -68,6 +68,10 @@ module.exports = defineCommand('deploy', ({ Parent }) => {
|
|
|
68
68
|
try {
|
|
69
69
|
return await super.spawnCommand(command, args, options);
|
|
70
70
|
} catch (error) {
|
|
71
|
+
console.error('Error with command: ', { dryRun, command, args, options }, error);
|
|
72
|
+
if (error.stderr)
|
|
73
|
+
console.error(error.stderr);
|
|
74
|
+
|
|
71
75
|
if (error instanceof Error)
|
|
72
76
|
throw error;
|
|
73
77
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const Nife = require('nife');
|
|
3
4
|
const { defineCommand } = require('./cli-utils');
|
|
4
5
|
const { Logger } = require('../logger');
|
|
5
|
-
const { buildRoutes } = require('../controllers/controller-utils');
|
|
6
|
-
|
|
7
|
-
const TAB_SIZE = 8;
|
|
8
6
|
|
|
9
7
|
module.exports = defineCommand('routes', ({ Parent }) => {
|
|
10
8
|
return class RoutesCommand extends Parent {
|
|
@@ -19,40 +17,19 @@ module.exports = defineCommand('routes', ({ Parent }) => {
|
|
|
19
17
|
};
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
buildRoutes(httpServer, routes) {
|
|
23
|
-
let application = this.getApplication();
|
|
24
|
-
let customParserTypes = application.getCustomRouteParserTypes(httpServer, routes);
|
|
25
|
-
|
|
26
|
-
return buildRoutes(routes, customParserTypes);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
20
|
execute() {
|
|
30
|
-
const whitespaceOfLength = (len) => {
|
|
31
|
-
if (len < 0)
|
|
32
|
-
return '';
|
|
33
|
-
|
|
34
|
-
let parts = new Array(len);
|
|
35
|
-
for (let i = 0, il = parts.length; i < il; i++)
|
|
36
|
-
parts[i] = ' ';
|
|
37
|
-
|
|
38
|
-
return parts.join('');
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const stringToLength = (str, len) => {
|
|
42
|
-
return `${str}${whitespaceOfLength(len - str.length)}`;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
21
|
let application = this.getApplication();
|
|
46
|
-
let routes =
|
|
22
|
+
let routes = application._getRoutes();
|
|
23
|
+
let whitespace = ' ';
|
|
47
24
|
|
|
48
|
-
|
|
49
|
-
let methods = route.methods;
|
|
50
|
-
if (!methods === '*')
|
|
51
|
-
methods = [ '{ANY}' ];
|
|
25
|
+
console.log(`${application.getApplicationName()} routes:`);
|
|
52
26
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
27
|
+
routes.walkRoutes(({ endpoint }) => {
|
|
28
|
+
let methods = endpoint.methods;
|
|
29
|
+
for (let i = 0, il = methods.length; i < il; i++) {
|
|
30
|
+
let method = methods[i];
|
|
31
|
+
console.log(` ${method}${whitespace.substring(0, whitespace.length - method.length)}/${endpoint.path} -> [${endpoint.controller}]${(endpoint.isDynamic) ? ' (dynamic)' : ''}`);
|
|
32
|
+
}
|
|
56
33
|
});
|
|
57
34
|
}
|
|
58
35
|
};
|
|
@@ -7,5 +7,4 @@ export class ControllerModule extends BaseModule {
|
|
|
7
7
|
public getControllerFilePaths(controllersPath: string): Array<string>;
|
|
8
8
|
public loadControllers(controllersPath: string): ControllerClasses;
|
|
9
9
|
public getController(name: string): { controller: ControllerClass, controllerMethod: string | undefined };
|
|
10
|
-
public buildRoutes(httpServer: HTTPServer, routes: Array<GenericObject>): Array<GenericObject>;
|
|
11
10
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const Nife = require('nife');
|
|
4
4
|
const { BaseModule } = require('../modules/base-module');
|
|
5
|
-
const { buildRoutes } = require('./controller-utils');
|
|
6
5
|
const {
|
|
7
6
|
fileNameWithoutExtension,
|
|
8
7
|
walkDir,
|
|
@@ -108,22 +107,14 @@ class ControllerModule extends BaseModule {
|
|
|
108
107
|
};
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
buildRoutes(httpServer, routes) {
|
|
112
|
-
let application = this.getApplication();
|
|
113
|
-
let customParserTypes = application.getCustomRouteParserTypes(httpServer, routes);
|
|
114
|
-
|
|
115
|
-
return buildRoutes(routes, customParserTypes);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
110
|
async start(options) {
|
|
119
|
-
let application
|
|
120
|
-
let httpServer
|
|
121
|
-
let controllers
|
|
111
|
+
let application = this.getApplication();
|
|
112
|
+
let httpServer = (typeof application.getHTTPServer === 'function') ? application.getHTTPServer() : null;
|
|
113
|
+
let controllers = await this.loadControllers(options.controllersPath);
|
|
122
114
|
|
|
123
115
|
this.controllers = controllers;
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
httpServer.setRoutes(routes);
|
|
117
|
+
httpServer.setRoutes(application._getRoutes());
|
|
127
118
|
}
|
|
128
119
|
|
|
129
120
|
async stop() {
|
|
@@ -1,34 +1,7 @@
|
|
|
1
1
|
import { Application } from '../application';
|
|
2
2
|
import { HTTPServer } from '../http-server';
|
|
3
|
-
import { GenericObject } from '../interfaces/common';
|
|
4
3
|
import { ControllerClass } from './controller-base';
|
|
5
4
|
|
|
6
|
-
export declare interface BuildPatternMatcherOptions {
|
|
7
|
-
strict?: boolean;
|
|
8
|
-
sanitize?: (value: string) => string;
|
|
9
|
-
flags?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export declare interface PatternMatcherMethod {
|
|
13
|
-
(value: string): boolean;
|
|
14
|
-
regexp: RegExp;
|
|
15
|
-
directPatterns: Array<RegExp>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export declare interface PathMatcherMethod {
|
|
19
|
-
(pathPart: string): GenericObject | undefined;
|
|
20
|
-
regexp: RegExp;
|
|
21
|
-
params: Array<string>;
|
|
22
|
-
sanitizedPath: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export declare type RoutePatterns = string | RegExp | Array<string | RegExp>;
|
|
26
|
-
|
|
27
|
-
export declare function buildPatternMatcher(
|
|
28
|
-
patterns: RoutePatterns,
|
|
29
|
-
options?: BuildPatternMatcherOptions
|
|
30
|
-
): PatternMatcherMethod;
|
|
31
|
-
|
|
32
5
|
export declare interface DefineControllerContext<T = ControllerClass> {
|
|
33
6
|
Parent: T;
|
|
34
7
|
application: Application;
|
|
@@ -36,11 +9,6 @@ export declare interface DefineControllerContext<T = ControllerClass> {
|
|
|
36
9
|
controllerName: string;
|
|
37
10
|
}
|
|
38
11
|
|
|
39
|
-
export declare function buildMethodMatcher(patterns: RoutePatterns): PatternMatcherMethod;
|
|
40
|
-
export declare function buildContentTypeMatcher(patterns: RoutePatterns): PatternMatcherMethod;
|
|
41
|
-
export declare function buildPathMatcher(routeName: string, customParserTypes: GenericObject): PathMatcherMethod;
|
|
42
|
-
export declare function buildRoutes(routes: GenericObject | Array<GenericObject>, customParserTypes?: GenericObject): Array<GenericObject>;
|
|
43
|
-
|
|
44
12
|
export declare function defineController<T = ControllerClass>(
|
|
45
13
|
controllerName: string,
|
|
46
14
|
definer: (context: DefineControllerContext<T>) => ControllerClass,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { ControllerBase } = require('./controller-base');
|
|
3
|
+
const { ControllerBase } = require('./controller-base');
|
|
5
4
|
|
|
6
5
|
function defineController(controllerName, definer, _parent) {
|
|
7
6
|
let parentKlass = _parent || ControllerBase;
|
|
@@ -20,411 +19,6 @@ function defineController(controllerName, definer, _parent) {
|
|
|
20
19
|
};
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
const ROUTE_PROPERTIES = [
|
|
24
|
-
'name',
|
|
25
|
-
'accept',
|
|
26
|
-
'controller',
|
|
27
|
-
'methods',
|
|
28
|
-
'middleware',
|
|
29
|
-
'priority',
|
|
30
|
-
'queryParams',
|
|
31
|
-
'clientOptions',
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
function buildPatternMatcher(_patterns, _opts) {
|
|
35
|
-
let opts = _opts || {};
|
|
36
|
-
let patterns = _patterns;
|
|
37
|
-
let sanitizeFunc = opts.sanitize;
|
|
38
|
-
let strict = opts.strict;
|
|
39
|
-
let flags = (Nife.instanceOf(opts.flags, 'string') && Nife.isNotEmpty(opts.flags)) ? opts.flags : 'i';
|
|
40
|
-
let matchRE;
|
|
41
|
-
let matchFunc;
|
|
42
|
-
|
|
43
|
-
if (Nife.instanceOf(patterns, 'array'))
|
|
44
|
-
patterns = Nife.uniq(patterns);
|
|
45
|
-
|
|
46
|
-
if (patterns === '*' || (Nife.instanceOf(patterns, 'array') && patterns.indexOf('*') >= 0) || patterns instanceof RegExp) {
|
|
47
|
-
matchRE = (patterns instanceof RegExp) ? patterns : /.*/i;
|
|
48
|
-
|
|
49
|
-
matchFunc = function patternMatcher(value) {
|
|
50
|
-
if (!value || !Nife.instanceOf(value, 'string'))
|
|
51
|
-
return true;
|
|
52
|
-
|
|
53
|
-
return !!value.match(matchRE);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
Object.defineProperties(matchFunc, {
|
|
57
|
-
'regexp': {
|
|
58
|
-
writable: false,
|
|
59
|
-
enumerable: false,
|
|
60
|
-
configurable: false,
|
|
61
|
-
value: matchRE,
|
|
62
|
-
},
|
|
63
|
-
'directPatterns': {
|
|
64
|
-
writable: false,
|
|
65
|
-
enumerable: false,
|
|
66
|
-
configurable: false,
|
|
67
|
-
value: [],
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
return matchFunc;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!Nife.instanceOf(patterns, 'array'))
|
|
75
|
-
patterns = [ patterns ];
|
|
76
|
-
|
|
77
|
-
let parts = [];
|
|
78
|
-
let directPatterns = [];
|
|
79
|
-
|
|
80
|
-
for (let i = 0, il = patterns.length; i < il; i++) {
|
|
81
|
-
let part = patterns[i];
|
|
82
|
-
|
|
83
|
-
if (part instanceof RegExp) {
|
|
84
|
-
directPatterns.push(part);
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (typeof sanitizeFunc === 'function') {
|
|
89
|
-
part = sanitizeFunc(part);
|
|
90
|
-
} else {
|
|
91
|
-
part = part.replace(/\*/g, '@@@WILD_MATCH@@@');
|
|
92
|
-
part = Nife.regexpEscape(part);
|
|
93
|
-
part = part.replace(/@@@WILD_MATCH@@@/g, '.*?');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
parts.push(part);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (parts && parts.length)
|
|
100
|
-
matchRE = new RegExp((strict) ? `^(${parts.join('|')})$` : `(${parts.join('|')})`, flags);
|
|
101
|
-
|
|
102
|
-
matchFunc = function patternMatcher(value) {
|
|
103
|
-
if (!value || !Nife.instanceOf(value, 'string'))
|
|
104
|
-
return false;
|
|
105
|
-
|
|
106
|
-
if (directPatterns && directPatterns.length) {
|
|
107
|
-
for (let j = 0, jl = directPatterns.length; j < jl; j++) {
|
|
108
|
-
let pattern = directPatterns[j];
|
|
109
|
-
if (value.match(pattern))
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!matchRE)
|
|
115
|
-
return false;
|
|
116
|
-
|
|
117
|
-
return !!value.match(matchRE);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
Object.defineProperties(matchFunc, {
|
|
121
|
-
'regexp': {
|
|
122
|
-
writable: false,
|
|
123
|
-
enumerable: false,
|
|
124
|
-
configurable: false,
|
|
125
|
-
value: matchRE,
|
|
126
|
-
},
|
|
127
|
-
'directPatterns': {
|
|
128
|
-
writable: false,
|
|
129
|
-
enumerable: false,
|
|
130
|
-
configurable: false,
|
|
131
|
-
value: directPatterns,
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
return matchFunc;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function buildMethodMatcher(methods) {
|
|
139
|
-
return buildPatternMatcher(methods, { strict: true });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function buildContentTypeMatcher(contentTypePatterns) {
|
|
143
|
-
return buildPatternMatcher(contentTypePatterns);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function buildPathMatcher(routeName, customParserTypes) {
|
|
147
|
-
let params = [];
|
|
148
|
-
let parts = [];
|
|
149
|
-
let lastOffset = 0;
|
|
150
|
-
|
|
151
|
-
let sanitizedPath = routeName.replace(/<\s*([^\s:]+?\??)\s*(:\w+?)?\s*(=\s*[^>]+)?>/g, function(m, _name, _type, _defaultValue, offset, str) {
|
|
152
|
-
if (offset > lastOffset) {
|
|
153
|
-
parts.push(str.substring(lastOffset, offset));
|
|
154
|
-
lastOffset = offset + m.length;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
let defaultValue = _defaultValue;
|
|
158
|
-
let type = _type;
|
|
159
|
-
let optional = false;
|
|
160
|
-
let name = _name;
|
|
161
|
-
|
|
162
|
-
if (name.match(/\?$/)) {
|
|
163
|
-
optional = true;
|
|
164
|
-
name = name.substring(0, name.length - 1);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (type)
|
|
168
|
-
type = type.replace(/\W/g, '');
|
|
169
|
-
|
|
170
|
-
if (defaultValue) {
|
|
171
|
-
defaultValue = defaultValue.trim().replace(/^=\s*/, '');
|
|
172
|
-
defaultValue = Nife.coerceValue(defaultValue, type);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let matcher;
|
|
176
|
-
|
|
177
|
-
if (type === 'number' || type === 'int' || type === 'integer' || type === 'bigint')
|
|
178
|
-
matcher = '([\\d.e-]+)';
|
|
179
|
-
else if (type === 'boolean' || type === 'bool')
|
|
180
|
-
matcher = '(true|True|TRUE|false|False|FALSE)';
|
|
181
|
-
else
|
|
182
|
-
matcher = (optional) ? '(.*?)' : '(.+?)';
|
|
183
|
-
|
|
184
|
-
if (optional)
|
|
185
|
-
matcher = matcher + '?';
|
|
186
|
-
|
|
187
|
-
let param = {
|
|
188
|
-
startOffset: offset,
|
|
189
|
-
endOffset: offset + m.length,
|
|
190
|
-
name,
|
|
191
|
-
type,
|
|
192
|
-
defaultValue,
|
|
193
|
-
matcher,
|
|
194
|
-
optional,
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
params.push(param);
|
|
198
|
-
parts.push(param);
|
|
199
|
-
|
|
200
|
-
return `<<${name}${(optional) ? '?' : ''}>>`;
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (lastOffset < routeName.length)
|
|
204
|
-
parts.push(routeName.substring(lastOffset));
|
|
205
|
-
|
|
206
|
-
let finalRegExpStr = parts.reduce((items, _item, index) => {
|
|
207
|
-
let item = _item;
|
|
208
|
-
|
|
209
|
-
if (typeof item === 'string') {
|
|
210
|
-
item = item.replace(/\?/g, '@@@CHAR_MATCH@@@').replace(/\*/g, '@@@WILD_MATCH@@@').replace(/\/+/g, '@@@FORWARD_SLASH@@@');
|
|
211
|
-
item = Nife.regexpEscape(item);
|
|
212
|
-
item = item.replace(/@@@CHAR_MATCH@@@/g, '.').replace(/@@@WILD_MATCH@@@/g, '.*?').replace(/@@@FORWARD_SLASH@@@/g, '/');
|
|
213
|
-
|
|
214
|
-
if (item.match(/\/$/)) {
|
|
215
|
-
let nextItem = parts[index + 1];
|
|
216
|
-
if (nextItem && typeof nextItem !== 'string' && nextItem.optional)
|
|
217
|
-
item = item + '?';
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
items.push(item);
|
|
221
|
-
} else {
|
|
222
|
-
items.push(item.matcher);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return items;
|
|
226
|
-
}, []).join('');
|
|
227
|
-
|
|
228
|
-
let matcherRE = new RegExp(`^${finalRegExpStr}$`);
|
|
229
|
-
let matchFunc = function routeMatcher(pathPart) {
|
|
230
|
-
let match = pathPart.match(matcherRE);
|
|
231
|
-
if (!match)
|
|
232
|
-
return;
|
|
233
|
-
|
|
234
|
-
let result = {};
|
|
235
|
-
for (let i = 1, il = match.length; i < il; i++) {
|
|
236
|
-
let part = match[i];
|
|
237
|
-
if (!part)
|
|
238
|
-
continue;
|
|
239
|
-
|
|
240
|
-
let paramIndex = i - 1;
|
|
241
|
-
let param = params[paramIndex];
|
|
242
|
-
if (!param)
|
|
243
|
-
continue;
|
|
244
|
-
|
|
245
|
-
if (customParserTypes && Object.prototype.hasOwnProperty.call(customParserTypes, param.type))
|
|
246
|
-
result[param.name] = customParserTypes[param.type](part, param, paramIndex);
|
|
247
|
-
else
|
|
248
|
-
result[param.name] = Nife.coerceValue(part, param.type);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return result;
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
Object.defineProperties(matchFunc, {
|
|
255
|
-
'regexp': {
|
|
256
|
-
writable: false,
|
|
257
|
-
enumerable: false,
|
|
258
|
-
configurable: false,
|
|
259
|
-
value: matcherRE,
|
|
260
|
-
},
|
|
261
|
-
'params': {
|
|
262
|
-
writable: false,
|
|
263
|
-
enumerable: false,
|
|
264
|
-
configurable: false,
|
|
265
|
-
value: params,
|
|
266
|
-
},
|
|
267
|
-
'sanitizedPath': {
|
|
268
|
-
writable: false,
|
|
269
|
-
enumerable: false,
|
|
270
|
-
configurable: false,
|
|
271
|
-
value: sanitizedPath,
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
return matchFunc;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function compileRoutes(routes, customParserTypes, _context) {
|
|
279
|
-
const addRoute = (theseRoutes, route, path, priority) => {
|
|
280
|
-
let newRoute = Object.assign(
|
|
281
|
-
{
|
|
282
|
-
methods: 'GET',
|
|
283
|
-
accept: '*',
|
|
284
|
-
priority,
|
|
285
|
-
},
|
|
286
|
-
route || {},
|
|
287
|
-
{
|
|
288
|
-
path: path.replace(/\/{2,}/g, '/'),
|
|
289
|
-
},
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
if (Nife.instanceOf(newRoute.methods, 'array')) {
|
|
293
|
-
newRoute.methods = Nife
|
|
294
|
-
.uniq(newRoute.methods)
|
|
295
|
-
.filter((method) => ((typeof method === 'string' || method instanceof String) && Nife.isNotEmpty(method)))
|
|
296
|
-
.map((method) => method.toUpperCase());
|
|
297
|
-
|
|
298
|
-
if (newRoute.methods.indexOf('*') >= 0)
|
|
299
|
-
newRoute.methods = '*';
|
|
300
|
-
} else {
|
|
301
|
-
if (Nife.instanceOf(newRoute.methods, 'string') || Nife.isEmpty(newRoute.methods))
|
|
302
|
-
newRoute.methods = 'GET';
|
|
303
|
-
|
|
304
|
-
newRoute.methods = newRoute.methods.toUpperCase();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
theseRoutes.push(newRoute);
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
let context = _context || {};
|
|
311
|
-
let theseRoutes = [];
|
|
312
|
-
let isArray = (routes instanceof Array);
|
|
313
|
-
let {
|
|
314
|
-
routeName,
|
|
315
|
-
path,
|
|
316
|
-
alreadyVisited,
|
|
317
|
-
depth,
|
|
318
|
-
} = context;
|
|
319
|
-
|
|
320
|
-
if (!alreadyVisited)
|
|
321
|
-
alreadyVisited = new Map();
|
|
322
|
-
|
|
323
|
-
if (alreadyVisited.get(routes))
|
|
324
|
-
return [];
|
|
325
|
-
|
|
326
|
-
alreadyVisited.set(routes, true);
|
|
327
|
-
|
|
328
|
-
if (!depth)
|
|
329
|
-
depth = 0;
|
|
330
|
-
|
|
331
|
-
if (Nife.isEmpty(routeName))
|
|
332
|
-
routeName = '/';
|
|
333
|
-
|
|
334
|
-
if (!path)
|
|
335
|
-
path = '/';
|
|
336
|
-
|
|
337
|
-
path = path.replace(/\/{2,}/g, '/');
|
|
338
|
-
|
|
339
|
-
// eslint-disable-next-line no-magic-numbers
|
|
340
|
-
let basePriority = 1000000 - (depth * 1000);
|
|
341
|
-
let keys = Object.keys(routes);
|
|
342
|
-
|
|
343
|
-
for (let i = 0, il = keys.length; i < il; i++) {
|
|
344
|
-
let key = keys[i];
|
|
345
|
-
let route = routes[key];
|
|
346
|
-
|
|
347
|
-
if (route && Nife.isNotEmpty(route.controller)) {
|
|
348
|
-
let newPath = (isArray) ? path : `${path}/${key}`;
|
|
349
|
-
addRoute(theseRoutes, route, newPath, basePriority + i);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (ROUTE_PROPERTIES.indexOf(key) >= 0 || Nife.instanceOf(route, 'boolean', 'string', 'number', 'bigint'))
|
|
353
|
-
continue;
|
|
354
|
-
|
|
355
|
-
let thisRouteName = (isArray) ? routeName : key;
|
|
356
|
-
let newPath = (isArray) ? path : `${path}/${key}`;
|
|
357
|
-
|
|
358
|
-
if (Nife.instanceOf(route, 'object', 'array')) {
|
|
359
|
-
let subRoutes = compileRoutes(route, customParserTypes, {
|
|
360
|
-
routeName: thisRouteName,
|
|
361
|
-
path: newPath,
|
|
362
|
-
priority: i,
|
|
363
|
-
depth: depth + 1,
|
|
364
|
-
alreadyVisited,
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
if (!subRoutes || !subRoutes.length)
|
|
368
|
-
continue;
|
|
369
|
-
|
|
370
|
-
theseRoutes = [].concat(subRoutes, theseRoutes);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return theseRoutes;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function buildRoutes(_routes, customParserTypes) {
|
|
378
|
-
const sortRoutes = (routesToSort) => {
|
|
379
|
-
return routesToSort.sort((a, b) => {
|
|
380
|
-
// We convert "<" to "{" and ">" to "}"
|
|
381
|
-
// to get the desired sort order...
|
|
382
|
-
// This is so that capture parameters
|
|
383
|
-
// always come last.
|
|
384
|
-
const mangle = (str) => {
|
|
385
|
-
return str.replace(/</g, '{').replace(/>/g, '}');
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
// We pad the priority number so as not to get:
|
|
389
|
-
// 100
|
|
390
|
-
// 10
|
|
391
|
-
// 1
|
|
392
|
-
// sort order funkiness
|
|
393
|
-
|
|
394
|
-
// eslint-disable-next-line no-magic-numbers
|
|
395
|
-
let pathA = mangle(`${a.path}${('' + a.priority).padStart(12, '0')}`);
|
|
396
|
-
// eslint-disable-next-line no-magic-numbers
|
|
397
|
-
let pathB = mangle(`${b.path}${('' + b.priority).padStart(12, '0')}`);
|
|
398
|
-
|
|
399
|
-
if (pathA === pathB)
|
|
400
|
-
return 0;
|
|
401
|
-
|
|
402
|
-
return (pathA < pathB) ? -1 : 1;
|
|
403
|
-
});
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
let routes = compileRoutes(_routes, customParserTypes);
|
|
407
|
-
|
|
408
|
-
routes = sortRoutes(routes);
|
|
409
|
-
|
|
410
|
-
return routes.map((route) => {
|
|
411
|
-
// Filter out priority key
|
|
412
|
-
let thisRoute = Nife.extend(Nife.extend.FILTER, (key) => !key.match(/^(priority)$/), {}, route);
|
|
413
|
-
|
|
414
|
-
// Inject route matchers
|
|
415
|
-
thisRoute.methodMatcher = buildMethodMatcher(thisRoute.methods || '*');
|
|
416
|
-
thisRoute.contentTypeMatcher = buildContentTypeMatcher(thisRoute.accept || '*');
|
|
417
|
-
thisRoute.pathMatcher = buildPathMatcher(thisRoute.path, customParserTypes);
|
|
418
|
-
|
|
419
|
-
return thisRoute;
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
|
|
423
22
|
module.exports = {
|
|
424
|
-
buildPatternMatcher,
|
|
425
|
-
buildMethodMatcher,
|
|
426
|
-
buildContentTypeMatcher,
|
|
427
|
-
buildPathMatcher,
|
|
428
|
-
buildRoutes,
|
|
429
23
|
defineController,
|
|
430
24
|
};
|