Repository: honojs/honox
Pull request #143 (2024-04-12 21:23:37)

fix: correct routing priority if file name has brackets
Fixed a problem if the path has brackets overriding other directory paths in the same hierarchy.



Patch:
diff --git a/mocks/app-nested-middleware/routes/nested/foo/bar/[id]/index.tsx b/mocks/app-nested-middleware/routes/nested/foo/bar/[id]/index.tsx
new file mode 100644
index 0000000..bba334e
--- /dev/null
+++ b/mocks/app-nested-middleware/routes/nested/foo/bar/[id]/index.tsx
@@ -0,0 +1,3 @@
+export default function Id() {
+  return <h1>Id</h1>
+}
diff --git a/src/utils/file.ts b/src/utils/file.ts
index f0f14eb..946f06f 100644
--- a/src/utils/file.ts
+++ b/src/utils/file.ts
@@ -56,11 +56,20 @@ export const groupByDirectory = <T = unknown>(files: Record<string, T>) => {
 }
 
 export const sortDirectoriesByDepth = <T>(directories: Record<string, T>) => {
-  const sortedKeys = Object.keys(directories).sort((a, b) => {
-    const depthA = a.split('/').length
-    const depthB = b.split('/').length
-    return depthA - depthB
-  })
+  const sortedKeys = Object.keys(directories)
+    .sort((a, b) => {
+      const depthA = a.split('/').length
+      const depthB = b.split('/').length
+      return depthA - depthB
+    })
+    .sort((a, b) => {
+      const depthA = a.split('/').length
+      const depthB = b.split('/').length
+      if (depthA === depthB) {
+        return b.localeCompare(a)
+      }
+      return 1
+    })
 
   // if we have root routes, make sure they are registered last
   if (sortedKeys.find((x) => /.*\/routes$/.test(x))) {


Test patch:
diff --git a/src/utils/file.test.ts b/src/utils/file.test.ts
index 3c33e25..ed9086f 100644
--- a/src/utils/file.test.ts
+++ b/src/utils/file.test.ts
@@ -63,30 +63,38 @@ describe('sortDirectoriesByDepth', () => {
   it('Should sort directories by the depth', () => {
     expect(
       sortDirectoriesByDepth({
-        '/app/routes': {
+        '/dir': {
           'index.tsx': 'file1',
         },
-        '/app/routes/blog/posts': {
+        '/dir/blog/[id]': {
           'index.tsx': 'file2',
         },
-        '/app/routes/blog': {
+        '/dir/blog/posts': {
           'index.tsx': 'file3',
         },
+        '/dir/blog': {
+          'index.tsx': 'file4',
+        },
       })
-    ).toEqual([
+    ).toStrictEqual([
       {
-        '/app/routes/blog': {
-          'index.tsx': 'file3',
+        '/dir': {
+          'index.tsx': 'file1',
         },
       },
       {
-        '/app/routes/blog/posts': {
-          'index.tsx': 'file2',
+        '/dir/blog': {
+          'index.tsx': 'file4',
         },
       },
       {
-        '/app/routes': {
-          'index.tsx': 'file1',
+        '/dir/blog/posts': {
+          'index.tsx': 'file3',
+        },
+      },
+      {
+        '/dir/blog/[id]': {
+          'index.tsx': 'file2',
         },
       },
     ])
diff --git a/test-integration/api.test.ts b/test-integration/api.test.ts
index 4533a52..4b95232 100644
--- a/test-integration/api.test.ts
+++ b/test-integration/api.test.ts
@@ -60,7 +60,7 @@ describe('Basic', () => {
     ]
 
     expect(app.routes).toHaveLength(routes.length)
-    expect(app.routes).toEqual(routes)
+    expect(app.routes).toEqual(expect.arrayContaining(routes))
   })
 
   it('Should return 200 response - / with a Powered By header', async () => {
diff --git a/test-integration/apps.test.ts b/test-integration/apps.test.ts
index a627176..bdb45cd 100644
--- a/test-integration/apps.test.ts
+++ b/test-integration/apps.test.ts
@@ -451,6 +451,14 @@ describe('Nested Middleware', () => {
     expect(res.headers.get('bar')).toEqual('bar')
     expect(res.headers.get('baz')).toEqual('baz')
   })
+  it('/nested/foo/bar/123', async () => {
+    const res = await app.request('/nested/foo/bar/123')
+    expect(res.status).toBe(200)
+    expect(res.headers.get('root')).toEqual('root')
+    expect(res.headers.get('root2')).toEqual('root2')
+    expect(res.headers.get('foo')).toEqual('foo')
+    expect(res.headers.get('bar')).toEqual('bar')
+  })
 })
 
 describe('<Script /> component', () => {