var NotFoundError = require('./error').NotFound; var utils = require('./utils'); var assign = utils.assign; var isFunction = utils.isFunction; var isRegExp = utils.isRegExp; var isString = utils.isString; var noop = utils.noop; function RouteNode () { this._children = Object.create(null); this._funcs = Object.create(null); this._regExs = Object.create(null); } assign(RouteNode.prototype, { handler: null, add: function add(parts, handler, context) { parts = parts || []; handler = handler || noop; context = context || null; if (parts.length === 0) { this.handler = handler; this.context = context; return this; } var part = parts.shift(); var node = null; if (isString(part)) { node = this._children[part]; } else if (isRegExp(part)) { this._regExs[part] = part; } else if (isFunction(part)) { this._funcs[part] = part; } if (node == null) { node = new RouteNode(); this._children[part] = node; } return node.add(parts, handler, context); }, get: function get(parts, args, done) { parts = parts || []; args = args || []; if (parts.length === 0) { return done(null, this.handler, this.context, args); } var part = parts.shift(); // Check exact matches if (this._children[part]) { return this._children[part].get(parts, args, done); } // Check regex matches var results = this._getRegexChild(part); if (results && results.node) { return results.node.get(parts, args.concat(results.args), done); } // Check function matches results = this._getFunctionChild(part); if (results && results.node) { return results.node.get(parts, args.concat(results.args), done); } return done(new NotFoundError('not found', {location: parts})); }, _getRegexChild: function _getRegexChild(part) { var self = this; return Object.keys(this._regExs).reduce(function checkRegex(memo, key) { if (memo) { return memo; } var regex = self._regExs[key]; var results = regex.exec(part); if (!results) { return null; } var lastIndex = null; var args = []; while (results && results.index !== lastIndex) { args = args.concat(results[0]); lastIndex = results.index; results = regex.exec(part); } return {args: args, key: key, node: self._children[key]}; }, null); }, _getFunctionChild: function _getFunctionChild(part) { var self = this; return Object.keys(self._funcs).reduce(function checkFunc(memo, key) { if (memo) { return memo; } var func = self._funcs[key]; var result = func(part); if (result) { return {args: [result], key: key, node: self._children[key]}; } else { return null; } }, null); } }); module.exports = RouteNode;