Initial commit

This commit is contained in:
Alejandro Martinez
2026-02-12 02:04:10 +01:00
commit f09af719cf
13433 changed files with 2193445 additions and 0 deletions

23
node_modules/astro/dist/assets/build/generate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import type { BuildPipeline } from '../../core/build/pipeline.js';
import type { Logger } from '../../core/logger/core.js';
import type { MapValue } from '../../type-utils.js';
import type { AstroConfig } from '../../types/public/config.js';
import type { AssetsGlobalStaticImagesList } from '../types.js';
type AssetEnv = {
logger: Logger;
isSSR: boolean;
count: {
total: number;
current: number;
};
useCache: boolean;
assetsCacheDir: URL;
serverRoot: URL;
clientRoot: URL;
imageConfig: AstroConfig['image'];
assetsFolder: AstroConfig['build']['assets'];
};
export declare function prepareAssetsGenerationEnv(pipeline: BuildPipeline, totalCount: number): Promise<AssetEnv>;
export declare function generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv): Promise<void>;
export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
export {};

250
node_modules/astro/dist/assets/build/generate.js generated vendored Normal file
View File

@@ -0,0 +1,250 @@
import fs, { readFileSync } from "node:fs";
import { basename } from "node:path/posix";
import colors from "piccolore";
import { getOutDirWithinCwd } from "../../core/build/common.js";
import { getTimeStat } from "../../core/build/util.js";
import { AstroError } from "../../core/errors/errors.js";
import { AstroErrorData } from "../../core/errors/index.js";
import { isRemotePath, removeLeadingForwardSlash } from "../../core/path.js";
import { getConfiguredImageService } from "../internal.js";
import { isESMImportedImage } from "../utils/imageKind.js";
import { loadRemoteImage, revalidateRemoteImage } from "./remote.js";
async function prepareAssetsGenerationEnv(pipeline, totalCount) {
const { config, logger, settings } = pipeline;
let useCache = true;
const assetsCacheDir = new URL("assets/", config.cacheDir);
const count = { total: totalCount, current: 1 };
try {
await fs.promises.mkdir(assetsCacheDir, { recursive: true });
} catch (err) {
logger.warn(
null,
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
);
useCache = false;
}
const isServerOutput = settings.buildOutput === "server";
let serverRoot, clientRoot;
if (isServerOutput) {
serverRoot = config.build.server;
clientRoot = config.build.client;
} else {
serverRoot = getOutDirWithinCwd(config.outDir);
clientRoot = config.outDir;
}
return {
logger,
isSSR: isServerOutput,
count,
useCache,
assetsCacheDir,
serverRoot,
clientRoot,
imageConfig: config.image,
assetsFolder: config.build.assets
};
}
function getFullImagePath(originalFilePath, env) {
return new URL(removeLeadingForwardSlash(originalFilePath), env.serverRoot);
}
async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
let originalImage;
for (const [_, transform] of transformsAndPath.transforms) {
await generateImage(transform.finalPath, transform.transform);
}
if (!env.isSSR && transformsAndPath.originalSrcPath && !globalThis.astroAsset.referencedImages?.has(transformsAndPath.originalSrcPath)) {
try {
if (transformsAndPath.originalSrcPath) {
env.logger.debug(
"assets",
`Deleting ${originalFilePath} as it's not referenced outside of image processing.`
);
await fs.promises.unlink(getFullImagePath(originalFilePath, env));
}
} catch {
}
}
async function generateImage(filepath, options) {
const timeStart = performance.now();
const generationData = await generateImageInternal(filepath, options);
const timeEnd = performance.now();
const timeChange = getTimeStat(timeStart, timeEnd);
const timeIncrease = `(+${timeChange})`;
const statsText = generationData.cached !== "miss" ? generationData.cached === "hit" ? `(reused cache entry)` : `(revalidated cache entry)` : `(before: ${generationData.weight.before}kB, after: ${generationData.weight.after}kB)`;
const count = `(${env.count.current}/${env.count.total})`;
env.logger.info(
null,
` ${colors.green("\u25B6")} ${filepath} ${colors.dim(statsText)} ${colors.dim(timeIncrease)} ${colors.dim(count)}`
);
env.count.current++;
}
async function generateImageInternal(filepath, options) {
const isLocalImage = isESMImportedImage(options.src);
const finalFileURL = new URL("." + filepath, env.clientRoot);
const finalFolderURL = new URL("./", finalFileURL);
await fs.promises.mkdir(finalFolderURL, { recursive: true });
const cacheFile = basename(filepath);
const cachedFileURL = new URL(cacheFile, env.assetsCacheDir);
const cacheMetaFile = cacheFile + ".json";
const cachedMetaFileURL = new URL(cacheMetaFile, env.assetsCacheDir);
try {
if (isLocalImage) {
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return {
cached: "hit"
};
} else {
const JSONData = JSON.parse(readFileSync(cachedMetaFileURL, "utf-8"));
if (!JSONData.expires) {
try {
await fs.promises.unlink(cachedFileURL);
} catch {
}
await fs.promises.unlink(cachedMetaFileURL);
throw new Error(
`Malformed cache entry for ${filepath}, cache will be regenerated for this file.`
);
}
if (JSONData.data) {
const { data, ...meta } = JSONData;
await Promise.all([
fs.promises.writeFile(cachedFileURL, Buffer.from(data, "base64")),
writeCacheMetaFile(cachedMetaFileURL, meta, env)
]);
}
if (JSONData.expires > Date.now()) {
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return {
cached: "hit"
};
}
if (JSONData.etag || JSONData.lastModified) {
try {
const revalidatedData = await revalidateRemoteImage(options.src, {
etag: JSONData.etag,
lastModified: JSONData.lastModified
});
if (revalidatedData.data.length) {
originalImage = revalidatedData;
} else {
await writeCacheMetaFile(cachedMetaFileURL, revalidatedData, env);
await fs.promises.copyFile(
cachedFileURL,
finalFileURL,
fs.constants.COPYFILE_FICLONE
);
return { cached: "revalidated" };
}
} catch (e) {
env.logger.warn(
null,
`An error was encountered while revalidating a cached remote asset. Proceeding with stale cache. ${e}`
);
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return { cached: "hit" };
}
}
await fs.promises.unlink(cachedFileURL);
await fs.promises.unlink(cachedMetaFileURL);
}
} catch (e) {
if (e.code !== "ENOENT") {
throw new Error(`An error was encountered while reading the cache file. Error: ${e}`);
}
}
const originalImagePath = isLocalImage ? options.src.src : options.src;
if (!originalImage) {
originalImage = await loadImage(originalFilePath, env);
}
let resultData = {
data: void 0,
expires: originalImage.expires,
etag: originalImage.etag,
lastModified: originalImage.lastModified
};
const imageService = await getConfiguredImageService();
try {
resultData.data = (await imageService.transform(
originalImage.data,
{ ...options, src: originalImagePath },
env.imageConfig
)).data;
} catch (e) {
if (AstroError.is(e)) {
throw e;
}
const error = new AstroError(
{
...AstroErrorData.CouldNotTransformImage,
message: AstroErrorData.CouldNotTransformImage.message(originalFilePath)
},
{ cause: e }
);
throw error;
}
try {
if (env.useCache) {
if (isLocalImage) {
await fs.promises.writeFile(cachedFileURL, resultData.data);
} else {
await Promise.all([
fs.promises.writeFile(cachedFileURL, resultData.data),
writeCacheMetaFile(cachedMetaFileURL, resultData, env)
]);
}
}
} catch (e) {
env.logger.warn(
null,
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
);
} finally {
await fs.promises.writeFile(finalFileURL, resultData.data);
}
return {
cached: "miss",
weight: {
// Divide by 1024 to get size in kilobytes
before: Math.trunc(originalImage.data.byteLength / 1024),
after: Math.trunc(Buffer.from(resultData.data).byteLength / 1024)
}
};
}
}
async function writeCacheMetaFile(cachedMetaFileURL, resultData, env) {
try {
return await fs.promises.writeFile(
cachedMetaFileURL,
JSON.stringify({
expires: resultData.expires,
etag: resultData.etag,
lastModified: resultData.lastModified
})
);
} catch (e) {
env.logger.warn(
null,
`An error was encountered while writing the cache file for a remote asset. Proceeding without caching this asset. Error: ${e}`
);
}
}
function getStaticImageList() {
if (!globalThis?.astroAsset?.staticImages) {
return /* @__PURE__ */ new Map();
}
return globalThis.astroAsset.staticImages;
}
async function loadImage(path, env) {
if (isRemotePath(path)) {
return await loadRemoteImage(path);
}
return {
data: await fs.promises.readFile(getFullImagePath(path, env)),
expires: 0
};
}
export {
generateImagesForPath,
getStaticImageList,
prepareAssetsGenerationEnv
};

30
node_modules/astro/dist/assets/build/remote.d.ts generated vendored Normal file
View File

@@ -0,0 +1,30 @@
export type RemoteCacheEntry = {
data?: string;
expires: number;
etag?: string;
lastModified?: string;
};
export declare function loadRemoteImage(src: string): Promise<{
data: Buffer<ArrayBuffer>;
expires: number;
etag: string | undefined;
lastModified: string | undefined;
}>;
/**
* Revalidate a cached remote asset using its entity-tag or modified date.
* Uses the [If-None-Match](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) and [If-Modified-Since](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since)
* headers to check with the remote server if the cached version of a remote asset is still up to date.
* The remote server may respond that the cached asset is still up-to-date if the entity-tag or modification time matches (304 Not Modified), or respond with an updated asset (200 OK)
* @param src - url to remote asset
* @param revalidationData - an object containing the stored Entity-Tag of the cached asset and/or the Last Modified time
* @returns An ImageData object containing the asset data, a new expiry time, and the asset's etag. The data buffer will be empty if the asset was not modified.
*/
export declare function revalidateRemoteImage(src: string, revalidationData: {
etag?: string;
lastModified?: string;
}): Promise<{
data: Buffer<ArrayBuffer>;
expires: number;
etag: string | undefined;
lastModified: string | undefined;
}>;

77
node_modules/astro/dist/assets/build/remote.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import CachePolicy from "http-cache-semantics";
async function loadRemoteImage(src) {
const req = new Request(src);
const res = await fetch(req);
if (!res.ok) {
throw new Error(
`Failed to load remote image ${src}. The request did not return a 200 OK response. (received ${res.status}))`
);
}
const policy = new CachePolicy(webToCachePolicyRequest(req), webToCachePolicyResponse(res));
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data: Buffer.from(await res.arrayBuffer()),
expires: Date.now() + expires,
etag: res.headers.get("Etag") ?? void 0,
lastModified: res.headers.get("Last-Modified") ?? void 0
};
}
async function revalidateRemoteImage(src, revalidationData) {
const headers = {
...revalidationData.etag && { "If-None-Match": revalidationData.etag },
...revalidationData.lastModified && { "If-Modified-Since": revalidationData.lastModified }
};
const req = new Request(src, { headers, cache: "no-cache" });
const res = await fetch(req);
if (!res.ok && res.status !== 304) {
throw new Error(
`Failed to revalidate cached remote image ${src}. The request did not return a 200 OK / 304 NOT MODIFIED response. (received ${res.status} ${res.statusText})`
);
}
const data = Buffer.from(await res.arrayBuffer());
if (res.ok && !data.length) {
return await loadRemoteImage(src);
}
const policy = new CachePolicy(
webToCachePolicyRequest(req),
webToCachePolicyResponse(
res.ok ? res : new Response(null, { status: 200, headers: res.headers })
)
// 304 responses themselves are not cacheable, so just pretend to get the refreshed TTL
);
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data,
expires: Date.now() + expires,
// While servers should respond with the same headers as a 200 response, if they don't we should reuse the stored value
etag: res.headers.get("Etag") ?? (res.ok ? void 0 : revalidationData.etag),
lastModified: res.headers.get("Last-Modified") ?? (res.ok ? void 0 : revalidationData.lastModified)
};
}
function webToCachePolicyRequest({ url, method, headers: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
method,
url,
headers
};
}
function webToCachePolicyResponse({ status, headers: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
status,
headers
};
}
export {
loadRemoteImage,
revalidateRemoteImage
};

11
node_modules/astro/dist/assets/consts.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
export declare const VIRTUAL_MODULE_ID = "astro:assets";
export declare const VIRTUAL_SERVICE_ID = "virtual:image-service";
export declare const VALID_INPUT_FORMATS: readonly ["jpeg", "jpg", "png", "tiff", "webp", "gif", "svg", "avif"];
/**
* Valid formats that our base services support.
* Certain formats can be imported (namely SVGs) but will not be processed.
*/
export declare const VALID_SUPPORTED_FORMATS: readonly ["jpeg", "jpg", "png", "tiff", "webp", "gif", "svg", "avif"];
export declare const DEFAULT_OUTPUT_FORMAT: "webp";
export declare const VALID_OUTPUT_FORMATS: readonly ["avif", "png", "webp", "jpeg", "jpg", "svg"];
export declare const DEFAULT_HASH_PROPS: string[];

43
node_modules/astro/dist/assets/consts.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
const VIRTUAL_MODULE_ID = "astro:assets";
const VIRTUAL_SERVICE_ID = "virtual:image-service";
const VALID_INPUT_FORMATS = [
"jpeg",
"jpg",
"png",
"tiff",
"webp",
"gif",
"svg",
"avif"
];
const VALID_SUPPORTED_FORMATS = [
"jpeg",
"jpg",
"png",
"tiff",
"webp",
"gif",
"svg",
"avif"
];
const DEFAULT_OUTPUT_FORMAT = "webp";
const VALID_OUTPUT_FORMATS = ["avif", "png", "webp", "jpeg", "jpg", "svg"];
const DEFAULT_HASH_PROPS = [
"src",
"width",
"height",
"format",
"quality",
"fit",
"position",
"background"
];
export {
DEFAULT_HASH_PROPS,
DEFAULT_OUTPUT_FORMAT,
VALID_INPUT_FORMATS,
VALID_OUTPUT_FORMATS,
VALID_SUPPORTED_FORMATS,
VIRTUAL_MODULE_ID,
VIRTUAL_SERVICE_ID
};

2
node_modules/astro/dist/assets/endpoint/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { AstroSettings, RoutesList } from '../../types/astro.js';
export declare function injectImageEndpoint(settings: AstroSettings, manifest: RoutesList, mode: 'dev' | 'build', cwd?: string): void;

40
node_modules/astro/dist/assets/endpoint/config.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import {
removeLeadingForwardSlash,
removeTrailingForwardSlash
} from "@astrojs/internal-helpers/path";
import { resolveInjectedRoute } from "../../core/routing/manifest/create.js";
import { getPattern } from "../../core/routing/manifest/pattern.js";
function injectImageEndpoint(settings, manifest, mode, cwd) {
manifest.routes.unshift(getImageEndpointData(settings, mode, cwd));
}
function getImageEndpointData(settings, mode, cwd) {
const endpointEntrypoint = settings.config.image.endpoint.entrypoint === void 0 ? mode === "dev" ? "astro/assets/endpoint/dev" : "astro/assets/endpoint/generic" : settings.config.image.endpoint.entrypoint;
const segments = [
[
{
content: removeTrailingForwardSlash(
removeLeadingForwardSlash(settings.config.image.endpoint.route)
),
dynamic: false,
spread: false
}
]
];
return {
type: "endpoint",
isIndex: false,
route: settings.config.image.endpoint.route,
pattern: getPattern(segments, settings.config.base, settings.config.trailingSlash),
segments,
params: [],
component: resolveInjectedRoute(endpointEntrypoint, settings.config.root, cwd).component,
generate: () => "",
pathname: settings.config.image.endpoint.route,
prerender: false,
fallbackRoutes: [],
origin: "internal"
};
}
export {
injectImageEndpoint
};

5
node_modules/astro/dist/assets/endpoint/dev.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../types/public/common.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

76
node_modules/astro/dist/assets/endpoint/dev.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import { safeModulePaths, viteFSConfig } from "astro:assets";
import { readFile } from "node:fs/promises";
import os from "node:os";
import picomatch from "picomatch";
import { isFileLoadingAllowed } from "vite";
import { handleImageRequest, loadRemoteImage } from "./shared.js";
function replaceFileSystemReferences(src) {
return os.platform().includes("win32") ? src.replace(/^\/@fs\//, "") : src.replace(/^\/@fs/, "");
}
async function loadLocalImage(src, url) {
let returnValue;
let fsPath;
if (src.startsWith("/@fs/")) {
fsPath = replaceFileSystemReferences(src);
}
if (fsPath && isFileLoadingAllowed(
{
fsDenyGlob: picomatch(
// matchBase: true does not work as it's documented
// https://github.com/micromatch/picomatch/issues/89
// convert patterns without `/` on our side for now
viteFSConfig.deny.map(
(pattern) => pattern.includes("/") ? pattern : `**/${pattern}`
),
{
matchBase: false,
nocase: true,
dot: true
}
),
server: { fs: viteFSConfig },
safeModulePaths
},
fsPath
)) {
try {
returnValue = await readFile(fsPath);
} catch {
returnValue = void 0;
}
if (!returnValue) {
try {
const res = await fetch(new URL(src, url));
if (res.ok) {
returnValue = Buffer.from(await res.arrayBuffer());
}
} catch {
returnValue = void 0;
}
}
} else {
const sourceUrl = new URL(src, url.origin);
if (sourceUrl.origin !== url.origin) {
returnValue = void 0;
}
return loadRemoteImage(sourceUrl);
}
return returnValue;
}
const GET = async ({ request }) => {
if (!import.meta.env.DEV) {
console.error("The dev image endpoint can only be used in dev mode.");
return new Response("Invalid endpoint", { status: 500 });
}
try {
return await handleImageRequest({ request, loadLocalImage });
} catch (err) {
console.error("Could not process image request:", err);
return new Response(`Could not process image request: ${err}`, {
status: 500
});
}
};
export {
GET
};

5
node_modules/astro/dist/assets/endpoint/generic.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../types/public/common.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

66
node_modules/astro/dist/assets/endpoint/generic.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import { imageConfig } from "astro:assets";
import { isRemotePath } from "@astrojs/internal-helpers/path";
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
async function loadRemoteImage(src, headers) {
try {
const res = await fetch(src, {
// Forward all headers from the original request
headers
});
if (!res.ok) {
return void 0;
}
return await res.arrayBuffer();
} catch {
return void 0;
}
}
const GET = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
if (!("transform" in imageService)) {
throw new Error("Configured image service is not a local service");
}
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
if (!transform?.src) {
throw new Error("Incorrect transform returned by `parseURL`");
}
let inputBuffer = void 0;
const isRemoteImage = isRemotePath(transform.src);
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response("Forbidden", { status: 403 });
}
const sourceUrl = new URL(transform.src, url.origin);
if (!isRemoteImage && sourceUrl.origin !== url.origin) {
return new Response("Forbidden", { status: 403 });
}
inputBuffer = await loadRemoteImage(sourceUrl, isRemoteImage ? new Headers() : request.headers);
if (!inputBuffer) {
return new Response("Not Found", { status: 404 });
}
const { data, format } = await imageService.transform(
new Uint8Array(inputBuffer),
transform,
imageConfig
);
return new Response(data, {
status: 200,
headers: {
"Content-Type": mime.lookup(format) ?? `image/${format}`,
"Cache-Control": "public, max-age=31536000",
ETag: etag(data.toString()),
Date: (/* @__PURE__ */ new Date()).toUTCString()
}
});
} catch (err) {
console.error("Could not process image request:", err);
return new Response(`Server Error: ${err}`, { status: 500 });
}
};
export {
GET
};

