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