diff --git a/src/utils.url.ts b/src/utils.url.ts index 5a725353..17b9aded 100644 --- a/src/utils.url.ts +++ b/src/utils.url.ts @@ -66,6 +66,15 @@ export function withQuery(input: string, query?: QueryObject): string { return input; } + // The fragment always comes last (RFC 3986), so split it off before + // touching the query and re-append it at the end. + const hashIndex = input.indexOf("#"); + let hash = ""; + if (hashIndex !== -1) { + hash = input.slice(hashIndex); + input = input.slice(0, hashIndex); + } + const searchIndex = input.indexOf("?"); if (searchIndex === -1) { @@ -80,7 +89,7 @@ export function withQuery(input: string, query?: QueryObject): string { }); const searchParams = new URLSearchParams(normalizedQuery); const queryString = searchParams.toString(); - return queryString ? `${input}?${queryString}` : input; + return queryString ? `${input}?${queryString}${hash}` : `${input}${hash}`; } const searchParams = new URLSearchParams(input.slice(searchIndex + 1)); @@ -99,7 +108,7 @@ export function withQuery(input: string, query?: QueryObject): string { } const queryString = searchParams.toString(); - return queryString ? `${base}?${queryString}` : base; + return queryString ? `${base}?${queryString}${hash}` : `${base}${hash}`; } function normalizeQueryValue(value: QueryValue): string { diff --git a/test/index.test.ts b/test/index.test.ts index 5ac20b07..8acb0b55 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -382,6 +382,30 @@ describe("ofetch", () => { expect(parseParams(path)).toMatchObject({ a: "1", b: "2", c: "3" }); }); + it("keeps the hash out of the query", async () => { + // The hash is always last, so query params have to be inserted before it. + expect( + await $fetch(getURL("echo#hash"), { query: { foo: "1" } }).then( + (r) => r.path + ) + ).to.equal("/echo?foo=1"); + + expect( + await $fetch(getURL("echo?a=1#hash"), { query: { b: "2" } }).then( + (r) => r.path + ) + ).to.equal("/echo?a=1&b=2"); + + let requestURL: string | undefined; + await $fetch(getURL("echo#hash"), { + query: { foo: "1" }, + onResponse({ request }) { + requestURL = request as string; + }, + }); + expect(requestURL).to.equal(getURL("echo") + "?foo=1#hash"); + }); + it("uses request headers", async () => { expect( await $fetch(