5
node_modules/astro/dist/assets/endpoint/node.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../types/public/common.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

56
node_modules/astro/dist/assets/endpoint/node.js generated vendored Normal file
View File

@@ -0,0 +1,56 @@
import { outDir, serverDir } from "astro:assets";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isParentDirectory } from "@astrojs/internal-helpers/path";
import { handleImageRequest } from "./shared.js";
async function loadLocalImage(src, url) {
const outDirURL = resolveOutDir();
const idx = url.pathname.indexOf("/_image");
if (idx > 0) {
src = src.slice(idx);
}
if (!URL.canParse("." + src, outDirURL)) {
return void 0;
}
const fileUrl = new URL("." + src, outDirURL);
if (fileUrl.protocol !== "file:") {
return void 0;
}
if (!isParentDirectory(fileURLToPath(outDirURL), fileURLToPath(fileUrl))) {
return void 0;
}
try {
return await readFile(fileUrl);
} catch {
return void 0;
}
}
const GET = async ({ request }) => {
try {
return await handleImageRequest({ request, loadLocalImage });
} catch (err) {
console.error("Could not process image request:", err);
return new Response("Internal Server Error", {
status: 500
});
}
};
function resolveOutDir() {
const serverDirPath = fileURLToPath(serverDir);
const rel = path.relative(serverDirPath, fileURLToPath(outDir));
const serverFolder = path.basename(serverDirPath);
let serverEntryFolderURL = path.dirname(import.meta.url);
while (!serverEntryFolderURL.endsWith(serverFolder)) {
serverEntryFolderURL = path.dirname(serverEntryFolderURL);
}
const serverEntryURL = serverEntryFolderURL + "/entry.mjs";
const outDirURL = new URL(appendForwardSlash(rel), serverEntryURL);
return outDirURL;
}
function appendForwardSlash(pth) {
return pth.endsWith("/") ? pth : pth + "/";
}
export {
GET
};

5
node_modules/astro/dist/assets/endpoint/shared.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export declare function loadRemoteImage(src: URL): Promise<Buffer | undefined>;
export declare const handleImageRequest: ({ request, loadLocalImage, }: {
request: Request;
loadLocalImage: (src: string, baseUrl: URL) => Promise<Buffer | undefined>;
}) => Promise<Response>;

57
node_modules/astro/dist/assets/endpoint/shared.js generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import { imageConfig } from "astro:assets";
import { isRemotePath, removeQueryString } from "@astrojs/internal-helpers/path";
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
async function loadRemoteImage(src) {
try {
const res = await fetch(src);
if (!res.ok) {
return void 0;
}
return Buffer.from(await res.arrayBuffer());
} catch {
return void 0;
}
}
const handleImageRequest = async ({
request,
loadLocalImage
}) => {
const imageService = await getConfiguredImageService();
if (!("transform" in imageService)) {
throw new Error("Configured image service is not a local service");
}
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
if (!transform?.src) {
return new Response("Invalid request", { status: 400 });
}
let inputBuffer = void 0;
if (isRemotePath(transform.src)) {
if (!isRemoteAllowed(transform.src, imageConfig)) {
return new Response("Forbidden", { status: 403 });
}
inputBuffer = await loadRemoteImage(new URL(transform.src));
} else {
inputBuffer = await loadLocalImage(removeQueryString(transform.src), url);
}
if (!inputBuffer) {
return new Response("Internal Server Error", { status: 500 });
}
const { data, format } = await imageService.transform(inputBuffer, transform, imageConfig);
return new Response(data, {
status: 200,
headers: {
"Content-Type": mime.lookup(format) ?? `image/${format}`,
"Cache-Control": "public, max-age=31536000",
ETag: etag(data.toString()),
Date: (/* @__PURE__ */ new Date()).toUTCString()
}
});
};
export {
handleImageRequest,
loadRemoteImage
};

55
node_modules/astro/dist/assets/fonts/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,55 @@
import { z } from 'zod';
import type { FontProvider } from './types.js';
export declare const weightSchema: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
export declare const styleSchema: z.ZodEnum<["normal", "italic", "oblique"]>;
export declare const displaySchema: z.ZodEnum<["auto", "block", "swap", "fallback", "optional"]>;
export declare const fontProviderSchema: z.ZodType<FontProvider<never>, z.ZodTypeDef, FontProvider<never>>;
export declare const fontFamilySchema: z.ZodObject<{
provider: z.ZodType<FontProvider<never>, z.ZodTypeDef, FontProvider<never>>;
options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
weights: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "atleastone">>;
styles: z.ZodOptional<z.ZodArray<z.ZodEnum<["normal", "italic", "oblique"]>, "atleastone">>;
subsets: z.ZodOptional<z.ZodArray<z.ZodString, "atleastone">>;
formats: z.ZodOptional<z.ZodArray<z.ZodEnum<["woff2", "woff", "otf", "ttf", "eot"]>, "atleastone">>;
display: z.ZodOptional<z.ZodEnum<["auto", "block", "swap", "fallback", "optional"]>>;
stretch: z.ZodOptional<z.ZodString>;
featureSettings: z.ZodOptional<z.ZodString>;
variationSettings: z.ZodOptional<z.ZodString>;
unicodeRange: z.ZodOptional<z.ZodArray<z.ZodString, "atleastone">>;
fallbacks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
name: z.ZodString;
cssVariable: z.ZodString;
}, "strict", z.ZodTypeAny, {
name: string;
cssVariable: string;
provider: FontProvider<never>;
weights?: [string | number, ...(string | number)[]] | undefined;
styles?: ["normal" | "italic" | "oblique", ...("normal" | "italic" | "oblique")[]] | undefined;
subsets?: [string, ...string[]] | undefined;
fallbacks?: string[] | undefined;
optimizedFallbacks?: boolean | undefined;
formats?: ["woff2" | "woff" | "otf" | "ttf" | "eot", ...("woff2" | "woff" | "otf" | "ttf" | "eot")[]] | undefined;
display?: "auto" | "block" | "swap" | "fallback" | "optional" | undefined;
stretch?: string | undefined;
featureSettings?: string | undefined;
variationSettings?: string | undefined;
unicodeRange?: [string, ...string[]] | undefined;
options?: Record<string, any> | undefined;
}, {
name: string;
cssVariable: string;
provider: FontProvider<never>;
weights?: [string | number, ...(string | number)[]] | undefined;
styles?: ["normal" | "italic" | "oblique", ...("normal" | "italic" | "oblique")[]] | undefined;
subsets?: [string, ...string[]] | undefined;
fallbacks?: string[] | undefined;
optimizedFallbacks?: boolean | undefined;
formats?: ["woff2" | "woff" | "otf" | "ttf" | "eot", ...("woff2" | "woff" | "otf" | "ttf" | "eot")[]] | undefined;
display?: "auto" | "block" | "swap" | "fallback" | "optional" | undefined;
stretch?: string | undefined;
featureSettings?: string | undefined;
variationSettings?: string | undefined;
unicodeRange?: [string, ...string[]] | undefined;
options?: Record<string, any> | undefined;
}>;

53
node_modules/astro/dist/assets/fonts/config.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
import { z } from "zod";
import { FONT_TYPES } from "./constants.js";
const weightSchema = z.union([z.string(), z.number()]);
const styleSchema = z.enum(["normal", "italic", "oblique"]);
const displaySchema = z.enum(["auto", "block", "swap", "fallback", "optional"]);
const familyPropertiesSchema = z.object({
weight: weightSchema.optional(),
style: styleSchema.optional(),
display: displaySchema.optional(),
stretch: z.string().optional(),
featureSettings: z.string().optional(),
variationSettings: z.string().optional(),
unicodeRange: z.array(z.string()).nonempty().optional()
});
const fallbacksSchema = z.object({
fallbacks: z.array(z.string()).optional(),
optimizedFallbacks: z.boolean().optional()
});
const requiredFamilyAttributesSchema = z.object({
name: z.string(),
cssVariable: z.string()
});
const _fontProviderSchema = z.object({
name: z.string(),
config: z.record(z.string(), z.any()).optional(),
init: z.custom((v) => typeof v === "function").optional(),
resolveFont: z.custom((v) => typeof v === "function"),
listFonts: z.custom((v) => typeof v === "function").optional()
}).strict();
const fontProviderSchema = z.custom((v) => {
return _fontProviderSchema.safeParse(v).success;
}, "Invalid FontProvider object");
const fontFamilySchema = z.object({
...requiredFamilyAttributesSchema.shape,
...fallbacksSchema.shape,
...familyPropertiesSchema.omit({
weight: true,
style: true
}).shape,
provider: fontProviderSchema,
options: z.record(z.string(), z.any()).optional(),
weights: z.array(weightSchema).nonempty().optional(),
styles: z.array(styleSchema).nonempty().optional(),
subsets: z.array(z.string()).nonempty().optional(),
formats: z.array(z.enum(FONT_TYPES)).nonempty().optional()
}).strict();
export {
displaySchema,
fontFamilySchema,
fontProviderSchema,
styleSchema,
weightSchema
};

15
node_modules/astro/dist/assets/fonts/constants.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import type { Defaults, FontType } from './types.js';
export declare const DEFAULTS: Defaults;
export declare const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
export declare const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
export declare const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID: string;
export declare const ASSETS_DIR = "fonts";
export declare const CACHE_DIR = "./fonts/";
export declare const FONT_TYPES: readonly ["woff2", "woff", "otf", "ttf", "eot"];
export declare const FONT_FORMATS: Array<{
type: FontType;
format: string;
}>;
export declare const GENERIC_FALLBACK_NAMES: readonly ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded", "emoji", "math", "fangsong"];
export declare const FONTS_TYPES_FILE = "fonts.d.ts";

52
node_modules/astro/dist/assets/fonts/constants.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
const DEFAULTS = {
weights: ["400"],
styles: ["normal", "italic"],
subsets: ["latin"],
// Technically serif is the browser default but most websites these days use sans-serif
fallbacks: ["sans-serif"],
optimizedFallbacks: true,
formats: ["woff2"]
};
const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID = "\0" + RUNTIME_VIRTUAL_MODULE_ID;
const ASSETS_DIR = "fonts";
const CACHE_DIR = "./fonts/";
const FONT_TYPES = ["woff2", "woff", "otf", "ttf", "eot"];
const FONT_FORMATS = [
{ type: "woff2", format: "woff2" },
{ type: "woff", format: "woff" },
{ type: "otf", format: "opentype" },
{ type: "ttf", format: "truetype" },
{ type: "eot", format: "embedded-opentype" }
];
const GENERIC_FALLBACK_NAMES = [
"serif",
"sans-serif",
"monospace",
"cursive",
"fantasy",
"system-ui",
"ui-serif",
"ui-sans-serif",
"ui-monospace",
"ui-rounded",
"emoji",
"math",
"fangsong"
];
const FONTS_TYPES_FILE = "fonts.d.ts";
export {
ASSETS_DIR,
CACHE_DIR,
DEFAULTS,
FONTS_TYPES_FILE,
FONT_FORMATS,
FONT_TYPES,
GENERIC_FALLBACK_NAMES,
RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
RUNTIME_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
};

View File

@@ -0,0 +1,9 @@
import type { CssRenderer } from '../definitions.js';
import type { Collaborator, ComponentDataByCssVariable, Defaults, FontFamilyAssets } from '../types.js';
import type { optimizeFallbacks as _optimizeFallbacks } from './optimize-fallbacks.js';
export declare function collectComponentData({ fontFamilyAssets, cssRenderer, defaults, optimizeFallbacks, }: {
fontFamilyAssets: Array<FontFamilyAssets>;
cssRenderer: CssRenderer;
defaults: Pick<Defaults, 'fallbacks' | 'optimizedFallbacks'>;
optimizeFallbacks: Collaborator<typeof _optimizeFallbacks, 'family' | 'fallbacks' | 'collectedFonts'>;
}): Promise<ComponentDataByCssVariable>;

View File

@@ -0,0 +1,47 @@
import { unifontFontFaceDataToProperties } from "../utils.js";
async function collectComponentData({
fontFamilyAssets,
cssRenderer,
defaults,
optimizeFallbacks
}) {
const componentDataByCssVariable = /* @__PURE__ */ new Map();
for (const { family, fonts, collectedFontsForMetricsByUniqueKey, preloads } of fontFamilyAssets) {
let css = "";
for (const data of fonts) {
css += cssRenderer.generateFontFace(
family.uniqueName,
unifontFontFaceDataToProperties({
src: data.src,
weight: data.weight,
style: data.style,
// User settings override the generated font settings
display: data.display ?? family.display,
unicodeRange: data.unicodeRange ?? family.unicodeRange,
stretch: data.stretch ?? family.stretch,
featureSettings: data.featureSettings ?? family.featureSettings,
variationSettings: data.variationSettings ?? family.variationSettings
})
);
}
const fallbacks = family.fallbacks ?? defaults.fallbacks;
const cssVarValues = [family.uniqueName];
const optimizeFallbacksResult = family.optimizedFallbacks ?? defaults.optimizedFallbacks ? await optimizeFallbacks({
family,
fallbacks,
collectedFonts: Array.from(collectedFontsForMetricsByUniqueKey.values())
}) : null;
if (optimizeFallbacksResult) {
css += optimizeFallbacksResult.css;
cssVarValues.push(...optimizeFallbacksResult.fallbacks);
} else {
cssVarValues.push(...fallbacks);
}
css += cssRenderer.generateCssVariable(family.cssVariable, cssVarValues);
componentDataByCssVariable.set(family.cssVariable, { preloads, css });
}
return componentDataByCssVariable;
}
export {
collectComponentData
};

View File

@@ -0,0 +1,17 @@
import type * as unifont from 'unifont';
import type { FontFileIdGenerator, Hasher } from '../definitions.js';
import type { Defaults, FontFileById, PreloadData, ResolvedFontFamily } from '../types.js';
import type { CollectedFontForMetrics } from './optimize-fallbacks.js';
export declare function collectFontAssetsFromFaces({ fonts, fontFileIdGenerator, family, fontFilesIds, collectedFontsIds, hasher, defaults, }: {
fonts: Array<unifont.FontFaceData>;
fontFileIdGenerator: FontFileIdGenerator;
family: Pick<ResolvedFontFamily, 'cssVariable' | 'fallbacks'>;
fontFilesIds: Set<string>;
collectedFontsIds: Set<string>;
hasher: Hasher;
defaults: Pick<Defaults, 'fallbacks'>;
}): {
fontFileById: FontFileById;
preloads: PreloadData[];
collectedFontsForMetricsByUniqueKey: Map<string, CollectedFontForMetrics>;
};

View File

@@ -0,0 +1,71 @@
import { FONT_FORMATS } from "../constants.js";
import { renderFontWeight } from "../utils.js";
function collectFontAssetsFromFaces({
fonts,
fontFileIdGenerator,
family,
fontFilesIds,
collectedFontsIds,
hasher,
defaults
}) {
const fontFileById = /* @__PURE__ */ new Map();
const collectedFontsForMetricsByUniqueKey = /* @__PURE__ */ new Map();
const preloads = [];
for (const font of fonts) {
let index = 0;
for (const source of font.src) {
if ("name" in source) {
continue;
}
const format = FONT_FORMATS.find((e) => e.format === source.format);
const originalUrl = source.originalURL;
const id = fontFileIdGenerator.generate({
cssVariable: family.cssVariable,
font,
originalUrl,
type: format.type
});
if (!fontFilesIds.has(id) && !fontFileById.has(id)) {
fontFileById.set(id, { url: originalUrl, init: font.meta?.init });
if (index === 0) {
preloads.push({
style: font.style,
subset: font.meta?.subset,
type: format.type,
url: source.url,
weight: renderFontWeight(font.weight)
});
}
}
const collected = {
id,
url: originalUrl,
init: font.meta?.init,
data: {
weight: font.weight,
style: font.style,
meta: {
subset: font.meta?.subset
}
}
};
const collectedKey = hasher.hashObject(collected.data);
const fallbacks = family.fallbacks ?? defaults.fallbacks;
if (fallbacks.length > 0 && // If the same data has already been sent for this family, we don't want to have
// duplicated fallbacks. Such scenario can occur with unicode ranges.
!collectedFontsIds.has(collectedKey) && !collectedFontsForMetricsByUniqueKey.has(collectedKey)) {
collectedFontsForMetricsByUniqueKey.set(collectedKey, collected);
}
index++;
}
}
return {
fontFileById,
preloads,
collectedFontsForMetricsByUniqueKey
};
}
export {
collectFontAssetsFromFaces
};

