0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-29 17:46:30 +01:00

fix(trie-router): fix the rule for capturing named parameter (#419)

Close #418
This commit is contained in:
Yusuke Wada 2022-07-24 11:03:04 +09:00 committed by GitHub
parent 34b218ddf6
commit f6f454ed42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 28 deletions

View File

@ -135,9 +135,23 @@ export class Node<T> {
const part: string = parts[i]
const isLast = i === len - 1
const tempNodes: Node<T>[] = []
let matched = false
for (let j = 0, len2 = curNodes.length; j < len2; j++) {
const node = curNodes[j]
const nextNode = node.children[part]
if (nextNode) {
if (isLast === true) {
// '/hello/*' => match '/hello'
if (nextNode.children['*']) {
handlerSets.push(...this.getHandlerSets(nextNode.children['*'], method, true))
}
handlerSets.push(...this.getHandlerSets(nextNode, method))
matched = true
}
tempNodes.push(nextNode)
}
for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k]
@ -165,24 +179,16 @@ export class Node<T> {
}
tempNodes.push(node.children[key])
}
if (typeof name === 'string') {
// '/book/a' => not-slug
// '/book/:slug' => slug
// GET /book/a ~> no-slug, param['slug'] => undefined
// GET /book/foo ~> slug, param['slug'] => foo
if (typeof name === 'string' && !matched) {
params[name] = part
}
}
}
const nextNode = node.children[part]
if (nextNode) {
if (isLast === true) {
// '/hello/*' => match '/hello'
if (nextNode.children['*']) {
handlerSets.push(...this.getHandlerSets(nextNode.children['*'], method, true))
}
handlerSets.push(...this.getHandlerSets(nextNode, method))
}
tempNodes.push(nextNode)
}
}
curNodes = tempNodes

View File

@ -527,3 +527,21 @@ describe('star', () => {
expect(res?.handlers).toEqual(['/*', '*', '/x', '/x/*'])
})
})
describe('Routing order With named parameters', () => {
const node = new Node()
node.insert('get', '/book/a', 'no-slug')
node.insert('get', '/book/:slug', 'slug')
it('/book/a', () => {
const res = node.search('get', '/book/a')
expect(res).not.toBeNull()
expect(res?.handlers).toEqual(['no-slug', 'slug'])
expect(res?.params['slug']).toBeUndefined()
})
it('/book/foo', () => {
const res = node.search('get', '/book/foo')
expect(res).not.toBeNull()
expect(res?.handlers).toEqual(['slug'])
expect(res?.params['slug']).toBe('foo')
})
})

View File

@ -135,9 +135,23 @@ export class Node<T> {
const part: string = parts[i]
const isLast = i === len - 1
const tempNodes: Node<T>[] = []
let matched = false
for (let j = 0, len2 = curNodes.length; j < len2; j++) {
const node = curNodes[j]
const nextNode = node.children[part]
if (nextNode) {
if (isLast === true) {
// '/hello/*' => match '/hello'
if (nextNode.children['*']) {
handlerSets.push(...this.getHandlerSets(nextNode.children['*'], method, true))
}
handlerSets.push(...this.getHandlerSets(nextNode, method))
matched = true
}
tempNodes.push(nextNode)
}
for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k]
@ -165,24 +179,16 @@ export class Node<T> {
}
tempNodes.push(node.children[key])
}
if (typeof name === 'string') {
// '/book/a' => not-slug
// '/book/:slug' => slug
// GET /book/a ~> no-slug, param['slug'] => undefined
// GET /book/foo ~> slug, param['slug'] => foo
if (typeof name === 'string' && !matched) {
params[name] = part
}
}
}
const nextNode = node.children[part]
if (nextNode) {
if (isLast === true) {
// '/hello/*' => match '/hello'
if (nextNode.children['*']) {
handlerSets.push(...this.getHandlerSets(nextNode.children['*'], method, true))
}
handlerSets.push(...this.getHandlerSets(nextNode, method))
}
tempNodes.push(nextNode)
}
}
curNodes = tempNodes

View File

@ -129,3 +129,19 @@ describe('page', () => {
expect(res?.handlers).toEqual(['page', 'fallback'])
})
})
describe('routing order with named parameters', () => {
const router = new TrieRouter<string>()
router.add('GET', '/book/a', 'no-slug')
router.add('GET', '/book/:slug', 'slug')
it('GET /book/a', async () => {
const res = router.match('GET', '/book/a')
expect(res?.handlers).toEqual(['no-slug', 'slug'])
expect(res?.params['slug']).toBeUndefined()
})
it('GET /book/foo', async () => {
const res = router.match('GET', '/book/foo')
expect(res?.handlers).toEqual(['slug'])
expect(res?.params['slug']).toBe('foo')
})
})