Skip to content
This repository has been archived by the owner on Jan 18, 2023. It is now read-only.

Commit

Permalink
fix(router): add initial working router (#57)
Browse files Browse the repository at this point in the history
fix(router): add initial working router
  • Loading branch information
nahtnam authored Dec 17, 2019
2 parents 86be05f + 1f753ad commit 6b6d50b
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 31 deletions.
58 changes: 45 additions & 13 deletions package-lock.json

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

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"decache": "^4.5.1",
"emojic": "^1.1.15",
"find-my-way": "^2.1.0",
"lodash.camelcase": "^4.3.0",
"lodash.set": "^4.3.2",
"micro": "^9.3.4",
"micro-boom": "^1.2.0",
Expand All @@ -53,12 +54,14 @@
"repl.history": "^0.1.4",
"signale": "^1.4.0",
"test-listen": "^1.1.0",
"url-join": "^4.0.1",
"yargs": "^13.3.0",
"youch": "^2.0.10",
"youch-terminal": "^1.0.0"
},
"devDependencies": {
"@types/jest": "^24.0.18",
"@types/lodash.camelcase": "^4.3.6",
"@types/lodash.set": "^4.3.6",
"@types/micro": "^7.3.3",
"@types/micromatch": "^3.1.0",
Expand All @@ -80,7 +83,6 @@
"node-fetch": "^2.6.0",
"strip-ansi": "^5.2.0",
"ts-jest": "^24.0.2",
"typescript": "^3.5.3",
"url-join": "^4.0.1"
"typescript": "^3.5.3"
}
}
5 changes: 3 additions & 2 deletions src/cli/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ const handle = async (argv: Args): Promise<void> => {
watcher.on('change', (p: string): void => {
logger.hmr(`swapping out ${chalk.yellow(relative(cwd, p))}`);
app.router.reset();
const files: string[] = findRoutes(routesPath);
decache(join(routesPath, '../', 'routes.js'));
const files: any[] = findRoutes(routesPath);
files.forEach((f): void => {
decache(f);
decache(f.handler);
});
const routeObjs = importRoutes(files, routesPath, true);
routeObjs.forEach((route: Route): void => {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as params } from './params';
export { default as query } from './query';
export { default as test } from './test';
export { default as route } from './route';
export { default as router } from './router';
export { default as global } from './global';
export {
buffer,
Expand Down
44 changes: 44 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { METHODS } from 'http';
import join from 'url-join';
import camelCase from 'lodash.camelcase';

interface RouterRouteType {
method: string;
path: string;
handler: string;
}

export default (): any => {
// closures
const _routes: RouterRouteType[] = [];

const getRouterObj = (namespace: string): any => {
const obj: any = {
namespace(name: string, handler: (route: any) => {}): void {
handler(getRouterObj(join(namespace, name)));
},
};

METHODS.forEach((method: string): void => {
const name = camelCase(method);
obj[name] = (rawPath: string | string[], handler: string): void => {
let path: any = rawPath;
if (typeof rawPath === 'string') {
path = [path];
}
path = path.map((r: string): string => join('/', namespace, r));
_routes.push({
method,
path,
handler: join('/', handler),
});
};
});
return obj;
};

return {
routes: _routes,
route: getRouterObj(''),
};
};
3 changes: 2 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ const app = ({
});

let routeObjs: RouteType[] = [];

if (typeof routes === 'string') {
const files: string[] = findRoutes(routes);
const files: any[] = findRoutes(routes);
routeObjs = importRoutes(files, routes);
} else {
routeObjs = routes;
Expand Down
15 changes: 12 additions & 3 deletions src/utils/find-routes.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { join } from 'path';
import { existsSync } from 'fs';
import glob from './glob';

export default (routesPath: string): string[] => {
export default (routesPath: string): any[] => {
const routesFilePath = join(routesPath, '../', 'routes.js');
if (existsSync(routesFilePath)) {
const routerRoutes = require(routesFilePath) || []; // eslint-disable-line
const mappedRoutes = routerRoutes.map((r: any): any => ({
...r,
handler: join(routesPath, r.handler),
}));
return mappedRoutes;
}
const routes: string[] = [];

const addRoutes = (path: any): number => {
const files: string[] = glob(join('/', path), '**/*.{js,ts}');
return routes.push(...files);
};

addRoutes(routesPath);

return routes;
return routes.map((s: string): any => ({ handler: s }));
};
13 changes: 7 additions & 6 deletions src/utils/import-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ import forTerminal from 'youch-terminal';
import RouteType from '../types/route';
import { route } from '../index';

export default (routes: string[], routesPath: string, safe: boolean = false): RouteType[] => {
export default (routes: any[], routesPath: string, safe: boolean = false): RouteType[] => {
let results: RouteType[] = [];

try {
results = routes.map((r: string): RouteType => {
results = routes.map((r: any): RouteType => {
let handler;
handler = require(r); // eslint-disable-line
handler = require(r.handler); // eslint-disable-line
if (handler.default) {
handler = handler.default;
}

const path = relative(routesPath, r);
const path = r.path || relative(routesPath, r.handler);
const method = r.method || METHODS;

return {
file: r,
method: METHODS,
file: r.handler,
method,
handler,
path,
};
Expand Down
8 changes: 4 additions & 4 deletions tests/utils/import-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ describe('utils', () => {
describe('with regular route', () => {
it('returns a route', async () => {
expect.assertions(1);
const route = importRoutes([join(routesPath, './index.ts')], routesPath);
const route = importRoutes([{ handler: join(routesPath, './index.ts') }], routesPath);
expect(route.length).toBe(1);
});
});

describe('with default route', () => {
it('returns a route', async () => {
expect.assertions(1);
const route = importRoutes([join(routesPath, './default.ts')], routesPath);
const route = importRoutes([{ handler: join(routesPath, './default.ts') }], routesPath);
expect(route.length).toBe(1);
});
});

describe('with an invalid route', () => {
it('throws', async () => {
expect.assertions(1);
expect(() => importRoutes([join(routesPath, './throw.ts')], routesPath)).toThrow('error');
expect(() => importRoutes([{ handler: join(routesPath, './throw.ts') }], routesPath)).toThrow('error');
});
});

// using a different file as the previous "throw" test causes issues if you use the same file
describe('with safe mode', () => {
it('returns a single route containing the youch error page', async () => {
expect.assertions(5);
const routes = importRoutes([join(routesPath, './youch.ts')], routesPath, true);
const routes = importRoutes([{ handler: join(routesPath, './youch.ts') }], routesPath, true);
expect(routes.length).toBe(1);
expect(Object.keys(routes[0]).sort()).toEqual(['handler', 'method', 'path'].sort());

Expand Down

0 comments on commit 6b6d50b

Please sign in to comment.