View File

@@ -0,0 +1,4 @@
import type { FontDataByCssVariable, FontFamilyAssets } from '../types.js';
export declare function collectFontData(fontFamilyAssets: Array<Pick<FontFamilyAssets, 'fonts'> & {
family: Pick<FontFamilyAssets['family'], 'cssVariable'>;
}>): FontDataByCssVariable;

View File

@@ -0,0 +1,23 @@
import { renderFontWeight } from "../utils.js";
function collectFontData(fontFamilyAssets) {
const fontDataByCssVariable = {};
for (const { family, fonts } of fontFamilyAssets) {
const fontData = [];
for (const data of fonts) {
fontData.push({
weight: renderFontWeight(data.weight),
style: data.style,
src: data.src.filter((src) => "url" in src).map((src) => ({
url: src.url,
format: src.format,
tech: src.tech
}))
});
}
fontDataByCssVariable[family.cssVariable] = fontData;
}
return fontDataByCssVariable;
}
export {
collectFontData
};

View File

@@ -0,0 +1,20 @@
import type { Logger } from '../../../core/logger/core.js';
import type { FontResolver, StringMatcher } from '../definitions.js';
import type { Collaborator, Defaults, FontFileById, ResolvedFontFamily } from '../types.js';
import type { collectFontAssetsFromFaces as _collectFontAssetsFromFaces } from './collect-font-assets-from-faces.js';
import type { filterAndTransformFontFaces as _filterAndTransformFontFaces } from './filter-and-transform-font-faces.js';
import type { getOrCreateFontFamilyAssets as _getOrCreateFontFamilyAssets } from './get-or-create-font-family-assets.js';
export declare function computeFontFamiliesAssets({ resolvedFamilies, fontResolver, logger, bold, defaults, stringMatcher, getOrCreateFontFamilyAssets, collectFontAssetsFromFaces, filterAndTransformFontFaces, }: {
resolvedFamilies: Array<ResolvedFontFamily>;
fontResolver: FontResolver;
logger: Logger;
bold: (input: string) => string;
defaults: Defaults;
stringMatcher: StringMatcher;
getOrCreateFontFamilyAssets: Collaborator<typeof _getOrCreateFontFamilyAssets, 'family' | 'fontFamilyAssetsByUniqueKey'>;
filterAndTransformFontFaces: Collaborator<typeof _filterAndTransformFontFaces, 'family' | 'fonts'>;
collectFontAssetsFromFaces: Collaborator<typeof _collectFontAssetsFromFaces, 'family' | 'fonts' | 'collectedFontsIds' | 'fontFilesIds'>;
}): Promise<{
fontFamilyAssets: import("../types.js").FontFamilyAssets[];
fontFileById: FontFileById;
}>;

View File

@@ -0,0 +1,67 @@
async function computeFontFamiliesAssets({
resolvedFamilies,
fontResolver,
logger,
bold,
defaults,
stringMatcher,
getOrCreateFontFamilyAssets,
collectFontAssetsFromFaces,
filterAndTransformFontFaces
}) {
const fontFamilyAssetsByUniqueKey = /* @__PURE__ */ new Map();
const fontFileById = /* @__PURE__ */ new Map();
for (const family of resolvedFamilies) {
const fontAssets = getOrCreateFontFamilyAssets({
fontFamilyAssetsByUniqueKey,
family
});
const _fonts = await fontResolver.resolveFont({
familyName: family.name,
provider: family.provider,
// We do not merge the defaults, we only provide defaults as a fallback
weights: family.weights ?? defaults.weights,
styles: family.styles ?? defaults.styles,
subsets: family.subsets ?? defaults.subsets,
formats: family.formats ?? defaults.formats,
options: family.options
});
if (_fonts.length === 0) {
logger.warn(
"assets",
`No data found for font family ${bold(family.name)}. Review your configuration`
);
const availableFamilies = await fontResolver.listFonts({ provider: family.provider });
if (availableFamilies && availableFamilies.length > 0 && !availableFamilies.includes(family.name)) {
logger.warn(
"assets",
`${bold(family.name)} font family cannot be retrieved by the provider. Did you mean ${bold(stringMatcher.getClosestMatch(family.name, availableFamilies))}?`
);
}
continue;
}
fontAssets.fonts.push(
...filterAndTransformFontFaces({
fonts: _fonts,
family
})
);
const result = collectFontAssetsFromFaces({
fonts: fontAssets.fonts,
family,
fontFilesIds: new Set(fontFileById.keys()),
collectedFontsIds: new Set(fontAssets.collectedFontsForMetricsByUniqueKey.keys())
});
for (const [key, value] of result.fontFileById.entries()) {
fontFileById.set(key, value);
}
for (const [key, value] of result.collectedFontsForMetricsByUniqueKey.entries()) {
fontAssets.collectedFontsForMetricsByUniqueKey.set(key, value);
}
fontAssets.preloads.push(...result.preloads);
}
return { fontFamilyAssets: Array.from(fontFamilyAssetsByUniqueKey.values()), fontFileById };
}
export {
computeFontFamiliesAssets
};

View File

@@ -0,0 +1,20 @@
import type * as unifont from 'unifont';
import type { FontFileIdGenerator, FontTypeExtractor, UrlResolver } from '../definitions.js';
import type { ResolvedFontFamily } from '../types.js';
export declare function filterAndTransformFontFaces({ fonts, fontTypeExtractor, fontFileIdGenerator, urlResolver, family, }: {
fonts: Array<unifont.FontFaceData>;
fontTypeExtractor: FontTypeExtractor;
fontFileIdGenerator: FontFileIdGenerator;
urlResolver: UrlResolver;
family: Pick<ResolvedFontFamily, 'cssVariable'>;
}): {
src: (unifont.LocalFontSource | unifont.RemoteFontSource)[];
display?: "auto" | "block" | "swap" | "fallback" | "optional";
weight?: string | number | [number, number];
stretch?: string;
style?: string;
unicodeRange?: string[];
featureSettings?: string;
variationSettings?: string;
meta?: unifont.FontFaceMeta;
}[];

View File

@@ -0,0 +1,39 @@
import { FONT_FORMATS } from "../constants.js";
function filterAndTransformFontFaces({
fonts,
fontTypeExtractor,
fontFileIdGenerator,
urlResolver,
family
}) {
return fonts.filter((font) => typeof font.meta?.priority === "number" ? font.meta.priority <= 1 : true).map((font) => ({
...font,
src: font.src.map((source) => {
if ("name" in source) {
return source;
}
const originalUrl = source.url.startsWith("//") ? `https:${source.url}` : source.url;
let format = FONT_FORMATS.find((e) => e.format === source.format);
if (!format) {
format = FONT_FORMATS.find((e) => e.type === fontTypeExtractor.extract(source.url));
}
const id = fontFileIdGenerator.generate({
cssVariable: family.cssVariable,
font,
originalUrl,
type: format.type
});
const url = urlResolver.resolve(id);
const newSource = {
originalURL: originalUrl,
url,
format: format.format,
tech: source.tech
};
return newSource;
})
}));
}
export {
filterAndTransformFontFaces
};

View File

@@ -0,0 +1,2 @@
import type { PreloadData, PreloadFilter } from '../types.js';
export declare function filterPreloads(data: Array<PreloadData>, preload: PreloadFilter): Array<PreloadData> | null;

View File

@@ -0,0 +1,37 @@
function filterPreloads(data, preload) {
if (!preload) {
return null;
}
if (preload === true) {
return data;
}
return data.filter(
({ weight, style, subset }) => preload.some((p) => {
if (p.weight !== void 0 && weight !== void 0 && !checkWeight(p.weight.toString(), weight)) {
return false;
}
if (p.style !== void 0 && p.style !== style) {
return false;
}
if (p.subset !== void 0 && p.subset !== subset) {
return false;
}
return true;
})
);
}
function checkWeight(input, target) {
const trimmedInput = input.trim();
if (trimmedInput.includes(" ")) {
return trimmedInput === target;
}
if (target.includes(" ")) {
const [a, b] = target.split(" ");
const parsedInput = Number.parseInt(input);
return parsedInput >= Number.parseInt(a) && parsedInput <= Number.parseInt(b);
}
return input === target;
}
export {
filterPreloads
};

View File

@@ -0,0 +1,8 @@
import type { Logger } from '../../../core/logger/core.js';
import type { FontFamilyAssetsByUniqueKey, ResolvedFontFamily } from '../types.js';
export declare function getOrCreateFontFamilyAssets({ fontFamilyAssetsByUniqueKey, logger, bold, family, }: {
fontFamilyAssetsByUniqueKey: FontFamilyAssetsByUniqueKey;
logger: Logger;
bold: (input: string) => string;
family: ResolvedFontFamily;
}): import("../types.js").FontFamilyAssets;

View File

@@ -0,0 +1,34 @@
function getOrCreateFontFamilyAssets({
fontFamilyAssetsByUniqueKey,
logger,
bold,
family
}) {
const key = `${family.cssVariable}:${family.name}:${family.provider.name}`;
let fontAssets = fontFamilyAssetsByUniqueKey.get(key);
if (!fontAssets) {
if (Array.from(fontFamilyAssetsByUniqueKey.keys()).find(
(k) => k.startsWith(`${family.cssVariable}:`)
)) {
logger.warn(
"assets",
`Several font families have been registered for the ${bold(family.cssVariable)} cssVariable but they do not share the same name and provider.`
);
logger.warn(
"assets",
"These families will not be merged together. The last occurrence will override previous families for this cssVariable. Review your Astro configuration."
);
}
fontAssets = {
family,
fonts: [],
collectedFontsForMetricsByUniqueKey: /* @__PURE__ */ new Map(),
preloads: []
};
fontFamilyAssetsByUniqueKey.set(key, fontAssets);
}
return fontAssets;
}
export {
getOrCreateFontFamilyAssets
};

View File

@@ -0,0 +1,16 @@
import type * as unifont from 'unifont';
import type { FontMetricsResolver, SystemFallbacksProvider } from '../definitions.js';
import type { FontFileData, ResolvedFontFamily } from '../types.js';
export interface CollectedFontForMetrics extends FontFileData {
data: Partial<unifont.FontFaceData>;
}
export declare function optimizeFallbacks({ family, fallbacks: _fallbacks, collectedFonts, systemFallbacksProvider, fontMetricsResolver, }: {
family: Pick<ResolvedFontFamily, 'name' | 'uniqueName'>;
fallbacks: Array<string>;
collectedFonts: Array<CollectedFontForMetrics>;
systemFallbacksProvider: SystemFallbacksProvider;
fontMetricsResolver: FontMetricsResolver;
}): Promise<null | {
css: string;
fallbacks: Array<string>;
}>;

View File

@@ -0,0 +1,46 @@
import { isGenericFontFamily, unifontFontFaceDataToProperties } from "../utils.js";
async function optimizeFallbacks({
family,
fallbacks: _fallbacks,
collectedFonts,
systemFallbacksProvider,
fontMetricsResolver
}) {
let fallbacks = [..._fallbacks];
if (fallbacks.length === 0 || collectedFonts.length === 0) {
return null;
}
const lastFallback = fallbacks[fallbacks.length - 1];
if (!isGenericFontFamily(lastFallback)) {
return null;
}
const localFonts = systemFallbacksProvider.getLocalFonts(lastFallback);
if (!localFonts || localFonts.length === 0) {
return null;
}
if (localFonts.includes(family.name)) {
return null;
}
const localFontsMappings = localFonts.map((font) => ({
font,
// We mustn't wrap in quote because that's handled by the CSS renderer
name: `${family.uniqueName} fallback: ${font}`
}));
fallbacks = [...localFontsMappings.map((m) => m.name), ...fallbacks];
let css = "";
for (const { font, name } of localFontsMappings) {
for (const collected of collectedFonts) {
css += fontMetricsResolver.generateFontFace({
metrics: await fontMetricsResolver.getMetrics(family.name, collected),
fallbackMetrics: systemFallbacksProvider.getMetricsForLocalFont(font),
font,
name,
properties: unifontFontFaceDataToProperties(collected.data)
});
}
}
return { css, fallbacks };
}
export {
optimizeFallbacks
};

View File

@@ -0,0 +1,6 @@
import type { Hasher } from '../definitions.js';
import type { FontFamily, ResolvedFontFamily } from '../types.js';
export declare function resolveFamily({ family, hasher, }: {
family: FontFamily;
hasher: Hasher;
}): ResolvedFontFamily;

View File

@@ -0,0 +1,23 @@
import { dedupe, withoutQuotes } from "../utils.js";
function resolveFamily({
family,
hasher
}) {
const name = withoutQuotes(family.name);
return {
...family,
name,
// This will be used in CSS font faces. Quotes are added by the CSS renderer if
// this value contains a space.
uniqueName: `${name}-${hasher.hashObject(family)}`,
weights: family.weights ? dedupe(family.weights.map((weight) => weight.toString())) : void 0,
styles: family.styles ? dedupe(family.styles) : void 0,
subsets: family.subsets ? dedupe(family.subsets) : void 0,
formats: family.formats ? dedupe(family.formats) : void 0,
fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0,
unicodeRange: family.unicodeRange ? dedupe(family.unicodeRange) : void 0
};
}
export {
resolveFamily
};

72
node_modules/astro/dist/assets/fonts/definitions.d.ts generated vendored Normal file
View File

@@ -0,0 +1,72 @@
import type * as unifont from 'unifont';
import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js';
import type { CssProperties, FontFaceMetrics, FontFileData, FontProvider, FontType, GenericFallbackName, ResolveFontOptions, Style } from './types.js';
export interface Hasher {
hashString: (input: string) => string;
hashObject: (input: Record<string, any>) => string;
}
export interface UrlResolver {
resolve: (id: string) => string;
readonly cspResources: Array<string>;
}
export interface FontFileContentResolver {
resolve: (url: string) => string;
}
export interface CssRenderer {
generateFontFace: (family: string, properties: CssProperties) => string;
generateCssVariable: (key: string, values: Array<string>) => string;
}
export interface FontMetricsResolver {
getMetrics: (name: string, font: CollectedFontForMetrics) => Promise<FontFaceMetrics>;
generateFontFace: (input: {
metrics: FontFaceMetrics;
fallbackMetrics: FontFaceMetrics;
name: string;
font: string;
properties: CssProperties;
}) => string;
}
export interface SystemFallbacksProvider {
getLocalFonts: (fallback: GenericFallbackName) => Array<string> | null;
getMetricsForLocalFont: (family: string) => FontFaceMetrics;
}
export interface FontFetcher {
fetch: (input: FontFileData) => Promise<Buffer>;
}
export interface FontTypeExtractor {
extract: (url: string) => FontType;
}
export interface FontFileReader {
extract: (input: {
family: string;
url: string;
}) => {
weight: string;
style: Style;
};
}
export interface FontFileIdGenerator {
generate: (input: {
originalUrl: string;
type: FontType;
cssVariable: string;
font: unifont.FontFaceData;
}) => string;
}
export interface StringMatcher {
getClosestMatch: (target: string, candidates: Array<string>) => string;
}
export interface Storage {
getItem: (key: string) => Promise<any | null>;
getItemRaw: (key: string) => Promise<Buffer | null>;
setItem: (key: string, value: any) => Promise<void>;
setItemRaw: (key: string, value: any) => Promise<void>;
}
export interface FontResolver {
resolveFont: (options: ResolveFontOptions<Record<string, any>> & {
provider: FontProvider;
}) => Promise<Array<unifont.FontFaceData>>;
listFonts: (options: {
provider: FontProvider;
}) => Promise<string[] | undefined>;
}

0
node_modules/astro/dist/assets/fonts/definitions.js generated vendored Normal file
View File

View File

@@ -0,0 +1,13 @@
import type { FontFileContentResolver, FontFileIdGenerator, Hasher } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class BuildFontFileIdGenerator implements FontFileIdGenerator {
#private;
constructor({ hasher, contentResolver, }: {
hasher: Hasher;
contentResolver: FontFileContentResolver;
});
generate({ originalUrl, type }: {
originalUrl: string;
type: FontType;
}): string;
}

View File

@@ -0,0 +1,17 @@
class BuildFontFileIdGenerator {
#hasher;
#contentResolver;
constructor({
hasher,
contentResolver
}) {
this.#hasher = hasher;
this.#contentResolver = contentResolver;
}
generate({ originalUrl, type }) {
return `${this.#hasher.hashString(this.#contentResolver.resolve(originalUrl))}.${type}`;
}
}
export {
BuildFontFileIdGenerator
};

View File

@@ -0,0 +1,12 @@
import type { AssetsPrefix } from '../../../types/public/index.js';
import type { UrlResolver } from '../definitions.js';
export declare class BuildUrlResolver implements UrlResolver {
#private;
constructor({ base, assetsPrefix, searchParams, }: {
base: string;
assetsPrefix: AssetsPrefix;
searchParams: URLSearchParams;
});
resolve(id: string): string;
get cspResources(): Array<string>;
}

View File

