diff --git a/packages/router-core/src/new-process-route-tree.ts b/packages/router-core/src/new-process-route-tree.ts index 2d3b41cc111..21b1eddc62b 100644 --- a/packages/router-core/src/new-process-route-tree.ts +++ b/packages/router-core/src/new-process-route-tree.ts @@ -320,6 +320,7 @@ function parseSegments( nextNode = next next.parent = node next.depth = depth + next.isIndex = true node.wildcard ??= [] node.wildcard.push(next) } @@ -856,7 +857,6 @@ function getNodeMatch( }, ] - let wildcardMatch: Frame | null = null let bestFuzzy: Frame | null = null let bestMatch: Frame | null = null @@ -888,7 +888,7 @@ function getNodeMatch( let lowerPart: string // 5. Try wildcard match - if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) { + if (node.wildcard) { for (const segment of node.wildcard) { const { prefix, suffix } = segment if (prefix) { @@ -905,15 +905,15 @@ function getNodeMatch( if (casePart !== suffix) continue } // the first wildcard match is the highest priority one - wildcardMatch = { + stack.push({ node: segment, - index, + index: partsLength, skipped, - depth, + depth: depth + 1, statics, dynamics, optionals, - } + }) break } } @@ -1020,8 +1020,6 @@ function getNodeMatch( if (bestMatch) return bestMatch - if (wildcardMatch) return wildcardMatch - if (fuzzy && bestFuzzy) { let sliceIndex = bestFuzzy.index for (let i = 0; i < bestFuzzy.index; i++) { diff --git a/packages/router-core/tests/new-process-route-tree.test.ts b/packages/router-core/tests/new-process-route-tree.test.ts index ced5ac1b8b0..ea1dc0db045 100644 --- a/packages/router-core/tests/new-process-route-tree.test.ts +++ b/packages/router-core/tests/new-process-route-tree.test.ts @@ -546,6 +546,23 @@ describe('findRouteMatch', () => { expect(res?.route.id).toBe('/a/b/$') expect(res?.params).toEqual({ _splat: 'foo', '*': 'foo' }) }) + describe('edge-case #5969: trailing empty wildcard should match', () => { + it('basic', () => { + const tree = makeTree(['/a/$']) + expect(findRouteMatch('/a/', tree)?.route.id).toBe('/a/$') + expect(findRouteMatch('/a', tree)?.route.id).toBe('/a/$') + }) + it('with layout route', () => { + const tree = makeTree(['/a', '/a/$']) + expect(findRouteMatch('/a/', tree)?.route.id).toBe('/a/$') + expect(findRouteMatch('/a', tree)?.route.id).toBe('/a/$') + }) + it('with index route (should not match)', () => { + const tree = makeTree(['/a/', '/a/$']) + expect(findRouteMatch('/a/', tree)?.route.id).toBe('/a/') + expect(findRouteMatch('/a', tree)?.route.id).toBe('/a/') + }) + }) }) describe('nested routes', () => {