Skip to content

Commit 05d939a

Browse files
authored
Merge pull request #9 from fabrix-app/v1.1
[fix] fixes #8
2 parents 8d10b2d + cbea87e commit 05d939a

File tree

6 files changed

+481
-189
lines changed

6 files changed

+481
-189
lines changed

lib/interfaces/IRoute.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
export interface IRoute {
22
[key: string]: any,
3-
_orgPath: string,
3+
_orgPath?: string,
4+
_newPath?: string,
45
config?: {
5-
pre?: any,
6-
[key: string]: { [key: string]: any }
6+
[key: string]: { [key: string]: any },
7+
prefix?: any,
8+
pre?: any
79
}
810
}

lib/utils.ts

Lines changed: 157 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { FabrixApp } from '@fabrix/fabrix'
2+
import { FabrixController } from '@fabrix/fabrix/dist/common'
3+
import { FabrixPolicy } from '@fabrix/fabrix/dist/common'
24
import { get, omit, isString } from 'lodash'
35
import { Router } from 'call'
46
import { IRoute } from './interfaces/IRoute'
57

8+
69
export const Utils = {
710
methods: [
811
'GET',
@@ -23,10 +26,143 @@ export const Utils = {
2326
return isString(strOrArray) ? [ strOrArray ] : strOrArray
2427
},
2528

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+
26162
/**
27163
* Build a complete route, with bound handler and attached preconditions
28164
*/
29-
buildRoute (app: FabrixApp, path: string, rawRoute: IRoute) {
165+
buildRoute(app: FabrixApp, path: string, rawRoute: IRoute): {path: string, route: any}[] {
30166
const orgRoute = Object.assign({ }, rawRoute)
31167
orgRoute.config = orgRoute.config || (orgRoute.config = { })
32168
orgRoute.config.pre = orgRoute.config.pre || (orgRoute.config.pre = [ ])
@@ -53,7 +189,7 @@ export const Utils = {
53189
if (!orgRouteHandlers.some(v => Utils.methods.indexOf(v) >= 0 || !!orgRoute[v])) {
54190
app.log.error('spool-router: route ', path, ' handler [', orgRouteHandlers.join(', '), ']',
55191
'does not correspond to any defined Controller handler')
56-
return {}
192+
return []
57193
}
58194

59195
orgRouteHandlers.forEach(method => {
@@ -69,15 +205,16 @@ export const Utils = {
69205

70206
const route = omit(orgRoute, 'config')
71207

72-
return { path, route }
208+
return [{ path, route }]
73209
},
74210

75211
/**
76212
* Expands the search for the prefix to the route or config.* level
77213
*/
78-
getRouteLevelPrefix(app: FabrixApp, route) {
214+
getRouteLevelPrefix(app: FabrixApp, route): string | null {
79215
const configuredPrefix = app.config.get(route.config.prefix)
80-
const routePrefix = route.config.prefix
216+
const routePrefix = get(route, 'config.prefix')
217+
81218
if (typeof configuredPrefix !== 'undefined') {
82219
if (configuredPrefix) {
83220
return (configuredPrefix).replace(/$\//, '')
@@ -110,7 +247,7 @@ export const Utils = {
110247
/**
111248
* Build the Path from the Route config
112249
*/
113-
getPathFromRoute (app: FabrixApp, path, route) {
250+
getPathFromRoute (app: FabrixApp, path, route): string {
114251
if (!route || !(route instanceof Object)) {
115252
throw new RangeError('Expected a route object')
116253
}
@@ -121,14 +258,14 @@ export const Utils = {
121258
return `${ prefix }/${ path }`
122259
},
123260

124-
getPolicyFromString(app: FabrixApp, handler) {
261+
getPolicyFromString(app: FabrixApp, handler): FabrixPolicy {
125262
return get(app.policies, handler)
126263
},
127264

128265
/**
129266
* Get a Controller's method's policies
130267
*/
131-
getControllerPolicy(app: FabrixApp, handler, routeMethod, pre = [ ]) {
268+
getControllerPolicy(app: FabrixApp, handler, routeMethod, pre = [ ]): FabrixPolicy[] {
132269
const controller = Utils.getControllerFromHandler(handler)
133270

134271
if (app.config.get('policies.*.*')) {
@@ -176,11 +313,17 @@ export const Utils = {
176313
return handler
177314
},
178315

179-
getControllerFromString(app: FabrixApp, handler) {
316+
/**
317+
*
318+
*/
319+
getControllerFromString(app: FabrixApp, handler): FabrixController {
180320
return get(app.controllers, handler)
181321
},
182322

183-
getControllerFromHandler(handler) {
323+
/**
324+
*
325+
*/
326+
getControllerFromHandler(handler): string {
184327
return isString(handler) ? handler.split('.')[0] : handler
185328
},
186329

@@ -237,9 +380,10 @@ export const Utils = {
237380
* Build a route collection
238381
*/
239382
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+
})
243387
})
244388
return Utils.sortRoutes(toReturn, app.config.get('router.sortOrder'))
245389
},

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fabrix/spool-router",
3-
"version": "1.1.3",
3+
"version": "1.1.4",
44
"description": "Spool - Router for Fabrix",
55
"scripts": {
66
"build": "tsc -p ./lib/tsconfig.release.json",
@@ -49,7 +49,7 @@
4949
"lodash": "^4.17.10"
5050
},
5151
"devDependencies": {
52-
"@fabrix/fabrix": "^1.1.2",
52+
"@fabrix/fabrix": "^1.1.4",
5353
"@fabrix/lint": "^1.0.0-alpha.3",
5454
"@types/lodash": "^4.14.109",
5555
"@types/node": "~10.3.4",
@@ -64,7 +64,7 @@
6464
"typescript": "~2.8.1"
6565
},
6666
"peerDependencies": {
67-
"@fabrix/fabrix": "^1.1.2"
67+
"@fabrix/fabrix": "^1.1.4"
6868
},
6969
"license": "MIT",
7070
"bugs": {

0 commit comments

Comments
 (0)