Skip to content

Commit

Permalink
Fix getStaticPaths regression (#11993)
Browse files Browse the repository at this point in the history
* Revert "Remove dependency on path-to-regexp (#11983)"

This reverts commit 633eeaa.

* Add test for regression

* Add a changeset

* Pin path-to-regexp
  • Loading branch information
matthewp authored Sep 13, 2024
1 parent 2d016d4 commit ffba5d7
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 31 deletions.
7 changes: 7 additions & 0 deletions .changeset/happy-ways-sin.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
69 changes: 38 additions & 31 deletions packages/astro/src/core/routing/manifest/generator.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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 || '/';
};
}
Original file line number Diff line number Diff line change
@@ -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>
8 changes: 8 additions & 0 deletions packages/astro/test/get-static-paths-pages.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
})
});
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ffba5d7

Please sign in to comment.