Skip to content

Commit

Permalink
Hanlde multi-parametric route (issue #17)
Browse files Browse the repository at this point in the history
Detect multi parametric path (new nodeType=4)

Handle lookup for multi parametric path

Unit test issue #17
  • Loading branch information
Bruno Scopelliti committed Sep 23, 2017
1 parent ddc113a commit c4b5515
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 4 deletions.
32 changes: 28 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ function Router (opts) {
this.tree = new Node()
}

const forbiddenCharactersInParameterName = ['-']

Router.prototype.on = function (method, path, handler, store) {
if (Array.isArray(method)) {
for (var k = 0; k < method.length; k++) {
Expand All @@ -54,13 +56,21 @@ Router.prototype.on = function (method, path, handler, store) {
// search for parametric or wildcard routes
// parametric route
if (path.charCodeAt(i) === 58) {
var nodeType = 1
j = i + 1
this._insert(method, path.slice(0, i), 0, null, null, null)

// isolate the parameter name
while (i < len && path.charCodeAt(i) !== 47) i++
var isRegex = false
while (i < len && path.charCodeAt(i) !== 47 && ((isRegex = isRegex || path[i] === '(') || forbiddenCharactersInParameterName.indexOf(path[i]) < 0)) i++

if (isRegex) {
nodeType = 3
} else if (i < len) {
nodeType = 4
}

var parameter = path.slice(j, i)
var isRegex = parameter.indexOf('(') > -1
var regex = isRegex ? parameter.slice(parameter.indexOf('('), i) : null
if (isRegex) regex = new RegExp(regex)
params.push(parameter.slice(0, isRegex ? parameter.indexOf('(') : i))
Expand All @@ -71,9 +81,9 @@ Router.prototype.on = function (method, path, handler, store) {

// if the path is ended
if (i === len) {
return this._insert(method, path.slice(0, i), regex ? 3 : 1, params, handler, store, regex)
return this._insert(method, path.slice(0, i), nodeType, params, handler, store, regex)
}
this._insert(method, path.slice(0, i), regex ? 3 : 1, params, null, null, regex)
this._insert(method, path.slice(0, i), nodeType, params, null, null, regex)

// wildcard route
} else if (path.charCodeAt(i) === 42) {
Expand Down Expand Up @@ -258,6 +268,20 @@ Router.prototype.find = function (method, path) {
continue
}

// multiparametric route
if (kind === 4) {
currentNode = node
i = 0
while (i < pathLen && path.charCodeAt(i) !== 47 && forbiddenCharactersInParameterName.indexOf(path[i]) < 0) i++
decoded = fastDecode(path.slice(0, i))
if (errored) {
return null
}
params[pindex++] = decoded
path = path.slice(i)
continue
}

// route not found
if (len !== prefixLen) return null
}
Expand Down
132 changes: 132 additions & 0 deletions test/issue-17.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
'use strict'

const t = require('tap')
const test = t.test
const FindMyWay = require('../')

test('Parametric route with fixed suffix', t => {
t.plan(1)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:param-bar', (req, res, params) => {
t.equal(params.param, 'foo')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar' }, null)
})

test('Parametric route with fixed suffix', t => {
t.plan(1)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:$param', (req, res, params) => {
t.equal(params.$param, 'foo')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo' }, null)
})

test('Multi parametric route / 1', t => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p1-:p2', (req, res, params) => {
t.equal(params.p1, 'foo')
t.equal(params.p2, 'bar')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar' }, null)
})

test('Multi parametric route / 2', t => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p1-:p2', (req, res, params) => {
t.equal(params.p1, 'foo')
t.equal(params.p2, 'bar-baz')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar-baz' }, null)
})

test('Multi parametric route / 3', t => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p_1-:$p', (req, res, params) => {
t.equal(params.p_1, 'foo')
t.equal(params.$p, 'bar')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar' }, null)
})

test('Multi parametric route with fixed suffix', t => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p1-:p2-baz', (req, res, params) => {
t.equal(params.p1, 'foo')
t.equal(params.p2, 'bar')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar-baz' }, null)
})

test('Multi parametric route with wildcard', t => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p1-:p2/*', (req, res, params) => {
t.equal(params.p1, 'foo')
t.equal(params.p2, 'bar')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar/baz' }, null)
})

test('Nested multi parametric route', t => {
t.plan(3)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})

findMyWay.on('GET', '/a/:p1-:p2/b/:p3', (req, res, params) => {
t.equal(params.p1, 'foo')
t.equal(params.p2, 'bar')
t.equal(params.p3, 'baz')
})

findMyWay.lookup({ method: 'GET', url: '/a/foo-bar/b/baz' }, null)
})

0 comments on commit c4b5515

Please sign in to comment.