Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
language: node_js
node_js:
- "8"
- "6"
- "5"
- "4"
142 changes: 1 addition & 141 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,151 +1,11 @@
'use strict';
const fs = require('fs');
const glob = require('glob');
const path = require('path');
const _ = require('lodash');
const async = require('async');

const defaults = {
path: `${process.cwd()}/routes`,
base: '/',
prefix: '',
verbose: false,
autoLoad: true
};
exports.routeLoader = require('./lib/routeLoader');

exports.register = (server, options, next) => {
exports.routeLoader(server, options, next, true);
};

// the 'base' of the path for all routes defined in a given file.
// eg "/api/folder1/myfile.js" will return "/api/folder/myfile/",
const getRoutePathBase = (options, fileName) => {
// gets relative path, minus absolute path specifier:
const segment = path.dirname(fileName.replace(options.path, ''));
let base = options.base ? options.base : defaults.base;
if (segment === '.' || !segment) {
return base;
}
if (!_.endsWith(options.base, '/')) {
base += '/';
}
return `${base}${segment}`;
};

// get the full route path:
const getCompletePath = (options, fileName, originalPath) => {
const prefix = options.prefix ? options.prefix : defaults.prefix;
// if the originalPath started with a slash just return it, there is no basePath:
if (_.startsWith(originalPath, '/')) {
let resultPath = `${prefix}${originalPath}`;
return resultPath;
}
// otherwise add the basePath to the returnPath:
const basePath = getRoutePathBase(options, fileName);
let returnPath = path.join(basePath, originalPath ? originalPath : '').replace(new RegExp('(\\\\)', 'g'), '/');
returnPath = `${prefix}${returnPath}`;
// if there's a trailing slash, make sure it should be there:
if (_.endsWith(returnPath, '/') && (!_.endsWith(basePath, '/') || basePath === '/') && returnPath !== '/') {
if (!_.endsWith(originalPath, '/')) {
returnPath = returnPath.substr(0, returnPath.length - 1);
}
}
if (_.startsWith(returnPath, '//')) {
returnPath = returnPath.replace('//', '/');
}
return returnPath;
};

exports.routeLoader = (server, options, next) => {
const load = (loadOptions, loadDone) => {
const stub = () => {};
loadDone = loadDone || stub;
const settings = _.clone(loadOptions);
_.defaults(settings, defaults);
// the main flow is here:
async.auto({
// confirm that settings.path exists and is a directory:
confirmDirectoryExists: (done) => {
fs.exists(settings.path, (exists) => {
if (!exists) {
server.log(['hapi-route-loader', 'warning'], { message: 'path doesnt exist', path: settings.path });
return done();
}
fs.stat(settings.path, (err, stat) => {
if (err) {
return done(err);
}
if (!stat.isDirectory()) {
server.log(['hapi-route-loader', 'warning'], { message: 'path not a directory', path: settings.path });
return done(`path ${settings.path} not a directory`);
}
return done();
});
});
},
// get the list of all matching route-containing files
files: ['confirmDirectoryExists', (results, done) => {
glob('**/*.js', {
cwd: settings.path
}, (globErr, files) => {
if (globErr) {
return done(globErr);
}
done(null, files);
});
}],
// for each filename, get a list of configured routes defined by it
configureAllRoutes: ['files', (results, done) => {
const routeConfigs = {};
results.files.forEach((fileName) => {
const fileRouteList = [];
const moduleRoutes = require(path.join(settings.path, fileName));
_.forIn(moduleRoutes, (originalRouteConfig) => {
if (typeof originalRouteConfig === 'function') {
originalRouteConfig = originalRouteConfig(server, settings);
}
const processedRouteConfig = _.clone(originalRouteConfig);
// set up the route's 'config' option:
if (options.routeConfig) {
if (originalRouteConfig.config) {
processedRouteConfig.config = _.defaults(options.routeConfig, originalRouteConfig.config);
} else {
processedRouteConfig.config = options.routeConfig;
}
}
// set up the route's 'path' option:
processedRouteConfig.path = getCompletePath(options, fileName, originalRouteConfig.path);
fileRouteList.push(processedRouteConfig);
});
routeConfigs[fileName] = fileRouteList;
});
done(null, routeConfigs);
}],
// register all routes with server.route:
registerAllRoutes: ['configureAllRoutes', (results, done) => {
Object.keys(results.configureAllRoutes).forEach((fileName) => {
results.configureAllRoutes[fileName].forEach((routeConfig) => {
if (options.verbose) {
server.log(['debug', 'hapi-route-loader'], { msg: 'registering', data: routeConfig });
}
server.route(routeConfig);
});
});
done();
}]
}, (err2) => {
if (err2) {
server.log(['hapi-route-loader', 'error'], err2);
}
return loadDone(err2);
});
};
if (options.autoLoad === false) {
return next();
}
load(options, next);
};

exports.register.attributes = {
pkg: require('./package.json')
};
16 changes: 16 additions & 0 deletions lib/configureRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const getCompletePath = require('./getCompletePath');

