astro 5.2.3 → 5.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -322,7 +322,24 @@ async function add(names, { flags }) {
322
322
  ${list}`
323
323
  )
324
324
  );
325
- logger.info("SKIP_FORMAT", msg.success("Import './src/styles/global.css' in a layout"));
325
+ if (integrations.find((integration) => integration.integrationName === "tailwind")) {
326
+ const code = boxen(
327
+ getDiffContent("---\n---", "---\nimport './src/styles/global.css'\n---"),
328
+ {
329
+ margin: 0.5,
330
+ padding: 0.5,
331
+ borderStyle: "round",
332
+ title: "src/layouts/Layout.astro"
333
+ }
334
+ );
335
+ logger.warn(
336
+ "SKIP_FORMAT",
337
+ msg.actionRequired(
338
+ "You must import your Tailwind stylesheet, e.g. in a shared layout:\n"
339
+ )
340
+ );
341
+ logger.info("SKIP_FORMAT", code + "\n");
342
+ }
326
343
  }
327
344
  }
328
345
  const updateTSConfigResult = await updateTSConfig(cwd, logger, integrations, flags);
@@ -153,7 +153,7 @@ ${contentConfig.error.message}`);
153
153
  logger.info("Content config changed");
154
154
  shouldClear = true;
155
155
  }
156
- if (previousAstroVersion && previousAstroVersion !== "5.2.3") {
156
+ if (previousAstroVersion && previousAstroVersion !== "5.2.5") {
157
157
  logger.info("Astro version changed");
158
158
  shouldClear = true;
159
159
  }
@@ -161,8 +161,8 @@ ${contentConfig.error.message}`);
161
161
  logger.info("Clearing content store");
162
162
  this.#store.clearAll();
163
163
  }
164
- if ("5.2.3") {
165
- await this.#store.metaStore().set("astro-version", "5.2.3");
164
+ if ("5.2.5") {
165
+ await this.#store.metaStore().set("astro-version", "5.2.5");
166
166
  }
167
167
  if (currentConfigDigest) {
168
168
  await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.2.3";
1
+ const ASTRO_VERSION = "5.2.5";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -22,7 +22,7 @@ async function dev(inlineConfig) {
22
22
  await telemetry.record([]);
23
23
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
24
24
  const logger = restart.container.logger;
25
- const currentVersion = "5.2.3";
25
+ const currentVersion = "5.2.5";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -44,6 +44,7 @@ export declare function prerelease({ currentVersion }: {
44
44
  }): string;
45
45
  export declare function success(message: string, tip?: string): string;
46
46
  export declare function failure(message: string, tip?: string): string;
47
+ export declare function actionRequired(message: string): string;
47
48
  export declare function cancelled(message: string, tip?: string): string;
48
49
  export declare function formatConfigErrorMessage(err: ZodError): string;
49
50
  export declare function formatErrorMessage(err: ErrorWithMetadata, showFullStacktrace: boolean): string;
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "5.2.3";
41
+ const version = "5.2.5";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -162,6 +162,11 @@ function failure(message, tip) {
162
162
  \u25B6 ${tip}` : void 0;
163
163
  return ["", `${badge} ${headline}`, footer].filter((v) => v !== void 0).map((msg) => ` ${msg}`).join("\n");
164
164
  }
