Skip to content

Commit

Permalink
Merge pull request #32 from shekohex/resolve-path
Browse files Browse the repository at this point in the history
 feat(RouterModule): add `reolvePath` method to get controller full path.
  • Loading branch information
Shady Khalifa authored Nov 4, 2018
2 parents 84a731e + fc1e787 commit e8dffc8
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 7 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"devDependencies": {
"@nestjs/common": "^5.0.0",
"@nestjs/core": "^5.0.0",
"@nestjs/testing": "^5.3.11",
"@types/jest": "^23.0.0",
"@types/node": "^10.0.3",
"coveralls": "^3.0.2",
Expand Down
31 changes: 30 additions & 1 deletion src/router.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Module, DynamicModule } from '@nestjs/common';
import { MODULE_PATH } from '@nestjs/common/constants';
import { MODULE_PATH, PATH_METADATA } from '@nestjs/common/constants';
import { ModulesContainer } from '@nestjs/core/injector/modules-container';
import { Controller, Type } from '@nestjs/common/interfaces';
import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception';
import { validatePath } from './utils/validate-path.util';
import { flatRoutes } from './utils/flat-routes.util';
import { Routes } from './routes.interface';
Expand All @@ -10,6 +13,17 @@ import { Routes } from './routes.interface';
*/
@Module({})
export class RouterModule {
private static readonly routesContainer: Map<string, string> = new Map();
constructor(readonly modulesContainer: ModulesContainer) {
const modules = [...modulesContainer.values()];
for (const nestModule of modules) {
const modulePath: string = Reflect.getMetadata(MODULE_PATH, nestModule.metatype);
for (const route of nestModule.routes.values()) {
RouterModule.routesContainer.set(route.name, validatePath(modulePath));
}
}
}

/**
* takes an array of modules and organize them in hierarchy way
* @param {Routes} routes Array of Routes
Expand All @@ -20,6 +34,21 @@ export class RouterModule {
module: RouterModule,
};
}

/**
* get the controller full route path eg: (controller's module prefix + controller's path).
* @param {Type<Controller>} controller the controller you need to get it's full path
*/
public static resolvePath(controller: Type<Controller>): string {
const controllerPath: string = Reflect.getMetadata(PATH_METADATA, controller);
const modulePath = RouterModule.routesContainer.get(controller.name);
if (modulePath && controllerPath) {
return validatePath(modulePath + controllerPath);
} else {
throw new UnknownElementException();
}
}

private static buildPathMap(routes: Routes) {
const flattenRoutes = flatRoutes(routes);
flattenRoutes.forEach(route => {
Expand Down
46 changes: 41 additions & 5 deletions src/test/router.module.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { RouterModule } from '../router.module';
import { Route, Routes } from '../routes.interface';
import { Module } from '@nestjs/common';
import { Routes } from '../routes.interface';
import { Module, Controller } from '@nestjs/common';
import { MODULE_PATH } from '@nestjs/common/constants';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';

describe('RouterModule', () => {
const MODULE_PATH = '__module_path__';
let app: INestApplication;

@Module({})
@Controller('/parent-controller')
class ParentController {}
@Controller('/child-controller')
class ChildController {}

class UnknownController {}
@Module({ controllers: [ParentController] })
class ParentModule {}
@Module({})

@Module({ controllers: [ChildController] })
class ChildModule {}

@Module({})
Expand Down Expand Up @@ -47,4 +58,29 @@ describe('RouterModule', () => {
expect(authPath).toEqual('/v1');
expect(paymentPath).toEqual('/v1');
});

describe('Full Running App', async () => {
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [MainModule, AppModule],
}).compile();
app = module.createNestApplication();
await app.init();
});

it('should Resolve Controllers path with its Module Path if any', async () => {
expect(RouterModule.resolvePath(ParentController)).toEqual('/parent/parent-controller');
expect(RouterModule.resolvePath(ChildController)).toEqual('/parent/child/child-controller');
});

it('should throw error when we cannot find the controller', async () => {
expect(() => RouterModule.resolvePath(UnknownController)).toThrowError(
'Nest cannot find given element (it does not exist in current context)',
);
});

afterAll(async () => {
await app.close();
});
});
});
2 changes: 1 addition & 1 deletion tslint.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"defaultSeverity": "error",
"defaultSeverity": "warn",
"extends": ["tslint:recommended"],
"jsRules": {
"no-unused-expression": true
Expand Down

0 comments on commit e8dffc8

Please sign in to comment.