diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index bc4f05a890..c897c719fa 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -712,8 +712,8 @@ export type InjectedScriptStage = 'before-hydration' | 'head-inline' | 'page' | */ export interface InjectedRoute { - pattern: string, - entryPoint: string + pattern: string; + entryPoint: string; } export interface AstroConfig extends z.output { // Public: @@ -726,7 +726,7 @@ export interface AstroConfig extends z.output { // that is different from the user-exposed configuration. // TODO: Create an AstroConfig class to manage this, long-term. _ctx: { - injectedRoutes: InjectedRoute[], + injectedRoutes: InjectedRoute[]; adapter: AstroAdapter | undefined; renderers: AstroRenderer[]; scripts: { stage: InjectedScriptStage; content: string }[]; @@ -973,7 +973,7 @@ export interface RoutePart { } export interface RouteData { - route: string, + route: string; component: string; generate: (data?: any) => string; params: string[]; diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 4f1e1c6438..70ca80160b 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -55,7 +55,7 @@ class AstroBuilder { this.origin = config.site ? new URL(config.site).origin : `http://localhost:${config.server.port}`; - this.manifest = {routes: []}; + this.manifest = { routes: [] }; this.timer = {}; } diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index b68b690376..85e5fea15b 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -2,9 +2,9 @@ import type { AstroConfig, ManifestData, RouteData, RoutePart } from '../../../@ import type { LogOptions } from '../../logger/core'; import fs from 'fs'; +import { createRequire } from 'module'; import path from 'path'; import slash from 'slash'; -import { createRequire } from 'module'; import { fileURLToPath } from 'url'; import { warn } from '../../logger/core.js'; import { resolvePages } from '../../util.js'; @@ -96,20 +96,22 @@ function isSpread(str: string) { } function validateSegment(segment: string, file = '') { - if(!file) file = segment; + if (!file) file = segment; - if (/^\$/.test(segment)) { - throw new Error(`Invalid route ${file} \u2014 Astro's Collections API has been replaced by dynamic route params.`); - } - if (/\]\[/.test(segment)) { - throw new Error(`Invalid route ${file} \u2014 parameters must be separated`); - } - if (countOccurrences("[", segment) !== countOccurrences("]", segment)) { - throw new Error(`Invalid route ${file} \u2014 brackets are unbalanced`); - } - if (/.+\[\.\.\.[^\]]+\]/.test(segment) || /\[\.\.\.[^\]]+\].+/.test(segment)) { - throw new Error(`Invalid route ${file} \u2014 rest parameter must be a standalone segment`); - } + if (/^\$/.test(segment)) { + throw new Error( + `Invalid route ${file} \u2014 Astro's Collections API has been replaced by dynamic route params.` + ); + } + if (/\]\[/.test(segment)) { + throw new Error(`Invalid route ${file} \u2014 parameters must be separated`); + } + if (countOccurrences('[', segment) !== countOccurrences(']', segment)) { + throw new Error(`Invalid route ${file} \u2014 brackets are unbalanced`); + } + if (/.+\[\.\.\.[^\]]+\]/.test(segment) || /\[\.\.\.[^\]]+\].+/.test(segment)) { + throw new Error(`Invalid route ${file} \u2014 rest parameter must be a standalone segment`); + } } function comparator(a: Item, b: Item) { @@ -253,7 +255,9 @@ export function createRouteManifest( const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join('/')}` : null; - const route = `/${segments.map(([{dynamic, content}]) => dynamic ? `[${content}]` : content).join('/')}`.toLowerCase(); + const route = `/${segments + .map(([{ dynamic, content }]) => (dynamic ? `[${content}]` : content)) + .join('/')}`.toLowerCase(); routes.push({ route, @@ -279,43 +283,64 @@ export function createRouteManifest( warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`); } - config?._ctx?.injectedRoutes?.forEach(({pattern: name, entryPoint}) => { + config?._ctx?.injectedRoutes?.forEach(({ pattern: name, entryPoint }) => { const resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] }); const component = slash(path.relative(cwd || fileURLToPath(config.root), resolved)); const isDynamic = (str: string) => str?.[0] === '['; const normalize = (str: string) => str?.substring(1, str?.length - 1); - const segments = name.split(path.sep) + const segments = name + .split(path.sep) .filter(Boolean) .map((s: string) => { validateSegment(s); const dynamic = isDynamic(s); const content = dynamic ? normalize(s) : s; - return [{ - content, - dynamic, - spread: isSpread(s) - }] + return [ + { + content, + dynamic, + spread: isSpread(s), + }, + ]; }); const type = resolved.endsWith('.astro') ? 'page' : 'endpoint'; const isPage = type === 'page'; - const trailingSlash = isPage ? config.trailingSlash : "never"; + const trailingSlash = isPage ? config.trailingSlash : 'never'; const pattern = getPattern(segments, trailingSlash); const generate = getRouteGenerator(segments, trailingSlash); - const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null; - const params = segments.flat().filter((p) => p.dynamic).map((p) => p.content); - const route = `/${segments.map(([{dynamic, content}]) => dynamic ? `[${content}]` : content).join('/')}`.toLowerCase(); + const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) + ? `/${segments.map((segment) => segment[0].content).join('/')}` + : null; + const params = segments + .flat() + .filter((p) => p.dynamic) + .map((p) => p.content); + const route = `/${segments + .map(([{ dynamic, content }]) => (dynamic ? `[${content}]` : content)) + .join('/')}`.toLowerCase(); - const collision = routes.find(({route: r}) => r === route); - if(collision) { - throw new Error(`An integration attempted to inject a route that is already used in your project: "${route}" at "${component}". \nThis route collides with: "${collision.component}".`); + const collision = routes.find(({ route: r }) => r === route); + if (collision) { + throw new Error( + `An integration attempted to inject a route that is already used in your project: "${route}" at "${component}". \nThis route collides with: "${collision.component}".` + ); } - routes.push({type, route, pattern, segments, params, component, generate, pathname: pathname || void 0}) + routes.push({ + type, + route, + pattern, + segments, + params, + component, + generate, + pathname: pathname || void 0, + }); }); return {