0
0
mirror of https://github.com/honojs/hono.git synced 2024-12-01 11:51:01 +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 part: string = parts[i]
const isLast = i === len - 1 const isLast = i === len - 1
const tempNodes: Node<T>[] = [] const tempNodes: Node<T>[] = []
let matched = false
for (let j = 0, len2 = curNodes.length; j < len2; j++) { for (let j = 0, len2 = curNodes.length; j < len2; j++) {
const node = curNodes[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++) { for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k] const pattern = node.patterns[k]
@ -165,24 +179,16 @@ export class Node<T> {
} }
tempNodes.push(node.children[key]) 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 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 curNodes = tempNodes

View File

@ -527,3 +527,21 @@ describe('star', () => {
expect(res?.handlers).toEqual(['/*', '*', '/x', '/x/*']) 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 part: string = parts[i]
const isLast = i === len - 1 const isLast = i === len - 1
const tempNodes: Node<T>[] = [] const tempNodes: Node<T>[] = []
let matched = false
for (let j = 0, len2 = curNodes.length; j < len2; j++) { for (let j = 0, len2 = curNodes.length; j < len2; j++) {
const node = curNodes[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++) { for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k] const pattern = node.patterns[k]
@ -165,24 +179,16 @@ export class Node<T> {
} }
tempNodes.push(node.children[key]) 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 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 curNodes = tempNodes

View File

@ -129,3 +129,19 @@ describe('page', () => {
expect(res?.handlers).toEqual(['page', 'fallback']) 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')
})
})