@@ -0,0 +1,40 @@
import { fileExtension, joinPaths, prependForwardSlash } from "../../../core/path.js";
import { getAssetsPrefix } from "../../utils/getAssetsPrefix.js";
import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
class BuildUrlResolver {
#resources = /* @__PURE__ */ new Set();
#base;
#assetsPrefix;
#searchParams;
constructor({
base,
assetsPrefix,
searchParams
}) {
this.#base = base;
this.#assetsPrefix = assetsPrefix;
this.#searchParams = searchParams;
}
resolve(id) {
const prefix = this.#assetsPrefix ? getAssetsPrefix(fileExtension(id), this.#assetsPrefix) : void 0;
let urlPath;
if (prefix) {
this.#resources.add(prefix);
urlPath = joinPaths(prefix, this.#base, id);
} else {
this.#resources.add("'self'");
urlPath = prependForwardSlash(joinPaths(this.#base, id));
}
const url = createPlaceholderURL(urlPath);
this.#searchParams.forEach((value, key) => {
url.searchParams.set(key, value);
});
return stringifyPlaceholderURL(url);
}
get cspResources() {
return Array.from(this.#resources);
}
}
export {
BuildUrlResolver
};

View File

@@ -0,0 +1,11 @@
import type { FontFetcher, Storage } from '../definitions.js';
import type { FontFileData } from '../types.js';
export declare class CachedFontFetcher implements FontFetcher {
#private;
constructor({ storage, fetch, readFile, }: {
storage: Storage;
fetch: (url: string, init?: RequestInit) => Promise<Response>;
readFile: (url: string) => Promise<Buffer>;
});
fetch({ id, url, init }: FontFileData): Promise<Buffer>;
}

View File

@@ -0,0 +1,50 @@
import { isAbsolute } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class CachedFontFetcher {
#storage;
#fetch;
#readFile;
constructor({
storage,
fetch,
readFile
}) {
this.#storage = storage;
this.#fetch = fetch;
this.#readFile = readFile;
}
async #cache(storage, key, cb) {
const existing = await storage.getItemRaw(key);
if (existing) {
return existing;
}
const data = await cb();
await storage.setItemRaw(key, data);
return data;
}
async fetch({ id, url, init }) {
return await this.#cache(this.#storage, id, async () => {
try {
if (isAbsolute(url)) {
return await this.#readFile(url);
}
const response = await this.#fetch(url, init ?? void 0);
if (!response.ok) {
throw new Error(`Response was not successful, received status code ${response.status}`);
}
return Buffer.from(await response.arrayBuffer());
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotFetchFontFile,
message: AstroErrorData.CannotFetchFontFile.message(url)
},
{ cause }
);
}
});
}
}
export {
CachedFontFetcher
};

View File

@@ -0,0 +1,18 @@
import type { CollectedFontForMetrics } from '../core/optimize-fallbacks.js';
import type { CssRenderer, FontFetcher, FontMetricsResolver } from '../definitions.js';
import type { CssProperties, FontFaceMetrics } from '../types.js';
export declare class CapsizeFontMetricsResolver implements FontMetricsResolver {
#private;
constructor({ fontFetcher, cssRenderer, }: {
fontFetcher: FontFetcher;
cssRenderer: CssRenderer;
});
getMetrics(name: string, font: CollectedFontForMetrics): Promise<FontFaceMetrics>;
generateFontFace({ metrics, fallbackMetrics, name: fallbackName, font: fallbackFontName, properties, }: {
metrics: FontFaceMetrics;
fallbackMetrics: FontFaceMetrics;
name: string;
font: string;
properties: CssProperties;
}): string;
}

View File

@@ -0,0 +1,71 @@
import { fromBuffer } from "@capsizecss/unpack";
import { renderFontSrc } from "../utils.js";
function filterRequiredMetrics({
ascent,
descent,
lineGap,
unitsPerEm,
xWidthAvg
}) {
return {
ascent,
descent,
lineGap,
unitsPerEm,
xWidthAvg
};
}
function round(value) {
return parseFloat(value.toFixed(4));
}
function toPercentString(value) {
return `${round(value * 100)}%`;
}
class CapsizeFontMetricsResolver {
#cache = {};
#fontFetcher;
#cssRenderer;
constructor({
fontFetcher,
cssRenderer
}) {
this.#fontFetcher = fontFetcher;
this.#cssRenderer = cssRenderer;
}
async getMetrics(name, font) {
return this.#cache[name] ??= filterRequiredMetrics(
await fromBuffer(await this.#fontFetcher.fetch(font))
);
}
// Adapted from Capsize
// Source: https://github.com/seek-oss/capsize/blob/b752693428b45994442433f7e3476ca4e3e3c507/packages/core/src/createFontStack.ts
generateFontFace({
metrics,
fallbackMetrics,
name: fallbackName,
font: fallbackFontName,
properties
}) {
const preferredFontXAvgRatio = metrics.xWidthAvg / metrics.unitsPerEm;
const fallbackFontXAvgRatio = fallbackMetrics.xWidthAvg / fallbackMetrics.unitsPerEm;
const sizeAdjust = preferredFontXAvgRatio && fallbackFontXAvgRatio ? preferredFontXAvgRatio / fallbackFontXAvgRatio : 1;
const adjustedEmSquare = metrics.unitsPerEm * sizeAdjust;
const ascentOverride = metrics.ascent / adjustedEmSquare;
const descentOverride = Math.abs(metrics.descent) / adjustedEmSquare;
const lineGapOverride = metrics.lineGap / adjustedEmSquare;
const fallbackAscentOverride = fallbackMetrics.ascent / adjustedEmSquare;
const fallbackDescentOverride = Math.abs(fallbackMetrics.descent) / adjustedEmSquare;
const fallbackLineGapOverride = fallbackMetrics.lineGap / adjustedEmSquare;
return this.#cssRenderer.generateFontFace(fallbackName, {
...properties,
src: renderFontSrc([{ name: fallbackFontName }]),
"size-adjust": sizeAdjust && sizeAdjust !== 1 ? toPercentString(sizeAdjust) : void 0,
"ascent-override": ascentOverride && ascentOverride !== fallbackAscentOverride ? toPercentString(ascentOverride) : void 0,
"descent-override": descentOverride && descentOverride !== fallbackDescentOverride ? toPercentString(descentOverride) : void 0,
"line-gap-override": lineGapOverride !== fallbackLineGapOverride ? toPercentString(lineGapOverride) : void 0
});
}
}
export {
CapsizeFontMetricsResolver
};

View File

@@ -0,0 +1,16 @@
import type * as unifont from 'unifont';
import type { FontFileContentResolver, FontFileIdGenerator, Hasher } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class DevFontFileIdGenerator implements FontFileIdGenerator {
#private;
constructor({ hasher, contentResolver, }: {
hasher: Hasher;
contentResolver: FontFileContentResolver;
});
generate({ cssVariable, originalUrl, type, font, }: {
originalUrl: string;
type: FontType;
cssVariable: string;
font: unifont.FontFaceData;
}): string;
}

View File

@@ -0,0 +1,37 @@
class DevFontFileIdGenerator {
#hasher;
#contentResolver;
constructor({
hasher,
contentResolver
}) {
this.#hasher = hasher;
this.#contentResolver = contentResolver;
}
#formatWeight(weight) {
if (Array.isArray(weight)) {
return weight.join("-");
}
if (typeof weight === "number") {
return weight.toString();
}
return weight?.replace(/\s+/g, "-");
}
generate({
cssVariable,
originalUrl,
type,
font
}) {
return [
cssVariable.slice(2),
this.#formatWeight(font.weight),
font.style,
font.meta?.subset,
`${this.#hasher.hashString(this.#contentResolver.resolve(originalUrl))}.${type}`
].filter(Boolean).join("-");
}
}
export {
DevFontFileIdGenerator
};

View File

@@ -0,0 +1,10 @@
import type { UrlResolver } from '../definitions.js';
export declare class DevUrlResolver implements UrlResolver {
#private;
constructor({ base, searchParams, }: {
base: string;
searchParams: URLSearchParams;
});
resolve(id: string): string;
get cspResources(): Array<string>;
}

View File

@@ -0,0 +1,29 @@
import { joinPaths, prependForwardSlash } from "../../../core/path.js";
import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
class DevUrlResolver {
#resolved = false;
#base;
#searchParams;
constructor({
base,
searchParams
}) {
this.#base = base;
this.#searchParams = searchParams;
}
resolve(id) {
this.#resolved ||= true;
const urlPath = prependForwardSlash(joinPaths(this.#base, id));
const url = createPlaceholderURL(urlPath);
this.#searchParams.forEach((value, key) => {
url.searchParams.set(key, value);
});
return stringifyPlaceholderURL(url);
}
get cspResources() {
return this.#resolved ? ["'self'"] : [];
}
}
export {
DevUrlResolver
};

View File

@@ -0,0 +1,11 @@
import type { FontFileReader } from '../definitions.js';
import type { Style } from '../types.js';
export declare class FontaceFontFileReader implements FontFileReader {
extract({ family, url }: {
family: string;
url: string;
}): {
weight: string;
style: Style;
};
}

View File

@@ -0,0 +1,25 @@
import { readFileSync } from "node:fs";
import { fontace } from "fontace";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class FontaceFontFileReader {
extract({ family, url }) {
try {
const data = fontace(readFileSync(url));
return {
weight: data.weight,
style: data.style
};
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotDetermineWeightAndStyleFromFontFile,
message: AstroErrorData.CannotDetermineWeightAndStyleFromFontFile.message(family, url)
},
{ cause }
);
}
}
}
export {
FontaceFontFileReader
};

View File

@@ -0,0 +1,10 @@
import type { FontFileContentResolver } from '../definitions.js';
type ReadFileSync = (path: string) => string;
export declare class FsFontFileContentResolver implements FontFileContentResolver {
#private;
constructor({ readFileSync }: {
readFileSync: ReadFileSync;
});
resolve(url: string): string;
}
export {};

View File

@@ -0,0 +1,21 @@
import { isAbsolute } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class FsFontFileContentResolver {
#readFileSync;
constructor({ readFileSync }) {
this.#readFileSync = readFileSync;
}
resolve(url) {
if (!isAbsolute(url)) {
return url;
}
try {
return url + this.#readFileSync(url);
} catch (cause) {
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
}
}
}
export {
FsFontFileContentResolver
};

View File

@@ -0,0 +1,5 @@
import type { StringMatcher } from '../definitions.js';
export declare class LevenshteinStringMatcher implements StringMatcher {
#private;
getClosestMatch(target: string, candidates: Array<string>): string;
}

View File

@@ -0,0 +1,145 @@
class LevenshteinStringMatcher {
#peq = new Uint32Array(65536);
#myers_32(a, b) {
const n = a.length;
const m = b.length;
const lst = 1 << n - 1;
let pv = -1;
let mv = 0;
let sc = n;
let i = n;
while (i--) {
this.#peq[a.charCodeAt(i)] |= 1 << i;
}
for (i = 0; i < m; i++) {
let eq = this.#peq[b.charCodeAt(i)];
const xv = eq | mv;
eq |= (eq & pv) + pv ^ pv;
mv |= ~(eq | pv);
pv &= eq;
if (mv & lst) {
sc++;
}
if (pv & lst) {
sc--;
}
mv = mv << 1 | 1;
pv = pv << 1 | ~(xv | mv);
mv &= xv;
}
i = n;
while (i--) {
this.#peq[a.charCodeAt(i)] = 0;
}
return sc;
}
#myers_x(b, a) {
const n = a.length;
const m = b.length;
const mhc = [];
const phc = [];
const hsize = Math.ceil(n / 32);
const vsize = Math.ceil(m / 32);
for (let i = 0; i < hsize; i++) {
phc[i] = -1;
mhc[i] = 0;
}
let j = 0;
for (; j < vsize - 1; j++) {
let mv2 = 0;
let pv2 = -1;
const start2 = j * 32;
const vlen2 = Math.min(32, m) + start2;
for (let k = start2; k < vlen2; k++) {
this.#peq[b.charCodeAt(k)] |= 1 << k;
}
for (let i = 0; i < n; i++) {
const eq = this.#peq[a.charCodeAt(i)];
const pb = phc[i / 32 | 0] >>> i & 1;
const mb = mhc[i / 32 | 0] >>> i & 1;
const xv = eq | mv2;
const xh = ((eq | mb) & pv2) + pv2 ^ pv2 | eq | mb;
let ph = mv2 | ~(xh | pv2);
let mh = pv2 & xh;
if (ph >>> 31 ^ pb) {
phc[i / 32 | 0] ^= 1 << i;
}
if (mh >>> 31 ^ mb) {
mhc[i / 32 | 0] ^= 1 << i;
}
ph = ph << 1 | pb;
mh = mh << 1 | mb;
pv2 = mh | ~(xv | ph);
mv2 = ph & xv;
}
for (let k = start2; k < vlen2; k++) {
this.#peq[b.charCodeAt(k)] = 0;
}
}
let mv = 0;
let pv = -1;
const start = j * 32;
const vlen = Math.min(32, m - start) + start;
for (let k = start; k < vlen; k++) {
this.#peq[b.charCodeAt(k)] |= 1 << k;
}
let score = m;
for (let i = 0; i < n; i++) {
const eq = this.#peq[a.charCodeAt(i)];
const pb = phc[i / 32 | 0] >>> i & 1;
const mb = mhc[i / 32 | 0] >>> i & 1;
const xv = eq | mv;
const xh = ((eq | mb) & pv) + pv ^ pv | eq | mb;
let ph = mv | ~(xh | pv);
let mh = pv & xh;
score += ph >>> m - 1 & 1;
score -= mh >>> m - 1 & 1;
if (ph >>> 31 ^ pb) {
phc[i / 32 | 0] ^= 1 << i;
}
if (mh >>> 31 ^ mb) {
mhc[i / 32 | 0] ^= 1 << i;
}
ph = ph << 1 | pb;
mh = mh << 1 | mb;
pv = mh | ~(xv | ph);
mv = ph & xv;
}
for (let k = start; k < vlen; k++) {
this.#peq[b.charCodeAt(k)] = 0;
}
return score;
}
#distance(a, b) {
if (a.length < b.length) {
const tmp = b;
b = a;
a = tmp;
}
if (b.length === 0) {
return a.length;
}
if (a.length <= 32) {
return this.#myers_32(a, b);
}
return this.#myers_x(a, b);
}
#closest(str, arr) {
let min_distance = Infinity;
let min_index = 0;
for (let i = 0; i < arr.length; i++) {
const dist = this.#distance(str, arr[i]);
if (dist < min_distance) {
min_distance = dist;
min_index = i;
}
}
return arr[min_index];
}
getClosestMatch(target, candidates) {
return this.#closest(target, candidates);
}
}
export {
LevenshteinStringMatcher
};

View File

@@ -0,0 +1,15 @@
import type { CssRenderer } from '../definitions.js';
import type { CssProperties } from '../types.js';
export declare function renderFontFace(properties: CssProperties, minify: boolean): string;
export declare function renderCssVariable(key: string, values: Array<string>, minify: boolean): string;
export declare function withFamily(family: string, properties: CssProperties): CssProperties;
/** If the value contains spaces (which would be incorrectly interpreted), we wrap it in quotes. */
export declare function handleValueWithSpaces(value: string): string;
export declare class MinifiableCssRenderer implements CssRenderer {
#private;
constructor({ minify }: {
minify: boolean;
});
generateFontFace(family: string, properties: CssProperties): string;
generateCssVariable(key: string, values: Array<string>): string;
}

View File

