var url = require('url'); var NotFoundError = require('./error').NotFound; var RouteNode = require('./route-node'); var utils = require('./utils'); var assign = utils.assign; var isArray = utils.isArray; var isFunction = utils.isFunction; var isString = utils.isString; var noop = utils.noop; function Router() { this.routes = new RouteNode(); } assign(Router.prototype, { add: function add(path, handler) { return this.routes.add(this._uriToParts(path), handler); }, route: function route(path, options, done) { if (done == null && isFunction(options)) { done = options; options = {}; } options = options || {}; var routeArray = this._uriToParts(path); done = done || noop; function _routeCallback(err, func, context, args) { if (err) { return done(err); } else { if (isFunction(func)) { return done(null, func.apply(context, args)); } else { return done(new NotFoundError('not found', {location: path})); } } } return this.routes.get(routeArray, (options.args || []), _routeCallback); }, _uriToParts: function _uriToParts(uri) { if (isString(uri)) { return url.parse(uri) .pathname .split('/') .filter(function (str) { return str !== ''; }); } else if (isArray(uri)) { return uri.reduce(this._uriToPartsReducer.bind(this), []); } }, _uriToPartsReducer: function _uriToPartsReducer(memo, item) { if (isArray(item)) { return memo.concat(item); } else if (isString(item)) { return memo.concat(this._uriToParts(item)); } else { return memo.concat(item); } } }); Router.isNotFound = function isNotFound(err) { return err instanceof NotFoundError; }; module.exports = Router;