Skip to content

Commit d9e7596

Browse files
committed
fix interception route rewrite regex not supporting special characters
1 parent ea0f516 commit d9e7596

File tree

7 files changed

+85
-3
lines changed

7 files changed

+85
-3
lines changed

packages/next/src/lib/generate-interception-routes-rewrites.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import type { Rewrite } from './load-custom-routes'
1010
// a function that converts normalised paths (e.g. /foo/[bar]/[baz]) to the format expected by pathToRegexp (e.g. /foo/:bar/:baz)
1111
function toPathToRegexpPath(path: string): string {
1212
return path.replace(/\[\[?([^\]]+)\]\]?/g, (_, capture) => {
13+
// path-to-regexp only supports word characters, so we replace any non-word characters with underscores
14+
const paramName = capture.replace(/\W+/g, '_')
15+
1316
// handle catch-all segments (e.g. /foo/bar/[...baz] or /foo/bar/[[...baz]])
14-
if (capture.startsWith('...')) {
15-
return `:${capture.slice(3)}*`
17+
if (paramName.startsWith('...')) {
18+
return `:${paramName.slice(3)}*`
1619
}
17-
return ':' + capture
20+
return ':' + paramName
1821
})
1922
}
2023

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function Page({ params }) {
2+
return (
3+
<div>
4+
Hello from [this-is-my-route]/@intercept/some-page. Param:{' '}
5+
{params['this-is-my-route']}
6+
</div>
7+
)
8+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return null
3+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export default function Layout({
2+
children,
3+
intercept,
4+
}: {
5+
children: React.ReactNode
6+
intercept: React.ReactNode
7+
}) {
8+
return (
9+
<div>
10+
<div>{children}</div>
11+
<div>{intercept}</div>
12+
</div>
13+
)
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<Link href="/interception-route-special-params/some-random-param/some-page">
6+
Trigger Interception
7+
</Link>
8+
)
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function Page({ params }) {
2+
return (
3+
<div>
4+
Hello from [this-is-my-route]/some-page. Param:{' '}
5+
{params['this-is-my-route']}
6+
</div>
7+
)
8+
}

test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,43 @@ createNextDescribe(
873873
await check(() => browser.waitForElementByCss('#main-slot').text(), '1')
874874
})
875875

876+
it('should intercept on routes that contain hyphenated/special dynamic params', async () => {
877+
const browser = await next.browser(
878+
'/interception-route-special-params/some-random-param'
879+
)
880+
881+
await browser
882+
.elementByCss(
883+
"[href='/interception-route-special-params/some-random-param/some-page']"
884+
)
885+
.click()
886+
887+
const interceptionText =
888+
'Hello from [this-is-my-route]/@intercept/some-page. Param: some-random-param'
889+
const pageText =
890+
'Hello from [this-is-my-route]/some-page. Param: some-random-param'
891+
892+
await retry(async () => {
893+
expect(await browser.elementByCss('body').text()).toContain(
894+
interceptionText
895+
)
896+
897+
expect(await browser.elementByCss('body').text()).not.toContain(
898+
pageText
899+
)
900+
})
901+
902+
await browser.refresh()
903+
904+
await retry(async () => {
905+
expect(await browser.elementByCss('body').text()).toContain(pageText)
906+
907+
expect(await browser.elementByCss('body').text()).not.toContain(
908+
interceptionText
909+
)
910+
})
911+
})
912+
876913
if (isNextStart) {
877914
it('should not have /default paths in the prerender manifest', async () => {
878915
const prerenderManifest = JSON.parse(

0 commit comments

Comments
 (0)