@@ -0,0 +1,44 @@
function renderFontFace(properties, minify) {
const lf = minify ? "" : `
`;
const sp = minify ? "" : " ";
return `@font-face${sp}{${lf}${Object.entries(properties).filter(([, value]) => Boolean(value)).map(([key, value]) => `${sp}${sp}${key}:${sp}${value};`).join(lf)}${lf}}${lf}`;
}
function renderCssVariable(key, values, minify) {
const lf = minify ? "" : `
`;
const sp = minify ? "" : " ";
return `:root${sp}{${lf}${sp}${sp}${key}:${sp}${values.map((v) => handleValueWithSpaces(v)).join(`,${sp}`)};${lf}}${lf}`;
}
function withFamily(family, properties) {
return {
"font-family": handleValueWithSpaces(family),
...properties
};
}
const SPACE_RE = /\s/;
function handleValueWithSpaces(value) {
if (SPACE_RE.test(value)) {
return JSON.stringify(value);
}
return value;
}
class MinifiableCssRenderer {
#minify;
constructor({ minify }) {
this.#minify = minify;
}
generateFontFace(family, properties) {
return renderFontFace(withFamily(family, properties), this.#minify);
}
generateCssVariable(key, values) {
return renderCssVariable(key, values, this.#minify);
}
}
export {
MinifiableCssRenderer,
handleValueWithSpaces,
renderCssVariable,
renderFontFace,
withFamily
};

View File

@@ -0,0 +1,5 @@
import type { FontTypeExtractor } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class NodeFontTypeExtractor implements FontTypeExtractor {
extract(url: string): FontType;
}

View File

@@ -0,0 +1,21 @@
import { extname } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
import { isFontType } from "../utils.js";
class NodeFontTypeExtractor {
extract(url) {
const extension = extname(url).slice(1);
if (!isFontType(extension)) {
throw new AstroError(
{
...AstroErrorData.CannotExtractFontType,
message: AstroErrorData.CannotExtractFontType.message(url)
},
{ cause: `Unexpected extension, got "${extension}"` }
);
}
return extension;
}
}
export {
NodeFontTypeExtractor
};

View File

@@ -0,0 +1,6 @@
import type { SystemFallbacksProvider } from '../definitions.js';
import type { FontFaceMetrics, GenericFallbackName } from '../types.js';
export declare class RealSystemFallbacksProvider implements SystemFallbacksProvider {
getLocalFonts(fallback: GenericFallbackName): Array<string> | null;
getMetricsForLocalFont(family: string): FontFaceMetrics;
}

View File

@@ -0,0 +1,71 @@
const SYSTEM_METRICS = {
"Times New Roman": {
ascent: 1825,
descent: -443,
lineGap: 87,
unitsPerEm: 2048,
xWidthAvg: 832
},
Arial: {
ascent: 1854,
descent: -434,
lineGap: 67,
unitsPerEm: 2048,
xWidthAvg: 913
},
"Courier New": {
ascent: 1705,
descent: -615,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 1229
},
BlinkMacSystemFont: {
ascent: 1980,
descent: -432,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 853
},
"Segoe UI": {
ascent: 2210,
descent: -514,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 908
},
Roboto: {
ascent: 1900,
descent: -500,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 911
},
"Helvetica Neue": {
ascent: 952,
descent: -213,
lineGap: 28,
unitsPerEm: 1e3,
xWidthAvg: 450
}
};
const DEFAULT_FALLBACKS = {
serif: ["Times New Roman"],
"sans-serif": ["Arial"],
monospace: ["Courier New"],
"system-ui": ["BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial"],
"ui-serif": ["Times New Roman"],
"ui-sans-serif": ["Arial"],
"ui-monospace": ["Courier New"]
};
class RealSystemFallbacksProvider {
getLocalFonts(fallback) {
return DEFAULT_FALLBACKS[fallback] ?? null;
}
getMetricsForLocalFont(family) {
return SYSTEM_METRICS[family];
}
}
export {
RealSystemFallbacksProvider
};

View File

@@ -0,0 +1,34 @@
import type { FontFaceData, Provider } from 'unifont';
import type { FontResolver, Hasher, Storage } from '../definitions.js';
import type { FontProvider, ResolvedFontFamily, ResolveFontOptions } from '../types.js';
type NonEmptyProviders = [
Provider<string, Record<string, any>>,
...Array<Provider<string, Record<string, any>>>
];
export declare class UnifontFontResolver implements FontResolver {
#private;
private constructor();
static idFromProvider({ hasher, provider }: {
hasher: Hasher;
provider: FontProvider;
}): string;
static astroToUnifontProvider(astroProvider: FontProvider, root: URL): Provider;
static extractUnifontProviders({ families, hasher, root, }: {
families: Array<ResolvedFontFamily>;
hasher: Hasher;
root: URL;
}): NonEmptyProviders;
static create({ families, hasher, storage, root, }: {
families: Array<ResolvedFontFamily>;
hasher: Hasher;
storage: Storage;
root: URL;
}): Promise<UnifontFontResolver>;
resolveFont({ familyName, provider, options, ...rest }: ResolveFontOptions<Record<string, any>> & {
provider: FontProvider;
}): Promise<Array<FontFaceData>>;
listFonts({ provider }: {
provider: FontProvider;
}): Promise<string[] | undefined>;
}
export {};

View File

@@ -0,0 +1,98 @@
import { createUnifont, defineFontProvider } from "unifont";
class UnifontFontResolver {
#unifont;
#hasher;
constructor({
unifont,
hasher
}) {
this.#unifont = unifont;
this.#hasher = hasher;
}
static idFromProvider({ hasher, provider }) {
const hash = hasher.hashObject({
name: provider.name,
...provider.config
});
return `${provider.name}-${hash}`;
}
static astroToUnifontProvider(astroProvider, root) {
return defineFontProvider(astroProvider.name, async (_options, ctx) => {
await astroProvider?.init?.({ ...ctx, root });
return {
async resolveFont(familyName, { options, ...rest }) {
return await astroProvider.resolveFont({ familyName, options, ...rest });
},
async listFonts() {
return astroProvider.listFonts?.();
}
};
})(astroProvider.config);
}
static extractUnifontProviders({
families,
hasher,
root
}) {
const providers = /* @__PURE__ */ new Map();
for (const { provider } of families) {
const id = this.idFromProvider({ hasher, provider });
if (!providers.has(id)) {
const unifontProvider = this.astroToUnifontProvider(provider, root);
unifontProvider._name = this.idFromProvider({ hasher, provider });
providers.set(id, unifontProvider);
}
}
return Array.from(providers.values());
}
static async create({
families,
hasher,
storage,
root
}) {
return new UnifontFontResolver({
unifont: await createUnifont(this.extractUnifontProviders({ families, hasher, root }), {
storage,
// TODO: consider enabling, would require new astro errors
throwOnError: false
}),
hasher
});
}
async resolveFont({
familyName,
provider,
options,
...rest
}) {
const id = UnifontFontResolver.idFromProvider({
hasher: this.#hasher,
provider
});
const { fonts } = await this.#unifont.resolveFont(
familyName,
{
// Options are currently namespaced by provider name, it may change in
// https://github.com/unjs/unifont/pull/287
options: {
[id]: options
},
...rest
},
[id]
);
return fonts;
}
async listFonts({ provider }) {
return await this.#unifont.listFonts([
UnifontFontResolver.idFromProvider({
hasher: this.#hasher,
provider
})
]);
}
}
export {
UnifontFontResolver
};

View File

@@ -0,0 +1,11 @@
import type { Storage } from '../definitions.js';
export declare class UnstorageFsStorage implements Storage {
#private;
constructor({ base }: {
base: URL;
});
getItem(key: string): Promise<any | null>;
getItemRaw(key: string): Promise<Buffer | null>;
setItem(key: string, value: any): Promise<void>;
setItemRaw(key: string, value: any): Promise<void>;
}

View File

@@ -0,0 +1,26 @@
import { fileURLToPath } from "node:url";
import * as unstorage from "unstorage";
import fsLiteDriver from "unstorage/drivers/fs-lite";
class UnstorageFsStorage {
#unstorage;
constructor({ base }) {
this.#unstorage = unstorage.createStorage({
driver: fsLiteDriver({ base: fileURLToPath(base) })
});
}
async getItem(key) {
return await this.#unstorage.getItem(key);
}
async getItemRaw(key) {
return await this.#unstorage.getItemRaw(key);
}
async setItem(key, value) {
return await this.#unstorage.setItem(key, value);
}
async setItemRaw(key, value) {
return await this.#unstorage.setItemRaw(key, value);
}
}
export {
UnstorageFsStorage
};

View File

@@ -0,0 +1,7 @@
import type { Hasher } from '../definitions.js';
export declare class XxhashHasher implements Hasher {
hashString: (input: string) => string;
private constructor();
static create(): Promise<XxhashHasher>;
hashObject(input: Record<string, any>): string;
}

View File

@@ -0,0 +1,18 @@
import xxhash from "xxhash-wasm";
import { sortObjectByKey } from "../utils.js";
class XxhashHasher {
hashString;
constructor(hashString) {
this.hashString = hashString;
}
static async create() {
const { h64ToString } = await xxhash();
return new XxhashHasher(h64ToString);
}
hashObject(input) {
return this.hashString(JSON.stringify(sortObjectByKey(input)));
}
}
export {
XxhashHasher
};

View File

@@ -0,0 +1,37 @@
import { type AdobeProviderOptions, type GoogleFamilyOptions, type GoogleiconsFamilyOptions } from 'unifont';
import type { FontProvider } from '../types.js';
import { type LocalFamilyOptions } from './local.js';
/** [Adobe](https://fonts.adobe.com/) */
declare function adobe(config: AdobeProviderOptions): FontProvider;
/** [Bunny](https://fonts.bunny.net/) */
declare function bunny(): FontProvider;
/** [Fontshare](https://www.fontshare.com/) */
declare function fontshare(): FontProvider;
/** [Fontsource](https://fontsource.org/) */
declare function fontsource(): FontProvider;
/** [Google](https://fonts.google.com/) */
declare function google(): FontProvider<GoogleFamilyOptions | undefined>;
/** [Google Icons](https://fonts.google.com/icons) */
declare function googleicons(): FontProvider<GoogleiconsFamilyOptions | undefined>;
/** A provider that handles local files. */
declare function local(): FontProvider<LocalFamilyOptions>;
/**
* Astro exports a few built-in providers:
* - [Adobe](https://fonts.adobe.com/)
* - [Bunny](https://fonts.bunny.net/)
* - [Fontshare](https://www.fontshare.com/)
* - [Fontsource](https://fontsource.org/)
* - [Google](https://fonts.google.com/)
* - [Google Icons](https://fonts.google.com/icons)
* - Local
*/
export declare const fontProviders: {
adobe: typeof adobe;
bunny: typeof bunny;
fontshare: typeof fontshare;
fontsource: typeof fontsource;
google: typeof google;
googleicons: typeof googleicons;
local: typeof local;
};
export {};

