astro 6.4.2 → 6.4.3

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.
@@ -1,4 +1,17 @@
1
1
  import { isGenericFontFamily, unifontFontFaceDataToProperties } from "../utils.js";
2
+ function deriveFallbackVariant(data) {
3
+ const weight = data.weight;
4
+ if (typeof weight === "number" && weight >= 700) {
5
+ return "bold";
6
+ }
7
+ if (typeof weight === "string") {
8
+ if (weight === "bold") return "bold";
9
+ if (weight.includes(" ")) return "normal";
10
+ const n = Number.parseInt(weight, 10);
11
+ if (!Number.isNaN(n) && n >= 700) return "bold";
12
+ }
13
+ return "normal";
14
+ }
2
15
  async function optimizeFallbacks({
3
16
  family,
4
17
  fallbacks: _fallbacks,
@@ -14,28 +27,40 @@ async function optimizeFallbacks({
14
27
  if (!isGenericFontFamily(lastFallback)) {
15
28
  return null;
16
29
  }
17
- const localFonts = systemFallbacksProvider.getLocalFonts(lastFallback);
18
- if (!localFonts || localFonts.length === 0) {
30
+ const collectedWithLocalFonts = collectedFonts.map((collected) => ({
31
+ collected,
32
+ localFonts: systemFallbacksProvider.getLocalFonts(lastFallback, deriveFallbackVariant(collected.data)) ?? []
33
+ }));
34
+ const uniqueLocalFonts = [];
35
+ for (const { localFonts } of collectedWithLocalFonts) {
36
+ for (const font of localFonts) {
37
+ if (!uniqueLocalFonts.includes(font)) {
38
+ uniqueLocalFonts.push(font);
39
+ }
40
+ }
41
+ }
42
+ if (uniqueLocalFonts.length === 0) {
19
43
  return null;
20
44
  }
21
- if (localFonts.includes(family.name)) {
45
+ if (uniqueLocalFonts.includes(family.name)) {
22
46
  return null;
23
47
  }
24
- const localFontsMappings = localFonts.map((font) => ({
25
- font,
48
+ const nameForFont = (font) => (
26
49
  // We mustn't wrap in quote because that's handled by the CSS renderer
27
- name: `${family.uniqueName} fallback: ${font}`
28
- }));
29
- fallbacks = [...localFontsMappings.map((m) => m.name), ...fallbacks];
50
+ `${family.uniqueName} fallback: ${font}`
51
+ );
52
+ fallbacks = [...uniqueLocalFonts.map(nameForFont), ...fallbacks];
30
53
  let css = "";
31
- for (const { font, name } of localFontsMappings) {
32
- for (const collected of collectedFonts) {
54
+ for (const { collected, localFonts } of collectedWithLocalFonts) {
55
+ const properties = unifontFontFaceDataToProperties(collected.data);
56
+ const metrics = await fontMetricsResolver.getMetrics(family.name, collected);
57
+ for (const font of localFonts) {
33
58
  css += fontMetricsResolver.generateFontFace({
34
- metrics: await fontMetricsResolver.getMetrics(family.name, collected),
59
+ metrics,
35
60
  fallbackMetrics: systemFallbacksProvider.getMetricsForLocalFont(font),
36
61
  font,
37
- name,
38
- properties: unifontFontFaceDataToProperties(collected.data)
62
+ name: nameForFont(font),
63
+ properties
39
64
  });
40
65
  }
41
66
  }
@@ -1,6 +1,6 @@
1
1
  import type * as unifont from 'unifont';
2
2
  import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js';
3
- import type { CssProperties, FontFaceMetrics, FontFileData, FontProvider, FontType, GenericFallbackName, ResolveFontOptions, Style } from './types.js';
3
+ import type { CssProperties, FallbackVariant, FontFaceMetrics, FontFileData, FontProvider, FontType, GenericFallbackName, ResolveFontOptions, Style } from './types.js';
4
4
  export interface Hasher {
5
5
  hashString: (input: string) => string;
6
6
  hashObject: (input: Record<string, any>) => string;
@@ -28,7 +28,7 @@ export interface FontMetricsResolver {
28
28
  }) => string;
29
29
  }
30
30
  export interface SystemFallbacksProvider {
31
- getLocalFonts: (fallback: GenericFallbackName) => Array<string> | null;
31
+ getLocalFonts: (fallback: GenericFallbackName, variant: FallbackVariant) => Array<string> | null;
32
32
  getMetricsForLocalFont: (family: string) => FontFaceMetrics;
33
33
  }
34
34
  export interface FontFetcher {
@@ -1,6 +1,6 @@
1
1
  import type { SystemFallbacksProvider } from '../definitions.js';
2
- import type { FontFaceMetrics, GenericFallbackName } from '../types.js';
2
+ import type { FallbackVariant, FontFaceMetrics, GenericFallbackName } from '../types.js';
3
3
  export declare class RealSystemFallbacksProvider implements SystemFallbacksProvider {
4
- getLocalFonts(fallback: GenericFallbackName): Array<string> | null;
4
+ getLocalFonts(fallback: GenericFallbackName, variant: FallbackVariant): Array<string> | null;
5
5
  getMetricsForLocalFont(family: string): FontFaceMetrics;
6
6
  }
@@ -6,6 +6,14 @@ const SYSTEM_METRICS = {
6
6
  unitsPerEm: 2048,
7
7
  xWidthAvg: 832
8
8
  },
9
+ "Times New Roman Bold": {
10
+ ascent: 1825,
11
+ descent: -443,
12
+ lineGap: 87,
13
+ unitsPerEm: 2048,
14
+ xWidthAvg: 886
15
+ },
16
+ // Times New Roman Italic almost has the same properties as Times New Roman, we don't include it
9
17
  Arial: {
10
18
  ascent: 1854,
11
19
  descent: -434,
@@ -13,6 +21,14 @@ const SYSTEM_METRICS = {
13
21
  unitsPerEm: 2048,
14
22
  xWidthAvg: 913
15
23
  },
24
+ "Arial Bold": {
25
+ ascent: 1854,
26
+ descent: -434,
27
+ lineGap: 67,
28
+ unitsPerEm: 2048,
29
+ xWidthAvg: 983
30
+ },
31
+ // Arial Italic has the same properties as Arial, we don't include it
16
32
  "Courier New": {
17
33
  ascent: 1705,
18
34
  descent: -615,
@@ -20,6 +36,8 @@ const SYSTEM_METRICS = {
20
36
  unitsPerEm: 2048,
21
37
  xWidthAvg: 1229
22
38
  },
39
+ // Courier New Bold has the same properties as Courier New, we don't include it
40
+ // Courier New Italic has the same properties as Courier New, we don't include it
23
41
  BlinkMacSystemFont: {
24
42
  ascent: 1980,
25
43
  descent: -432,
@@ -50,17 +68,36 @@ const SYSTEM_METRICS = {
50
68
  }
51
69
  };
52
70
  const DEFAULT_FALLBACKS = {
53
- serif: ["Times New Roman"],
54
- "sans-serif": ["Arial"],
55
- monospace: ["Courier New"],
56
- "system-ui": ["BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial"],
57
- "ui-serif": ["Times New Roman"],
58
- "ui-sans-serif": ["Arial"],
59
- "ui-monospace": ["Courier New"]
71
+ serif: {
72
+ normal: ["Times New Roman"],
73
+ bold: ["Times New Roman Bold"]
74
+ },
75
+ "sans-serif": {
76
+ normal: ["Arial"],
77
+ bold: ["Arial Bold"]
78
+ },
79
+ monospace: { normal: ["Courier New"] },
80
+ "system-ui": {
81
+ normal: ["BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial"],
82
+ bold: ["BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial Bold"]
83
+ },
84
+ "ui-serif": {
85
+ normal: ["Times New Roman"],
86
+ bold: ["Times New Roman Bold"]
87
+ },
88
+ "ui-sans-serif": {
89
+ normal: ["Arial"],
90
+ bold: ["Arial Bold"]
91
+ },
92
+ "ui-monospace": { normal: ["Courier New"] }
60
93
  };
61
94
  class RealSystemFallbacksProvider {
62
- getLocalFonts(fallback) {
63
- return DEFAULT_FALLBACKS[fallback] ?? null;
95
+ getLocalFonts(fallback, variant) {
96
+ const entry = DEFAULT_FALLBACKS[fallback];
97
+ if (!entry) {
98
+ return null;
99
+ }
100
+ return entry[variant] ?? entry.normal ?? null;
64
101
  }
65
102
  getMetricsForLocalFont(family) {
66
103
  return SYSTEM_METRICS[family];
@@ -191,6 +191,7 @@ export interface PreloadData {
191
191
  }
192
192
  export type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
193
193
  export type GenericFallbackName = (typeof GENERIC_FALLBACK_NAMES)[number];
194
+ export type FallbackVariant = 'normal' | 'bold';
194
195
  export type Defaults = Required<Pick<ResolvedFontFamily, 'weights' | 'styles' | 'subsets' | 'fallbacks' | 'optimizedFallbacks' | 'formats'>>;
195
196
  export interface FontFileData {
196
197
  id: string;
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "6.4.2";
3
+ version = "6.4.3";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
197
197
  logger.info("Content config changed");
198
198
  shouldClear = true;
199
199
  }
200
- if (previousAstroVersion && previousAstroVersion !== "6.4.2") {
200
+ if (previousAstroVersion && previousAstroVersion !== "6.4.3") {
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 ("6.4.2") {
209
- this.#store.metaStore().set("astro-version", "6.4.2");
208
+ if ("6.4.3") {
209
+ this.#store.metaStore().set("astro-version", "6.4.3");
210
210
  }
211
211
  if (currentConfigDigest) {
212
212
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -29,6 +29,9 @@ export declare const PipelineFeatures: {
29
29
  readonly i18n: number;
30
30
  readonly cache: number;
31
31
  };
32
+ /** All feature bits ORed together. Keep next to `PipelineFeatures` so
33
+ * new flags are hard to forget. */
34
+ export declare const ALL_PIPELINE_FEATURES: number;
32
35
  /**
33
36
  * The `Pipeline` represents the static parts of rendering that do not change between requests.
34
37
  * These are mostly known when the server first starts up and do not change.
@@ -21,6 +21,7 @@ const PipelineFeatures = {
21
21
  i18n: 1 << 4,
22
22
  cache: 1 << 5
23
23
  };
24
+ const ALL_PIPELINE_FEATURES = PipelineFeatures.redirects | PipelineFeatures.sessions | PipelineFeatures.actions | PipelineFeatures.middleware | PipelineFeatures.i18n | PipelineFeatures.cache;
24
25
  class Pipeline {
25
26
  internalMiddleware;
26
27
  resolvedMiddleware = void 0;
@@ -295,6 +296,7 @@ class Pipeline {
295
296
  }
296
297
  }
297
298
  export {
299
+ ALL_PIPELINE_FEATURES,
298
300
  Pipeline,
299
301
  PipelineFeatures
300
302
  };
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "6.4.2";
1
+ const ASTRO_VERSION = "6.4.3";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
4
4
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
@@ -37,7 +37,7 @@ async function dev(inlineConfig) {
37
37
  await telemetry.record([]);
38
38
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
39
39
  const logger = restart.container.logger;
40
- const currentVersion = "6.4.2";
40
+ const currentVersion = "6.4.3";
41
41
  const isPrerelease = currentVersion.includes("-");
42
42
  if (!isPrerelease) {
43
43
  try {
@@ -10,7 +10,6 @@ import { AstroCookies } from "../cookies/index.js";
10
10
  import { Slots } from "../render/index.js";
11
11
  import {
12
12
  ASTRO_GENERATOR,
13
- DEFAULT_404_COMPONENT,
14
13
  fetchStateSymbol,
15
14
  originPathnameSymbol,
16
15
  pipelineSymbol,
@@ -30,7 +29,7 @@ import { Rewrites } from "../rewrites/handler.js";
30
29
  import { isRoute404or500, isRouteServerIsland } from "../routing/match.js";
31
30
  import { normalizeUrl } from "../util/normalized-url.js";
32
31
  import { getOriginPathname, setOriginPathname } from "../routing/rewrite.js";
33
- import { routeHasHtmlExtension } from "../routing/helpers.js";
32
+ import { getCustom404Route, routeHasHtmlExtension } from "../routing/helpers.js";
34
33
  import { getRenderOptions } from "../app/render-options.js";
35
34
  import { getFirstForwardedValue, validateForwardedHeaders } from "../app/validate-headers.js";
36
35
  function getFetchStateFromAPIContext(context) {
@@ -422,10 +421,8 @@ class FetchState {
422
421
  }
423
422
  return {
424
423
  insertDirective(payload) {
425
- if (state?.result?.directives) {
424
+ if (state.result) {
426
425
  state.result.directives = pushDirective(state.result.directives, payload);
427
- } else {
428
- state?.result?.directives.push(payload);
429
426
  }
430
427
  },
431
428
  insertScriptResource(resource) {
@@ -620,9 +617,10 @@ class FetchState {
620
617
  pipeline.logger.debug("router", "Astro matched the following route for " + this.request.url);
621
618
  pipeline.logger.debug("router", "RouteData:\n" + this.routeData);
622
619
  if (!this.routeData) {
623
- this.routeData = pipeline.manifestData.routes.find(
624
- (route) => route.component === "404.astro" || route.component === DEFAULT_404_COMPONENT
625
- );
620
+ const custom404 = getCustom404Route(pipeline.manifestData);
621
+ if (custom404 && !custom404.prerender) {
622
+ this.routeData = custom404;
623
+ }
626
624
  }
627
625
  if (!this.routeData) {
628
626
  pipeline.logger.debug("router", "Astro hasn't found routes that match " + this.request.url);
@@ -37,6 +37,9 @@ class I18n {
37
37
  state.pipeline.usedFeatures |= PipelineFeatures.i18n;
38
38
  const i18n = this.#i18n;
39
39
  const typeHeader = response.headers.get(ROUTE_TYPE_HEADER);
40
+ if (typeHeader) {
41
+ response.headers.delete(ROUTE_TYPE_HEADER);
42
+ }
40
43
  const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER);
41
44
  if (isReroute === "no" && typeof i18n.fallback === "undefined") {
42
45
  return response;
@@ -276,7 +276,7 @@ function printHelp({
276
276
  message.push(
277
277
  linebreak(),
278
278
  ` ${bgGreen(black(` ${commandName} `))} ${green(
279
- `v${"6.4.2"}`
279
+ `v${"6.4.3"}`
280
280
  )} ${headline}`
281
281
  );
282
282
  }
@@ -1,5 +1,4 @@
1
1
  import { PipelineFeatures } from "../base-pipeline.js";
2
- import { ROUTE_TYPE_HEADER } from "../constants.js";
3
2
  import { attachCookiesToResponse } from "../cookies/index.js";
4
3
  import { applyRewriteToState } from "../rewrites/handler.js";
5
4
  import { callMiddleware } from "./callMiddleware.js";
@@ -43,9 +42,6 @@ class AstroMiddleware {
43
42
  return response;
44
43
  }
45
44
  #finalize(state, response) {
46
- if (response.headers.get(ROUTE_TYPE_HEADER)) {
47
- response.headers.delete(ROUTE_TYPE_HEADER);
48
- }
49
45
  attachCookiesToResponse(response, state.cookies);
50
46
  return response;
51
47
  }
@@ -12,7 +12,7 @@ import { PagesHandler } from "../pages/handler.js";
12
12
  import { renderRedirect } from "../redirects/render.js";
13
13
  import { provideSession } from "../session/handler.js";
14
14
  import { prepareResponse } from "../app/prepare-response.js";
15
- import { PipelineFeatures } from "../base-pipeline.js";
15
+ import { ALL_PIPELINE_FEATURES, PipelineFeatures } from "../base-pipeline.js";
16
16
  class AstroHandler {
17
17
  #app;
18
18
  #trailingSlashHandler;
@@ -64,6 +64,7 @@ class AstroHandler {
64
64
  return this.#pagesHandler.handle(state, ctx);
65
65
  }
66
66
  async handle(state) {
67
+ state.pipeline.usedFeatures |= ALL_PIPELINE_FEATURES;
67
68
  const trailingSlashRedirect = this.#trailingSlashHandler.handle(state);
68
69
  if (trailingSlashRedirect) {
69
70
  return trailingSlashRedirect;
@@ -25,6 +25,14 @@
25
25
  import { aria, roles } from "aria-query";
26
26
  import { AXObjectRoles, elementAXObjects } from "axobject-query";
27
27
  const WHITESPACE_REGEX = /\s+/;
28
+ function isHiddenByClosedDetails(element) {
29
+ for (let parent = element.parentElement; parent; parent = parent.parentElement) {
30
+ if (parent.localName !== "details" || parent.open) continue;
31
+ const summary = Array.from(parent.children).find((child) => child.localName === "summary");
32
+ if (!summary?.contains(element)) return true;
33
+ }
34
+ return false;
35
+ }
28
36
  const a11y_required_attributes = {
29
37
  a: ["href"],
30
38
  area: ["alt", "aria-label", "aria-labelledby"],
@@ -321,6 +329,7 @@ const a11y = [
321
329
  message: "Headings and anchors must have an accessible name, which can come from: inner text, aria-label, aria-labelledby, an img with alt property, or an svg with a tag <title></title>.",
322
330
  selector: a11y_required_content.join(","),
323
331
  match(element) {
332
+ if (isHiddenByClosedDetails(element)) return false;
324
333
  const innerText = element.innerText?.trim();
325
334
  if (innerText && innerText !== "") return false;
326
335
  const ariaLabel = element.getAttribute("aria-label")?.trim();
@@ -207,9 +207,9 @@ export type I18nMiddlewareOptions = {
207
207
  /**
208
208
  * @param {AstroConfig['i18n']['routing']} customOptions
209
209
  *
210
- * A function that allows to programmatically create the Astro i18n middleware.
210
+ * A function that allows you to programmatically create the Astro i18n middleware.
211
211
  *
212
- * This is use useful when you still want to use the default i18n logic, but add only few exceptions to your website.
212
+ * This is useful when you still want to use the default i18n logic, but add only a few exceptions to your website.
213
213
  *
214
214
  * ## Examples
215
215
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.4.2",
3
+ "version": "6.4.3",
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",
@@ -124,7 +124,7 @@
124
124
  "clsx": "^2.1.1",
125
125
  "common-ancestor-path": "^2.0.0",
126
126
  "cookie": "^1.1.1",
127
- "devalue": "^5.6.3",
127
+ "devalue": "^5.8.1",
128
128
  "diff": "^8.0.3",
129
129
  "dset": "^3.1.4",
130
130
  "es-module-lexer": "^2.0.0",