feat: remove automatic flattening of getStaticPaths
result (#7845)
* feat: remove automatic flattening of `getStaticPaths` result * chore: changeset
This commit is contained in:
parent
3dc1ca2fac
commit
76ddef19cc
12 changed files with 42 additions and 62 deletions
5
.changeset/chilled-ducks-grin.md
Normal file
5
.changeset/chilled-ducks-grin.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': major
|
||||||
|
---
|
||||||
|
|
||||||
|
Removed automatic flattening of `getStaticPaths` result. `.flatMap` and `.flat` should now be used to ensure that you're returning a flat array.
|
|
@ -1525,10 +1525,7 @@ export type GetStaticPathsResultKeyed = GetStaticPathsResult & {
|
||||||
*/
|
*/
|
||||||
export type GetStaticPaths = (
|
export type GetStaticPaths = (
|
||||||
options: GetStaticPathsOptions
|
options: GetStaticPathsOptions
|
||||||
) =>
|
) => Promise<GetStaticPathsResult> | GetStaticPathsResult;
|
||||||
| Promise<GetStaticPathsResult | GetStaticPathsResult[]>
|
|
||||||
| GetStaticPathsResult
|
|
||||||
| GetStaticPathsResult[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infers the shape of the `params` property returned by `getStaticPaths()`.
|
* Infers the shape of the `params` property returned by `getStaticPaths()`.
|
||||||
|
|
|
@ -300,7 +300,6 @@ async function getPathsForRoute(
|
||||||
mod,
|
mod,
|
||||||
route,
|
route,
|
||||||
routeCache: opts.routeCache,
|
routeCache: opts.routeCache,
|
||||||
isValidate: false,
|
|
||||||
logging: opts.logging,
|
logging: opts.logging,
|
||||||
ssr: isServerLikeOutput(opts.settings.config),
|
ssr: isServerLikeOutput(opts.settings.config),
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
|
|
@ -231,6 +231,28 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
|
||||||
`Invalid params given to \`getStaticPaths\` path. Expected an \`object\`, got \`${paramType}\``,
|
`Invalid params given to \`getStaticPaths\` path. Expected an \`object\`, got \`${paramType}\``,
|
||||||
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
|
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @see
|
||||||
|
* - [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
|
||||||
|
* @description
|
||||||
|
* `getStaticPaths`'s return value must be an array of objects. In most cases, this error happens because an array of array was returned. Using [`.flatMap()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap) or a [`.flat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) call may be useful.
|
||||||
|
*
|
||||||
|
* ```ts title="pages/blog/[id].astro"
|
||||||
|
* export async function getStaticPaths() {
|
||||||
|
* return [ // <-- Array
|
||||||
|
* { params: { slug: "blog" } }, // <-- Object
|
||||||
|
* { params: { slug: "about" } }
|
||||||
|
* ];
|
||||||
|
*}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
InvalidGetStaticPathsEntry: {
|
||||||
|
title: "Invalid entry inside getStaticPath's return value",
|
||||||
|
message: (entryType) =>
|
||||||
|
`Invalid entry returned by getStaticPaths. Expected an object, got \`${entryType}\``,
|
||||||
|
hint: "If you're using a `.map` call, you might be looking for `.flatMap()` instead. See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.",
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @see
|
* @see
|
||||||
|
@ -254,6 +276,7 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
|
||||||
`Invalid type returned by \`getStaticPaths\`. Expected an \`array\`, got \`${returnType}\``,
|
`Invalid type returned by \`getStaticPaths\`. Expected an \`array\`, got \`${returnType}\``,
|
||||||
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
|
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @see
|
* @see
|
||||||
|
|
|
@ -33,7 +33,6 @@ export async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise
|
||||||
mod,
|
mod,
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
isValidate: true,
|
|
||||||
logging,
|
logging,
|
||||||
ssr,
|
ssr,
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,6 @@ interface CallGetStaticPathsOptions {
|
||||||
mod: ComponentInstance;
|
mod: ComponentInstance;
|
||||||
route: RouteData;
|
route: RouteData;
|
||||||
routeCache: RouteCache;
|
routeCache: RouteCache;
|
||||||
isValidate: boolean;
|
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
ssr: boolean;
|
ssr: boolean;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +26,6 @@ export async function callGetStaticPaths({
|
||||||
mod,
|
mod,
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
isValidate,
|
|
||||||
logging,
|
logging,
|
||||||
ssr,
|
ssr,
|
||||||
}: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed> {
|
}: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed> {
|
||||||
|
@ -58,14 +56,7 @@ export async function callGetStaticPaths({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Flatten the array before validating the content, otherwise users using `.map` will run into errors
|
validateGetStaticPathsResult(staticPaths, logging, route);
|
||||||
if (Array.isArray(staticPaths)) {
|
|
||||||
staticPaths = staticPaths.flat();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isValidate) {
|
|
||||||
validateGetStaticPathsResult(staticPaths, logging, route);
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
|
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
|
||||||
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
|
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
|
||||||
|
|
|
@ -54,6 +54,15 @@ export function validateGetStaticPathsResult(
|
||||||
}
|
}
|
||||||
|
|
||||||
result.forEach((pathObject) => {
|
result.forEach((pathObject) => {
|
||||||
|
if ((typeof pathObject === 'object' && Array.isArray(pathObject)) || pathObject === null) {
|
||||||
|
throw new AstroError({
|
||||||
|
...AstroErrorData.InvalidGetStaticPathsEntry,
|
||||||
|
message: AstroErrorData.InvalidGetStaticPathsEntry.message(
|
||||||
|
Array.isArray(pathObject) ? 'array' : typeof pathObject
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
pathObject.params === undefined ||
|
pathObject.params === undefined ||
|
||||||
pathObject.params === null ||
|
pathObject.params === null ||
|
||||||
|
@ -67,16 +76,6 @@ export function validateGetStaticPathsResult(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof pathObject.params !== 'object') {
|
|
||||||
throw new AstroError({
|
|
||||||
...AstroErrorData.InvalidGetStaticPathParam,
|
|
||||||
message: AstroErrorData.InvalidGetStaticPathParam.message(typeof pathObject.params),
|
|
||||||
location: {
|
|
||||||
file: route.component,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Replace those with errors? They technically don't crash the build, but users might miss the warning. - erika, 2022-11-07
|
// TODO: Replace those with errors? They technically don't crash the build, but users might miss the warning. - erika, 2022-11-07
|
||||||
for (const [key, val] of Object.entries(pathObject.params)) {
|
for (const [key, val] of Object.entries(pathObject.params)) {
|
||||||
if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) {
|
if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture } from './test-utils.js';
|
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('getStaticPaths - build calls', () => {
|
describe('getStaticPaths - build calls', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -92,11 +92,6 @@ describe('getStaticPaths - dev calls', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('route params type validation', () => {
|
describe('route params type validation', () => {
|
||||||
it('resolves 200 on nested array parameters', async () => {
|
|
||||||
const res = await fixture.fetch('/nested-arrays/slug1');
|
|
||||||
expect(res.status).to.equal(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves 200 on matching static path - string params', async () => {
|
it('resolves 200 on matching static path - string params', async () => {
|
||||||
// route provided with { params: { year: "2022", slug: "post-2" }}
|
// route provided with { params: { year: "2022", slug: "post-2" }}
|
||||||
const res = await fixture.fetch('/blog/2022/post-1');
|
const res = await fixture.fetch('/blog/2022/post-1');
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
export function getStaticPaths() {
|
|
||||||
return [
|
|
||||||
[ { params: {slug: "slug1"} } ],
|
|
||||||
[ { params: {slug: "slug2"} } ],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
---
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
export async function getStaticPaths({paginate}) {
|
export async function getStaticPaths({paginate}) {
|
||||||
const allPosts = await Astro.glob('../../post/*.md');
|
const allPosts = await Astro.glob('../../post/*.md');
|
||||||
return ['red', 'blue'].map((filter) => {
|
return ['red', 'blue'].flatMap((filter) => {
|
||||||
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === filter);
|
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === filter);
|
||||||
return paginate(filteredPosts, {
|
return paginate(filteredPosts, {
|
||||||
params: { slug: filter },
|
params: { slug: filter },
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
---
|
|
||||||
export function getStaticPaths() {
|
|
||||||
return [
|
|
||||||
[ { params: {slug: "slug1"} } ],
|
|
||||||
[ { params: {slug: "slug2"} } ],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const prerender = true;
|
|
||||||
---
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture } from './test-utils.js';
|
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import testAdapter from './test-adapter.js';
|
import testAdapter from './test-adapter.js';
|
||||||
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('Prerender', () => {
|
describe('Prerender', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -102,11 +102,6 @@ describe('Prerender', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('route params type validation', () => {
|
describe('route params type validation', () => {
|
||||||
it('resolves 200 on nested array parameters', async () => {
|
|
||||||
const res = await fixture.fetch('/blog/nested-arrays/slug1');
|
|
||||||
expect(res.status).to.equal(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves 200 on matching static path - string params', async () => {
|
it('resolves 200 on matching static path - string params', async () => {
|
||||||
// route provided with { params: { year: "2022", slug: "post-2" }}
|
// route provided with { params: { year: "2022", slug: "post-2" }}
|
||||||
const res = await fixture.fetch('/blog/blog/2022/post-1');
|
const res = await fixture.fetch('/blog/blog/2022/post-1');
|
||||||
|
@ -234,11 +229,6 @@ describe('Prerender', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('route params type validation', () => {
|
describe('route params type validation', () => {
|
||||||
it('resolves 200 on nested array parameters', async () => {
|
|
||||||
const res = await fixture.fetch('/blog/nested-arrays/slug1');
|
|
||||||
expect(res.status).to.equal(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves 200 on matching static path - string params', async () => {
|
it('resolves 200 on matching static path - string params', async () => {
|
||||||
// route provided with { params: { year: "2022", slug: "post-2" }}
|
// route provided with { params: { year: "2022", slug: "post-2" }}
|
||||||
const res = await fixture.fetch('/blog/blog/2022/post-1');
|
const res = await fixture.fetch('/blog/blog/2022/post-1');
|
||||||
|
|
Loading…
Reference in a new issue