119
node_modules/astro/dist/assets/fonts/providers/index.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
import {
providers
} from "unifont";
import { FontaceFontFileReader } from "../infra/fontace-font-file-reader.js";
import { LocalFontProvider } from "./local.js";
function adobe(config) {
const provider = providers.adobe(config);
let initializedProvider;
return {
name: provider._name,
config,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function bunny() {
const provider = providers.bunny();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function fontshare() {
const provider = providers.fontshare();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function fontsource() {
const provider = providers.fontsource();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function google() {
const provider = providers.google();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function googleicons() {
const provider = providers.googleicons();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function local() {
return new LocalFontProvider({
fontFileReader: new FontaceFontFileReader()
});
}
const fontProviders = {
adobe,
bunny,
fontshare,
fontsource,
google,
googleicons,
local
};
export {
fontProviders
};

View File

@@ -0,0 +1,44 @@
import type * as unifont from 'unifont';
import type { FontFileReader } from '../definitions.js';
import type { FamilyProperties, FontProvider, FontProviderInitContext, ResolveFontOptions, Style, Weight } from '../types.js';
type RawSource = string | URL | {
url: string | URL;
tech?: string | undefined;
};
interface Variant extends FamilyProperties {
/**
* Font [sources](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src). It can be a path relative to the root, a package import or a URL. URLs are particularly useful if you inject local fonts through an integration.
*/
src: [RawSource, ...Array<RawSource>];
/**
* A [font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight). If the associated font is a [variable font](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide), you can specify a range of weights:
*
* ```js
* weight: "100 900"
* ```
*/
weight?: Weight | undefined;
/**
* A [font style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style).
*/
style?: Style | undefined;
}
export interface LocalFamilyOptions {
/**
* Each variant represents a [`@font-face` declaration](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/).
*/
variants: [Variant, ...Array<Variant>];
}
export declare class LocalFontProvider implements FontProvider<LocalFamilyOptions> {
#private;
name: string;
config?: Record<string, any> | undefined;
constructor({ fontFileReader, }: {
fontFileReader: FontFileReader;
});
init(context: Pick<FontProviderInitContext, 'root'>): void;
resolveFont(options: ResolveFontOptions<LocalFamilyOptions>): {
fonts: Array<unifont.FontFaceData>;
};
}
export {};

View File

@@ -0,0 +1,69 @@
import { createRequire } from "node:module";
import { fileURLToPath, pathToFileURL } from "node:url";
class LocalFontProvider {
name = "local";
config;
#fontFileReader;
#root;
constructor({
fontFileReader
}) {
this.config = void 0;
this.#fontFileReader = fontFileReader;
this.#root = void 0;
}
init(context) {
this.#root = context.root;
}
#resolveEntrypoint(root, entrypoint) {
const require2 = createRequire(root);
try {
return pathToFileURL(require2.resolve(entrypoint));
} catch {
return new URL(entrypoint, root);
}
}
#normalizeSource(value) {
const isValue = typeof value === "string" || value instanceof URL;
const url = (isValue ? value : value.url).toString();
const tech = isValue ? void 0 : value.tech;
return {
url: fileURLToPath(this.#resolveEntrypoint(this.#root ?? new URL(import.meta.url), url)),
tech
};
}
resolveFont(options) {
return {
fonts: options.options?.variants.map((variant) => {
const shouldInfer = variant.weight === void 0 || variant.style === void 0;
const data = {
// If it should be inferred, we don't want to set the value
weight: variant.weight,
style: variant.style,
src: [],
unicodeRange: variant.unicodeRange,
display: variant.display,
stretch: variant.stretch,
featureSettings: variant.featureSettings,
variationSettings: variant.variationSettings
};
data.src = variant.src.map((rawSource, index) => {
const source = this.#normalizeSource(rawSource);
if (shouldInfer && index === 0) {
const result = this.#fontFileReader.extract({
family: options.familyName,
url: source.url
});
if (variant.weight === void 0) data.weight = result.weight;
if (variant.style === void 0) data.style = result.style;
}
return source;
});
return data;
}) ?? []
};
}
}
export {
LocalFontProvider
};

1
node_modules/astro/dist/assets/fonts/runtime.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare const fontData: import("./types.js").FontDataByCssVariable;

5
node_modules/astro/dist/assets/fonts/runtime.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import * as fontsMod from "virtual:astro:assets/fonts/internal";
const fontData = fontsMod.fontDataByCssVariable ?? {};
export {
fontData
};

2
node_modules/astro/dist/assets/fonts/sync.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { AstroSettings } from '../../types/astro.js';
export declare function syncFonts(settings: AstroSettings): void;

17
node_modules/astro/dist/assets/fonts/sync.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { FONTS_TYPES_FILE } from "./constants.js";
function syncFonts(settings) {
if (!settings.config.experimental.fonts) {
return;
}
settings.injectedTypes.push({
filename: FONTS_TYPES_FILE,
content: `declare module 'astro:assets' {
/** @internal */
export type CssVariable = (${JSON.stringify(settings.config.experimental.fonts.map((family) => family.cssVariable))})[number];
}
`
});
}
export {
syncFonts
};

233
node_modules/astro/dist/assets/fonts/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,233 @@
import type { Font } from '@capsizecss/unpack';
import type * as unifont from 'unifont';
import type { z } from 'zod';
import type { displaySchema, styleSchema, weightSchema } from './config.js';
import type { FONT_TYPES, GENERIC_FALLBACK_NAMES } from './constants.js';
import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js';
export type Weight = z.infer<typeof weightSchema>;
type Display = z.infer<typeof displaySchema>;
export interface FontProviderInitContext {
storage: {
getItem: {
<T = unknown>(key: string): Promise<T | null>;
<T = unknown>(key: string, init: () => Awaitable<T>): Promise<T>;
};
setItem: (key: string, value: unknown) => Awaitable<void>;
};
root: URL;
}
type Awaitable<T> = T | Promise<T>;
export interface FontProvider<TFamilyOptions extends Record<string, any> | undefined | never = never> {
/**
* The font provider name, used for display and deduplication.
*/
name: string;
/**
* Optional serializable object, used for deduplication.
*/
config?: Record<string, any> | undefined;
/**
* Optional callback, used to perform any initialization logic.
*/
init?: ((context: FontProviderInitContext) => Awaitable<void>) | undefined;
/**
* Required callback, used to retrieve and return font face data based on the given options.
*/
resolveFont: (options: ResolveFontOptions<TFamilyOptions>) => Awaitable<{
fonts: Array<unifont.FontFaceData>;
} | undefined>;
/**
* Optional callback, used to return the list of available font names.
*/
listFonts?: (() => Awaitable<Array<string> | undefined>) | undefined;
}
export interface FamilyProperties {
/**
* @default `"swap"`
*
* A [font display](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display).
*/
display?: Display | undefined;
/**
* A [font stretch](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch).
*/
stretch?: string | undefined;
/**
* Font [feature settings](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings).
*/
featureSettings?: string | undefined;
/**
* Font [variation settings](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-variation-settings).
*/
variationSettings?: string | undefined;
/**
* A [unicode range](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range).
*/
unicodeRange?: [string, ...Array<string>] | undefined;
}
type WithOptions<TFontProvider extends FontProvider> = TFontProvider extends FontProvider<infer TFamilyOptions> ? [TFamilyOptions] extends [never] ? {
/**
* Options forwarded to the font provider while resolving this font family.
*/
options?: undefined;
} : undefined extends TFamilyOptions ? {
/**
* Options forwarded to the font provider while resolving this font family.
*/
options?: TFamilyOptions;
} : {
/**
* Options forwarded to the font provider while resolving this font family.
*/
options: TFamilyOptions;
} : {
/**
* Options forwarded to the font provider while resolving this font family.
*/
options?: undefined;
};
export type FontFamily<TFontProvider extends FontProvider = FontProvider> = FamilyProperties & WithOptions<NoInfer<TFontProvider>> & {
/**
* The font family name, as identified by your font provider.
*/
name: string;
/**
* A valid [ident](https://developer.mozilla.org/en-US/docs/Web/CSS/ident) in the form of a CSS variable (i.e. starting with `--`).
*/
cssVariable: string;
/**
* The source of your font files. You can use a built-in provider or write your own custom provider.
*/
provider: TFontProvider;
/**
* @default `[400]`
*
* An array of [font weights](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight). If the associated font is a [variable font](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide), you can specify a range of weights:
*
* ```js
* weight: "100 900"
* ```
*/
weights?: [Weight, ...Array<Weight>] | undefined;
/**
* @default `["normal", "italic"]`
*
* An array of [font styles](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style).
*/
styles?: [Style, ...Array<Style>] | undefined;
/**
* @default `["latin"]`
*
* An array of [font subsets](https://knaap.dev/posts/font-subsetting/):
*/
subsets?: [string, ...Array<string>] | undefined;
/**
* @default `["woff2"]`
*
* An array of [font formats](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face/src#font_formats).
*/
formats?: [FontType, ...Array<FontType>] | undefined;
/**
* @default `["sans-serif"]`
*
* An array of fonts to use when your chosen font is unavailable, or loading. Fallback fonts will be chosen in the order listed. The first available font will be used:
*
* ```js
* fallbacks: ["CustomFont", "serif"]
* ```
*
* To disable fallback fonts completely, configure an empty array:
*
* ```js
* fallbacks: []
* ```
*
* If the last font in the `fallbacks` array is a [generic family name](https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#generic-name), Astro will attempt to generate [optimized fallbacks](https://developer.chrome.com/blog/font-fallbacks) using font metrics will be generated. To disable this optimization, set `optimizedFallbacks` to false.
*/
fallbacks?: Array<string> | undefined;
/**
* @default `true`
*
* Whether or not to enable optimized fallback generation. You may disable this default optimization to have full control over `fallbacks`.
*/
optimizedFallbacks?: boolean | undefined;
};
export interface ResolvedFontFamily extends Omit<FontFamily, 'weights'> {
uniqueName: string;
weights?: Array<string>;
}
export type FontType = (typeof FONT_TYPES)[number];
/**
* Preload data is used for links generation inside the <Font /> component
*/
export interface PreloadData {
/**
* Absolute link to a font file, eg. /_astro/fonts/abc.woff
*/
url: string;
/**
* A font type, eg. woff2, woff, ttf...
*/
type: FontType;
weight: string | undefined;
style: string | undefined;
subset: string | undefined;
}
export type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
export type GenericFallbackName = (typeof GENERIC_FALLBACK_NAMES)[number];
export type Defaults = Required<Pick<ResolvedFontFamily, 'weights' | 'styles' | 'subsets' | 'fallbacks' | 'optimizedFallbacks' | 'formats'>>;
export interface FontFileData {
id: string;
url: string;
init: RequestInit | undefined;
}
/**
* Holds associations of id and original font file URLs, so they can be
* downloaded whenever the id is requested.
*/
export type FontFileById = Map<FontFileData['id'], Pick<FontFileData, 'url' | 'init'>>;
export type ComponentDataByCssVariable = Map<string, {
preloads: Array<PreloadData>;
css: string;
}>;
export interface FontData {
src: Array<{
url: string;
format?: string;
tech?: string;
}>;
weight?: string;
style?: string;
}
/**
* Holds associations of CSS variables and font data to be exposed via virtual module.
*/
export type FontDataByCssVariable = Record<string, Array<FontData>>;
export type Style = z.output<typeof styleSchema>;
export type PreloadFilter = boolean | Array<{
weight?: string | number;
style?: string;
subset?: string;
}>;
export interface ResolveFontOptions<FamilyOptions extends Record<string, any> | undefined | never = never> {
familyName: string;
weights: string[];
styles: Style[];
subsets: string[];
formats: FontType[];
options: [FamilyOptions] extends [never] ? undefined : FamilyOptions | undefined;
}
export type CssProperties = Record<string, string | undefined>;
export interface FontFamilyAssets {
family: ResolvedFontFamily;
fonts: Array<unifont.FontFaceData>;
/**
* Holds a list of font files to be used for optimized fallbacks generation
*/
collectedFontsForMetricsByUniqueKey: Map<string, CollectedFontForMetrics>;
preloads: Array<PreloadData>;
}
export type FontFamilyAssetsByUniqueKey = Map<string, FontFamilyAssets>;
export type Collaborator<T extends (input: any) => any, U extends keyof Parameters<T>[0]> = (params: Pick<Parameters<T>[0], U>) => ReturnType<T>;
export {};

0
node_modules/astro/dist/assets/fonts/types.js generated vendored Normal file
View File

20
node_modules/astro/dist/assets/fonts/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import type * as unifont from 'unifont';
import type { CssProperties, FontType, GenericFallbackName } from './types.js';
/**
* Turns unifont font face data into generic CSS properties, to be consumed by the CSS renderer.
*/
export declare function unifontFontFaceDataToProperties(font: Partial<unifont.FontFaceData>): CssProperties;
export declare function renderFontWeight(weight: unifont.FontFaceData['weight']): string | undefined;
/**
* Turns unifont font face data src into a valid CSS property.
* Adapted from https://github.com/nuxt/fonts/blob/main/src/css/render.ts#L68-L81
*/
export declare function renderFontSrc(sources: Exclude<unifont.FontFaceData['src'][number], string>[]): string;
/**
* Removes the quotes from a string. Used for family names
*/
export declare function withoutQuotes(str: string): string;
export declare function isFontType(str: string): str is FontType;
export declare function isGenericFontFamily(str: string): str is GenericFallbackName;
export declare function dedupe<const T extends Array<any>>(arr: T): T;
export declare function sortObjectByKey<T extends Record<string, any>>(unordered: T): T;

62
node_modules/astro/dist/assets/fonts/utils.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
import { FONT_TYPES, GENERIC_FALLBACK_NAMES } from "./constants.js";
function unifontFontFaceDataToProperties(font) {
return {
src: font.src ? renderFontSrc(font.src) : void 0,
"font-display": font.display ?? "swap",
"unicode-range": font.unicodeRange?.length ? font.unicodeRange.join(",") : void 0,
"font-weight": renderFontWeight(font.weight),
"font-style": font.style,
"font-stretch": font.stretch,
"font-feature-settings": font.featureSettings,
"font-variation-settings": font.variationSettings
};
}
function renderFontWeight(weight) {
return Array.isArray(weight) ? weight.join(" ") : weight?.toString();
}
function renderFontSrc(sources) {
return sources.map((src) => {
if ("name" in src) {
return `local("${src.name}")`;
}
let rendered = `url("${src.url}")`;
if (src.format) {
rendered += ` format("${src.format}")`;
}
if (src.tech) {
rendered += ` tech(${src.tech})`;
}
return rendered;
}).join(", ");
}
const QUOTES_RE = /^["']|["']$/g;
function withoutQuotes(str) {
return str.trim().replace(QUOTES_RE, "");
}
function isFontType(str) {
return FONT_TYPES.includes(str);
}
function isGenericFontFamily(str) {
return GENERIC_FALLBACK_NAMES.includes(str);
}
function dedupe(arr) {
return [...new Set(arr)];
}
function sortObjectByKey(unordered) {
const ordered = Object.keys(unordered).sort().reduce((obj, key) => {
const value = unordered[key];
obj[key] = Array.isArray(value) ? value.map((v) => typeof v === "object" && v !== null ? sortObjectByKey(v) : v) : typeof value === "object" && value !== null ? sortObjectByKey(value) : value;
return obj;
}, {});
return ordered;
}
export {
dedupe,
isFontType,
isGenericFontFamily,
renderFontSrc,
renderFontWeight,
sortObjectByKey,
unifontFontFaceDataToProperties,
withoutQuotes
};

View File

@@ -0,0 +1,10 @@
import type { Plugin } from 'vite';
import type { Logger } from '../../core/logger/core.js';
import type { AstroSettings } from '../../types/astro.js';
interface Options {
settings: AstroSettings;
sync: boolean;
logger: Logger;
}
export declare function fontsPlugin({ settings, sync, logger }: Options): Plugin;
export {};

View File

@@ -0,0 +1,300 @@
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { isAbsolute } from "node:path";
import colors from "piccolore";
import { getAlgorithm, shouldTrackCspHashes } from "../../core/csp/common.js";
import { generateCspDigest } from "../../core/encryption.js";
import { collectErrorMetadata } from "../../core/errors/dev/utils.js";
import { AstroError, AstroErrorData, isAstroError } from "../../core/errors/index.js";
import { formatErrorMessage } from "../../core/messages.js";
import { appendForwardSlash, joinPaths, prependForwardSlash } from "../../core/path.js";
import { getClientOutputDirectory } from "../../prerender/utils.js";
import {
ASSETS_DIR,
CACHE_DIR,
DEFAULTS,
RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
RUNTIME_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
} from "./constants.js";
import { collectComponentData } from "./core/collect-component-data.js";
import { collectFontAssetsFromFaces } from "./core/collect-font-assets-from-faces.js";
import { collectFontData } from "./core/collect-font-data.js";
import { computeFontFamiliesAssets } from "./core/compute-font-families-assets.js";
import { filterAndTransformFontFaces } from "./core/filter-and-transform-font-faces.js";
import { getOrCreateFontFamilyAssets } from "./core/get-or-create-font-family-assets.js";
import { optimizeFallbacks } from "./core/optimize-fallbacks.js";
import { resolveFamily } from "./core/resolve-family.js";
import { BuildFontFileIdGenerator } from "./infra/build-font-file-id-generator.js";
import { BuildUrlResolver } from "./infra/build-url-resolver.js";
import { CachedFontFetcher } from "./infra/cached-font-fetcher.js";
import { CapsizeFontMetricsResolver } from "./infra/capsize-font-metrics-resolver.js";
import { DevFontFileIdGenerator } from "./infra/dev-font-file-id-generator.js";
import { DevUrlResolver } from "./infra/dev-url-resolver.js";
import { FsFontFileContentResolver } from "./infra/fs-font-file-content-resolver.js";
import { LevenshteinStringMatcher } from "./infra/levenshtein-string-matcher.js";
import { MinifiableCssRenderer } from "./infra/minifiable-css-renderer.js";
import { NodeFontTypeExtractor } from "./infra/node-font-type-extractor.js";
import { RealSystemFallbacksProvider } from "./infra/system-fallbacks-provider.js";
import { UnifontFontResolver } from "./infra/unifont-font-resolver.js";
import { UnstorageFsStorage } from "./infra/unstorage-fs-storage.js";
import { XxhashHasher } from "./infra/xxhash-hasher.js";
function fontsPlugin({ settings, sync, logger }) {
if (!settings.config.experimental.fonts) {
return {
name: "astro:fonts:fallback",
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return RESOLVED_VIRTUAL_MODULE_ID;
}
if (id === RUNTIME_VIRTUAL_MODULE_ID) {
return RESOLVED_RUNTIME_VIRTUAL_MODULE_ID;
}
},
load(id) {
if (id === RESOLVED_VIRTUAL_MODULE_ID || id === RESOLVED_RUNTIME_VIRTUAL_MODULE_ID) {
return {
code: ""
};
}
}
};
}
const assetsDir = prependForwardSlash(
appendForwardSlash(joinPaths(settings.config.build.assets, ASSETS_DIR))
);
const baseUrl = joinPaths(settings.config.base, assetsDir);
let fontFileById = null;
let componentDataByCssVariable = null;
let fontDataByCssVariable = null;
let isBuild;
let fontFetcher = null;
let fontTypeExtractor = null;
const cleanup = () => {
componentDataByCssVariable = null;
fontDataByCssVariable = null;
fontFileById = null;
fontFetcher = null;
};
return {
name: "astro:fonts",
config(_, { command }) {
isBuild = command === "build";
},
async buildStart() {
const { root } = settings.config;
const hasher = await XxhashHasher.create();
const storage = new UnstorageFsStorage({
// In dev, we cache fonts data in .astro so it can be easily inspected and cleared
base: new URL(CACHE_DIR, isBuild ? settings.config.cacheDir : settings.dotAstroDir)
});
const systemFallbacksProvider = new RealSystemFallbacksProvider();
fontFetcher = new CachedFontFetcher({ storage, fetch, readFile });
const cssRenderer = new MinifiableCssRenderer({ minify: isBuild });
const fontMetricsResolver = new CapsizeFontMetricsResolver({ fontFetcher, cssRenderer });
fontTypeExtractor = new NodeFontTypeExtractor();
const stringMatcher = new LevenshteinStringMatcher();
const urlResolver = isBuild ? new BuildUrlResolver({
base: baseUrl,
assetsPrefix: settings.config.build.assetsPrefix,
searchParams: settings.adapter?.client?.assetQueryParams ?? new URLSearchParams()
}) : new DevUrlResolver({
base: baseUrl,
searchParams: settings.adapter?.client?.assetQueryParams ?? new URLSearchParams()
});
const contentResolver = new FsFontFileContentResolver({
readFileSync: (path) => readFileSync(path, "utf-8")
});
const fontFileIdGenerator = isBuild ? new BuildFontFileIdGenerator({
hasher,
contentResolver
}) : new DevFontFileIdGenerator({
hasher,
contentResolver
});
const { bold } = colors;
const defaults = DEFAULTS;
const resolvedFamilies = settings.config.experimental.fonts.map(
(family) => resolveFamily({ family, hasher })
);
const { fontFamilyAssets, fontFileById: _fontFileById } = await computeFontFamiliesAssets({
resolvedFamilies,
defaults,
bold,
logger,
stringMatcher,
fontResolver: await UnifontFontResolver.create({
families: resolvedFamilies,
hasher,
storage,
root
}),
getOrCreateFontFamilyAssets: ({ family, fontFamilyAssetsByUniqueKey }) => getOrCreateFontFamilyAssets({
family,
fontFamilyAssetsByUniqueKey,
bold,
logger
}),
filterAndTransformFontFaces: ({ family, fonts }) => filterAndTransformFontFaces({
family,
fonts,
fontFileIdGenerator,
fontTypeExtractor,
urlResolver
}),
collectFontAssetsFromFaces: ({ collectedFontsIds, family, fontFilesIds, fonts }) => collectFontAssetsFromFaces({
collectedFontsIds,
family,
fontFilesIds,
fonts,
fontFileIdGenerator,
hasher,
defaults
})
});
fontDataByCssVariable = collectFontData(fontFamilyAssets);
componentDataByCssVariable = await collectComponentData({
cssRenderer,
defaults,
fontFamilyAssets,
optimizeFallbacks: ({ collectedFonts, fallbacks, family }) => optimizeFallbacks({
collectedFonts,
fallbacks,
family,
fontMetricsResolver,
systemFallbacksProvider
})
});
fontFileById = _fontFileById;
if (shouldTrackCspHashes(settings.config.experimental.csp)) {
const algorithm = getAlgorithm(settings.config.experimental.csp);
for (const { css } of componentDataByCssVariable.values()) {
settings.injectedCsp.styleHashes.push(await generateCspDigest(css, algorithm));
}
for (const resource of urlResolver.cspResources) {
settings.injectedCsp.fontResources.add(resource);
}
}
},
async configureServer(server) {
server.watcher.on("change", (path) => {
if (!fontFileById) {
return;
}
const localPaths = [...fontFileById.values()].filter(({ url }) => isAbsolute(url)).map((v) => v.url);
if (localPaths.includes(path)) {
logger.info("assets", "Font file updated");
server.restart();
}
});
server.watcher.on("unlink", (path) => {
if (!fontFileById) {
return;
}
const localPaths = [...fontFileById.values()].filter(({ url }) => isAbsolute(url)).map((v) => v.url);
if (localPaths.includes(path)) {
logger.warn(
"assets",
`The font file ${JSON.stringify(path)} referenced in your config has been deleted. Restore the file or remove this font from your configuration if it is no longer needed.`
);
}
});
server.middlewares.use(assetsDir, async (req, res, next) => {
if (!fontFetcher || !fontTypeExtractor) {
logger.debug(
"assets",
"Fonts dependencies should be initialized by now, skipping dev middleware."
);
return next();
}
if (!req.url) {
return next();
}
const fontId = req.url.slice(1);
const fontData = fontFileById?.get(fontId);
if (!fontData) {
return next();
}
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
res.setHeader("Pragma", "no-cache");
res.setHeader("Expires", 0);
try {
const buffer = await fontFetcher.fetch({ id: fontId, ...fontData });
res.setHeader("Content-Length", buffer.length);
res.setHeader("Content-Type", `font/${fontTypeExtractor.extract(fontId)}`);
res.end(buffer);
} catch (err) {
logger.error("assets", "Cannot download font file");
if (isAstroError(err)) {
logger.error(
"SKIP_FORMAT",
formatErrorMessage(collectErrorMetadata(err), logger.level() === "debug")
);
}
res.statusCode = 500;
res.end();
}
});
},
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return RESOLVED_VIRTUAL_MODULE_ID;
}
if (id === RUNTIME_VIRTUAL_MODULE_ID) {
return RESOLVED_RUNTIME_VIRTUAL_MODULE_ID;
}
},
async load(id) {
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
return {
code: `
export const componentDataByCssVariable = new Map(${JSON.stringify(Array.from(componentDataByCssVariable?.entries() ?? []))});
export const fontDataByCssVariable = ${JSON.stringify(fontDataByCssVariable ?? {})}
`
};
}
if (id === RESOLVED_RUNTIME_VIRTUAL_MODULE_ID) {
return {
code: `export * from 'astro/assets/fonts/runtime.js';`
};
}
},
async buildEnd() {
if (sync || settings.config.experimental.fonts.length === 0 || !isBuild) {
cleanup();
return;
}
try {
const dir = getClientOutputDirectory(settings);
const fontsDir = new URL(`.${assetsDir}`, dir);
try {
mkdirSync(fontsDir, { recursive: true });
} catch (cause) {
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
}
if (fontFileById) {
logger.info(
"assets",
`Copying fonts (${fontFileById.size} file${fontFileById.size === 1 ? "" : "s"})...`
);
await Promise.all(
Array.from(fontFileById.entries()).map(async ([id, associatedData]) => {
const data = await fontFetcher.fetch({ id, ...associatedData });
try {
writeFileSync(new URL(id, fontsDir), data);
} catch (cause) {
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
}
})
);
}
} finally {
cleanup();
}
}
};
}
export {
fontsPlugin
};

3
node_modules/astro/dist/assets/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export { getConfiguredImageService, getImage } from './internal.js';
export { baseService, isLocalService } from './services/service.js';
export { type LocalImageProps, type RemoteImageProps } from './types.js';

9
node_modules/astro/dist/assets/index.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import { getConfiguredImageService, getImage } from "./internal.js";
import { baseService, isLocalService } from "./services/service.js";
import {} from "./types.js";
export {
baseService,
getConfiguredImageService,
getImage,
isLocalService
};

6
node_modules/astro/dist/assets/internal.d.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import type { AstroConfig } from '../types/public/config.js';
import type { AstroAdapterClientConfig } from '../types/public/integrations.js';
import { type ImageService } from './services/service.js';
import { type GetImageResult, type UnresolvedImageTransform } from './types.js';
export declare function getConfiguredImageService(): Promise<ImageService>;
export declare function getImage(options: UnresolvedImageTransform, imageConfig: AstroConfig['image'] & AstroAdapterClientConfig): Promise<GetImageResult>;

179
node_modules/astro/dist/assets/internal.js generated vendored Normal file
View File

