Add support for functions in router
Can add a function as to match a route. The function takes in a string
url segment and returns some value if the route matches or returns null
or undefined for no match.
Example usage:
function toInt(part) {
var results = /^(\d+)$/.exec(part)
return results ? parseInt(results[0], 10) : null
}
var router = new Router()
router.add(['/by/order', toInt], function (val) {
// val === 123
})
router.route('/by/order/123')
This commit is contained in:
parent
a317aa86a8
commit
7c34964dff
@ -1,14 +1,17 @@
|
||||
'use strict'
|
||||
var utils = require('./utils')
|
||||
|
||||
var noop = utils.noop
|
||||
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._regExs = Object.create(null)
|
||||
this._funcs = Object.create(null)
|
||||
}
|
||||
|
||||
assign(RouteNode.prototype, {
|
||||
@ -29,8 +32,10 @@ assign(RouteNode.prototype, {
|
||||
|
||||
if (isString(part)) {
|
||||
node = this._children[part]
|
||||
} else {
|
||||
} else if (isRegExp(part)) {
|
||||
this._regExs[part] = part
|
||||
} else if (isFunction(part)) {
|
||||
this._funcs[part] = part
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
@ -56,42 +61,54 @@ assign(RouteNode.prototype, {
|
||||
if (results && results.node) {
|
||||
return results.node.get(parts, args.concat(results.args), done)
|
||||
} else {
|
||||
return done(new Error('not found'))
|
||||
results = this._getFunctionChild(part)
|
||||
if (results && results.node) {
|
||||
return results.node.get(parts, args.concat(results.args), done)
|
||||
} else {
|
||||
return done(new Error('not found'))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getRegexChild: function _getRegexChild(part) {
|
||||
var childKey = null
|
||||
var args = []
|
||||
var self = this
|
||||
|
||||
Object.keys(this._regExs).forEach(function checkRegex(key) {
|
||||
if (childKey) {
|
||||
return
|
||||
return Object.keys(this._regExs).reduce(function checkRegex(memo, key) {
|
||||
if (memo) {
|
||||
return memo
|
||||
}
|
||||
var regex = self._regExs[key]
|
||||
var results = regex.exec(part)
|
||||
var lastIndex = null
|
||||
if (results) {
|
||||
childKey = key
|
||||
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)
|
||||
},
|
||||
|
||||
if (childKey) {
|
||||
return {
|
||||
args: args,
|
||||
key: childKey,
|
||||
node: this._children[childKey]
|
||||
_getFunctionChild: function _getFunctionChild(part) {
|
||||
var self = this
|
||||
return Object.keys(self._funcs).reduce(function checkFunc(memo, key) {
|
||||
if (memo) {
|
||||
return memo
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
var func = self._funcs[key]
|
||||
var result = func(part)
|
||||
if (result) {
|
||||
return {args: [result], key: key, node: self._children[key]}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
@ -31,8 +31,8 @@ function checkType(type) {
|
||||
}
|
||||
}
|
||||
|
||||
// add isRegExp, isArray
|
||||
['RegExp', 'Array'].forEach(function addIsChecks(type) {
|
||||
// add isRegExp, isArray, isFunction
|
||||
['RegExp', 'Array', 'Function'].forEach(function addIsChecks(type) {
|
||||
utils['is' + type] = checkType(type)
|
||||
})
|
||||
|
||||
|
||||
@ -58,5 +58,25 @@ module.exports = describe('RouteNode', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('→ get route with function', function (done) {
|
||||
function toInt(part) {
|
||||
var results = /^(\d+)$/.exec(part)
|
||||
if (results) {
|
||||
return parseInt(results[0], 10)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
node.add(['by', 'id', toInt], callback, context)
|
||||
node.get(['by', 'id', '123'], [], function (err, func, cbContext, args) {
|
||||
expect(err).toBe(null, err && err.message)
|
||||
expect(func).toBe(callback)
|
||||
expect(cbContext).toBe(context)
|
||||
expect(args).toEqual([123])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
@ -75,4 +75,25 @@ describe('Router', function () {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('→ get based on function', function (done) {
|
||||
function toInt(part) {
|
||||
var results = /^(\d+)$/.exec(part)
|
||||
if (results) {
|
||||
return parseInt(results[0], 10)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
var router = new Router()
|
||||
router.add(['by', 'order', toInt], function (val) {
|
||||
expect(val).toBe(123)
|
||||
})
|
||||
|
||||
router.route('/by/order/123', function (err) {
|
||||
expect(err).toBe(null, err && err.message)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,6 +4,7 @@ var utils = require('../lib/utils')
|
||||
var assign = utils.assign
|
||||
var forEach = utils.forEach
|
||||
var isArray = utils.isArray
|
||||
var isFunction = utils.isFunction
|
||||
var isRegExp = utils.isRegExp
|
||||
var isString = utils.isString
|
||||
var noop = utils.noop
|
||||
@ -58,6 +59,24 @@ describe('utils', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('→ isFunction', function () {
|
||||
it('→ true for function', function () {
|
||||
expect(isFunction(function () {})).toBe(true)
|
||||
})
|
||||
|
||||
it('→ false for array', function () {
|
||||
expect(isFunction([])).toBe(false)
|
||||
})
|
||||
|
||||
it('→ false for regex', function () {
|
||||
expect(isFunction(/some regex/)).toBe(false)
|
||||
})
|
||||
|
||||
it('→ false for strings', function () {
|
||||
expect(isFunction('some string')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('→ forEach', function () {
|
||||
it('→ does not call properties on prototype', function () {
|
||||
var count = 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user