'use strict' 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 (options) { options = options || {} 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