165
+ function actionRequired(message) {
166
+ const badge = bgYellow(black(` action required `));
167
+ const headline = yellow(message);
168
+ return ["", `${badge} ${headline}`].filter((v) => v !== void 0).map((msg) => ` ${msg}`).join("\n");
169
+ }
165
170
  function cancelled(message, tip) {
166
171
  const badge = bgYellow(black(` cancelled `));
167
172
  const headline = yellow(message);
@@ -276,7 +281,7 @@ function printHelp({
276
281
  message.push(
277
282
  linebreak(),
278
283
  ` ${bgGreen(black(` ${commandName} `))} ${green(
279
- `v${"5.2.3"}`
284
+ `v${"5.2.5"}`
280
285
  )} ${headline}`
281
286
  );
282
287
  }
@@ -300,6 +305,7 @@ function printHelp({
300
305
  console.log(message.join("\n") + "\n");
301
306
  }
302
307
  export {
308
+ actionRequired,
303
309
  cancelled,
304
310
  failure,
305
311
  formatConfigErrorMessage,
@@ -24,7 +24,7 @@ import { callMiddleware } from "./middleware/callMiddleware.js";
24
24
  import { sequence } from "./middleware/index.js";
25
25
  import { renderRedirect } from "./redirects/render.js";
26
26
  import { Slots, getParams, getProps } from "./render/index.js";
27
- import { isRoute404or500, isRouteServerIsland } from "./routing/match.js";
27
+ import { isRoute404or500, isRouteExternalRedirect, isRouteServerIsland } from "./routing/match.js";
28
28
  import { copyRequest, getOriginPathname, setOriginPathname } from "./routing/rewrite.js";
29
29
  import { AstroSession } from "./session.js";
30
30
  const apiContextRoutesSymbol = Symbol.for("context.routes");
@@ -199,6 +199,9 @@ class RenderContext {
199
199
  }
200
200
  return response2;
201
201
  };
202
+ if (isRouteExternalRedirect(this.routeData)) {
203
+ return renderRedirect(this);
204
+ }
202
205
  const response = await callMiddleware(middleware, apiContext, lastNext);
203
206
  if (response.headers.get(ROUTE_TYPE_HEADER)) {
204
207
  response.headers.delete(ROUTE_TYPE_HEADER);
@@ -14,7 +14,7 @@ import {
14
14
  UnsupportedExternalRedirect
15
15
  } from "../../errors/errors-data.js";
16
16
  import { AstroError } from "../../errors/index.js";
17
- import { removeLeadingForwardSlash, slash } from "../../path.js";
17
+ import { hasFileExtension, removeLeadingForwardSlash, slash } from "../../path.js";
18
18
  import { injectServerIslandRoute } from "../../server-islands/endpoint.js";
19
19
  import { resolvePages } from "../../util.js";
20
20
  import { ensure404Route } from "../astro-designed-error-pages.js";
@@ -145,10 +145,10 @@ function createFileBasedRoutes({ settings, cwd, fsMod }, logger) {
145
145
  } else {
146
146
  components.push(item.file);
147
147
  const component = item.file;
148
- const { trailingSlash } = settings.config;
148
+ const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
149
+ const trailingSlash = trailingSlashForPath(pathname, settings.config);
149
150
  const pattern = getPattern(segments, settings.config.base, trailingSlash);
150
151
  const generate = getRouteGenerator(segments, trailingSlash);
151
- const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
152
152
  const route = joinSegments(segments);
153
153
  routes.push({
154
154
  route,
@@ -178,6 +178,7 @@ function createFileBasedRoutes({ settings, cwd, fsMod }, logger) {
178
178
  }
179
179
  return routes;
180
180
  }
181
+ const trailingSlashForPath = (pathname, config) => pathname && hasFileExtension(pathname) ? "ignore" : config.trailingSlash;
181
182
  function createInjectedRoutes({ settings, cwd }) {
182
183
  const { config } = settings;
183
184
  const prerender = getPrerenderDefault(config);
@@ -190,10 +191,10 @@ function createInjectedRoutes({ settings, cwd }) {
190
191
  return getParts(s, component);
191
192
  });
192
193
  const type = resolved.endsWith(".astro") ? "page" : "endpoint";
193
- const { trailingSlash } = config;
194
+ const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
195
+ const trailingSlash = trailingSlashForPath(pathname, config);
194
196
  const pattern = getPattern(segments, settings.config.base, trailingSlash);
195
197
  const generate = getRouteGenerator(segments, trailingSlash);
196
- const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
197
198
  const params = segments.flat().filter((p) => p.dynamic).map((p) => p.content);
198
199
  const route = joinSegments(segments);
199
200
  routes.push({
@@ -36,3 +36,10 @@ export declare function isRequestServerIsland(request: Request, base?: string):
36
36
  * @return {boolean} Returns true if the request matches a 404 or 500 route; otherwise, returns false.
37
37
  */
38
38
  export declare function requestIs404Or500(request: Request, base?: string): boolean;
39
+ /**
40
+ * Determines whether a given route is an external redirect.
41
+ *
42
+ * @param {RouteData} route - The route object to check.
43
+ * @return {boolean} Returns true if the route is an external redirect, otherwise false.
44
+ */
45
+ export declare function isRouteExternalRedirect(route: RouteData): boolean;
@@ -1,3 +1,4 @@
1
+ import { redirectIsExternal } from "../redirects/render.js";
1
2
  import { SERVER_ISLAND_BASE_PREFIX, SERVER_ISLAND_COMPONENT } from "../server-islands/endpoint.js";
2
3
  function matchRoute(pathname, manifest) {
3
4
  const decodedPathname = decodeURI(pathname);
@@ -32,11 +33,15 @@ function requestIs404Or500(request, base = "") {
32
33
  const pathname = url.pathname.slice(base.length);
33
34
  return isRoute404(pathname) || isRoute500(pathname);
34
35
  }
36
+ function isRouteExternalRedirect(route) {
37
+ return !!(route.type === "redirect" && route.redirect && redirectIsExternal(route.redirect));
38
+ }
35
39
  export {
36
40
  isRequestServerIsland,
37
41
  isRoute404,
38
42
  isRoute404or500,
39
43
  isRoute500,
44
+ isRouteExternalRedirect,
40
45
  isRouteServerIsland,
41
46
  matchAllRoutes,
42
47
  matchRoute,
@@ -1,5 +1,4 @@
1
- import { escape } from 'html-escaper';
2
- export declare const escapeHTML: typeof escape;
1
+ export declare const escapeHTML: (str: string) => string;
3
2
  export declare class HTMLBytes extends Uint8Array {
4
3
  }
5
4
  /**
@@ -4,20 +4,20 @@ import { writeHtmlResponse, writeRedirectResponse } from "./response.js";
4
4
  function trailingSlashMiddleware(settings) {
5
5
  const { trailingSlash } = settings.config;
6
6
  return function devTrailingSlash(req, res, next) {
7
- const url = req.url;
8
- const destination = collapseDuplicateTrailingSlashes(url, true);
9
- if (url && destination !== url) {
10
- return writeRedirectResponse(res, 301, destination);
11
- }
7
+ const url = new URL(`http://localhost${req.url}`);
12
8
  let pathname;
13
9
  try {
14
- pathname = decodeURI(new URL(url, "http://localhost").pathname);
10
+ pathname = decodeURI(url.pathname);
15
11
  } catch (e) {
16
12
  return next(e);
17
13
  }
18
14
  if (pathname.startsWith("/_") || pathname.startsWith("/@")) {
19
15
  return next();
20
16
  }
17
+ const destination = collapseDuplicateTrailingSlashes(pathname, true);
18
+ if (pathname && destination !== pathname) {
19
+ return writeRedirectResponse(res, 301, `${destination}${url.search}`);
20
+ }
21
21
  if (trailingSlash === "never" && pathname.endsWith("/") && pathname !== "/" || trailingSlash === "always" && !pathname.endsWith("/") && !hasFileExtension(pathname)) {
22
22
  const html = trailingSlashMismatchTemplate(pathname, trailingSlash);
23
23
  return writeHtmlResponse(res, 404, html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "5.2.3",
3
+ "version": "5.2.5",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -139,10 +139,10 @@
139
139
  "neotraverse": "^0.6.18",
140
140
  "p-limit": "^6.2.0",
141
141
  "p-queue": "^8.1.0",
142
- "preferred-pm": "^4.1.0",
142
+ "preferred-pm": "^4.1.1",
143
143
  "prompts": "^2.4.2",
144
144
  "rehype": "^13.0.2",
145
- "semver": "^7.7.0",
145
+ "semver": "^7.7.1",
146
146
  "shiki": "^1.29.2",
147
147
  "tinyexec": "^0.3.2",
148
148
  "tsconfck": "^3.1.4",
@@ -152,14 +152,14 @@
152
152
  "vfile": "^6.0.3",
153
153
  "vite": "^6.0.11",
154
154
  "vitefu": "^1.0.5",
155
- "which-pm": "^3.0.0",
155
+ "which-pm": "^3.0.1",
156
156
  "xxhash-wasm": "^1.1.0",
157
157
  "yargs-parser": "^21.1.1",
158
158
  "yocto-spinner": "^0.2.0",
159
159
  "zod": "^3.24.1",
160
160
  "zod-to-json-schema": "^3.24.1",
161
161
  "zod-to-ts": "^1.2.0",
162
- "@astrojs/internal-helpers": "0.5.0",
162
+ "@astrojs/internal-helpers": "0.5.1",
163
163
  "@astrojs/markdown-remark": "6.1.0",
164
164
  "@astrojs/telemetry": "3.2.0"
165
165
  },
@@ -168,7 +168,7 @@
168
168
  },
169
169
  "devDependencies": {
170
170
  "@astrojs/check": "^0.9.4",
171
- "@playwright/test": "^1.50.0",
171
+ "@playwright/test": "^1.50.1",
172
172
  "@types/aria-query": "^5.0.4",
173
173
  "@types/common-ancestor-path": "^1.0.2",
174
174
  "@types/cssesc": "^3.0.2",
@@ -176,7 +176,7 @@
176
176
  "@types/diff": "^5.2.3",
177
177
  "@types/dlv": "^1.1.5",
178
178
  "@types/hast": "^3.0.4",
179
- "@types/html-escaper": "3.0.2",
179
+ "@types/html-escaper": "3.0.4",
180
180
  "@types/http-cache-semantics": "^4.0.4",
181
181
  "@types/js-yaml": "^4.0.9",
182
182
  "@types/micromatch": "^4.0.9",
@@ -196,11 +196,11 @@
196
196
  "rehype-slug": "^6.0.0",
197
197
  "rehype-toc": "^3.0.2",
198
198
  "remark-code-titles": "^0.1.2",
199
- "rollup": "^4.32.1",
199
+ "rollup": "^4.34.2",
200
200
  "sass": "^1.83.4",
201
201
  "undici": "^7.3.0",
202
202
  "unified": "^11.0.5",
203
- "vitest": "^3.0.4",
203
+ "vitest": "^3.0.5",
204
204
  "astro-scripts": "0.0.14"
205
205
  },
206
206
  "engines": {