@@ -0,0 +1,179 @@
import { isRemotePath } from "@astrojs/internal-helpers/path";
import { AstroError, AstroErrorData } from "../core/errors/index.js";
import { DEFAULT_HASH_PROPS } from "./consts.js";
import {
DEFAULT_RESOLUTIONS,
getSizesAttribute,
getWidths,
LIMITED_RESOLUTIONS
} from "./layout.js";
import { isLocalService } from "./services/service.js";
import {
isImageMetadata
} from "./types.js";
import { addCSSVarsToStyle, cssFitValues } from "./utils/imageAttributes.js";
import { isESMImportedImage, isRemoteImage, resolveSrc } from "./utils/imageKind.js";
import { inferRemoteSize } from "./utils/remoteProbe.js";
import { createPlaceholderURL, stringifyPlaceholderURL } from "./utils/url.js";
async function getConfiguredImageService() {
if (!globalThis?.astroAsset?.imageService) {
const { default: service } = await import(
// @ts-expect-error
"virtual:image-service"
).catch((e) => {
const error = new AstroError(AstroErrorData.InvalidImageService);
error.cause = e;
throw error;
});
if (!globalThis.astroAsset) globalThis.astroAsset = {};
globalThis.astroAsset.imageService = service;
return service;
}
return globalThis.astroAsset.imageService;
}
async function getImage(options, imageConfig) {
if (!options || typeof options !== "object") {
throw new AstroError({
...AstroErrorData.ExpectedImageOptions,
message: AstroErrorData.ExpectedImageOptions.message(JSON.stringify(options))
});
}
if (typeof options.src === "undefined") {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(
options.src,
"undefined",
JSON.stringify(options)
)
});
}
if (isImageMetadata(options)) {
throw new AstroError(AstroErrorData.ExpectedNotESMImage);
}
const service = await getConfiguredImageService();
const resolvedOptions = {
...options,
src: await resolveSrc(options.src)
};
let originalWidth;
let originalHeight;
if (options.inferSize && isRemoteImage(resolvedOptions.src) && isRemotePath(resolvedOptions.src)) {
const result = await inferRemoteSize(resolvedOptions.src);
resolvedOptions.width ??= result.width;
resolvedOptions.height ??= result.height;
originalWidth = result.width;
originalHeight = result.height;
delete resolvedOptions.inferSize;
}
const originalFilePath = isESMImportedImage(resolvedOptions.src) ? resolvedOptions.src.fsPath : void 0;
const clonedSrc = isESMImportedImage(resolvedOptions.src) ? (
// @ts-expect-error - clone is a private, hidden prop
resolvedOptions.src.clone ?? resolvedOptions.src
) : resolvedOptions.src;
if (isESMImportedImage(clonedSrc)) {
originalWidth = clonedSrc.width;
originalHeight = clonedSrc.height;
}
if (originalWidth && originalHeight) {
const aspectRatio = originalWidth / originalHeight;
if (resolvedOptions.height && !resolvedOptions.width) {
resolvedOptions.width = Math.round(resolvedOptions.height * aspectRatio);
} else if (resolvedOptions.width && !resolvedOptions.height) {
resolvedOptions.height = Math.round(resolvedOptions.width / aspectRatio);
} else if (!resolvedOptions.width && !resolvedOptions.height) {
resolvedOptions.width = originalWidth;
resolvedOptions.height = originalHeight;
}
}
resolvedOptions.src = clonedSrc;
const layout = options.layout ?? imageConfig.layout ?? "none";
if (resolvedOptions.priority) {
resolvedOptions.loading ??= "eager";
resolvedOptions.decoding ??= "sync";
resolvedOptions.fetchpriority ??= "high";
delete resolvedOptions.priority;
} else {
resolvedOptions.loading ??= "lazy";
resolvedOptions.decoding ??= "async";
resolvedOptions.fetchpriority ??= "auto";
}
if (layout !== "none") {
resolvedOptions.widths ||= getWidths({
width: resolvedOptions.width,
layout,
originalWidth,
breakpoints: imageConfig.breakpoints?.length ? imageConfig.breakpoints : isLocalService(service) ? LIMITED_RESOLUTIONS : DEFAULT_RESOLUTIONS
});
resolvedOptions.sizes ||= getSizesAttribute({ width: resolvedOptions.width, layout });
delete resolvedOptions.densities;
resolvedOptions.style = addCSSVarsToStyle(
{
fit: cssFitValues.includes(resolvedOptions.fit ?? "") && resolvedOptions.fit,
pos: resolvedOptions.position
},
resolvedOptions.style
);
resolvedOptions["data-astro-image"] = layout;
}
const validatedOptions = service.validateOptions ? await service.validateOptions(resolvedOptions, imageConfig) : resolvedOptions;
const srcSetTransforms = service.getSrcSet ? await service.getSrcSet(validatedOptions, imageConfig) : [];
let imageURL = await service.getURL(validatedOptions, imageConfig);
const matchesValidatedTransform = (transform) => transform.width === validatedOptions.width && transform.height === validatedOptions.height && transform.format === validatedOptions.format;
let srcSets = await Promise.all(
srcSetTransforms.map(async (srcSet) => {
return {
transform: srcSet.transform,
url: matchesValidatedTransform(srcSet.transform) ? imageURL : await service.getURL(srcSet.transform, imageConfig),
descriptor: srcSet.descriptor,
attributes: srcSet.attributes
};
})
);
if (isLocalService(service) && globalThis.astroAsset.addStaticImage && !(isRemoteImage(validatedOptions.src) && imageURL === validatedOptions.src)) {
const propsToHash = service.propertiesToHash ?? DEFAULT_HASH_PROPS;
imageURL = globalThis.astroAsset.addStaticImage(
validatedOptions,
propsToHash,
originalFilePath
);
srcSets = srcSetTransforms.map((srcSet) => {
return {
transform: srcSet.transform,
url: matchesValidatedTransform(srcSet.transform) ? imageURL : globalThis.astroAsset.addStaticImage(srcSet.transform, propsToHash, originalFilePath),
descriptor: srcSet.descriptor,
attributes: srcSet.attributes
};
});
} else if (imageConfig.assetQueryParams) {
const imageURLObj = createPlaceholderURL(imageURL);
imageConfig.assetQueryParams.forEach((value, key) => {
imageURLObj.searchParams.set(key, value);
});
imageURL = stringifyPlaceholderURL(imageURLObj);
srcSets = srcSets.map((srcSet) => {
const urlObj = createPlaceholderURL(srcSet.url);
imageConfig.assetQueryParams.forEach((value, key) => {
urlObj.searchParams.set(key, value);
});
return {
...srcSet,
url: stringifyPlaceholderURL(urlObj)
};
});
}
return {
rawOptions: resolvedOptions,
options: validatedOptions,
src: imageURL,
srcSet: {
values: srcSets,
attribute: srcSets.map((srcSet) => `${srcSet.url} ${srcSet.descriptor}`).join(", ")
},
attributes: service.getHTMLAttributes !== void 0 ? await service.getHTMLAttributes(validatedOptions, imageConfig) : {}
};
}
export {
getConfiguredImageService,
getImage
};

25
node_modules/astro/dist/assets/layout.d.ts generated vendored Normal file
View File

@@ -0,0 +1,25 @@
import type { ImageLayout } from './types.js';
export declare const DEFAULT_RESOLUTIONS: number[];
export declare const LIMITED_RESOLUTIONS: number[];
/**
* Gets the breakpoints for an image, based on the layout and width
*
* The rules are as follows:
*
* - For full-width layout we return all breakpoints smaller than the original image width
* - For fixed layout we return 1x and 2x the requested width, unless the original image is smaller than that.
* - For responsive layout we return all breakpoints smaller than 2x the requested width, unless the original image is smaller than that.
*/
export declare const getWidths: ({ width, layout, breakpoints, originalWidth, }: {
width?: number;
layout: ImageLayout;
breakpoints?: Array<number>;
originalWidth?: number;
}) => Array<number>;
/**
* Gets the `sizes` attribute for an image, based on the layout and width
*/
export declare const getSizesAttribute: ({ width, layout, }: {
width?: number;
layout?: ImageLayout;
}) => string | undefined;

107
node_modules/astro/dist/assets/layout.js generated vendored Normal file
View File

@@ -0,0 +1,107 @@
const DEFAULT_RESOLUTIONS = [
640,
// older and lower-end phones
750,
// iPhone 6-8
828,
// iPhone XR/11
960,
// older horizontal phones
1080,
// iPhone 6-8 Plus
1280,
// 720p
1668,
// Various iPads
1920,
// 1080p
2048,
// QXGA
2560,
// WQXGA
3200,
// QHD+
3840,
// 4K
4480,
// 4.5K
5120,
// 5K
6016
// 6K
];
const LIMITED_RESOLUTIONS = [
640,
// older and lower-end phones
750,
// iPhone 6-8
828,
// iPhone XR/11
1080,
// iPhone 6-8 Plus
1280,
// 720p
1668,
// Various iPads
2048,
// QXGA
2560
// WQXGA
];
const getWidths = ({
width,
layout,
breakpoints = DEFAULT_RESOLUTIONS,
originalWidth
}) => {
const smallerThanOriginal = (w) => !originalWidth || w <= originalWidth;
if (layout === "full-width") {
return breakpoints.filter(smallerThanOriginal);
}
if (!width) {
return [];
}
const doubleWidth = width * 2;
const maxSize = originalWidth ? Math.min(doubleWidth, originalWidth) : doubleWidth;
if (layout === "fixed") {
return originalWidth && width > originalWidth ? [originalWidth] : [width, maxSize];
}
if (layout === "constrained") {
return [
// Always include the image at 1x and 2x the specified width
width,
doubleWidth,
...breakpoints
].filter((w) => w <= maxSize).sort((a, b) => a - b);
}
return [];
};
const getSizesAttribute = ({
width,
layout
}) => {
if (!width || !layout) {
return void 0;
}
switch (layout) {
// If screen is wider than the max size then image width is the max size,
// otherwise it's the width of the screen
case "constrained":
return `(min-width: ${width}px) ${width}px, 100vw`;
// Image is always the same width, whatever the size of the screen
case "fixed":
return `${width}px`;
// Image is always the width of the screen
case "full-width":
return `100vw`;
case "none":
default:
return void 0;
}
};
export {
DEFAULT_RESOLUTIONS,
LIMITED_RESOLUTIONS,
getSizesAttribute,
getWidths
};

10
node_modules/astro/dist/assets/runtime.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import type { ImageMetadata } from './types.js';
export interface SvgComponentProps {
meta: ImageMetadata;
attributes: Record<string, string>;
children: string;
}
export declare function createSvgComponent({ meta, attributes, children }: SvgComponentProps): import("../runtime/server/index.js").AstroComponentFactory & ImageMetadata;
type SvgAttributes = Record<string, any>;
export declare function dropAttributes(attributes: SvgAttributes): SvgAttributes;
export {};

43
node_modules/astro/dist/assets/runtime.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import {
createComponent,
render,
spreadAttributes,
unescapeHTML
} from "../runtime/server/index.js";
function createSvgComponent({ meta, attributes, children }) {
const Component = createComponent((_, props) => {
const normalizedProps = normalizeProps(attributes, props);
return render`<svg${spreadAttributes(normalizedProps)}>${unescapeHTML(children)}</svg>`;
});
if (import.meta.env.DEV) {
makeNonEnumerable(Component);
Object.defineProperty(Component, Symbol.for("nodejs.util.inspect.custom"), {
value: (_, opts, inspect) => inspect(meta, opts)
});
}
Object.defineProperty(Component, "toJSON", {
value: () => meta,
enumerable: false
});
return Object.assign(Component, meta);
}
const ATTRS_TO_DROP = ["xmlns", "xmlns:xlink", "version"];
const DEFAULT_ATTRS = {};
function dropAttributes(attributes) {
for (const attr of ATTRS_TO_DROP) {
delete attributes[attr];
}
return attributes;
}
function normalizeProps(attributes, props) {
return dropAttributes({ ...DEFAULT_ATTRS, ...attributes, ...props });
}
function makeNonEnumerable(object) {
for (const property in object) {
Object.defineProperty(object, property, { enumerable: false });
}
}
export {
createSvgComponent,
dropAttributes
};

3
node_modules/astro/dist/assets/services/noop.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { type LocalImageService } from './service.js';
declare const noopService: LocalImageService;
export default noopService;

25
node_modules/astro/dist/assets/services/noop.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
import { isESMImportedImage } from "../utils/imageKind.js";
import { baseService, verifyOptions } from "./service.js";
const noopService = {
...baseService,
propertiesToHash: ["src"],
async validateOptions(options) {
if (isESMImportedImage(options.src) && options.src.format === "svg") {
options.format = "svg";
} else {
delete options.format;
}
verifyOptions(options);
return options;
},
async transform(inputBuffer, transformOptions) {
return {
data: inputBuffer,
format: transformOptions.format
};
}
};
var noop_default = noopService;
export {
noop_default as default
};

105
node_modules/astro/dist/assets/services/service.d.ts generated vendored Normal file
View File

@@ -0,0 +1,105 @@
import type { AstroConfig } from '../../types/public/config.js';
import type { ImageFit, ImageOutputFormat, ImageTransform, UnresolvedSrcSetValue } from '../types.js';
export type ImageService = LocalImageService | ExternalImageService;
export declare function isLocalService(service: ImageService | undefined): service is LocalImageService;
export declare function parseQuality(quality: string): string | number;
type ImageConfig<T> = Omit<AstroConfig['image'], 'service'> & {
service: {
entrypoint: string;
config: T;
};
assetQueryParams?: URLSearchParams;
};
interface SharedServiceProps<T extends Record<string, any> = Record<string, any>> {
/**
* Return the URL to the endpoint or URL your images are generated from.
*
* For a local service, your service should expose an endpoint handling the image requests, or use Astro's which by default, is located at `/_image`.
*
* For external services, this should point to the URL your images are coming from, for instance, `/_vercel/image`
*
*/
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
/**
* Generate additional `srcset` values for the image.
*
* While in most cases this is exclusively used for `srcset`, it can also be used in a more generic way to generate
* multiple variants of the same image. For instance, you can use this to generate multiple aspect ratios or multiple formats.
*/
getSrcSet?: (options: ImageTransform, imageConfig: ImageConfig<T>) => UnresolvedSrcSetValue[] | Promise<UnresolvedSrcSetValue[]>;
/**
* Return any additional HTML attributes separate from `src` that your service requires to show the image properly.
*
* For example, you might want to return the `width` and `height` to avoid CLS, or a particular `class` or `style`.
* In most cases, you'll want to return directly what your user supplied you, minus the attributes that were used to generate the image.
*/
getHTMLAttributes?: (options: ImageTransform, imageConfig: ImageConfig<T>) => Record<string, any> | Promise<Record<string, any>>;
/**
* Validate and return the options passed by the user.
*
* This method is useful to present errors to users who have entered invalid options.
* For instance, if they are missing a required property or have entered an invalid image format.
*
* This method should returns options, and can be used to set defaults (ex: a default output format to be used if the user didn't specify one.)
*/
validateOptions?: (options: ImageTransform, imageConfig: ImageConfig<T>) => ImageTransform | Promise<ImageTransform>;
}
export type ExternalImageService<T extends Record<string, any> = Record<string, any>> = SharedServiceProps<T>;
type LocalImageTransform = {
src: string;
[key: string]: any;
};
export interface LocalImageService<T extends Record<string, any> = Record<string, any>> extends SharedServiceProps<T> {
/**
* Parse the requested parameters passed in the URL from `getURL` back into an object to be used later by `transform`.
*
* In most cases, this will get query parameters using, for example, `params.get('width')` and return those.
*/
parseURL: (url: URL, imageConfig: ImageConfig<T>) => LocalImageTransform | undefined | Promise<LocalImageTransform> | Promise<undefined>;
/**
* Performs the image transformations on the input image and returns both the binary data and
* final image format of the optimized image.
*/
transform: (inputBuffer: Uint8Array, transform: LocalImageTransform, imageConfig: ImageConfig<T>) => Promise<{
data: Uint8Array;
format: ImageOutputFormat;
}>;
/**
* A list of properties that should be used to generate the hash for the image.
*
* Generally, this should be all the properties that can change the result of the image. By default, this is `src`, `width`, `height`, `format`, `quality`, `fit`, `position`, and `background`.
*/
propertiesToHash?: string[];
}
export type BaseServiceTransform = {
src: string;
width?: number;
height?: number;
format: string;
quality?: string | null;
fit?: ImageFit;
position?: string;
background?: string;
};
export declare function verifyOptions(options: ImageTransform): void;
/**
* Basic local service using the included `_image` endpoint.
* This service intentionally does not implement `transform`.
*
* Example usage:
* ```ts
* const service = {
* getURL: baseService.getURL,
* parseURL: baseService.parseURL,
* getHTMLAttributes: baseService.getHTMLAttributes,
* async transform(inputBuffer, transformOptions) {...}
* }
* ```
*
* This service adhere to the included services limitations:
* - Only a limited amount of formats are supported.
* - For remote images, `width` and `height` are always required.
*
*/
export declare const baseService: Omit<LocalImageService, 'transform'>;
export {};

245
node_modules/astro/dist/assets/services/service.js generated vendored Normal file
View File

