astro 7.0.3 → 7.0.4
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.
- package/dist/assets/services/sharp.js +1 -1
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/content/content-layer.js +3 -3
- package/dist/content/vite-plugin-content-virtual-mod.js +5 -1
- package/dist/core/app/node.js +7 -2
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/render/route-cache.d.ts +7 -2
- package/dist/core/routing/create-manifest.js +9 -7
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +49 -9
- package/dist/runtime/server/hydration.js +1 -1
- package/package.json +4 -21
|
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Content config changed");
|
|
198
198
|
shouldClear = true;
|
|
199
199
|
}
|
|
200
|
-
if (previousAstroVersion && previousAstroVersion !== "7.0.
|
|
200
|
+
if (previousAstroVersion && previousAstroVersion !== "7.0.4") {
|
|
201
201
|
logger.info("Astro version changed");
|
|
202
202
|
shouldClear = true;
|
|
203
203
|
}
|
|
@@ -205,8 +205,8 @@ ${contentConfig.error.message}`
|
|
|
205
205
|
logger.info("Clearing content store");
|
|
206
206
|
this.#store.clearAll();
|
|
207
207
|
}
|
|
208
|
-
if ("7.0.
|
|
209
|
-
this.#store.metaStore().set("astro-version", "7.0.
|
|
208
|
+
if ("7.0.4") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "7.0.4");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "./consts.js";
|
|
24
24
|
import { getDataStoreFile } from "./content-layer.js";
|
|
25
25
|
import { getContentPaths, isDeferredModule } from "./utils.js";
|
|
26
|
+
const LARGE_DATA_STORE_THRESHOLD = 5 * 1024 * 1024;
|
|
26
27
|
function invalidateAssetImports(viteServer, filePath) {
|
|
27
28
|
const timestamp = Date.now();
|
|
28
29
|
for (const environment of Object.values(viteServer.environments)) {
|
|
@@ -70,10 +71,12 @@ function astroContentVirtualModPlugin({
|
|
|
70
71
|
let dataStoreFile;
|
|
71
72
|
let devServer;
|
|
72
73
|
let liveConfig;
|
|
74
|
+
let isDev = false;
|
|
73
75
|
return {
|
|
74
76
|
name: "astro-content-virtual-mod-plugin",
|
|
75
77
|
enforce: "pre",
|
|
76
78
|
config(_, env) {
|
|
79
|
+
isDev = env.command === "serve";
|
|
77
80
|
dataStoreFile = getDataStoreFile(settings, env.command === "serve");
|
|
78
81
|
const contentPaths = getContentPaths(
|
|
79
82
|
settings.config,
|
|
@@ -169,8 +172,9 @@ function astroContentVirtualModPlugin({
|
|
|
169
172
|
const jsonData = await fs.promises.readFile(dataStoreFile, "utf-8");
|
|
170
173
|
try {
|
|
171
174
|
const parsed = JSON.parse(jsonData);
|
|
175
|
+
const useRuntimeJsonParse = isDev && Buffer.byteLength(jsonData) > LARGE_DATA_STORE_THRESHOLD;
|
|
172
176
|
return {
|
|
173
|
-
code: dataToEsm(parsed, {
|
|
177
|
+
code: useRuntimeJsonParse ? `export default JSON.parse(${JSON.stringify(jsonData)})` : dataToEsm(parsed, {
|
|
174
178
|
compact: true
|
|
175
179
|
}),
|
|
176
180
|
map: { mappings: "" }
|
package/dist/core/app/node.js
CHANGED
|
@@ -42,8 +42,13 @@ function createRequestFromNodeRequest(req, {
|
|
|
42
42
|
protocol,
|
|
43
43
|
allowedDomains
|
|
44
44
|
);
|
|
45
|
-
const
|
|
46
|
-
|
|
45
|
+
const validatedForwardedHost = validateForwardedHeaders(
|
|
46
|
+
void 0,
|
|
47
|
+
getFirstForwardedValue(req.headers["x-forwarded-host"]),
|
|
48
|
+
void 0,
|
|
49
|
+
allowedDomains
|
|
50
|
+
).host;
|
|
51
|
+
const hostValidated = validatedHostname !== void 0 || validatedForwardedHost !== void 0;
|
|
47
52
|
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
48
53
|
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
49
54
|
if (clientIp) {
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
|
|
|
26
26
|
await telemetry.record([]);
|
|
27
27
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
28
28
|
const logger = restart.container.logger;
|
|
29
|
-
const currentVersion = "7.0.
|
|
29
|
+
const currentVersion = "7.0.4";
|
|
30
30
|
const isPrerelease = currentVersion.includes("-");
|
|
31
31
|
if (!isPrerelease) {
|
|
32
32
|
try {
|
|
@@ -18,8 +18,13 @@ interface RouteCacheEntry {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Manage the route cache, responsible for caching data related to each route,
|
|
21
|
-
* including the result of calling
|
|
22
|
-
*
|
|
21
|
+
* including the result of calling getStaticPaths(). This gives route matching,
|
|
22
|
+
* params/props resolution, and prerender generation a shared static-path table.
|
|
23
|
+
*
|
|
24
|
+
* In dev, this cache intentionally survives requests. It is invalidated by route
|
|
25
|
+
* module identity changes after HMR or by explicit cache clears from content data
|
|
26
|
+
* changes, not by each request. Dev route matching can call getStaticPaths()
|
|
27
|
+
* before rendering, and render-time props resolution may ask for it again.
|
|
23
28
|
*/
|
|
24
29
|
export declare class RouteCache {
|
|
25
30
|
private logger;
|
|
@@ -158,13 +158,14 @@ function createFileBasedRoutes({ settings, cwd, fsMod }, logger) {
|
|
|
158
158
|
} else {
|
|
159
159
|
const component = item.file;
|
|
160
160
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
161
|
+
const route = joinSegments(segments);
|
|
161
162
|
const trailingSlash = trailingSlashForPath(
|
|
162
163
|
pathname,
|
|
163
164
|
settings.config,
|
|
164
|
-
item.isPage ? "page" : "endpoint"
|
|
165
|
+
item.isPage ? "page" : "endpoint",
|
|
166
|
+
route
|
|
165
167
|
);
|
|
166
168
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
167
|
-
const route = joinSegments(segments);
|
|
168
169
|
routes.push({
|
|
169
170
|
route,
|
|
170
171
|
isIndex: item.isIndex,
|
|
@@ -277,13 +278,14 @@ function createRoutesFromEntriesByDir(entriesByDir, settings, logger, pagesDirRe
|
|
|
277
278
|
} else {
|
|
278
279
|
const component = item.file;
|
|
279
280
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
281
|
+
const route = joinSegments(segments);
|
|
280
282
|
const trailingSlash = trailingSlashForPath(
|
|
281
283
|
pathname,
|
|
282
284
|
settings.config,
|
|
283
|
-
item.isPage ? "page" : "endpoint"
|
|
285
|
+
item.isPage ? "page" : "endpoint",
|
|
286
|
+
route
|
|
284
287
|
);
|
|
285
288
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
286
|
-
const route = joinSegments(segments);
|
|
287
289
|
routes.push({
|
|
288
290
|
route,
|
|
289
291
|
isIndex: item.isIndex,
|
|
@@ -320,7 +322,7 @@ function groupEntriesByDir(entries) {
|
|
|
320
322
|
}
|
|
321
323
|
return entriesByDir;
|
|
322
324
|
}
|
|
323
|
-
const trailingSlashForPath = (pathname, config, type) => type === "endpoint" && pathname
|
|
325
|
+
const trailingSlashForPath = (pathname, config, type, route) => type === "endpoint" && hasFileExtension(pathname ?? route ?? "") ? "never" : config.trailingSlash;
|
|
324
326
|
function createInjectedRoutes({ settings, cwd }) {
|
|
325
327
|
const { config } = settings;
|
|
326
328
|
const prerender = getPrerenderDefault(config);
|
|
@@ -334,10 +336,10 @@ function createInjectedRoutes({ settings, cwd }) {
|
|
|
334
336
|
});
|
|
335
337
|
const type = resolved.endsWith(".astro") ? "page" : "endpoint";
|
|
336
338
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
337
|
-
const
|
|
339
|
+
const route = joinSegments(segments);
|
|
340
|
+
const trailingSlash = trailingSlashForPath(pathname, config, type, route);
|
|
338
341
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
339
342
|
const params = segments.flat().filter((p) => p.dynamic).map((p) => p.content);
|
|
340
|
-
const route = joinSegments(segments);
|
|
341
343
|
routes.push({
|
|
342
344
|
type,
|
|
343
345
|
// For backwards compatibility, an injected route is never considered an index route.
|
|
@@ -200,6 +200,32 @@ function isInteractive(element) {
|
|
|
200
200
|
}
|
|
201
201
|
return true;
|
|
202
202
|
}
|
|
203
|
+
function hasAccessibleName(element) {
|
|
204
|
+
return element.hasAttribute("aria-label") || element.hasAttribute("aria-labelledby");
|
|
205
|
+
}
|
|
206
|
+
const conditional_implicit_roles = /* @__PURE__ */ new Map([
|
|
207
|
+
["a", (el) => el.hasAttribute("href") ? "link" : null],
|
|
208
|
+
[
|
|
209
|
+
"aside",
|
|
210
|
+
(el) => {
|
|
211
|
+
const isNested = !!el.parentElement?.closest("article, aside, nav, section");
|
|
212
|
+
return !isNested || hasAccessibleName(el) ? "complementary" : null;
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
[
|
|
216
|
+
"img",
|
|
217
|
+
(el) => {
|
|
218
|
+
if (el.getAttribute("alt") === "") return null;
|
|
219
|
+
return "image";
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
"section",
|
|
224
|
+
(el) => {
|
|
225
|
+
return hasAccessibleName(el) ? "region" : null;
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
]);
|
|
203
229
|
const a11y = [
|
|
204
230
|
{
|
|
205
231
|
code: "a11y-accesskey",
|
|
@@ -378,19 +404,33 @@ const a11y = [
|
|
|
378
404
|
code: "a11y-no-redundant-roles",
|
|
379
405
|
title: "HTML element has redundant ARIA roles",
|
|
380
406
|
message: "Giving these elements an ARIA role that is already set by the browser has no effect and is redundant.",
|
|
381
|
-
selector
|
|
407
|
+
// The selector is all elements that have an implicit role, as well as input elements since their implicit role can change based on their attributes
|
|
408
|
+
selector: `[role]:is(${[...a11y_implicit_semantics.keys()].join(",")},input)`,
|
|
382
409
|
match(element) {
|
|
383
410
|
const role = element.getAttribute("role");
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
|
|
411
|
+
if (!role) return false;
|
|
412
|
+
const localName = element.localName;
|
|
413
|
+
if (
|
|
414
|
+
// <ul>, <ol>, and <li> are legitimate workarounds to restore list semantics
|
|
415
|
+
// that some browsers (e.g., Safari) strip when CSS `list-style: none` is applied.
|
|
416
|
+
// Reference: https://bugs.webkit.org/show_bug.cgi?id=170179
|
|
417
|
+
localName === "ul" && role === "list" || localName === "ol" && role === "list" || localName === "li" && role === "listitem"
|
|
418
|
+
) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
if (localName === "input") {
|
|
422
|
+
const type = element.getAttribute("type") || "text";
|
|
387
423
|
const implicitRoleForType = input_type_to_implicit_role.get(type);
|
|
388
|
-
|
|
389
|
-
|
|
424
|
+
return role === implicitRoleForType;
|
|
425
|
+
}
|
|
426
|
+
const getConditionalRole = conditional_implicit_roles.get(localName);
|
|
427
|
+
if (getConditionalRole) {
|
|
428
|
+
const effectiveRole = getConditionalRole(element);
|
|
429
|
+
return effectiveRole ? role === effectiveRole : false;
|
|
390
430
|
}
|
|
391
|
-
const implicitRole = a11y_implicit_semantics.get(
|
|
392
|
-
if (!implicitRole) return
|
|
393
|
-
|
|
431
|
+
const implicitRole = a11y_implicit_semantics.get(localName);
|
|
432
|
+
if (!implicitRole) return false;
|
|
433
|
+
return role === implicitRole;
|
|
394
434
|
}
|
|
395
435
|
},
|
|
396
436
|
{
|
|
@@ -116,7 +116,7 @@ async function generateHydrateScript(scriptOptions, metadata) {
|
|
|
116
116
|
);
|
|
117
117
|
transitionDirectivesToCopyOnIsland.forEach((name) => {
|
|
118
118
|
if (typeof props[name] !== "undefined") {
|
|
119
|
-
island.props[name] = props[name];
|
|
119
|
+
island.props[name] = escapeHTML(String(props[name]));
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
return island;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.4",
|
|
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",
|
|
@@ -12,23 +12,6 @@
|
|
|
12
12
|
},
|
|
13
13
|
"bugs": "https://github.com/withastro/astro/issues",
|
|
14
14
|
"homepage": "https://astro.build",
|
|
15
|
-
"types": "./dist/index.d.ts",
|
|
16
|
-
"typesVersions": {
|
|
17
|
-
"*": {
|
|
18
|
-
"app": [
|
|
19
|
-
"./dist/core/app/index"
|
|
20
|
-
],
|
|
21
|
-
"app/*": [
|
|
22
|
-
"./dist/core/app/*"
|
|
23
|
-
],
|
|
24
|
-
"hono": [
|
|
25
|
-
"./dist/core/hono/index"
|
|
26
|
-
],
|
|
27
|
-
"middleware": [
|
|
28
|
-
"./dist/virtual-modules/middleware.d.ts"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
15
|
"exports": {
|
|
33
16
|
".": "./dist/index.js",
|
|
34
17
|
"./env": "./env.d.ts",
|
|
@@ -113,7 +96,7 @@
|
|
|
113
96
|
"README.md"
|
|
114
97
|
],
|
|
115
98
|
"dependencies": {
|
|
116
|
-
"@astrojs/compiler-rs": "^0.
|
|
99
|
+
"@astrojs/compiler-rs": "^0.3.0",
|
|
117
100
|
"@capsizecss/unpack": "^4.0.0",
|
|
118
101
|
"@clack/prompts": "^1.1.0",
|
|
119
102
|
"@oslojs/encoding": "^1.1.0",
|
|
@@ -166,12 +149,12 @@
|
|
|
166
149
|
"xxhash-wasm": "^1.1.0",
|
|
167
150
|
"yargs-parser": "^22.0.0",
|
|
168
151
|
"zod": "^4.3.6",
|
|
169
|
-
"@astrojs/markdown-satteri": "0.3.2",
|
|
170
152
|
"@astrojs/internal-helpers": "0.10.0",
|
|
153
|
+
"@astrojs/markdown-satteri": "0.3.2",
|
|
171
154
|
"@astrojs/telemetry": "3.3.2"
|
|
172
155
|
},
|
|
173
156
|
"optionalDependencies": {
|
|
174
|
-
"sharp": "^0.34.0"
|
|
157
|
+
"sharp": "^0.34.0 || ^0.35.0"
|
|
175
158
|
},
|
|
176
159
|
"peerDependencies": {
|
|
177
160
|
"@astrojs/markdown-remark": "7.2.0"
|