|
|
|
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;
|