Skip to content

Commit

Permalink
proj: refactor routes command (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
gfogle authored Dec 4, 2019
1 parent 7e8ad6f commit 8e8f5ae
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 47 deletions.
85 changes: 85 additions & 0 deletions src/cli/Command/Routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const Command = require("./Command");
const Router = require("../../core/RouterV2");
const ProcessHelper = require("../../core/helpers/ProcessHelper");

module.exports = class RoutesCommand extends Command {
execute(context /* eslint-disable-line no-unused-vars */) {
const { rootDirectory, projectConfig } = requireArguments(context);
const routes = accumulateRoutes(rootDirectory, projectConfig);

printRoutes(routes);
}
};

/**
* @function requireArguments
* @private
* @description check if all values provided and are valid values
*
* @param {Context} context - the context object given
*
* @throws {Error}
*/
function requireArguments(context /* eslint-disable-line no-unused-vars */) {
const rootDirectory = ProcessHelper.cwd();
const projectConfig = ProcessHelper.require(`${rootDirectory}/config`);

return {
rootDirectory,
projectConfig
};
}

/**
* @function accumulateRoutes
* @private
*
* @param {string} rootDirectory - directory the new command was run from
* @param {string} projectConfig - config folder of the project
*
* @throws {Error}
*/
function accumulateRoutes(rootDirectory, projectConfig) {
const router = new Router(projectConfig, rootDirectory);
const routes = router.load();

return routes;
}

/**
* @function printRoutes
* @private
*
* @param {string} rootDirectory - directory the new command was run from
* @param {string} projectConfig - config folder of the project
*
* @throws {Error}
*/
function printRoutes(routes) {
const maxURILength = routes.reduce((acc, curr) => {
if (curr.url.length > acc.length) {
acc = curr.url;
}
return acc;
}, "").length;
const maxActionLength = 10;
const VERB_HEADER = "Verb".padEnd(8, " ");
const URI_HEADER = "URI Pattern".padEnd(Math.max(25, maxURILength + 5), " ");
const CA_HEADER = "Controller#Action".padEnd(
Math.max(25, maxActionLength + 5),
" "
);

console.log(`${VERB_HEADER}${URI_HEADER}${CA_HEADER}`);

routes.forEach(r => {
const verb = r.method.padEnd(8, " ");
const url = r.url.padEnd(Math.max(25, maxURILength + 5), " ");
const controllerAndAction = `${r.controller}#${r.action}`.padEnd(
Math.max(25, maxActionLength + 5),
" "
);

console.log(`${verb}${url}${controllerAndAction}`);
});
}
12 changes: 12 additions & 0 deletions src/cli/Interpreter/Expressions/Routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const InterpreterExpression = require("../InterpreterExpression");
const RoutesCommand = require("../../Command/Routes");

module.exports = class RoutesExpression extends InterpreterExpression {
interpret(context) {
const inputs = context.getInput();

if (inputs[0].trim() === "routes") {
context.setOutput(new RoutesCommand());
}
}
};
12 changes: 2 additions & 10 deletions src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const GenerateActionExpression = require("./Interpreter/Expressions/GenerateActi
const TestExpression = require("./Interpreter/Expressions/Test");
const MigrateExpression = require("./Interpreter/Expressions/Migrate");
const GenerateMigrationExpression = require("./Interpreter/Expressions/GenerateMigration");
const RoutesExpression = require("./Interpreter/Expressions/Routes");

(async () => {
try {
Expand All @@ -21,6 +22,7 @@ const GenerateMigrationExpression = require("./Interpreter/Expressions/GenerateM
tree.push(new TestExpression());
tree.push(new MigrateExpression());
tree.push(new GenerateMigrationExpression());
tree.push(new RoutesExpression());
tree.forEach(expression => expression.interpret(context));

const command = context.getOutput();
Expand All @@ -43,7 +45,6 @@ switch (cmd) {
case "new":
break;
case "routes":
showRoutes();
break;
case "server":
break;
Expand Down Expand Up @@ -97,12 +98,3 @@ function generateModel() {
process.exit(1);
}
}

function showRoutes() {
try {
require("./routes")();
} catch (ex) {
console.error(`Error building routes: ${ex.message}`);
process.exit(1);
}
}
35 changes: 0 additions & 35 deletions src/cli/routes.js

This file was deleted.

13 changes: 11 additions & 2 deletions src/core/RouterV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Router.prototype.load = function() {
case "create":
routes.push({
action,
controller: controllerName,
method: "POST",
url: `/${NounHelper.toPluralResource(controllerName)}`,
handler: (req, res) =>
Expand All @@ -62,6 +63,7 @@ Router.prototype.load = function() {
case "destroy":
routes.push({
action,
controller: controllerName,
method: "DELETE",
url: `/${NounHelper.toPluralResource(controllerName)}/:id`,
handler: (req, res) =>
Expand All @@ -71,6 +73,7 @@ Router.prototype.load = function() {
case "edit":
routes.push({
action,
controller: controllerName,
method: "GET",
url: `/${NounHelper.toPluralResource(controllerName)}/:id/edit`,
handler: (req, res) =>
Expand All @@ -80,6 +83,7 @@ Router.prototype.load = function() {
case "index":
routes.push({
action,
controller: controllerName,
method: "GET",
url: `/${NounHelper.toPluralResource(controllerName)}`,
handler: (req, res) =>
Expand All @@ -89,6 +93,7 @@ Router.prototype.load = function() {
case "new":
routes.push({
action,
controller: controllerName,
method: "GET",
url: `/${NounHelper.toPluralResource(controllerName)}/new`,
handler: (req, res) =>
Expand All @@ -98,6 +103,7 @@ Router.prototype.load = function() {
case "show":
routes.push({
action,
controller: controllerName,
method: "GET",
url: `/${NounHelper.toPluralResource(controllerName)}/:id`,
handler: (req, res) =>
Expand All @@ -107,6 +113,7 @@ Router.prototype.load = function() {
case "update":
routes.push({
action,
controller: controllerName,
method: "PUT",
url: `/${NounHelper.toPluralResource(controllerName)}/:id`,
handler: (req, res) =>
Expand All @@ -127,6 +134,8 @@ Router.prototype.load = function() {

if (!rootAction) {
routes.push({
action: "",
controller: "",
method: "GET",
url: "/",
handler: (req, res) => {
Expand Down Expand Up @@ -207,7 +216,7 @@ async function _invokeAction(req, res, controller, action) {

function _registerRoute(method, route, controllerAndAction) {
const split = controllerAndAction.split("#");
const controllerName = split[0];
const controller = split[0];
const action = split[1];

// TODO: check for an already existing route / method entry
Expand All @@ -216,7 +225,7 @@ function _registerRoute(method, route, controllerAndAction) {
action,
method,
url: route,
handler: (req, res) => _invokeAction(req, res, controllerName, action)
handler: (req, res) => _invokeAction(req, res, controller, action)
});
}

Expand Down
77 changes: 77 additions & 0 deletions test/cli/Command/Routes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
jest.mock("../../../src/core/helpers/ProcessHelper", () => {
return {
cwd: jest.fn().mockImplementation(() => {}),
exit: jest.fn().mockImplementation(() => {}),
require: jest.fn().mockImplementation(() => {})
};
});

jest.mock("../../../src/core/RouterV2", () => {
function MockRouter() {}

MockRouter.prototype.load = jest.fn().mockImplementation(() => {});

return MockRouter;
});

const Router = require("../../../src/core/RouterV2");
// const ProcessHelper = require("../../../src/core/helpers/ProcessHelper");
const InterpreterContext = require("../../../src/cli/Interpreter/InterpreterContext");
const RoutesExpression = require("../../../src/cli/Interpreter/Expressions/Routes");

afterEach(() => {
jest.restoreAllMocks();
jest.clearAllMocks();
});

test("throws if no config folder found", () => {
try {
interpretAndExecuteCommand(["$", "Boring", "routes"]);

throw new Error("should throw");
} catch (ignore) {}
});

test("prints empty header to the console if no routes", () => {
console.log = jest.fn(); // eslint-disable-line
Router.prototype.load.mockImplementation(() => []);

interpretAndExecuteCommand(["$", "Boring", "routes"]);

expect(Router.prototype.load).toHaveBeenCalled();
expect(console.log.mock.calls).toHaveLength(1); // eslint-disable-line
});

test("prints routes to the console if no routes", () => {
console.log = jest.fn(); // eslint-disable-line
Router.prototype.load.mockImplementation(() => [
{
method: "GET",
url: "/",
controller: "Fake",
action: "index"
}
]);

interpretAndExecuteCommand(["$", "Boring", "routes"]);

expect(Router.prototype.load).toHaveBeenCalled();
expect(console.log.mock.calls).toHaveLength(2); // eslint-disable-line

const loggedRoute = console.log.mock.calls[1][0];

expect(loggedRoute.indexOf("GET")).toBeGreaterThan(-1);
expect(loggedRoute.indexOf("/")).toBeGreaterThan(-1);
expect(loggedRoute.indexOf("Fake#index")).toBeGreaterThan(-1);
});

function interpretAndExecuteCommand(args) {
const context = new InterpreterContext(args);
const expression = new RoutesExpression();

expression.interpret(context);

const command = context.getOutput();

command.execute(context);
}
11 changes: 11 additions & 0 deletions test/cli/Interpreter/Expressions/Routes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const RoutesExpression = require("../../../../src/cli/Interpreter/Expressions/Routes");
const InterpreterContext = require("../../../../src/cli/Interpreter/InterpreterContext");

test("if context input is correct, sets the proper command", () => {
const context = new InterpreterContext(["$", "Boring", "routes"]);
const expression = new RoutesExpression();

expression.interpret(context);

expect(context.getOutput().constructor.name).toBe("RoutesCommand");
});

0 comments on commit 8e8f5ae

Please sign in to comment.