summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/happy-ways-sin.md7
-rw-r--r--packages/astro/package.json1
-rw-r--r--packages/astro/src/core/routing/manifest/generator.ts69
-rw-r--r--packages/astro/test/fixtures/get-static-paths-pages/src/pages/archive/[...slug]/[...page].astro37
-rw-r--r--packages/astro/test/get-static-paths-pages.test.js8
-rw-r--r--pnpm-lock.yaml8
6 files changed, 99 insertions, 31 deletions
diff --git a/.changeset/happy-ways-sin.md b/.changeset/happy-ways-sin.md
new file mode 100644
index 000000000..e100a3135
--- /dev/null
+++ b/.changeset/happy-ways-sin.md
@@ -0,0 +1,7 @@
+---
+'astro': patch
+---
+
+Fix getStaticPaths regression
+
+This reverts a previous change meant to remove a dependency, to fix a regression with multiple nested spread routes.
diff --git a/packages/astro/package.json b/packages/astro/package.json
index f3a2b7d0b..bd9bcc717 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -168,6 +168,7 @@
"ora": "^8.1.0",
"p-limit": "^6.1.0",
"p-queue": "^8.0.1",
+ "path-to-regexp": "6.2.2",
"preferred-pm": "^4.0.0",
"prompts": "^2.4.2",
"rehype": "^13.0.1",
diff --git a/packages/astro/src/core/routing/manifest/generator.ts b/packages/astro/src/core/routing/manifest/generator.ts
index 30758bfd1..4ab635ec6 100644
--- a/packages/astro/src/core/routing/manifest/generator.ts
+++ b/packages/astro/src/core/routing/manifest/generator.ts
@@ -1,5 +1,7 @@
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<string, string | number | undefined>} params - The parameters object to be sanitized.
@@ -22,40 +24,45 @@ export function getRouteGenerator(
segments: RoutePart[][],
addTrailingSlash: AstroConfig['trailingSlash'],
) {
+ const template = segments
+ .map((segment) => {
+ return (
+ '/' +
+ segment
+ .map((part) => {
+ if (part.spread) {
+ return `:${part.content.slice(3)}(.*)?`;
+ } else if (part.dynamic) {
+ return `:${part.content}`;
+ } else {
+ return part.content
+ .normalize()
+ .replace(/\?/g, '%3F')
+ .replace(/#/g, '%23')
+ .replace(/%5B/g, '[')
+ .replace(/%5D/g, ']')
+ .replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ }
+ })
+ .join('')
+ );
+ })
+ .join('');
+
+ // Unless trailingSlash config is set to 'always', don't automatically append it.
+ let trailing: '/' | '' = '';
+ if (addTrailingSlash === 'always' && segments.length) {
+ trailing = '/';
+ }
+ const toPath = compile(template + trailing);
return (params: Record<string, string | number | undefined>): string => {
const sanitizedParams = sanitizeParams(params);
+ const path = toPath(sanitizedParams);
- // Unless trailingSlash config is set to 'always', don't automatically append it.
- let trailing: '/' | '' = '';
- if (addTrailingSlash === 'always' && segments.length) {
- trailing = '/';
- }
-
- const path =
- segments
- .map((segment) => {
- return (
- '/' +
- segment
- .map((part) => {
- if (part.spread) {
- return `${sanitizedParams[part.content.slice(3)] || ''}`;
- } else if (part.dynamic) {
- return `${sanitizedParams[part.content] || ''}`;
- } else {
- return part.content
- .normalize()
- .replace(/\?/g, '%3F')
- .replace(/#/g, '%23')
- .replace(/%5B/g, '[')
- .replace(/%5D/g, ']');
- }
- })
- .join('')
- );
- })
- .join('') + trailing;
-
+ // 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
+ // in the incorrect routes being rendered.
+ // To fix this, we return "/" when the path is empty.
return path || '/';
};
}
diff --git a/packages/astro/test/fixtures/get-static-paths-pages/src/pages/archive/[...slug]/[...page].astro b/packages/astro/test/fixtures/get-static-paths-pages/src/pages/archive/[...slug]/[...page].astro
new file mode 100644
index 000000000..cf5a88640
--- /dev/null
+++ b/packages/astro/test/fixtures/get-static-paths-pages/src/pages/archive/[...slug]/[...page].astro
@@ -0,0 +1,37 @@
+---
+export async function getStaticPaths({ paginate }) {
+
+ const paths = [
+ {
+ slug: 'news/july-2024',
+ items: ['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6'],
+ contentType: 'news',
+ monthYear: 'july-2024',
+ }
+ ];
+
+ return paths.flatMap((path) => {
+ return paginate(path.items, {
+ params: { slug: path.slug },
+ props: {
+ contentType: path.contentType,
+ monthYear: path.monthYear,
+ },
+ pageSize: 2,
+ });
+ });
+}
+
+const { slug, page } = Astro.params;
+---
+
+<html>
+ <head>
+ <title>Testing</title>
+ </head>
+ <body>
+ <h1>Testing</h1>
+ <p id="slug">{slug}</p>
+ <p id="page">{page}</p>
+ </body>
+</html>
diff --git a/packages/astro/test/get-static-paths-pages.test.js b/packages/astro/test/get-static-paths-pages.test.js
index 170e1d485..b62b1baa1 100644
--- a/packages/astro/test/get-static-paths-pages.test.js
+++ b/packages/astro/test/get-static-paths-pages.test.js
@@ -25,4 +25,12 @@ describe('getStaticPaths with trailingSlash: ignore', () => {
let $ = cheerio.load(html);
assert.equal($('h1').text(), 'Page 2');
});
+
+ // for regression: https://github.com/withastro/astro/issues/11990
+ it('nested static paths generate', async () => {
+ let html = await fixture.readFile('/archive/news/july-2024/2/index.html');
+ let $ = cheerio.load(html);
+ assert.equal($('#slug').text(), 'news');
+ assert.equal($('#page').text(), 'july-2024/2');
+ })
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3f7eebdf6..a054e7f2b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -693,6 +693,9 @@ importers:
p-queue:
specifier: ^8.0.1
version: 8.0.1
+ path-to-regexp:
+ specifier: 6.2.2
+ version: 6.2.2
preferred-pm:
specifier: ^4.0.0
version: 4.0.0
@@ -9543,6 +9546,9 @@ packages:
resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
engines: {node: '>=16 || 14 >=14.17'}
+ path-to-regexp@6.2.2:
+ resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -15576,6 +15582,8 @@ snapshots:
lru-cache: 10.2.0
minipass: 7.1.2
+ path-to-regexp@6.2.2: {}
+
path-type@4.0.0: {}
path-type@5.0.0: {}