From 0defaeb00c4b7e4a1833ef4dd6f8d96ff60d355f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:28:15 +0000 Subject: [PATCH 1/3] Initial plan From 06c55d143b5962a9a6e58e00decb6398deb60eed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:33:43 +0000 Subject: [PATCH 2/3] fix: preserve trailing slash in route joining when it would not result in double slash Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- packages/http/src/route.ts | 15 +++++++++------ packages/http/test/routes.test.ts | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/http/src/route.ts b/packages/http/src/route.ts index 6a49a332498..2360d77312c 100644 --- a/packages/http/src/route.ts +++ b/packages/http/src/route.ts @@ -36,22 +36,25 @@ function needsSlashPrefix(fragment: string) { ); } -function normalizeFragment(fragment: string, trimLast = false) { +function normalizeFragment(fragment: string) { if (needsSlashPrefix(fragment)) { // Insert the default separator fragment = `/${fragment}`; } - if (trimLast && fragment[fragment.length - 1] === "/") { - return fragment.slice(0, -1); - } return fragment; } export function joinPathSegments(rest: string[]) { let current = ""; - for (const [index, segment] of rest.entries()) { - current += normalizeFragment(segment, index < rest.length - 1); + for (const segment of rest) { + const normalized = normalizeFragment(segment); + // Merge trailing and leading slashes to avoid double slashes + if (current.endsWith("/") && normalized.startsWith("/")) { + current += normalized.slice(1); + } else { + current += normalized; + } } return current; } diff --git a/packages/http/test/routes.test.ts b/packages/http/test/routes.test.ts index bdb1e60ac5f..39cec8801f5 100644 --- a/packages/http/test/routes.test.ts +++ b/packages/http/test/routes.test.ts @@ -346,6 +346,25 @@ describe("http: routes", () => { deepStrictEqual(routes, [{ verb: "get", path: `/abc${sep}restype=container`, params: [] }]); }); + + it("keeps trailing / on parent route when joining with child route", async () => { + const routes = await getRoutesFor( + ` + @route("{blobName}/") + interface Container { + @put @route("${sep}some-query=true") op foo(blobName: string): void; + } + `, + ); + + deepStrictEqual(routes, [ + { + verb: "put", + path: `/{blobName}/${sep}some-query=true`, + params: ["blobName"], + }, + ]); + }); }); describe("joinPathSegments", () => { From 96d0848fb22bcd981e64a4d6a0c2d70d97a32fda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:34:13 +0000 Subject: [PATCH 3/3] chore: add changelog entry for trailing slash route fix Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- ...opilot-fix-regression-http-1-10-1-2026-2-18-18-33-49.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .chronus/changes/copilot-fix-regression-http-1-10-1-2026-2-18-18-33-49.md diff --git a/.chronus/changes/copilot-fix-regression-http-1-10-1-2026-2-18-18-33-49.md b/.chronus/changes/copilot-fix-regression-http-1-10-1-2026-2-18-18-33-49.md new file mode 100644 index 00000000000..0d220f1033f --- /dev/null +++ b/.chronus/changes/copilot-fix-regression-http-1-10-1-2026-2-18-18-33-49.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http" +--- + +Fix route joining to preserve trailing `/` when it would not result in `//` \ No newline at end of file