1
1
import { FabrixApp } from '@fabrix/fabrix'
2
+ import { FabrixController } from '@fabrix/fabrix/dist/common'
3
+ import { FabrixPolicy } from '@fabrix/fabrix/dist/common'
2
4
import { get , omit , isString } from 'lodash'
3
5
import { Router } from 'call'
4
6
import { IRoute } from './interfaces/IRoute'
5
7
8
+
6
9
export const Utils = {
7
10
methods : [
8
11
'GET' ,
@@ -23,10 +26,143 @@ export const Utils = {
23
26
return isString ( strOrArray ) ? [ strOrArray ] : strOrArray
24
27
} ,
25
28
29
+ /**
30
+ * If a route has nested methods that have a seperate prefix, then it needs to be split into
31
+ * multiple routes
32
+ */
33
+ splitRoute ( app : FabrixApp , path : string , rawRoute : IRoute ) : { path : string , route : any } [ ] {
34
+ const methods = [ '*' , ...Utils . methods ]
35
+ const routeMethods = new Set ( )
36
+ const usedPrefixes = new Set ( )
37
+ const orgRoute = Object . assign ( { } , rawRoute )
38
+ const parentPrefix = get ( orgRoute , 'config.prefix' )
39
+
40
+ // The route must have a config to be set
41
+ orgRoute . config = orgRoute . config || ( orgRoute . config = { } )
42
+ orgRoute . config . pre = orgRoute . config . pre || ( orgRoute . config . pre = [ ] )
43
+
44
+ // Add a prefix if given
45
+ if ( typeof parentPrefix !== 'undefined' ) {
46
+ usedPrefixes . add ( parentPrefix )
47
+ }
48
+
49
+ // Scenario 1: A wild card has a an object config different then the top level config = method prefix
50
+ // Scenario 2: Prefix is set on the top level config and not on any methods = all have same prefix
51
+ // Scenario 3: An Identical Prefix is set on the methods and not on the parent = all have same prefix
52
+ // Scenario 4: A method has a different prefix then top level config = generate 2+ routes
53
+ // Scenario 5: There is only one method and it's prefix is different then the top level = method prefix
54
+ const cases = new Set ( )
55
+
56
+ methods . forEach ( method => {
57
+ if ( orgRoute . hasOwnProperty ( method ) ) {
58
+ const methodPrefix = get ( rawRoute [ method ] , 'config.prefix' )
59
+ routeMethods . add ( { [ method ] : methodPrefix } )
60
+
61
+ // Add a prefix if given
62
+ if ( typeof methodPrefix !== 'undefined' ) {
63
+ usedPrefixes . add ( methodPrefix )
64
+ }
65
+
66
+ // Scenario 1
67
+ if ( method === '*' && methodPrefix ) {
68
+ cases . add ( 1 )
69
+ }
70
+ // Scenario 4
71
+ if ( typeof parentPrefix === 'undefined' && methodPrefix && usedPrefixes . size > 1 ) {
72
+ cases . add ( 4 )
73
+ }
74
+ }
75
+ } )
76
+
77
+ // Scenario 2
78
+ if (
79
+ typeof parentPrefix !== 'undefined'
80
+ && usedPrefixes . size === 1
81
+ ) {
82
+ cases . add ( 2 )
83
+ }
84
+
85
+ // Scenario 3
86
+ if (
87
+ typeof parentPrefix === 'undefined'
88
+ && usedPrefixes . size === 1
89
+ ) {
90
+ cases . add ( 3 )
91
+ }
92
+
93
+ // Scenario 5
94
+ if (
95
+ typeof parentPrefix !== 'undefined'
96
+ && routeMethods . size === 1
97
+ && usedPrefixes . size > 1
98
+ ) {
99
+ cases . add ( 5 )
100
+ }
101
+
102
+ const scenarios = {
103
+ '1' : cases . has ( 1 ) ,
104
+ '2' : cases . has ( 2 ) ,
105
+ '3' : cases . has ( 3 ) ,
106
+ '4' : cases . has ( 4 ) ,
107
+ '5' : cases . has ( 5 )
108
+ }
109
+
110
+ const type = Object . keys ( scenarios ) . find ( ( key ) => scenarios [ key ] )
111
+
112
+ switch ( type ) {
113
+ case '1' : {
114
+ orgRoute . config . prefix = orgRoute [ '*' ] . config . prefix
115
+ return Utils . buildRoute ( app , path , orgRoute )
116
+ }
117
+ case '2' : {
118
+ return Utils . buildRoute ( app , path , orgRoute )
119
+ }
120
+ case '3' : {
121
+ orgRoute . config . prefix = usedPrefixes . values ( ) . next ( ) . value
122
+ return Utils . buildRoute ( app , path , orgRoute )
123
+ }
124
+ case '4' : {
125
+ const routes = new Set ( )
126
+ const newRoutes = new Map ( )
127
+ routeMethods . forEach ( route => {
128
+ const method : string = Object . keys ( route ) [ 0 ]
129
+ const prefix : any = route [ method ]
130
+ if ( prefix !== parentPrefix ) {
131
+ const newRoute : IRoute = {
132
+ [ method ] : orgRoute [ method ] ,
133
+ config : {
134
+ prefix : prefix
135
+ }
136
+ }
137
+ if ( newRoutes . has ( prefix ) ) {
138
+ newRoutes . set ( prefix , { ...newRoute , ...newRoutes . get ( prefix ) } )
139
+ }
140
+ else {
141
+ newRoutes . set ( prefix , newRoute )
142
+ }
143
+ delete orgRoute [ method ]
144
+ }
145
+ } )
146
+ newRoutes . forEach ( newRoute => {
147
+ routes . add ( Utils . buildRoute ( app , path , newRoute ) )
148
+ } )
149
+ routes . add ( Utils . buildRoute ( app , path , orgRoute ) )
150
+ return Array . from ( routes ) . reduce ( ( a , b ) => a . concat ( b ) , [ ] )
151
+ }
152
+ case '5' : {
153
+ orgRoute . config . prefix = Array . from ( usedPrefixes ) . pop ( )
154
+ return Utils . buildRoute ( app , path , orgRoute )
155
+ }
156
+ default : {
157
+ return Utils . buildRoute ( app , path , orgRoute )
158
+ }
159
+ }
160
+ } ,
161
+
26
162
/**
27
163
* Build a complete route, with bound handler and attached preconditions
28
164
*/
29
- buildRoute ( app : FabrixApp , path : string , rawRoute : IRoute ) {
165
+ buildRoute ( app : FabrixApp , path : string , rawRoute : IRoute ) : { path : string , route : any } [ ] {
30
166
const orgRoute = Object . assign ( { } , rawRoute )
31
167
orgRoute . config = orgRoute . config || ( orgRoute . config = { } )
32
168
orgRoute . config . pre = orgRoute . config . pre || ( orgRoute . config . pre = [ ] )
@@ -53,7 +189,7 @@ export const Utils = {
53
189
if ( ! orgRouteHandlers . some ( v => Utils . methods . indexOf ( v ) >= 0 || ! ! orgRoute [ v ] ) ) {
54
190
app . log . error ( 'spool-router: route ' , path , ' handler [' , orgRouteHandlers . join ( ', ' ) , ']' ,
55
191
'does not correspond to any defined Controller handler' )
56
- return { }
192
+ return [ ]
57
193
}
58
194
59
195
orgRouteHandlers . forEach ( method => {
@@ -69,15 +205,16 @@ export const Utils = {
69
205
70
206
const route = omit ( orgRoute , 'config' )
71
207
72
- return { path, route }
208
+ return [ { path, route } ]
73
209
} ,
74
210
75
211
/**
76
212
* Expands the search for the prefix to the route or config.* level
77
213
*/
78
- getRouteLevelPrefix ( app : FabrixApp , route ) {
214
+ getRouteLevelPrefix ( app : FabrixApp , route ) : string | null {
79
215
const configuredPrefix = app . config . get ( route . config . prefix )
80
- const routePrefix = route . config . prefix
216
+ const routePrefix = get ( route , 'config.prefix' )
217
+
81
218
if ( typeof configuredPrefix !== 'undefined' ) {
82
219
if ( configuredPrefix ) {
83
220
return ( configuredPrefix ) . replace ( / $ \/ / , '' )
@@ -110,7 +247,7 @@ export const Utils = {
110
247
/**
111
248
* Build the Path from the Route config
112
249
*/
113
- getPathFromRoute ( app : FabrixApp , path , route ) {
250
+ getPathFromRoute ( app : FabrixApp , path , route ) : string {
114
251
if ( ! route || ! ( route instanceof Object ) ) {
115
252
throw new RangeError ( 'Expected a route object' )
116
253
}
@@ -121,14 +258,14 @@ export const Utils = {
121
258
return `${ prefix } /${ path } `
122
259
} ,
123
260
124
- getPolicyFromString ( app : FabrixApp , handler ) {
261
+ getPolicyFromString ( app : FabrixApp , handler ) : FabrixPolicy {
125
262
return get ( app . policies , handler )
126
263
} ,
127
264
128
265
/**
129
266
* Get a Controller's method's policies
130
267
*/
131
- getControllerPolicy ( app : FabrixApp , handler , routeMethod , pre = [ ] ) {
268
+ getControllerPolicy ( app : FabrixApp , handler , routeMethod , pre = [ ] ) : FabrixPolicy [ ] {
132
269
const controller = Utils . getControllerFromHandler ( handler )
133
270
134
271
if ( app . config . get ( 'policies.*.*' ) ) {
@@ -176,11 +313,17 @@ export const Utils = {
176
313
return handler
177
314
} ,
178
315
179
- getControllerFromString ( app : FabrixApp , handler ) {
316
+ /**
317
+ *
318
+ */
319
+ getControllerFromString ( app : FabrixApp , handler ) : FabrixController {
180
320
return get ( app . controllers , handler )
181
321
} ,
182
322
183
- getControllerFromHandler ( handler ) {
323
+ /**
324
+ *
325
+ */
326
+ getControllerFromHandler ( handler ) : string {
184
327
return isString ( handler ) ? handler . split ( '.' ) [ 0 ] : handler
185
328
} ,
186
329
@@ -237,9 +380,10 @@ export const Utils = {
237
380
* Build a route collection
238
381
*/
239
382
buildRoutes ( app : FabrixApp , routes , toReturn = { } ) {
240
- Object . keys ( routes ) . forEach ( r => {
241
- const { path, route } = Utils . buildRoute ( app , r , routes [ r ] )
242
- toReturn [ path ] = route
383
+ Object . keys ( routes ) . forEach ( p => {
384
+ Utils . splitRoute ( app , p , routes [ p ] ) . forEach ( ( { path, route } ) => {
385
+ toReturn [ path ] = route
386
+ } )
243
387
} )
244
388
return Utils . sortRoutes ( toReturn , app . config . get ( 'router.sortOrder' ) )
245
389
} ,
0 commit comments