astro 7.0.0-alpha.1 → 7.0.0-alpha.2
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/components/Code.astro +1 -1
- package/dist/assets/endpoint/dev.js +1 -1
- package/dist/assets/endpoint/generic.js +7 -16
- package/dist/assets/endpoint/loadImage.d.ts +11 -0
- package/dist/assets/endpoint/loadImage.js +19 -0
- package/dist/assets/fonts/config.d.ts +4 -4
- package/dist/assets/fonts/core/optimize-fallbacks.js +38 -13
- package/dist/assets/fonts/definitions.d.ts +2 -2
- package/dist/assets/fonts/infra/system-fallbacks-provider.d.ts +2 -2
- package/dist/assets/fonts/infra/system-fallbacks-provider.js +46 -9
- package/dist/assets/fonts/types.d.ts +1 -0
- package/dist/assets/internal.js +20 -16
- package/dist/assets/services/service.d.ts +1 -1
- package/dist/assets/services/service.js +9 -9
- package/dist/assets/services/sharp.js +48 -28
- package/dist/assets/utils/generateImageStylesCSS.js +26 -6
- package/dist/assets/utils/inferSourceFormat.d.ts +8 -3
- package/dist/assets/utils/inferSourceFormat.js +15 -4
- package/dist/assets/utils/metadata.js +1 -1
- package/dist/assets/utils/vendor/image-size/types/svg.js +1 -1
- package/dist/cli/dev/background.d.ts +16 -0
- package/dist/cli/dev/background.js +116 -0
- package/dist/cli/dev/index.js +82 -3
- package/dist/cli/dev/logs.d.ts +6 -0
- package/dist/cli/dev/logs.js +72 -0
- package/dist/cli/dev/status.d.ts +15 -0
- package/dist/cli/dev/status.js +27 -0
- package/dist/cli/dev/stop.d.ts +12 -0
- package/dist/cli/dev/stop.js +43 -0
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/content/content-layer.js +16 -10
- package/dist/content/data-store.d.ts +1 -1
- package/dist/content/runtime-assets.d.ts +2 -2
- package/dist/content/runtime.d.ts +1 -1
- package/dist/content/runtime.js +9 -4
- package/dist/content/types-generator.js +5 -1
- package/dist/content/utils.d.ts +1 -1
- package/dist/content/utils.js +1 -1
- package/dist/core/app/base.d.ts +9 -0
- package/dist/core/app/base.js +47 -67
- package/dist/core/app/entrypoints/node.d.ts +1 -1
- package/dist/core/app/entrypoints/node.js +2 -0
- package/dist/core/app/node.d.ts +16 -0
- package/dist/core/app/node.js +59 -13
- package/dist/core/base-pipeline.d.ts +10 -0
- package/dist/core/base-pipeline.js +13 -1
- package/dist/core/build/generate.js +8 -1
- package/dist/core/build/index.d.ts +0 -11
- package/dist/core/build/index.js +0 -3
- package/dist/core/build/internal.d.ts +7 -0
- package/dist/core/build/plugins/plugin-chunk-imports.d.ts +6 -0
- package/dist/core/build/plugins/plugin-chunk-imports.js +29 -17
- package/dist/core/build/plugins/plugin-css.js +33 -0
- package/dist/core/build/plugins/plugin-internals.js +1 -1
- package/dist/core/build/static-build.js +22 -155
- package/dist/core/build/types.d.ts +0 -1
- package/dist/core/build/util.js +8 -1
- package/dist/core/build/vite-build-config.d.ts +28 -0
- package/dist/core/build/vite-build-config.js +165 -0
- package/dist/core/config/merge.js +4 -0
- package/dist/core/config/schemas/base.d.ts +19 -11
- package/dist/core/config/schemas/base.js +29 -4
- package/dist/core/config/schemas/relative.d.ts +69 -45
- package/dist/core/config/validate.js +59 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +3 -1
- package/dist/core/csp/config.js +17 -5
- package/dist/core/dev/dev.d.ts +1 -0
- package/dist/core/dev/dev.js +4 -1
- package/dist/core/dev/lockfile.d.ts +54 -0
- package/dist/core/dev/lockfile.js +93 -0
- package/dist/core/errors/errors-data.d.ts +43 -38
- package/dist/core/errors/errors-data.js +79 -73
- package/dist/core/errors/zod-error-map.js +3 -1
- package/dist/core/fetch/fetch-state.d.ts +12 -26
- package/dist/core/fetch/fetch-state.js +137 -20
- package/dist/core/fetch/types.d.ts +19 -0
- package/dist/core/fetch/vite-plugin.js +11 -4
- package/dist/core/hono/index.d.ts +1 -1
- package/dist/core/hono/index.js +6 -3
- package/dist/core/i18n/domain.d.ts +12 -0
- package/dist/core/i18n/domain.js +66 -0
- package/dist/core/i18n/handler.js +3 -0
- package/dist/core/logger/core.d.ts +1 -1
- package/dist/core/logger/core.js +1 -1
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/astro-middleware.js +3 -5
- package/dist/core/module-loader/vite.js +1 -2
- package/dist/core/pages/handler.js +1 -0
- package/dist/core/preview/index.js +6 -5
- package/dist/core/preview/static-preview-server.js +5 -2
- package/dist/core/render/params-and-props.js +1 -1
- package/dist/core/render/route-cache.d.ts +1 -0
- package/dist/core/render/route-cache.js +4 -4
- package/dist/core/routing/create-manifest.js +11 -1
- package/dist/core/routing/handler.js +5 -6
- package/dist/core/routing/parse-route.js +1 -1
- package/dist/core/routing/rewrite.js +1 -1
- package/dist/core/routing/router.d.ts +8 -0
- package/dist/core/routing/router.js +28 -0
- package/dist/core/routing/validation.js +1 -1
- package/dist/core/server-islands/vite-plugin-server-islands.d.ts +6 -1
- package/dist/core/server-islands/vite-plugin-server-islands.js +13 -3
- package/dist/core/session/config.d.ts +1 -1
- package/dist/core/util/normalized-url.js +5 -2
- package/dist/core/util/pathname.d.ts +10 -1
- package/dist/core/util/pathname.js +13 -4
- package/dist/environments.js +1 -1
- package/dist/events/session.d.ts +8 -0
- package/dist/events/session.js +11 -0
- package/dist/jsx/rehype.d.ts +1 -1
- package/dist/manifest/virtual-module.js +3 -1
- package/dist/markdown/index.d.ts +4 -0
- package/dist/markdown/index.js +14 -0
- package/dist/prerender/utils.js +5 -1
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +9 -0
- package/dist/runtime/server/jsx.js +1 -1
- package/dist/runtime/server/render/component.js +8 -6
- package/dist/runtime/server/render/head.js +1 -5
- package/dist/runtime/server/render/util.js +2 -2
- package/dist/runtime/server/transition.d.ts +1 -6
- package/dist/runtime/server/transition.js +0 -8
- package/dist/transitions/events.d.ts +0 -14
- package/dist/transitions/events.js +0 -14
- package/dist/transitions/index.d.ts +0 -1
- package/dist/transitions/index.js +0 -2
- package/dist/transitions/vite-plugin-transitions.js +2 -4
- package/dist/types/public/config.d.ts +66 -18
- package/dist/types/public/content.d.ts +1 -1
- package/dist/types/public/index.d.ts +2 -1
- package/dist/types/public/integrations.d.ts +11 -3
- package/dist/types/public/manifest.d.ts +1 -1
- package/dist/virtual-modules/i18n.d.ts +2 -2
- package/dist/virtual-modules/i18n.js +1 -1
- package/dist/vite-plugin-app/app.d.ts +9 -1
- package/dist/vite-plugin-app/app.js +31 -21
- package/dist/vite-plugin-app/createAstroServerApp.d.ts +3 -1
- package/dist/vite-plugin-app/createAstroServerApp.js +4 -3
- package/dist/vite-plugin-astro-server/plugin.js +11 -5
- package/dist/vite-plugin-astro-server/route-guard.d.ts +33 -0
- package/dist/vite-plugin-astro-server/route-guard.js +42 -23
- package/dist/vite-plugin-dev-status/index.d.ts +2 -0
- package/dist/vite-plugin-dev-status/index.js +15 -0
- package/dist/vite-plugin-hmr-reload/index.d.ts +1 -1
- package/dist/vite-plugin-hmr-reload/index.js +23 -1
- package/dist/vite-plugin-integrations-container/index.js +15 -6
- package/dist/vite-plugin-markdown/content-entry-type.js +7 -4
- package/dist/vite-plugin-markdown/images.js +9 -11
- package/dist/vite-plugin-markdown/index.js +12 -11
- package/dist/vite-plugin-utils/index.js +7 -1
- package/package.json +13 -13
- package/templates/content/types.d.ts +1 -0
- package/types/transitions.d.ts +0 -7
package/components/Code.astro
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { createShikiHighlighter, type ThemePresets } from '@astrojs/
|
|
2
|
+
import { createShikiHighlighter, type ThemePresets } from '@astrojs/internal-helpers/shiki';
|
|
3
3
|
import type { ShikiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
|
|
4
4
|
import { bundledLanguages } from 'shiki/langs';
|
|
5
5
|
import type { CodeLanguage } from '../dist/types/public/common.js';
|
|
@@ -4,21 +4,7 @@ import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
|
|
|
4
4
|
import * as mime from "mrmime";
|
|
5
5
|
import { getConfiguredImageService } from "../internal.js";
|
|
6
6
|
import { etag } from "../utils/etag.js";
|
|
7
|
-
import {
|
|
8
|
-
async function loadRemoteImage(src, headers) {
|
|
9
|
-
try {
|
|
10
|
-
const res = await fetchWithRedirects({ url: src, headers, imageConfig });
|
|
11
|
-
if (!isRemoteAllowed(res.url, imageConfig)) {
|
|
12
|
-
return void 0;
|
|
13
|
-
}
|
|
14
|
-
if (!res.ok) {
|
|
15
|
-
return void 0;
|
|
16
|
-
}
|
|
17
|
-
return await res.arrayBuffer();
|
|
18
|
-
} catch {
|
|
19
|
-
return void 0;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
7
|
+
import { loadImage } from "./loadImage.js";
|
|
22
8
|
const GET = async ({ request }) => {
|
|
23
9
|
try {
|
|
24
10
|
const imageService = await getConfiguredImageService();
|
|
@@ -39,7 +25,12 @@ const GET = async ({ request }) => {
|
|
|
39
25
|
if (!isRemoteImage && sourceUrl.origin !== url.origin) {
|
|
40
26
|
return new Response("Forbidden", { status: 403 });
|
|
41
27
|
}
|
|
42
|
-
inputBuffer = await
|
|
28
|
+
inputBuffer = await loadImage(
|
|
29
|
+
sourceUrl,
|
|
30
|
+
isRemoteImage ? new Headers() : request.headers,
|
|
31
|
+
imageConfig,
|
|
32
|
+
isRemoteImage
|
|
33
|
+
);
|
|
43
34
|
if (!inputBuffer) {
|
|
44
35
|
return new Response("Not Found", { status: 404 });
|
|
45
36
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RemoteImageConfig } from '../utils/redirectValidation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches an image by URL. Used by the generic image endpoint for both
|
|
4
|
+
* remote images and local images (self-fetched from the same origin).
|
|
5
|
+
*
|
|
6
|
+
* For remote images, the final URL (after any redirects) is validated
|
|
7
|
+
* against `imageConfig.domains` and `imageConfig.remotePatterns`.
|
|
8
|
+
* Local images skip this check — they are already guarded by the
|
|
9
|
+
* same-origin check in the caller.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadImage(src: URL, headers: Headers, imageConfig: RemoteImageConfig, isRemote: boolean, fetchFn?: typeof globalThis.fetch): Promise<ArrayBuffer | undefined>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
|
|
2
|
+
import { fetchWithRedirects } from "../utils/redirectValidation.js";
|
|
3
|
+
async function loadImage(src, headers, imageConfig, isRemote, fetchFn) {
|
|
4
|
+
try {
|
|
5
|
+
const res = await fetchWithRedirects({ url: src, headers, imageConfig, fetchFn });
|
|
6
|
+
if (isRemote && !isRemoteAllowed(res.url, imageConfig)) {
|
|
7
|
+
return void 0;
|
|
8
|
+
}
|
|
9
|
+
if (!res.ok) {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
return await res.arrayBuffer();
|
|
13
|
+
} catch {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
loadImage
|
|
19
|
+
};
|
|
@@ -7,11 +7,11 @@ export declare const StyleSchema: z.ZodEnum<{
|
|
|
7
7
|
oblique: "oblique";
|
|
8
8
|
}>;
|
|
9
9
|
export declare const DisplaySchema: z.ZodEnum<{
|
|
10
|
-
optional: "optional";
|
|
11
10
|
auto: "auto";
|
|
11
|
+
optional: "optional";
|
|
12
|
+
fallback: "fallback";
|
|
12
13
|
block: "block";
|
|
13
14
|
swap: "swap";
|
|
14
|
-
fallback: "fallback";
|
|
15
15
|
}>;
|
|
16
16
|
export declare const FontProviderSchema: z.ZodCustom<FontProvider<never>, FontProvider<never>>;
|
|
17
17
|
export declare const FontFamilySchema: z.ZodObject<{
|
|
@@ -45,11 +45,11 @@ export declare const FontFamilySchema: z.ZodObject<{
|
|
|
45
45
|
fallbacks: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
46
|
optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
|
|
47
47
|
display: z.ZodOptional<z.ZodEnum<{
|
|
48
|
-
optional: "optional";
|
|
49
48
|
auto: "auto";
|
|
49
|
+
optional: "optional";
|
|
50
|
+
fallback: "fallback";
|
|
50
51
|
block: "block";
|
|
51
52
|
swap: "swap";
|
|
52
|
-
fallback: "fallback";
|
|
53
53
|
}>>;
|
|
54
54
|
stretch: z.ZodOptional<z.ZodString>;
|
|
55
55
|
featureSettings: z.ZodOptional<z.ZodString>;
|
|
@@ -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
|
|
18
|
-
|
|
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 (
|
|
45
|
+
if (uniqueLocalFonts.includes(family.name)) {
|
|
22
46
|
return null;
|
|
23
47
|
}
|
|
24
|
-
const
|
|
25
|
-
font,
|
|
48
|
+
const nameForFont = (font) => (
|
|
26
49
|
// We mustn't wrap in quote because that's handled by the CSS renderer
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
fallbacks = [...
|
|
50
|
+
`${family.uniqueName} fallback: ${font}`
|
|
51
|
+
);
|
|
52
|
+
fallbacks = [...uniqueLocalFonts.map(nameForFont), ...fallbacks];
|
|
30
53
|
let css = "";
|
|
31
|
-
for (const {
|
|
32
|
-
|
|
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
|
|
59
|
+
metrics,
|
|
35
60
|
fallbackMetrics: systemFallbacksProvider.getMetricsForLocalFont(font),
|
|
36
61
|
font,
|
|
37
|
-
name,
|
|
38
|
-
properties
|
|
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:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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;
|
package/dist/assets/internal.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isImageMetadata
|
|
14
14
|
} from "./types.js";
|
|
15
15
|
import { isESMImportedImage, isRemoteImage, resolveSrc } from "./utils/imageKind.js";
|
|
16
|
+
import { resolveDefaultOutputFormat } from "./utils/inferSourceFormat.js";
|
|
16
17
|
import { inferRemoteSize } from "./utils/remoteProbe.js";
|
|
17
18
|
import { createPlaceholderURL, stringifyPlaceholderURL } from "./utils/url.js";
|
|
18
19
|
import { verifyOptions } from "./services/service.js";
|
|
@@ -73,6 +74,9 @@ async function getImage(options, imageConfig) {
|
|
|
73
74
|
const result = await getRemoteSize(resolvedOptions.src);
|
|
74
75
|
resolvedOptions.width ??= result.width;
|
|
75
76
|
resolvedOptions.height ??= result.height;
|
|
77
|
+
if (result.format) {
|
|
78
|
+
resolvedOptions.format ??= resolveDefaultOutputFormat(result.format);
|
|
79
|
+
}
|
|
76
80
|
originalWidth = result.width;
|
|
77
81
|
originalHeight = result.height;
|
|
78
82
|
}
|
|
@@ -124,24 +128,13 @@ async function getImage(options, imageConfig) {
|
|
|
124
128
|
}
|
|
125
129
|
const currentPosition = resolvedOptions.position || "center";
|
|
126
130
|
resolvedOptions["data-astro-image-pos"] = currentPosition.replace(/\s+/g, "-");
|
|
127
|
-
if (resolvedOptions.position) {
|
|
128
|
-
if (typeof resolvedOptions.style === "object" && resolvedOptions.style !== null) {
|
|
129
|
-
if (!("objectPosition" in resolvedOptions.style)) {
|
|
130
|
-
resolvedOptions.style = {
|
|
131
|
-
...resolvedOptions.style,
|
|
132
|
-
objectPosition: resolvedOptions.position
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
} else {
|
|
136
|
-
const existingStyle = typeof resolvedOptions.style === "string" ? resolvedOptions.style : "";
|
|
137
|
-
if (!existingStyle.includes("object-position")) {
|
|
138
|
-
const positionStyle = `object-position: ${resolvedOptions.position}`;
|
|
139
|
-
resolvedOptions.style = existingStyle ? existingStyle.replace(/;?\s*$/, "; ") + positionStyle : positionStyle;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
131
|
}
|
|
144
132
|
const validatedOptions = service.validateOptions ? await service.validateOptions(resolvedOptions, imageConfig) : resolvedOptions;
|
|
133
|
+
validatedOptions.format ??= await peekRemoteFormatForStaticEmit(
|
|
134
|
+
validatedOptions,
|
|
135
|
+
imageConfig,
|
|
136
|
+
service
|
|
137
|
+
);
|
|
145
138
|
const srcSetTransforms = service.getSrcSet ? await service.getSrcSet(validatedOptions, imageConfig) : [];
|
|
146
139
|
const lazyImageURLFactory = (getValue) => {
|
|
147
140
|
let cached = null;
|
|
@@ -203,6 +196,17 @@ async function getImage(options, imageConfig) {
|
|
|
203
196
|
attributes: service.getHTMLAttributes !== void 0 ? await service.getHTMLAttributes(validatedOptions, imageConfig) : {}
|
|
204
197
|
};
|
|
205
198
|
}
|
|
199
|
+
async function peekRemoteFormatForStaticEmit(options, imageConfig, service) {
|
|
200
|
+
if (!isRemoteImage(options.src) || !isRemoteAllowed(options.src, imageConfig) || !globalThis.astroAsset?.addStaticImage || !isLocalService(service) || !service.getRemoteSize) {
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const probed = await service.getRemoteSize(options.src, imageConfig);
|
|
205
|
+
return resolveDefaultOutputFormat(probed.format);
|
|
206
|
+
} catch {
|
|
207
|
+
return void 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
206
210
|
export {
|
|
207
211
|
cssFitValues,
|
|
208
212
|
getConfiguredImageService,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
|
|
2
2
|
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
|
|
3
3
|
import { isRemotePath, joinPaths } from "../../core/path.js";
|
|
4
|
-
import { DEFAULT_HASH_PROPS,
|
|
4
|
+
import { DEFAULT_HASH_PROPS, VALID_SUPPORTED_FORMATS } from "../consts.js";
|
|
5
5
|
import { isESMImportedImage, isRemoteImage } from "../utils/imageKind.js";
|
|
6
|
+
import { inferSourceFormat, resolveDefaultOutputFormat } from "../utils/inferSourceFormat.js";
|
|
6
7
|
import { inferRemoteSize } from "../utils/remoteProbe.js";
|
|
7
8
|
function isLocalService(service) {
|
|
8
9
|
if (!service) {
|
|
@@ -74,10 +75,11 @@ const baseService = {
|
|
|
74
75
|
validateOptions(options) {
|
|
75
76
|
verifyOptions(options);
|
|
76
77
|
if (!options.format) {
|
|
77
|
-
if (isESMImportedImage(options.src)
|
|
78
|
-
options.format =
|
|
78
|
+
if (isESMImportedImage(options.src)) {
|
|
79
|
+
options.format = resolveDefaultOutputFormat(options.src.format);
|
|
79
80
|
} else {
|
|
80
|
-
|
|
81
|
+
const inferred = inferSourceFormat(options.src);
|
|
82
|
+
if (inferred) options.format = resolveDefaultOutputFormat(inferred);
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
if (options.width) options.width = Math.round(options.width);
|
|
@@ -120,7 +122,7 @@ const baseService = {
|
|
|
120
122
|
const { targetWidth, targetHeight } = getTargetDimensions(options);
|
|
121
123
|
const aspectRatio = targetWidth / targetHeight;
|
|
122
124
|
const { widths, densities } = options;
|
|
123
|
-
const targetFormat = options.format
|
|
125
|
+
const targetFormat = options.format;
|
|
124
126
|
let transformedWidths = (widths ?? []).sort(sortNumeric);
|
|
125
127
|
let imageWidth = options.width;
|
|
126
128
|
let maxWidth = Number.POSITIVE_INFINITY;
|
|
@@ -164,9 +166,7 @@ const baseService = {
|
|
|
164
166
|
return {
|
|
165
167
|
transform,
|
|
166
168
|
descriptor,
|
|
167
|
-
attributes: {
|
|
168
|
-
type: `image/${targetFormat}`
|
|
169
|
-
}
|
|
169
|
+
attributes: targetFormat ? { type: `image/${targetFormat}` } : {}
|
|
170
170
|
};
|
|
171
171
|
});
|
|
172
172
|
},
|
|
@@ -210,7 +210,7 @@ const baseService = {
|
|
|
210
210
|
src: params.get("href"),
|
|
211
211
|
width: params.has("w") ? Number.parseInt(params.get("w")) : void 0,
|
|
212
212
|
height: params.has("h") ? Number.parseInt(params.get("h")) : void 0,
|
|
213
|
-
format: params.get("f"),
|
|
213
|
+
format: params.has("f") ? params.get("f") : void 0,
|
|
214
214
|
quality: params.get("q"),
|
|
215
215
|
fit: params.get("fit"),
|
|
216
216
|
position: params.get("position") ?? void 0,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
|
|
2
|
+
import { resolveDefaultOutputFormat } from "../utils/inferSourceFormat.js";
|
|
2
3
|
import { detector } from "../utils/vendor/image-size/detector.js";
|
|
3
4
|
import {
|
|
4
5
|
baseService,
|
|
@@ -21,6 +22,9 @@ function resolveSharpQuality(quality) {
|
|
|
21
22
|
}
|
|
22
23
|
function resolveSharpEncoderOptions(transform, inputFormat, serviceConfig = {}) {
|
|
23
24
|
const quality = resolveSharpQuality(transform.quality);
|
|
25
|
+
if (transform.format === void 0) {
|
|
26
|
+
return quality === void 0 ? void 0 : { quality };
|
|
27
|
+
}
|
|
24
28
|
switch (transform.format) {
|
|
25
29
|
case "jpg":
|
|
26
30
|
case "jpeg":
|
|
@@ -82,11 +86,27 @@ const sharpService = {
|
|
|
82
86
|
if (!sharp) sharp = await loadSharp();
|
|
83
87
|
const transform = transformOptions;
|
|
84
88
|
const kernel = config.service.config.kernel;
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
const bufferFormat = detector(inputBuffer);
|
|
90
|
+
const outputFormat = transform.format ?? resolveDefaultOutputFormat(bufferFormat);
|
|
91
|
+
if (outputFormat === "svg") {
|
|
92
|
+
if (bufferFormat && bufferFormat !== "svg") {
|
|
93
|
+
console.warn(
|
|
94
|
+
`\u26A0\uFE0F Astro expected an SVG for "${transform.src}" but the source is ${bufferFormat}. Passing it through as ${bufferFormat} instead.`
|
|
95
|
+
);
|
|
96
|
+
return { data: inputBuffer, format: bufferFormat };
|
|
97
|
+
}
|
|
98
|
+
return { data: inputBuffer, format: "svg" };
|
|
99
|
+
}
|
|
100
|
+
if (!bufferFormat) {
|
|
101
|
+
throw new AstroError({
|
|
102
|
+
...AstroErrorData.NoImageMetadata,
|
|
103
|
+
message: AstroErrorData.NoImageMetadata.message(transform.src)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (bufferFormat === "svg" && !config.dangerouslyProcessSVG) {
|
|
87
107
|
throw new AstroError({
|
|
88
108
|
...AstroErrorData.UnsupportedImageFormat,
|
|
89
|
-
message:
|
|
109
|
+
message: `SVG image processing is disabled, but the source for "${transform.src}" is an SVG. Pass it through unchanged by setting \`format="svg"\` on the component, or set \`image.dangerouslyProcessSVG: true\` to rasterize SVG sources.`
|
|
90
110
|
});
|
|
91
111
|
}
|
|
92
112
|
const result = sharp(inputBuffer, {
|
|
@@ -95,15 +115,6 @@ const sharpService = {
|
|
|
95
115
|
limitInputPixels: config.service.config.limitInputPixels
|
|
96
116
|
});
|
|
97
117
|
result.rotate();
|
|
98
|
-
let format;
|
|
99
|
-
try {
|
|
100
|
-
({ format } = await result.metadata());
|
|
101
|
-
} catch {
|
|
102
|
-
console.warn(
|
|
103
|
-
`\u26A0\uFE0F Astro could not optimize image "${transform.src}". Sharp doesn't support this format. The image will be used unoptimized. Consider converting to WebP or placing in the public/ folder.`
|
|
104
|
-
);
|
|
105
|
-
return { data: inputBuffer, format: transform.format };
|
|
106
|
-
}
|
|
107
118
|
if (transform.width && transform.height) {
|
|
108
119
|
const fit = transform.fit ? fitMap[transform.fit] ?? "inside" : void 0;
|
|
109
120
|
result.resize({
|
|
@@ -130,23 +141,32 @@ const sharpService = {
|
|
|
130
141
|
if (transform.background) {
|
|
131
142
|
result.flatten({ background: transform.background });
|
|
132
143
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
const encoderOptions = resolveSharpEncoderOptions(
|
|
145
|
+
{ format: outputFormat, quality: transform.quality },
|
|
146
|
+
bufferFormat,
|
|
147
|
+
config.service.config
|
|
148
|
+
);
|
|
149
|
+
if (outputFormat === "webp") {
|
|
150
|
+
result.webp(encoderOptions);
|
|
151
|
+
} else if (outputFormat === "png") {
|
|
152
|
+
result.png(encoderOptions);
|
|
153
|
+
} else if (outputFormat === "avif") {
|
|
154
|
+
result.avif(encoderOptions);
|
|
155
|
+
} else if (outputFormat === "jpeg" || outputFormat === "jpg") {
|
|
156
|
+
result.jpeg(encoderOptions);
|
|
157
|
+
} else {
|
|
158
|
+
result.toFormat(outputFormat, encoderOptions);
|
|
159
|
+
}
|
|
160
|
+
let data;
|
|
161
|
+
let info;
|
|
162
|
+
try {
|
|
163
|
+
({ data, info } = await result.toBuffer({ resolveWithObject: true }));
|
|
164
|
+
} catch {
|
|
165
|
+
console.warn(
|
|
166
|
+
`\u26A0\uFE0F Astro could not optimize image "${transform.src}". Sharp doesn't support this format. The image will be used unoptimized. Consider converting to WebP or placing in the public/ folder.`
|
|
167
|
+
);
|
|
168
|
+
return { data: inputBuffer, format: bufferFormat };
|
|
148
169
|
}
|
|
149
|
-
const { data, info } = await result.toBuffer({ resolveWithObject: true });
|
|
150
170
|
const needsCopy = "buffer" in data && data.buffer instanceof SharedArrayBuffer;
|
|
151
171
|
return {
|
|
152
172
|
data: needsCopy ? new Uint8Array(data) : data,
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { cssFitValues } from "../internal.js";
|
|
2
|
+
const POSITION_KEYWORDS = ["top", "bottom", "left", "right", "center"];
|
|
3
|
+
function getPositionEntries() {
|
|
4
|
+
const entries = [];
|
|
5
|
+
for (const kw of POSITION_KEYWORDS) {
|
|
6
|
+
entries.push([kw, kw]);
|
|
7
|
+
}
|
|
8
|
+
for (const a of POSITION_KEYWORDS) {
|
|
9
|
+
for (const b of POSITION_KEYWORDS) {
|
|
10
|
+
if (a === b) continue;
|
|
11
|
+
const cssValue = `${a} ${b}`;
|
|
12
|
+
const dataAttr = `${a}-${b}`;
|
|
13
|
+
entries.push([dataAttr, cssValue]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return entries;
|
|
17
|
+
}
|
|
2
18
|
function generateImageStylesCSS(defaultObjectFit, defaultObjectPosition) {
|
|
3
19
|
const fitStyles = cssFitValues.map(
|
|
4
20
|
(fit) => `
|
|
@@ -10,11 +26,14 @@ function generateImageStylesCSS(defaultObjectFit, defaultObjectPosition) {
|
|
|
10
26
|
:where([data-astro-image]:not([data-astro-image-fit])) {
|
|
11
27
|
object-fit: ${defaultObjectFit};
|
|
12
28
|
}` : "";
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
29
|
+
const positionEntries = getPositionEntries();
|
|
30
|
+
const positionStyles = positionEntries.map(
|
|
31
|
+
([dataAttr, cssValue]) => `
|
|
32
|
+
[data-astro-image-pos="${dataAttr}"] {
|
|
33
|
+
object-position: ${cssValue};
|
|
34
|
+
}`
|
|
35
|
+
).join("\n");
|
|
36
|
+
const defaultPositionStyle = defaultObjectPosition ? `
|
|
18
37
|
:where([data-astro-image]:not([data-astro-image-pos])) {
|
|
19
38
|
object-position: ${defaultObjectPosition};
|
|
20
39
|
}` : "";
|
|
@@ -30,7 +49,8 @@ function generateImageStylesCSS(defaultObjectFit, defaultObjectPosition) {
|
|
|
30
49
|
}
|
|
31
50
|
${fitStyles}
|
|
32
51
|
${defaultFitStyle}
|
|
33
|
-
${
|
|
52
|
+
${positionStyles}
|
|
53
|
+
${defaultPositionStyle}
|
|
34
54
|
`.trim();
|
|
35
55
|
}
|
|
36
56
|
export {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Infer the image format from a source path or URL
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Infer the image format from a source path or URL.
|
|
3
|
+
*
|
|
4
|
+
* For `data:` URIs the MIME is read up to the first `;` or `,` (whichever comes first),
|
|
5
|
+
* so both `data:image/svg+xml;base64,...` and `data:image/svg+xml,<svg>...` work.
|
|
6
|
+
* `image/svg+xml` normalizes to `svg`; otherwise the subtype after the slash is returned.
|
|
7
|
+
*
|
|
8
|
+
* Returns undefined when the format cannot be determined.
|
|
5
9
|
*/
|
|
6
10
|
export declare function inferSourceFormat(src: string): string | undefined;
|
|
11
|
+
export declare function resolveDefaultOutputFormat(sourceFormat: string | undefined): string;
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import { removeQueryString } from "@astrojs/internal-helpers/path";
|
|
2
|
+
import { DEFAULT_OUTPUT_FORMAT } from "../consts.js";
|
|
2
3
|
const DATA_PREFIX = "data:";
|
|
3
4
|
function inferSourceFormat(src) {
|
|
4
5
|
if (src.startsWith(DATA_PREFIX)) {
|
|
5
|
-
const
|
|
6
|
+
const sepIndex = src.indexOf(";");
|
|
7
|
+
const commaIndex = src.indexOf(",");
|
|
8
|
+
const mimeEnd = sepIndex === -1 ? commaIndex : commaIndex === -1 ? sepIndex : Math.min(sepIndex, commaIndex);
|
|
9
|
+
if (mimeEnd === -1) return void 0;
|
|
10
|
+
const mime = src.slice(DATA_PREFIX.length, mimeEnd);
|
|
6
11
|
if (mime === "image/svg+xml") return "svg";
|
|
7
12
|
const sub = mime.split("/")[1];
|
|
8
13
|
return sub || void 0;
|
|
9
14
|
}
|
|
10
15
|
try {
|
|
11
16
|
const cleanSrc = removeQueryString(src).split("#")[0];
|
|
12
|
-
const
|
|
17
|
+
const lastSlash = cleanSrc.lastIndexOf("/");
|
|
18
|
+
const basename = lastSlash === -1 ? cleanSrc : cleanSrc.slice(lastSlash + 1);
|
|
19
|
+
const lastDot = basename.lastIndexOf(".");
|
|
13
20
|
if (lastDot === -1) return void 0;
|
|
14
|
-
return
|
|
21
|
+
return basename.slice(lastDot + 1).toLowerCase();
|
|
15
22
|
} catch {
|
|
16
23
|
return void 0;
|
|
17
24
|
}
|
|
18
25
|
}
|
|
26
|
+
function resolveDefaultOutputFormat(sourceFormat) {
|
|
27
|
+
return sourceFormat === "svg" ? "svg" : DEFAULT_OUTPUT_FORMAT;
|
|
28
|
+
}
|
|
19
29
|
export {
|
|
20
|
-
inferSourceFormat
|
|
30
|
+
inferSourceFormat,
|
|
31
|
+
resolveDefaultOutputFormat
|
|
21
32
|
};
|