module.exports = (settings, fileName, routeConfig) => {
const finalRouteConfig = Object.assign({}, routeConfig);
// set up the route's 'config' option:
if (settings.routeConfig) {
if (routeConfig.config) {
finalRouteConfig.config = Object.assign({}, routeConfig.config, settings.routeConfig);
} else {
finalRouteConfig.config = settings.routeConfig;
}
}
// set up the route's 'path' option:
finalRouteConfig.path = getCompletePath(settings, fileName, routeConfig.path);
return finalRouteConfig;
};
7 changes: 7 additions & 0 deletions lib/defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
path: `${process.cwd()}/routes`,
base: '/',
prefix: '',
verbose: false,
autoLoad: true
};
26 changes: 26 additions & 0 deletions lib/getCompletePath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const path = require('path');
const defaults = require('./defaults');
const getRoutePathBase = require('./getRoutePathBase');

// get the full route path:
module.exports = (options, fileName, originalPath) => {
const prefix = options.prefix ? options.prefix : defaults.prefix;
// if the originalPath started with a slash just return it, there is no basePath:
if (originalPath && originalPath.startsWith('/')) {
return `${prefix}${originalPath}`;
}
// otherwise add the basePath to the returnPath:
const basePath = getRoutePathBase(options, fileName);
let returnPath = path.join(basePath, originalPath || '').replace(new RegExp('(\\\\)', 'g'), '/');
returnPath = `${prefix}${returnPath}`;
// if there's a trailing slash, make sure it should be there:
if (returnPath.endsWith('/') && (!basePath.endsWith('/') || basePath === '/') && returnPath !== '/') {
if (!originalPath || !originalPath.endsWith('/')) {
returnPath = returnPath.substr(0, returnPath.length - 1);
}
}
if (returnPath.endsWith('//')) {
returnPath = returnPath.replace('//', '/');
}
return returnPath;
};
19 changes: 19 additions & 0 deletions lib/getRoutePathBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const path = require('path');
const defaults = require('./defaults');

// the 'base' of the path for all routes defined in a given file.
// eg "/api/folder1/myfile.js" will return "/api/folder/myfile/",
const getRoutePathBase = (options, fileName) => {
// gets relative path, minus absolute path specifier:
const segment = path.dirname(fileName.replace(options.path, ''));
let base = options.base ? options.base : defaults.base;
if (segment === '.' || !segment) {
return base;
}
if (options.base && !options.base.endsWith('/')) {
base += '/';
}
return `${base}${segment}`;
};

module.exports = getRoutePathBase;
18 changes: 18 additions & 0 deletions lib/getRoutesFromFiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';
const path = require('path');
const configureRoute = require('./configureRoute');

module.exports = (server, settings, files, done) => {
const configuredRoutes = [];
files.forEach((fileName) => {
const moduleRoutes = require(path.join(settings.path, fileName));
Object.keys(moduleRoutes).forEach((originalRouteConfigKey) => {
let originalRouteConfig = moduleRoutes[originalRouteConfigKey];
if (typeof originalRouteConfig === 'function') {
originalRouteConfig = originalRouteConfig(server, settings);
}
configuredRoutes.push(configureRoute(settings, fileName, originalRouteConfig));
});
});
return done(null, configuredRoutes);
};
44 changes: 44 additions & 0 deletions lib/routeLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const fs = require('fs');
const glob = require('glob');
const async = require('async');
const defaults = require('./defaults');
const validateRoutesDirectory = require('./validateRoutesDirectory');
const getRoutesFromFiles = require('./getRoutesFromFiles');

module.exports = (server, options, next) => {
const load = (loadOptions, loadDone) => {
const stub = () => {};
loadDone = loadDone || stub;
const settings = Object.assign({}, defaults, loadOptions);
// the main flow is here:
async.autoInject({
// confirm that settings.path exists and is a directory:
confirmDirectoryExists(done) {
validateRoutesDirectory(server, settings, done);
},
// get the list of all matching route-containing files
files(confirmDirectoryExists, done) {
glob('**/*.js', {
cwd: settings.path
}, done);
},
configuredRoutes(files, done) {
getRoutesFromFiles(server, settings, files, done);
},
// register all routes with server.route:
registerAllRoutes: (configuredRoutes, done) => {
configuredRoutes.forEach((routeConfig) => {
if (options.verbose) {
server.log(['debug', 'hapi-route-loader'], { msg: 'registering', data: routeConfig });
}
server.route(routeConfig);
});
done();
}
}, loadDone);
};
if (options.autoLoad === false) {
return next();
}
load(options, next);
};
22 changes: 22 additions & 0 deletions lib/validateRoutesDirectory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const fs = require('fs');

const validateRoutesDirectory = (server, settings, done) => {
fs.exists(settings.path, (exists) => {
if (!exists) {
server.log(['hapi-route-loader', 'warning'], { message: 'path doesnt exist', path: settings.path });
return done();
}
fs.stat(settings.path, (err, stat) => {
if (err) {
return done(err);
}
if (!stat.isDirectory()) {
server.log(['hapi-route-loader', 'warning'], { message: 'path not a directory', path: settings.path });
return done(`path ${settings.path} not a directory`);
}
return done();
});
});
};

module.exports = validateRoutesDirectory;
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
"homepage": "https://github.com/firstandthird/hapi-route-loader#readme",
"dependencies": {
"async": "^2.1.2",
"glob": "^7.1.1",
"lodash": "^4.17.2"
"glob": "^7.1.1"
},
"devDependencies": {
"chai": "^3.4.1",
Expand Down
Loading