From 2ab9badae19bcab6d9e3bc3ab0a6079ff4bd9d4e Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Thu, 1 May 2025 16:10:58 -0700 Subject: [PATCH 1/2] Remove unused ts-expect-error directives --- packages/react-router/__tests__/generatePath-test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-router/__tests__/generatePath-test.tsx b/packages/react-router/__tests__/generatePath-test.tsx index 70232f7d46..61f0397849 100644 --- a/packages/react-router/__tests__/generatePath-test.tsx +++ b/packages/react-router/__tests__/generatePath-test.tsx @@ -45,10 +45,8 @@ describe("generatePath", () => { ).toBe("/courses/foo*"); }); it("handles a 0 parameter", () => { - // @ts-expect-error // incorrect usage but worked in 6.3.0 so keep it to avoid the regression expect(generatePath("/courses/:id", { id: 0 })).toBe("/courses/0"); - // @ts-expect-error // incorrect usage but worked in 6.3.0 so keep it to avoid the regression expect(generatePath("/courses/*", { "*": 0 })).toBe("/courses/0"); }); From a45ce4f33f8f58723d6a7448f08deece140b649f Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Thu, 1 May 2025 16:19:12 -0700 Subject: [PATCH 2/2] Properly escape :params in generatePath Fixes #11940 --- .changeset/eleven-oranges-design.md | 5 +++++ packages/react-router/__tests__/generatePath-test.tsx | 8 ++++++++ packages/react-router/lib/router/utils.ts | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .changeset/eleven-oranges-design.md diff --git a/.changeset/eleven-oranges-design.md b/.changeset/eleven-oranges-design.md new file mode 100644 index 0000000000..a5ca0a4068 --- /dev/null +++ b/.changeset/eleven-oranges-design.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +Properly escape interpolated :param values in generatePath() diff --git a/packages/react-router/__tests__/generatePath-test.tsx b/packages/react-router/__tests__/generatePath-test.tsx index 61f0397849..d15899d347 100644 --- a/packages/react-router/__tests__/generatePath-test.tsx +++ b/packages/react-router/__tests__/generatePath-test.tsx @@ -133,6 +133,14 @@ describe("generatePath", () => { }); }); + describe("with a param that contains a /", () => { + it("properly encodes the slash", () => { + expect(generatePath("/courses/:id/grades", { id: "a/b" })).toBe( + "/courses/a%2Fb/grades" + ); + }); + }); + it("throws only on on missing named parameters, but not missing splat params", () => { expect(() => generatePath(":foo")).toThrow(); expect(() => generatePath("/:foo")).toThrow(); diff --git a/packages/react-router/lib/router/utils.ts b/packages/react-router/lib/router/utils.ts index cebea7406f..0d494edb0f 100644 --- a/packages/react-router/lib/router/utils.ts +++ b/packages/react-router/lib/router/utils.ts @@ -1108,7 +1108,7 @@ export function generatePath( const [, key, optional] = keyMatch; let param = params[key as PathParam]; invariant(optional === "?" || param != null, `Missing ":${key}" param`); - return stringify(param); + return encodeURIComponent(stringify(param)); } // Remove any optional markers from optional static segments