Skip to content

Commit e8dffc8

Browse files
author
Shady Khalifa
authored
Merge pull request #32 from shekohex/resolve-path
feat(RouterModule): add `reolvePath` method to get controller full path.
2 parents 84a731e + fc1e787 commit e8dffc8

5 files changed

+83
-7
lines changed

package-lock.json

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"devDependencies": {
2626
"@nestjs/common": "^5.0.0",
2727
"@nestjs/core": "^5.0.0",
28+
"@nestjs/testing": "^5.3.11",
2829
"@types/jest": "^23.0.0",
2930
"@types/node": "^10.0.3",
3031
"coveralls": "^3.0.2",

src/router.module.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { Module, DynamicModule } from '@nestjs/common';
2-
import { MODULE_PATH } from '@nestjs/common/constants';
2+
import { MODULE_PATH, PATH_METADATA } from '@nestjs/common/constants';
3+
import { ModulesContainer } from '@nestjs/core/injector/modules-container';
4+
import { Controller, Type } from '@nestjs/common/interfaces';
5+
import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception';
36
import { validatePath } from './utils/validate-path.util';
47
import { flatRoutes } from './utils/flat-routes.util';
58
import { Routes } from './routes.interface';
@@ -10,6 +13,17 @@ import { Routes } from './routes.interface';
1013
*/
1114
@Module({})
1215
export class RouterModule {
16+
private static readonly routesContainer: Map<string, string> = new Map();
17+
constructor(readonly modulesContainer: ModulesContainer) {
18+
const modules = [...modulesContainer.values()];
19+
for (const nestModule of modules) {
20+
const modulePath: string = Reflect.getMetadata(MODULE_PATH, nestModule.metatype);
21+
for (const route of nestModule.routes.values()) {
22+
RouterModule.routesContainer.set(route.name, validatePath(modulePath));
23+
}
24+
}
25+
}
26+
1327
/**
1428
* takes an array of modules and organize them in hierarchy way
1529
* @param {Routes} routes Array of Routes
@@ -20,6 +34,21 @@ export class RouterModule {
2034
module: RouterModule,
2135
};
2236
}
37+
38+
/**
39+
* get the controller full route path eg: (controller's module prefix + controller's path).
40+
* @param {Type<Controller>} controller the controller you need to get it's full path
41+
*/
42+
public static resolvePath(controller: Type<Controller>): string {
43+
const controllerPath: string = Reflect.getMetadata(PATH_METADATA, controller);
44+
const modulePath = RouterModule.routesContainer.get(controller.name);
45+
if (modulePath && controllerPath) {
46+
return validatePath(modulePath + controllerPath);
47+
} else {
48+
throw new UnknownElementException();
49+
}
50+
}
51+
2352
private static buildPathMap(routes: Routes) {
2453
const flattenRoutes = flatRoutes(routes);
2554
flattenRoutes.forEach(route => {

src/test/router.module.spec.ts

+41-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import { RouterModule } from '../router.module';
2-
import { Route, Routes } from '../routes.interface';
3-
import { Module } from '@nestjs/common';
2+
import { Routes } from '../routes.interface';
3+
import { Module, Controller } from '@nestjs/common';
4+
import { MODULE_PATH } from '@nestjs/common/constants';
5+
import { Test } from '@nestjs/testing';
6+
import { INestApplication } from '@nestjs/common';
7+
48
describe('RouterModule', () => {
5-
const MODULE_PATH = '__module_path__';
9+
let app: INestApplication;
610

7-
@Module({})
11+
@Controller('/parent-controller')
12+
class ParentController {}
13+
@Controller('/child-controller')
14+
class ChildController {}
15+
16+
class UnknownController {}
17+
@Module({ controllers: [ParentController] })
818
class ParentModule {}
9-
@Module({})
19+
20+
@Module({ controllers: [ChildController] })
1021
class ChildModule {}
1122

1223
@Module({})
@@ -47,4 +58,29 @@ describe('RouterModule', () => {
4758
expect(authPath).toEqual('/v1');
4859
expect(paymentPath).toEqual('/v1');
4960
});
61+
62+
describe('Full Running App', async () => {
63+
beforeAll(async () => {
64+
const module = await Test.createTestingModule({
65+
imports: [MainModule, AppModule],
66+
}).compile();
67+
app = module.createNestApplication();
68+
await app.init();
69+
});
70+
71+
it('should Resolve Controllers path with its Module Path if any', async () => {
72+
expect(RouterModule.resolvePath(ParentController)).toEqual('/parent/parent-controller');
73+
expect(RouterModule.resolvePath(ChildController)).toEqual('/parent/child/child-controller');
74+
});
75+
76+
it('should throw error when we cannot find the controller', async () => {
77+
expect(() => RouterModule.resolvePath(UnknownController)).toThrowError(
78+
'Nest cannot find given element (it does not exist in current context)',
79+
);
80+
});
81+
82+
afterAll(async () => {
83+
await app.close();
84+
});
85+
});
5086
});

tslint.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"defaultSeverity": "error",
2+
"defaultSeverity": "warn",
33
"extends": ["tslint:recommended"],
44
"jsRules": {
55
"no-unused-expression": true

0 commit comments

Comments
 (0)