@@ -0,0 +1,245 @@
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { isRemotePath, joinPaths } from "../../core/path.js";
import { DEFAULT_HASH_PROPS, DEFAULT_OUTPUT_FORMAT, VALID_SUPPORTED_FORMATS } from "../consts.js";
import { isESMImportedImage, isRemoteImage } from "../utils/imageKind.js";
function isLocalService(service) {
if (!service) {
return false;
}
return "transform" in service;
}
function parseQuality(quality) {
let result = parseInt(quality);
if (Number.isNaN(result)) {
return quality;
}
return result;
}
const sortNumeric = (a, b) => a - b;
function verifyOptions(options) {
if (!options.src || !isRemoteImage(options.src) && !isESMImportedImage(options.src)) {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(
JSON.stringify(options.src),
typeof options.src,
JSON.stringify(options, (_, v) => v === void 0 ? null : v)
)
});
}
if (!isESMImportedImage(options.src)) {
if (options.src.startsWith("/@fs/") || !isRemotePath(options.src) && !options.src.startsWith("/")) {
throw new AstroError({
...AstroErrorData.LocalImageUsedWrongly,
message: AstroErrorData.LocalImageUsedWrongly.message(options.src)
});
}
let missingDimension;
if (!options.width && !options.height) {
missingDimension = "both";
} else if (!options.width && options.height) {
missingDimension = "width";
} else if (options.width && !options.height) {
missingDimension = "height";
}
if (missingDimension) {
throw new AstroError({
...AstroErrorData.MissingImageDimension,
message: AstroErrorData.MissingImageDimension.message(missingDimension, options.src)
});
}
} else {
if (!VALID_SUPPORTED_FORMATS.includes(options.src.format)) {
throw new AstroError({
...AstroErrorData.UnsupportedImageFormat,
message: AstroErrorData.UnsupportedImageFormat.message(
options.src.format,
options.src.src,
VALID_SUPPORTED_FORMATS
)
});
}
if (options.widths && options.densities) {
throw new AstroError(AstroErrorData.IncompatibleDescriptorOptions);
}
if (options.src.format === "svg" && options.format !== "svg" || options.src.format !== "svg" && options.format === "svg") {
throw new AstroError(AstroErrorData.UnsupportedImageConversion);
}
}
}
const baseService = {
propertiesToHash: DEFAULT_HASH_PROPS,
validateOptions(options) {
if (isESMImportedImage(options.src) && options.src.format === "svg") {
options.format = "svg";
}
verifyOptions(options);
if (!options.format) {
options.format = DEFAULT_OUTPUT_FORMAT;
}
if (options.width) options.width = Math.round(options.width);
if (options.height) options.height = Math.round(options.height);
if (options.layout && options.width && options.height) {
options.fit ??= "cover";
delete options.layout;
}
if (options.fit === "none") {
delete options.fit;
}
return options;
},
getHTMLAttributes(options) {
const { targetWidth, targetHeight } = getTargetDimensions(options);
const {
src,
width,
height,
format,
quality,
densities,
widths,
formats,
layout,
priority,
fit,
position,
background,
...attributes
} = options;
return {
...attributes,
width: targetWidth,
height: targetHeight,
loading: attributes.loading ?? "lazy",
decoding: attributes.decoding ?? "async"
};
},
getSrcSet(options) {
const { targetWidth, targetHeight } = getTargetDimensions(options);
const aspectRatio = targetWidth / targetHeight;
const { widths, densities } = options;
const targetFormat = options.format ?? DEFAULT_OUTPUT_FORMAT;
let transformedWidths = (widths ?? []).sort(sortNumeric);
let imageWidth = options.width;
let maxWidth = Infinity;
if (isESMImportedImage(options.src)) {
imageWidth = options.src.width;
maxWidth = imageWidth;
if (transformedWidths.length > 0 && transformedWidths.at(-1) > maxWidth) {
transformedWidths = transformedWidths.filter((width) => width <= maxWidth);
transformedWidths.push(maxWidth);
}
}
transformedWidths = Array.from(new Set(transformedWidths));
const {
width: transformWidth,
height: transformHeight,
...transformWithoutDimensions
} = options;
let allWidths = [];
if (densities) {
const densityValues = densities.map((density) => {
if (typeof density === "number") {
return density;
} else {
return parseFloat(density);
}
});
const densityWidths = densityValues.sort(sortNumeric).map((density) => Math.round(targetWidth * density));
allWidths = densityWidths.map((width, index) => ({
width,
descriptor: `${densityValues[index]}x`
}));
} else if (transformedWidths.length > 0) {
allWidths = transformedWidths.map((width) => ({
width,
descriptor: `${width}w`
}));
}
return allWidths.map(({ width, descriptor }) => {
const height = Math.round(width / aspectRatio);
const transform = { ...transformWithoutDimensions, width, height };
return {
transform,
descriptor,
attributes: {
type: `image/${targetFormat}`
}
};
});
},
getURL(options, imageConfig) {
const searchParams = new URLSearchParams();
if (isESMImportedImage(options.src)) {
searchParams.append("href", options.src.src);
} else if (isRemoteAllowed(options.src, imageConfig)) {
searchParams.append("href", options.src);
} else {
return options.src;
}
const params = {
w: "width",
h: "height",
q: "quality",
f: "format",
fit: "fit",
position: "position",
background: "background"
};
Object.entries(params).forEach(([param, key]) => {
options[key] && searchParams.append(param, options[key].toString());
});
const imageEndpoint = joinPaths(import.meta.env.BASE_URL, imageConfig.endpoint.route);
let url = `${imageEndpoint}?${searchParams}`;
if (imageConfig.assetQueryParams) {
const assetQueryString = imageConfig.assetQueryParams.toString();
if (assetQueryString) {
url += "&" + assetQueryString;
}
}
return url;
},
parseURL(url) {
const params = url.searchParams;
if (!params.has("href")) {
return void 0;
}
const transform = {
src: params.get("href"),
width: params.has("w") ? parseInt(params.get("w")) : void 0,
height: params.has("h") ? parseInt(params.get("h")) : void 0,
format: params.get("f"),
quality: params.get("q"),
fit: params.get("fit"),
position: params.get("position") ?? void 0,
background: params.get("background") ?? void 0
};
return transform;
}
};
function getTargetDimensions(options) {
let targetWidth = options.width;
let targetHeight = options.height;
if (isESMImportedImage(options.src)) {
const aspectRatio = options.src.width / options.src.height;
if (targetHeight && !targetWidth) {
targetWidth = Math.round(targetHeight * aspectRatio);
} else if (targetWidth && !targetHeight) {
targetHeight = Math.round(targetWidth / aspectRatio);
} else if (!targetWidth && !targetHeight) {
targetWidth = options.src.width;
targetHeight = options.src.height;
}
}
return {
targetWidth,
targetHeight
};
}
export {
baseService,
isLocalService,
parseQuality,
verifyOptions
};

14
node_modules/astro/dist/assets/services/sharp.d.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ResizeOptions, SharpOptions } from 'sharp';
import { type LocalImageService } from './service.js';
export interface SharpImageServiceConfig {
/**
* The `limitInputPixels` option passed to Sharp. See https://sharp.pixelplumbing.com/api-constructor for more information
*/
limitInputPixels?: SharpOptions['limitInputPixels'];
/**
* The `kernel` option is passed to resize calls. See https://sharp.pixelplumbing.com/api-resize/ for more information
*/
kernel?: ResizeOptions['kernel'];
}
declare const sharpService: LocalImageService<SharpImageServiceConfig>;
export default sharpService;

104
node_modules/astro/dist/assets/services/sharp.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import {
baseService,
parseQuality
} from "./service.js";
let sharp;
const qualityTable = {
low: 25,
mid: 50,
high: 80,
max: 100
};
async function loadSharp() {
let sharpImport;
try {
sharpImport = (await import("sharp")).default;
} catch {
throw new AstroError(AstroErrorData.MissingSharp);
}
sharpImport.cache(false);
return sharpImport;
}
const fitMap = {
fill: "fill",
contain: "inside",
cover: "cover",
none: "outside",
"scale-down": "inside",
outside: "outside",
inside: "inside"
};
const sharpService = {
validateOptions: baseService.validateOptions,
getURL: baseService.getURL,
parseURL: baseService.parseURL,
getHTMLAttributes: baseService.getHTMLAttributes,
getSrcSet: baseService.getSrcSet,
async transform(inputBuffer, transformOptions, config) {
if (!sharp) sharp = await loadSharp();
const transform = transformOptions;
const kernel = config.service.config.kernel;
if (transform.format === "svg") return { data: inputBuffer, format: "svg" };
const result = sharp(inputBuffer, {
failOnError: false,
pages: -1,
limitInputPixels: config.service.config.limitInputPixels
});
result.rotate();
const { format } = await result.metadata();
const withoutEnlargement = Boolean(transform.fit);
if (transform.width && transform.height && transform.fit) {
const fit = fitMap[transform.fit] ?? "inside";
result.resize({
width: Math.round(transform.width),
height: Math.round(transform.height),
kernel,
fit,
position: transform.position,
withoutEnlargement
});
} else if (transform.height && !transform.width) {
result.resize({
height: Math.round(transform.height),
kernel,
withoutEnlargement
});
} else if (transform.width) {
result.resize({
width: Math.round(transform.width),
kernel,
withoutEnlargement
});
}
if (transform.background) {
result.flatten({ background: transform.background });
}
if (transform.format) {
let quality = void 0;
if (transform.quality) {
const parsedQuality = parseQuality(transform.quality);
if (typeof parsedQuality === "number") {
quality = parsedQuality;
} else {
quality = transform.quality in qualityTable ? qualityTable[transform.quality] : void 0;
}
}
if (transform.format === "webp" && format === "gif") {
result.webp({ quality: typeof quality === "number" ? quality : void 0, loop: 0 });
} else {
result.toFormat(transform.format, { quality });
}
}
const { data, info } = await result.toBuffer({ resolveWithObject: true });
const needsCopy = "buffer" in data && data.buffer instanceof SharedArrayBuffer;
return {
data: needsCopy ? new Uint8Array(data) : data,
format: info.format
};
}
};
var sharp_default = sharpService;
export {
sharp_default as default
};

256
node_modules/astro/dist/assets/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,256 @@
import type { OmitPreservingIndexSignature, Simplify, WithRequired } from '../type-utils.js';
import type { VALID_INPUT_FORMATS, VALID_OUTPUT_FORMATS } from './consts.js';
import type { ImageService } from './services/service.js';
export type ImageQualityPreset = 'low' | 'mid' | 'high' | 'max' | (string & {});
export type ImageQuality = ImageQualityPreset | number;
export type ImageInputFormat = (typeof VALID_INPUT_FORMATS)[number];
export type ImageOutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
export type ImageLayout = 'constrained' | 'fixed' | 'full-width' | 'none';
export type ImageFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down' | (string & {});
export type AssetsGlobalStaticImagesList = Map<string, {
originalSrcPath: string | undefined;
transforms: Map<string, {
finalPath: string;
transform: ImageTransform;
}>;
}>;
declare global {
var astroAsset: {
imageService?: ImageService;
addStaticImage?: ((options: ImageTransform, hashProperties: string[], fsPath: string | undefined) => string) | undefined;
staticImages?: AssetsGlobalStaticImagesList;
referencedImages?: Set<string>;
};
}
declare const isESMImport: unique symbol;
export type OmitBrand<T> = Omit<T, typeof isESMImport>;
/**
* Type returned by ESM imports of images
*/
export type ImageMetadata = {
src: string;
width: number;
height: number;
format: ImageInputFormat;
orientation?: number;
[isESMImport]?: true;
};
export declare function isImageMetadata(src: any): src is ImageMetadata;
/**
* A yet to be completed with an url `SrcSetValue`. Other hooks will only see a resolved value, where the URL of the image has been added.
*/
export type UnresolvedSrcSetValue = {
transform: ImageTransform;
descriptor?: string;
attributes?: Record<string, any>;
};
export type SrcSetValue = UnresolvedSrcSetValue & {
url: string;
};
/**
* A yet to be resolved image transform. Used by `getImage`
*/
export type UnresolvedImageTransform = Simplify<OmitPreservingIndexSignature<ImageTransform, 'src'> & {
src: ImageMetadata | string | Promise<{
default: ImageMetadata;
}>;
inferSize?: boolean;
}> & {
[isESMImport]?: never;
};
/**
* Options accepted by the image transformation service.
*/
export type ImageTransform = {
src: ImageMetadata | string;
width?: number | undefined;
widths?: number[] | undefined;
densities?: (number | `${number}x`)[] | undefined;
height?: number | undefined;
quality?: ImageQuality | undefined;
format?: ImageOutputFormat | undefined;
fit?: ImageFit | undefined;
position?: string | undefined;
background?: string | undefined;
[key: string]: any;
} & Astro.CustomImageProps;
export interface GetImageResult {
rawOptions: ImageTransform;
options: ImageTransform;
src: string;
srcSet: {
values: SrcSetValue[];
attribute: string;
};
attributes: Record<string, any>;
}
type ImageSharedProps<T> = T & {
/**
* Width of the image, the value of this property will be used to assign the `width` property on the final `img` element.
*
* This value will additionally be used to resize the image to the desired width, taking into account the original aspect ratio of the image.
*
* **Example**:
* ```astro
* <Image src={...} width={300} alt="..." />
* ```
* **Result**:
* ```html
* <img src="..." width="300" height="..." alt="..." />
* ```
*/
width?: number | `${number}`;
/**
* Height of the image, the value of this property will be used to assign the `height` property on the final `img` element.
*
* For local images, if `width` is not present, this value will additionally be used to resize the image to the desired height, taking into account the original aspect ratio of the image.
*
* **Example**:
* ```astro
* <Image src={...} height={300} alt="..." />
* ```
* **Result**:
* ```html
* <img src="..." height="300" width="..." alt="..." />
* ```
*/
height?: number | `${number}`;
/**
* Desired output format for the image. Defaults to `webp`.
*
* **Example**:
* ```astro
* <Image src={...} format="avif" alt="..." />
* ```
*/
format?: ImageOutputFormat;
/**
* Desired quality for the image. Value can either be a preset such as `low` or `high`, or a numeric value from 0 to 100.
*
* The perceptual quality of the output image is service-specific.
* For instance, a certain service might decide that `high` results in a very beautiful image, but another could choose for it to be at best passable.
*
* **Example**:
* ```astro
* <Image src={...} quality='high' alt="..." />
* <Image src={...} quality={300} alt="..." />
* ```
*/
quality?: ImageQuality;
/**
* If true, the image will be loaded with a higher priority. This can be useful for images that are visible above the fold. There should usually be only one image with `priority` set to `true` per page.
* All other images will be lazy-loaded according to when they are in the viewport.
* **Example**:
* ```astro
* <Image src={...} priority alt="..." />
* ```
*/
priority?: boolean;
} & ({
/**
* The layout type for responsive images.
*
* Allowed values are `constrained`, `fixed`, `full-width` or `none`. Defaults to value of `image.layout`.
*
* - `constrained` - The image will scale to fit the container, maintaining its aspect ratio, but will not exceed the specified dimensions.
* - `fixed` - The image will maintain its original dimensions.
* - `full-width` - The image will scale to fit the container, maintaining its aspect ratio, even if that means the image will exceed its original dimensions.
*
* **Example**:
* ```astro
* <Image src={...} layout="constrained" alt="..." />
* ```
*/
layout?: ImageLayout;
/**
* Defines how the image should be cropped if the aspect ratio is changed. Requires `layout` to be set.
*
* Default is `cover`. Allowed values are `fill`, `contain`, `cover`, `none` or `scale-down`. These behave like the equivalent CSS `object-fit` values. Other values may be passed if supported by the image service.
*
* **Example**:
* ```astro
* <Image src={...} fit="contain" alt="..." />
* ```
*/
fit?: ImageFit;
/**
* Defines the position of the image when cropping. Requires `layout` to be set.
*
* The value is a string that specifies the position of the image, which matches the CSS `object-position` property. Other values may be passed if supported by the image service.
*
* **Example**:
* ```astro
* <Image src={...} position="center top" alt="..." />
* ```
*/
position?: string;
/**
* A list of widths to generate images for. The value of this property will be used to assign the `srcset` property on the final `img` element.
*
* This attribute is incompatible with `densities`.
*/
widths?: number[];
densities?: never;
} | {
/**
* A list of pixel densities to generate images for. The value of this property will be used to assign the `srcset` property on the final `img` element.
*
* This attribute is incompatible with `widths`.
*/
densities?: (number | `${number}x`)[];
widths?: never;
layout?: never;
fit?: never;
position?: never;
}) & Astro.CustomImageProps;
export type LocalImageProps<T> = ImageSharedProps<T> & {
/**
* A reference to a local image imported through an ESM import.
*
* **Example**:
* ```js
* import myImage from "../assets/my_image.png";
* ```
* And then refer to the image, like so:
* ```astro
* <Image src={myImage} alt="..."></Image>
* ```
*/
src: ImageMetadata | Promise<{
default: ImageMetadata;
}>;
};
export type RemoteImageProps<T> = (ImageSharedProps<T> & {
/**
* URL of a remote image. Can start with a protocol (ex: `https://`) or alternatively `/`, or `Astro.url`, for images in the `public` folder
*
* Remote images are not optimized, and require both `width` and `height` to be set.
*
* **Example**:
* ```
* <Image src="https://example.com/image.png" width={450} height={300} alt="..." />
* ```
*/
src: string;
/**
* When inferSize is true width and height are not required
*/
inferSize: true;
}) | (WithRequired<ImageSharedProps<T>, 'width' | 'height'> & {
/**
* URL of a remote image. Can start with a protocol (ex: `https://`) or alternatively `/`, or `Astro.url`, for images in the `public` folder
*
* Remote images are not optimized, and require both `width` and `height` to be set.
*
* **Example**:
* ```
* <Image src="https://example.com/image.png" width={450} height={300} alt="..." />
* ```
*/
src: string;
/**
* When inferSize is false or undefined width and height are required
*/
inferSize?: false | undefined;
});
export {};

7
node_modules/astro/dist/assets/types.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
const isESMImport = Symbol("#isESM");
function isImageMetadata(src) {
return src.fsPath && !("fsPath" in src);
}
export {
isImageMetadata
};

Some files were not shown because too many files have changed in this diff Show More