Skip to content

Commit 81bda2e

Browse files
authored
feat(helper/route): enable to get route path at specific index (#4423)
1 parent 393ded9 commit 81bda2e

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

src/helper/route/index.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ describe('routePath', () => {
6363

6464
expect(routePath(c)).toBe('/:id')
6565

66+
expect(routePath(c, 0)).toBe('/:id')
67+
expect(routePath(c, 1)).toBe('/:id/:name')
68+
expect(routePath(c, -1)).toBe('/:id/:name')
69+
expect(routePath(c, 2)).toBe('')
70+
6671
c.req.routeIndex = 1
6772
expect(routePath(c)).toBe('/:id/:name')
6873
})
@@ -96,6 +101,12 @@ describe('baseRoutePath', () => {
96101

97102
expect(baseRoutePath(c)).toBe('/')
98103

104+
expect(baseRoutePath(c, 0)).toBe('/')
105+
expect(baseRoutePath(c, 1)).toBe('/sub')
106+
expect(baseRoutePath(c, 2)).toBe('/:sub')
107+
expect(baseRoutePath(c, -1)).toBe('/:sub')
108+
expect(baseRoutePath(c, 3)).toBe('')
109+
99110
c.req.routeIndex = 1
100111
expect(baseRoutePath(c)).toBe('/sub')
101112

@@ -129,6 +140,11 @@ describe('basePath', () => {
129140
expect(basePath(c)).toBe('/')
130141
expect(basePath(c)).toBe('/') // cached value
131142

143+
expect(basePath(c, 0)).toBe('/')
144+
expect(basePath(c, 1)).toBe('/sub')
145+
expect(basePath(c, -1)).toBe('/sub')
146+
expect(basePath(c, 2)).toBe('')
147+
132148
c.req.routeIndex = 1
133149
expect(basePath(c)).toBe('/sub')
134150
})

src/helper/route/index.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,32 @@ export const matchedRoutes = (c: Context): RouterRoute[] =>
3737
* Get the route path registered within the handler
3838
*
3939
* @param {Context} c - The context object
40+
* @param {number} index - The index of the root from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching root. Defaults to the current root index.
4041
* @returns The route path registered within the handler
4142
*
4243
* @example
4344
* ```ts
4445
* import { routePath } from 'hono/route'
4546
*
47+
* app.use('*', (c, next) => {
48+
* console.log(routePath(c)) // '*'
49+
* console.log(routePath(c, -1)) // '/posts/:id'
50+
* return next()
51+
* })
52+
*
4653
* app.get('/posts/:id', (c) => {
4754
* return c.text(routePath(c)) // '/posts/:id'
4855
* })
4956
* ```
5057
*/
51-
export const routePath = (c: Context): string => matchedRoutes(c)[c.req.routeIndex].path
58+
export const routePath = (c: Context, index?: number): string =>
59+
matchedRoutes(c).at(index ?? c.req.routeIndex)?.path ?? ''
5260

5361
/**
5462
* Get the basePath of the as-is route specified by routing.
5563
*
5664
* @param {Context} c - The context object
65+
* @param {number} index - The index of the root from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching root. Defaults to the current root index.
5766
* @returns The basePath of the as-is route specified by routing.
5867
*
5968
* @example
@@ -70,12 +79,14 @@ export const routePath = (c: Context): string => matchedRoutes(c)[c.req.routeInd
7079
* app.route('/:sub', subApp)
7180
* ```
7281
*/
73-
export const baseRoutePath = (c: Context): string => matchedRoutes(c)[c.req.routeIndex].basePath
82+
export const baseRoutePath = (c: Context, index?: number): string =>
83+
matchedRoutes(c).at(index ?? c.req.routeIndex)?.basePath ?? ''
7484

7585
/**
7686
* Get the basePath with embedded parameters
7787
*
7888
* @param {Context} c - The context object
89+
* @param {number} index - The index of the root from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching root. Defaults to the current root index.
7990
* @returns The basePath with embedded parameters.
8091
*
8192
* @example
@@ -92,17 +103,17 @@ export const baseRoutePath = (c: Context): string => matchedRoutes(c)[c.req.rout
92103
* app.route('/:sub', subApp)
93104
* ```
94105
*/
95-
const basePathCacheMap: WeakMap<Context, string[]> = new WeakMap()
96-
export const basePath = (c: Context): string => {
97-
const routeIndex = c.req.routeIndex
106+
const basePathCacheMap: WeakMap<Context, Record<number, string>> = new WeakMap()
107+
export const basePath = (c: Context, index?: number): string => {
108+
index ??= c.req.routeIndex
98109

99110
const cache = basePathCacheMap.get(c) || []
100-
if (typeof cache[routeIndex] === 'string') {
101-
return cache[routeIndex]
111+
if (typeof cache[index] === 'string') {
112+
return cache[index]
102113
}
103114

104115
let result: string
105-
const rp = baseRoutePath(c)
116+
const rp = baseRoutePath(c, index)
106117
if (!/[:*]/.test(rp)) {
107118
result = rp
108119
} else {
@@ -123,7 +134,7 @@ export const basePath = (c: Context): string => {
123134
result = reqPath.substring(0, basePathLength)
124135
}
125136

126-
cache[routeIndex] = result
137+
cache[index] = result
127138
basePathCacheMap.set(c, cache)
128139

129140
return result

0 commit comments

Comments
 (0)