diff --git a/.changeset/mean-geckos-sell.md b/.changeset/mean-geckos-sell.md new file mode 100644 index 0000000000..5a72faa07f --- /dev/null +++ b/.changeset/mean-geckos-sell.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Update generator.ts to allow %23 (#) in dynamic urls diff --git a/packages/astro/src/core/routing/manifest/generator.ts b/packages/astro/src/core/routing/manifest/generator.ts index 9395a3de2f..c61ce6dca4 100644 --- a/packages/astro/src/core/routing/manifest/generator.ts +++ b/packages/astro/src/core/routing/manifest/generator.ts @@ -2,6 +2,25 @@ import type { AstroConfig, RoutePart } from '../../../@types/astro.js'; import { compile } from 'path-to-regexp'; +/** + * Sanitizes the parameters object by normalizing string values and replacing certain characters with their URL-encoded equivalents. + * @param {Record} params - The parameters object to be sanitized. + * @returns {Record} The sanitized parameters object. + */ +function sanitizeParams(params: Record): Record { + return Object.fromEntries( + Object.entries(params).map(([key, value]) => { + if (typeof value === 'string') { + return [key, value + .normalize() + .replace(/#/g, '%23') + .replace(/\?/g, '%3F')] + } + return [key, value]; + }) + ) +} + export function getRouteGenerator( segments: RoutePart[][], addTrailingSlash: AstroConfig['trailingSlash'] @@ -37,8 +56,9 @@ export function getRouteGenerator( trailing = '/'; } const toPath = compile(template + trailing); - return (params: object): string => { - const path = toPath(params); + return (params: Record): string => { + const sanitizedParams = sanitizeParams(params); + const path = toPath(sanitizedParams); // When generating an index from a rest parameter route, `path-to-regexp` will return an // empty string instead "/". This causes an inconsistency with static indexes that may result diff --git a/packages/astro/test/ssr-params.test.js b/packages/astro/test/ssr-params.test.js index c5d376fbfc..13c071e7d0 100644 --- a/packages/astro/test/ssr-params.test.js +++ b/packages/astro/test/ssr-params.test.js @@ -42,11 +42,11 @@ describe('Astro.params in SSR', () => { it('No double URL decoding', async () => { const app = await fixture.loadTestAdapterApp(); - const request = new Request('http://example.com/users/houston/%25'); + const request = new Request('http://example.com/users/houston/%25%23%3F'); const response = await app.render(request); assert.equal(response.status, 200); const html = await response.text(); const $ = cheerio.load(html); - assert.equal($('.category').text(), '%'); + assert.equal($('.category').text(), '%#?'); }); });