summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2023-06-08 18:12:39 -0400
committerGravatar GitHub <noreply@github.com> 2023-06-08 18:12:39 -0400
commite3271f8c167288dc60b94242d01d459c162ec06d (patch)
tree8aa0726a6499967a19f6ae913be50565086756c9
parent52f0480d14c328ab69bd1f2681ddfd83f7385ab1 (diff)
downloadastro-e3271f8c167288dc60b94242d01d459c162ec06d.tar.gz
astro-e3271f8c167288dc60b94242d01d459c162ec06d.tar.zst
astro-e3271f8c167288dc60b94242d01d459c162ec06d.zip
Better dynamic route regex error (#7339)
* feat: add helpful invalid route seg error * chore: add errors-data entry * refactor: add hint for non-spread errors * chore: add `undefined` to common cases * nit: if the param contains slashes * chore: changeset * chore: it's trivial my dear watson
-rw-r--r--.changeset/kind-cycles-smile.md5
-rw-r--r--packages/astro/src/core/build/generate.ts45
-rw-r--r--packages/astro/src/core/errors/errors-data.ts13
3 files changed, 61 insertions, 2 deletions
diff --git a/.changeset/kind-cycles-smile.md b/.changeset/kind-cycles-smile.md
new file mode 100644
index 000000000..9cdb28aa2
--- /dev/null
+++ b/.changeset/kind-cycles-smile.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Add readable error message for invalid dynamic routes.
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 01a755906..c1fd34654 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -10,6 +10,7 @@ import type {
ComponentInstance,
EndpointHandler,
EndpointOutput,
+ GetStaticPathsItem,
ImageTransform,
MiddlewareResponseHandler,
RouteData,
@@ -36,7 +37,7 @@ import { runHookBuildGenerated } from '../../integrations/index.js';
import { isServerLikeOutput } from '../../prerender/utils.js';
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { callEndpoint, createAPIContext, throwIfRedirectNotAllowed } from '../endpoint/index.js';
-import { AstroError } from '../errors/index.js';
+import { AstroError, AstroErrorData } from '../errors/index.js';
import { debug, info } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
import {
@@ -306,7 +307,16 @@ async function getPathsForRoute(
opts.routeCache.set(route, result);
paths = result.staticPaths
- .map((staticPath) => staticPath.params && route.generate(staticPath.params))
+ .map((staticPath) => {
+ try {
+ return route.generate(staticPath.params);
+ } catch (e) {
+ if (e instanceof TypeError) {
+ throw getInvalidRouteSegmentError(e, route, staticPath);
+ }
+ throw e;
+ }
+ })
.filter((staticPath) => {
// The path hasn't been built yet, include it
if (!builtPaths.has(removeTrailingForwardSlash(staticPath))) {
@@ -331,6 +341,37 @@ async function getPathsForRoute(
return paths;
}
+function getInvalidRouteSegmentError(
+ e: TypeError,
+ route: RouteData,
+ staticPath: GetStaticPathsItem
+): AstroError {
+ const invalidParam = e.message.match(/^Expected "([^"]+)"/)?.[1];
+ const received = invalidParam ? staticPath.params[invalidParam] : undefined;
+ let hint =
+ 'Learn about dynamic routes at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes';
+ if (invalidParam && typeof received === 'string') {
+ const matchingSegment = route.segments.find(
+ (segment) => segment[0]?.content === invalidParam
+ )?.[0];
+ const mightBeMissingSpread = matchingSegment?.dynamic && !matchingSegment?.spread;
+ if (mightBeMissingSpread) {
+ hint = `If the param contains slashes, try using a rest parameter: **[...${invalidParam}]**. Learn more at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes`;
+ }
+ }
+ return new AstroError({
+ ...AstroErrorData.InvalidDynamicRoute,
+ message: invalidParam
+ ? AstroErrorData.InvalidDynamicRoute.message(
+ route.route,
+ JSON.stringify(invalidParam),
+ JSON.stringify(received)
+ )
+ : `Generated path for ${route.route} is invalid.`,
+ hint,
+ });
+}
+
interface GeneratePathOptions {
pageData: PageBuildData;
internals: BuildInternals;
diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts
index 561d46f37..0425eb22e 100644
--- a/packages/astro/src/core/errors/errors-data.ts
+++ b/packages/astro/src/core/errors/errors-data.ts
@@ -760,6 +760,19 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
title: 'A redirect must be given a location with the `Location` header.',
code: 3037,
},
+ /**
+ * @docs
+ * @see
+ * - [Dynamic routes](https://docs.astro.build/en/core-concepts/routing/#dynamic-routes)
+ * @description
+ * A dynamic route param is invalid. This is often caused by an `undefined` parameter or a missing [rest parameter](https://docs.astro.build/en/core-concepts/routing/#rest-parameters).
+ */
+ InvalidDynamicRoute: {
+ title: 'Invalid dynamic route.',
+ code: 3038,
+ message: (route: string, invalidParam: string, received: string) =>
+ `The ${invalidParam} param for route ${route} is invalid. Received **${received}**.`,
+ },
// No headings here, that way Vite errors are merged with Astro ones in the docs, which makes more sense to users.
// Vite Errors - 4xxx
/**