astro 5.7.5 → 5.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/components/image.css +5 -12
  2. package/dist/assets/fonts/config.d.ts +9 -9
  3. package/dist/assets/fonts/config.js +3 -4
  4. package/dist/assets/fonts/constants.d.ts +3 -73
  5. package/dist/assets/fonts/constants.js +16 -68
  6. package/dist/assets/fonts/definitions.d.ts +73 -0
  7. package/dist/assets/fonts/definitions.js +0 -0
  8. package/dist/assets/fonts/implementations/css-renderer.d.ts +9 -0
  9. package/dist/assets/fonts/implementations/css-renderer.js +42 -0
  10. package/dist/assets/fonts/implementations/data-collector.d.ts +3 -0
  11. package/dist/assets/fonts/implementations/data-collector.js +21 -0
  12. package/dist/assets/fonts/implementations/error-handler.d.ts +2 -0
  13. package/dist/assets/fonts/implementations/error-handler.js +33 -0
  14. package/dist/assets/fonts/implementations/font-fetcher.d.ts +8 -0
  15. package/dist/assets/fonts/implementations/font-fetcher.js +34 -0
  16. package/dist/assets/fonts/implementations/font-metrics-resolver.d.ts +5 -0
  17. package/dist/assets/fonts/implementations/font-metrics-resolver.js +60 -0
  18. package/dist/assets/fonts/implementations/font-type-extractor.d.ts +4 -0
  19. package/dist/assets/fonts/implementations/font-type-extractor.js +22 -0
  20. package/dist/assets/fonts/implementations/hasher.d.ts +2 -0
  21. package/dist/assets/fonts/implementations/hasher.js +14 -0
  22. package/dist/assets/fonts/implementations/local-provider-url-resolver.d.ts +5 -0
  23. package/dist/assets/fonts/implementations/local-provider-url-resolver.js +17 -0
  24. package/dist/assets/fonts/implementations/remote-font-provider-mod-resolver.d.ts +6 -0
  25. package/dist/assets/fonts/implementations/remote-font-provider-mod-resolver.js +20 -0
  26. package/dist/assets/fonts/implementations/remote-font-provider-resolver.d.ts +6 -0
  27. package/dist/assets/fonts/implementations/remote-font-provider-resolver.js +47 -0
  28. package/dist/assets/fonts/implementations/storage.d.ts +4 -0
  29. package/dist/assets/fonts/implementations/storage.js +14 -0
  30. package/dist/assets/fonts/implementations/system-fallbacks-provider.d.ts +11 -0
  31. package/dist/assets/fonts/implementations/system-fallbacks-provider.js +74 -0
  32. package/dist/assets/fonts/implementations/url-proxy-content-resolver.d.ts +5 -0
  33. package/dist/assets/fonts/implementations/url-proxy-content-resolver.js +28 -0
  34. package/dist/assets/fonts/implementations/url-proxy.d.ts +8 -0
  35. package/dist/assets/fonts/implementations/url-proxy.js +26 -0
  36. package/dist/assets/fonts/logic/extract-unifont-providers.d.ts +10 -0
  37. package/dist/assets/fonts/logic/extract-unifont-providers.js +28 -0
  38. package/dist/assets/fonts/logic/normalize-remote-font-faces.d.ts +6 -0
  39. package/dist/assets/fonts/logic/normalize-remote-font-faces.js +36 -0
  40. package/dist/assets/fonts/logic/optimize-fallbacks.d.ts +17 -0
  41. package/dist/assets/fonts/logic/optimize-fallbacks.js +47 -0
  42. package/dist/assets/fonts/logic/resolve-families.d.ts +17 -0
  43. package/dist/assets/fonts/logic/resolve-families.js +67 -0
  44. package/dist/assets/fonts/orchestrate.d.ts +37 -0
  45. package/dist/assets/fonts/orchestrate.js +125 -0
  46. package/dist/assets/fonts/providers/local.d.ts +6 -7
  47. package/dist/assets/fonts/providers/local.js +26 -29
  48. package/dist/assets/fonts/types.d.ts +32 -2
  49. package/dist/assets/fonts/utils.d.ts +17 -87
  50. package/dist/assets/fonts/utils.js +21 -183
  51. package/dist/assets/fonts/vite-plugin-fonts.js +98 -80
  52. package/dist/assets/internal.js +0 -2
  53. package/dist/assets/layout.js +4 -4
  54. package/dist/assets/types.d.ts +4 -4
  55. package/dist/content/content-layer.js +3 -3
  56. package/dist/core/config/schemas/base.d.ts +19 -19
  57. package/dist/core/config/schemas/base.js +1 -1
  58. package/dist/core/config/schemas/relative.d.ts +25 -25
  59. package/dist/core/constants.js +1 -1
  60. package/dist/core/dev/dev.js +1 -1
  61. package/dist/core/errors/errors-data.d.ts +2 -1
  62. package/dist/core/errors/errors-data.js +2 -1
  63. package/dist/core/messages.js +2 -2
  64. package/dist/core/routing/manifest/create.js +4 -1
  65. package/dist/types/public/config.d.ts +19 -22
  66. package/dist/vite-plugin-markdown/images.js +4 -4
  67. package/package.json +4 -4
  68. package/types/content.d.ts +11 -4
  69. package/dist/assets/fonts/load.d.ts +0 -20
  70. package/dist/assets/fonts/load.js +0 -162
  71. package/dist/assets/fonts/metrics.d.ts +0 -10
  72. package/dist/assets/fonts/metrics.js +0 -55
  73. package/dist/assets/fonts/providers/utils.d.ts +0 -9
  74. package/dist/assets/fonts/providers/utils.js +0 -37
@@ -0,0 +1,125 @@
1
+ import * as unifont from "unifont";
2
+ import { LOCAL_PROVIDER_NAME } from "./constants.js";
3
+ import { extractUnifontProviders } from "./logic/extract-unifont-providers.js";
4
+ import { normalizeRemoteFontFaces } from "./logic/normalize-remote-font-faces.js";
5
+ import { optimizeFallbacks } from "./logic/optimize-fallbacks.js";
6
+ import { resolveFamilies } from "./logic/resolve-families.js";
7
+ import { resolveLocalFont } from "./providers/local.js";
8
+ import { pickFontFaceProperty, unifontFontFaceDataToProperties } from "./utils.js";
9
+ async function orchestrate({
10
+ families,
11
+ hasher,
12
+ remoteFontProviderResolver,
13
+ localProviderUrlResolver,
14
+ storage,
15
+ cssRenderer,
16
+ systemFallbacksProvider,
17
+ fontMetricsResolver,
18
+ fontTypeExtractor,
19
+ createUrlProxy,
20
+ defaults
21
+ }) {
22
+ let resolvedFamilies = await resolveFamilies({
23
+ families,
24
+ hasher,
25
+ remoteFontProviderResolver,
26
+ localProviderUrlResolver
27
+ });
28
+ const extractedUnifontProvidersResult = extractUnifontProviders({
29
+ families: resolvedFamilies,
30
+ hasher
31
+ });
32
+ resolvedFamilies = extractedUnifontProvidersResult.families;
33
+ const unifontProviders = extractedUnifontProvidersResult.providers;
34
+ const { resolveFont } = await unifont.createUnifont(unifontProviders, {
35
+ storage
36
+ });
37
+ const fontFileDataMap = /* @__PURE__ */ new Map();
38
+ const consumableMap = /* @__PURE__ */ new Map();
39
+ for (const family of resolvedFamilies) {
40
+ const preloadData = [];
41
+ let css = "";
42
+ const collectedFonts = [];
43
+ const fallbacks = family.fallbacks ?? defaults.fallbacks ?? [];
44
+ const urlProxy = createUrlProxy({
45
+ local: family.provider === LOCAL_PROVIDER_NAME,
46
+ hasUrl: (hash) => fontFileDataMap.has(hash),
47
+ saveUrl: ({ hash, url, init }) => {
48
+ fontFileDataMap.set(hash, { url, init });
49
+ },
50
+ savePreload: (preload) => {
51
+ preloadData.push(preload);
52
+ },
53
+ saveFontData: (collected) => {
54
+ if (fallbacks && fallbacks.length > 0 && // If the same data has already been sent for this family, we don't want to have
55
+ // duplicated fallbacks. Such scenario can occur with unicode ranges.
56
+ !collectedFonts.some((f) => JSON.stringify(f.data) === JSON.stringify(collected.data))) {
57
+ collectedFonts.push(collected);
58
+ }
59
+ }
60
+ });
61
+ let fonts;
62
+ if (family.provider === LOCAL_PROVIDER_NAME) {
63
+ const result = resolveLocalFont({
64
+ family,
65
+ urlProxy,
66
+ fontTypeExtractor
67
+ });
68
+ fonts = result.fonts;
69
+ } else {
70
+ const result = await resolveFont(
71
+ family.name,
72
+ // We do not merge the defaults, we only provide defaults as a fallback
73
+ {
74
+ weights: family.weights ?? defaults.weights,
75
+ styles: family.styles ?? defaults.styles,
76
+ subsets: family.subsets ?? defaults.subsets,
77
+ fallbacks: family.fallbacks ?? defaults.fallbacks
78
+ },
79
+ // By default, unifont goes through all providers. We use a different approach where
80
+ // we specify a provider per font. Name has been set while extracting unifont providers
81
+ // from families (inside extractUnifontProviders).
82
+ [family.provider.name]
83
+ );
84
+ fonts = normalizeRemoteFontFaces({ fonts: result.fonts, urlProxy });
85
+ }
86
+ for (const data of fonts) {
87
+ css += cssRenderer.generateFontFace(
88
+ family.nameWithHash,
89
+ unifontFontFaceDataToProperties({
90
+ src: data.src,
91
+ weight: data.weight,
92
+ style: data.style,
93
+ // User settings override the generated font settings. We use a helper function
94
+ // because local and remote providers store this data in different places.
95
+ display: pickFontFaceProperty("display", { data, family }),
96
+ unicodeRange: pickFontFaceProperty("unicodeRange", { data, family }),
97
+ stretch: pickFontFaceProperty("stretch", { data, family }),
98
+ featureSettings: pickFontFaceProperty("featureSettings", { data, family }),
99
+ variationSettings: pickFontFaceProperty("variationSettings", { data, family })
100
+ })
101
+ );
102
+ }
103
+ const cssVarValues = [family.nameWithHash];
104
+ const optimizeFallbacksResult = await optimizeFallbacks({
105
+ family,
106
+ fallbacks,
107
+ collectedFonts,
108
+ enabled: family.optimizedFallbacks ?? defaults.optimizedFallbacks ?? false,
109
+ systemFallbacksProvider,
110
+ fontMetricsResolver
111
+ });
112
+ if (optimizeFallbacksResult) {
113
+ css += optimizeFallbacksResult.css;
114
+ cssVarValues.push(...optimizeFallbacksResult.fallbacks);
115
+ } else {
116
+ cssVarValues.push(...fallbacks);
117
+ }
118
+ css += cssRenderer.generateCssVariable(family.cssVariable, cssVarValues);
119
+ consumableMap.set(family.cssVariable, { preloadData, css });
120
+ }
121
+ return { fontFileDataMap, consumableMap };
122
+ }
123
+ export {
124
+ orchestrate
125
+ };
@@ -1,13 +1,12 @@
1
1
  import type * as unifont from 'unifont';
2
+ import type { FontTypeExtractor, UrlProxy } from '../definitions.js';
2
3
  import type { ResolvedLocalFontFamily } from '../types.js';
3
- type InitializedProvider = NonNullable<Awaited<ReturnType<unifont.Provider>>>;
4
- type ResolveFontResult = NonNullable<Awaited<ReturnType<InitializedProvider['resolveFont']>>>;
5
4
  interface Options {
6
5
  family: ResolvedLocalFontFamily;
7
- proxyURL: (params: {
8
- value: string;
9
- data: Partial<unifont.FontFaceData>;
10
- }) => string;
6
+ urlProxy: UrlProxy;
7
+ fontTypeExtractor: FontTypeExtractor;
11
8
  }
12
- export declare function resolveLocalFont({ family, proxyURL }: Options): ResolveFontResult;
9
+ export declare function resolveLocalFont({ family, urlProxy, fontTypeExtractor }: Options): {
10
+ fonts: Array<unifont.FontFaceData>;
11
+ };
13
12
  export {};
@@ -1,35 +1,32 @@
1
1
  import { FONT_FORMAT_MAP } from "../constants.js";
2
- import { extractFontType } from "../utils.js";
3
- function resolveLocalFont({ family, proxyURL }) {
4
- const fonts = [];
5
- for (const variant of family.variants) {
6
- const data = {
2
+ function resolveLocalFont({ family, urlProxy, fontTypeExtractor }) {
3
+ return {
4
+ fonts: family.variants.map((variant) => ({
7
5
  weight: variant.weight,
8
6
  style: variant.style,
9
- src: variant.src.map(({ url: originalURL, tech }) => {
10
- return {
11
- originalURL,
12
- url: proxyURL({
13
- value: originalURL,
14
- data: {
15
- weight: variant.weight,
16
- style: variant.style
17
- }
18
- }),
19
- format: FONT_FORMAT_MAP[extractFontType(originalURL)],
20
- tech
21
- };
22
- })
23
- };
24
- if (variant.display) data.display = variant.display;
25
- if (variant.unicodeRange) data.unicodeRange = variant.unicodeRange;
26
- if (variant.stretch) data.stretch = variant.stretch;
27
- if (variant.featureSettings) data.featureSettings = variant.featureSettings;
28
- if (variant.variationSettings) data.variationSettings = variant.variationSettings;
29
- fonts.push(data);
30
- }
31
- return {
32
- fonts
7
+ // We proxy each source
8
+ src: variant.src.map((source, index) => ({
9
+ originalURL: source.url,
10
+ url: urlProxy.proxy({
11
+ url: source.url,
12
+ // We only use the first source for preloading. For example if woff2 and woff
13
+ // are available, we only keep woff2.
14
+ collectPreload: index === 0,
15
+ data: {
16
+ weight: variant.weight,
17
+ style: variant.style
18
+ },
19
+ init: null
20
+ }),
21
+ format: FONT_FORMAT_MAP[fontTypeExtractor.extract(source.url)],
22
+ tech: source.tech
23
+ })),
24
+ display: variant.display,
25
+ unicodeRange: variant.unicodeRange,
26
+ stretch: variant.stretch,
27
+ featureSettings: variant.featureSettings,
28
+ variationSettings: variant.variationSettings
29
+ }))
33
30
  };
34
31
  }
35
32
  export {
@@ -1,7 +1,9 @@
1
+ import type { Font } from '@capsizecss/unpack';
1
2
  import type * as unifont from 'unifont';
2
3
  import type { z } from 'zod';
3
4
  import type { fontProviderSchema, localFontFamilySchema, remoteFontFamilySchema } from './config.js';
4
- import type { FONT_TYPES } from './constants.js';
5
+ import type { FONT_TYPES, GENERIC_FALLBACK_NAMES } from './constants.js';
6
+ import type { CollectedFontForMetrics } from './logic/optimize-fallbacks.js';
5
7
  export type AstroFontProvider = z.infer<typeof fontProviderSchema>;
6
8
  export interface ResolvedFontProvider {
7
9
  name?: string;
@@ -22,6 +24,7 @@ export interface ResolvedLocalFontFamily extends ResolvedFontFamilyAttributes, O
22
24
  }>;
23
25
  }
24
26
  type RemoteFontFamily = z.infer<typeof remoteFontFamilySchema>;
27
+ /** @lintignore somehow required by pickFontFaceProperty in utils */
25
28
  export interface ResolvedRemoteFontFamily extends ResolvedFontFamilyAttributes, Omit<z.output<typeof remoteFontFamilySchema>, 'provider' | 'weights'> {
26
29
  provider: ResolvedFontProvider;
27
30
  weights?: Array<string>;
@@ -32,7 +35,7 @@ export type FontType = (typeof FONT_TYPES)[number];
32
35
  /**
33
36
  * Preload data is used for links generation inside the <Font /> component
34
37
  */
35
- export type PreloadData = Array<{
38
+ export interface PreloadData {
36
39
  /**
37
40
  * Absolute link to a font file, eg. /_astro/fonts/abc.woff
38
41
  */
@@ -41,5 +44,32 @@ export type PreloadData = Array<{
41
44
  * A font type, eg. woff2, woff, ttf...
42
45
  */
43
46
  type: FontType;
47
+ }
48
+ export type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
49
+ export type GenericFallbackName = (typeof GENERIC_FALLBACK_NAMES)[number];
50
+ export type Defaults = Partial<Pick<ResolvedRemoteFontFamily, 'weights' | 'styles' | 'subsets' | 'fallbacks' | 'optimizedFallbacks'>>;
51
+ export interface FontFileData {
52
+ hash: string;
53
+ url: string;
54
+ init: RequestInit | null;
55
+ }
56
+ export interface CreateUrlProxyParams {
57
+ local: boolean;
58
+ hasUrl: (hash: string) => boolean;
59
+ saveUrl: (input: FontFileData) => void;
60
+ savePreload: (preload: PreloadData) => void;
61
+ saveFontData: (collected: CollectedFontForMetrics) => void;
62
+ }
63
+ /**
64
+ * Holds associations of hash and original font file URLs, so they can be
65
+ * downloaded whenever the hash is requested.
66
+ */
67
+ export type FontFileDataMap = Map<FontFileData['hash'], Pick<FontFileData, 'url' | 'init'>>;
68
+ /**
69
+ * Holds associations of CSS variables and preloadData/css to be passed to the virtual module.
70
+ */
71
+ export type ConsumableMap = Map<string, {
72
+ preloadData: Array<PreloadData>;
73
+ css: string;
44
74
  }>;
45
75
  export {};
@@ -1,97 +1,27 @@
1
1
  import type * as unifont from 'unifont';
2
2
  import type { Storage } from 'unstorage';
3
- import { DEFAULT_FALLBACKS } from './constants.js';
4
- import type { FontFaceMetrics, generateFallbackFontFace } from './metrics.js';
5
- import { type ResolveProviderOptions } from './providers/utils.js';
6
- import type { FontFamily, FontType, ResolvedFontFamily } from './types.js';
7
- export declare function toCSS(properties: Record<string, string | undefined>, indent?: number): string;
8
- export declare function renderFontFace(properties: Record<string, string | undefined>): string;
9
- export declare function generateFontFace(family: string, font: unifont.FontFaceData): string;
10
- export declare function renderFontSrc(sources: Exclude<unifont.FontFaceData['src'][number], string>[]): string;
11
- export declare function withoutQuotes(str: string): string;
12
- export declare function extractFontType(str: string): FontType;
13
- export declare function isFontType(str: string): str is FontType;
14
- export declare function cache(storage: Storage, key: string, cb: () => Promise<Buffer>): Promise<Buffer>;
15
- export interface ProxyURLOptions {
16
- /**
17
- * The original URL
18
- */
19
- value: string;
20
- /**
21
- * Specifies how the hash is computed. Can be based on the value,
22
- * a specific string for testing etc
23
- */
24
- hashString: (value: string) => string;
25
- /**
26
- * Use the hook to save the associated value and hash, and possibly
27
- * transform it (eg. apply a base)
28
- */
29
- collect: (data: {
30
- hash: string;
31
- type: FontType;
32
- value: string;
33
- }) => string;
34
- }
3
+ import type { CssProperties } from './definitions.js';
4
+ import type { FontType, GenericFallbackName, ResolvedFontFamily } from './types.js';
35
5
  /**
36
- * The fonts data we receive contains urls or file paths we do no control.
37
- * However, we will emit font files ourselves so we store the original value
38
- * and replace it with a url we control. For example with the value "https://foo.bar/file.woff2":
39
- * - font type is woff2
40
- * - hash will be "<hash>.woff2"
41
- * - `collect` will save the association of the original url and the new hash for later use
42
- * - the returned url will be `/_astro/fonts/<hash>.woff2`
6
+ * Turns unifont font face data into generic CSS properties, to be consumed by the CSS renderer.
43
7
  */
44
- export declare function proxyURL({ value, hashString, collect }: ProxyURLOptions): string;
45
- export declare function isGenericFontFamily(str: string): str is keyof typeof DEFAULT_FALLBACKS;
46
- export type GetMetricsForFamilyFont = {
47
- hash: string;
48
- url: string;
49
- data: Partial<unifont.FontFaceData>;
50
- };
51
- export type GetMetricsForFamily = (name: string,
52
- /** A remote url or local filepath to a font file. Used if metrics can't be resolved purely from the family name */
53
- font: GetMetricsForFamilyFont) => Promise<FontFaceMetrics>;
8
+ export declare function unifontFontFaceDataToProperties(font: Partial<unifont.FontFaceData>): CssProperties;
54
9
  /**
55
- * Generates CSS for a given family fallbacks if possible.
56
- *
57
- * It works by trying to get metrics (using capsize) of the provided font family.
58
- * If some can be computed, they will be applied to the eligible fallbacks to match
59
- * the original font shape as close as possible.
10
+ * Turns unifont font face data src into a valid CSS property.
11
+ * Adapted from https://github.com/nuxt/fonts/blob/main/src/css/render.ts#L68-L81
60
12
  */
61
- export declare function generateFallbacksCSS({ family, fallbacks: _fallbacks, font: fontData, metrics, }: {
62
- family: Pick<ResolvedFontFamily, 'name' | 'nameWithHash'>;
63
- /** The family fallbacks */
64
- fallbacks: Array<string>;
65
- font: Array<GetMetricsForFamilyFont>;
66
- metrics: {
67
- getMetricsForFamily: GetMetricsForFamily;
68
- generateFontFace: typeof generateFallbackFontFace;
69
- } | null;
70
- }): Promise<null | {
71
- css?: string;
72
- fallbacks: Array<string>;
73
- }>;
13
+ export declare function renderFontSrc(sources: Exclude<unifont.FontFaceData['src'][number], string>[]): string;
74
14
  /**
75
- * Resolves the font family provider. If none is provided, it will infer the provider as
76
- * one of the built-in providers and resolve it. The most important part is that if a
77
- * provider is not provided but `src` is, then it's inferred as the local provider.
15
+ * Removes the quotes from a string. Used for family names
78
16
  */
79
- export declare function resolveFontFamily({ family, generateNameWithHash, root, resolveMod, }: Omit<ResolveProviderOptions, 'provider'> & {
80
- family: FontFamily;
81
- generateNameWithHash: (family: FontFamily) => string;
82
- }): Promise<ResolvedFontFamily>;
17
+ export declare function withoutQuotes(str: string): string;
18
+ export declare function isFontType(str: string): str is FontType;
19
+ export declare function cache(storage: Storage, key: string, cb: () => Promise<Buffer>): Promise<Buffer>;
20
+ export declare function isGenericFontFamily(str: string): str is GenericFallbackName;
21
+ export declare function dedupe<const T extends Array<any>>(arr: T): T;
83
22
  export declare function sortObjectByKey<T extends Record<string, any>>(unordered: T): T;
84
- /**
85
- * Extracts providers from families so they can be consumed by unifont.
86
- * It deduplicates them based on their config and provider name:
87
- * - If several families use the same provider (by value, not by reference), we only use one provider
88
- * - If one provider is used with different settings for 2 families, we make sure there are kept as 2 providers
89
- */
90
- export declare function familiesToUnifontProviders({ families, hashString, }: {
91
- families: Array<ResolvedFontFamily>;
92
- hashString: (value: string) => string;
93
- }): {
94
- families: Array<ResolvedFontFamily>;
95
- providers: Array<unifont.Provider>;
96
- };
97
23
  export declare function resolveEntrypoint(root: URL, entrypoint: string): URL;
24
+ export declare function pickFontFaceProperty<T extends keyof Pick<unifont.FontFaceData, 'display' | 'unicodeRange' | 'stretch' | 'featureSettings' | 'variationSettings'>>(property: T, { data, family }: {
25
+ data: unifont.FontFaceData;
26
+ family: ResolvedFontFamily;
27
+ }): import("./types.js").ResolvedRemoteFontFamily[T] | NonNullable<unifont.FontFaceData[T]> | undefined;
@@ -1,18 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
- import { extname } from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- import { AstroError, AstroErrorData } from "../../core/errors/index.js";
5
- import { DEFAULT_FALLBACKS, FONT_TYPES, LOCAL_PROVIDER_NAME, SYSTEM_METRICS } from "./constants.js";
6
- import { resolveProvider } from "./providers/utils.js";
7
- function toCSS(properties, indent = 2) {
8
- return Object.entries(properties).filter(([, value]) => Boolean(value)).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
9
- }
10
- function renderFontFace(properties) {
11
- return `@font-face {
12
- ${toCSS(properties)}
13
- }
14
- `;
15
- }
2
+ import { pathToFileURL } from "node:url";
3
+ import { FONT_TYPES, GENERIC_FALLBACK_NAMES, LOCAL_PROVIDER_NAME } from "./constants.js";
16
4
  function unifontFontFaceDataToProperties(font) {
17
5
  return {
18
6
  src: font.src ? renderFontSrc(font.src) : void 0,
@@ -25,46 +13,25 @@ function unifontFontFaceDataToProperties(font) {
25
13
  "font-variation-settings": font.variationSettings
26
14
  };
27
15
  }
28
- function generateFontFace(family, font) {
29
- return renderFontFace({
30
- "font-family": family,
31
- ...unifontFontFaceDataToProperties(font)
32
- });
33
- }
34
16
  function renderFontSrc(sources) {
35
17
  return sources.map((src) => {
36
- if ("url" in src) {
37
- let rendered = `url("${src.url}")`;
38
- if (src.format) {
39
- rendered += ` format("${src.format}")`;
40
- }
41
- if (src.tech) {
42
- rendered += ` tech(${src.tech})`;
43
- }
44
- return rendered;
18
+ if ("name" in src) {
19
+ return `local("${src.name}")`;
45
20
  }
46
- return `local("${src.name}")`;
21
+ let rendered = `url("${src.url}")`;
22
+ if (src.format) {
23
+ rendered += ` format("${src.format}")`;
24
+ }
25
+ if (src.tech) {
26
+ rendered += ` tech(${src.tech})`;
27
+ }
28
+ return rendered;
47
29
  }).join(", ");
48
30
  }
49
31
  const QUOTES_RE = /^["']|["']$/g;
50
32
  function withoutQuotes(str) {
51
33
  return str.trim().replace(QUOTES_RE, "");
52
34
  }
53
- function extractFontType(str) {
54
- const extension = extname(str).slice(1);
55
- if (!isFontType(extension)) {
56
- throw new AstroError(
57
- {
58
- ...AstroErrorData.CannotExtractFontType,
59
- message: AstroErrorData.CannotExtractFontType.message(str)
60
- },
61
- {
62
- cause: `Unexpected extension, got "${extension}"`
63
- }
64
- );
65
- }
66
- return extension;
67
- }
68
35
  function isFontType(str) {
69
36
  return FONT_TYPES.includes(str);
70
37
  }
@@ -77,147 +44,20 @@ async function cache(storage, key, cb) {
77
44
  await storage.setItemRaw(key, data);
78
45
  return data;
79
46
  }
80
- function proxyURL({ value, hashString, collect }) {
81
- const type = extractFontType(value);
82
- const hash = `${hashString(value)}.${type}`;
83
- const url = collect({ hash, type, value });
84
- return url;
85
- }
86
47
  function isGenericFontFamily(str) {
87
- return Object.keys(DEFAULT_FALLBACKS).includes(str);
88
- }
89
- async function generateFallbacksCSS({
90
- family,
91
- fallbacks: _fallbacks,
92
- font: fontData,
93
- metrics
94
- }) {
95
- let fallbacks = [..._fallbacks];
96
- if (fallbacks.length === 0) {
97
- return null;
98
- }
99
- if (fontData.length === 0 || !metrics) {
100
- return { fallbacks };
101
- }
102
- const lastFallback = fallbacks[fallbacks.length - 1];
103
- if (!isGenericFontFamily(lastFallback)) {
104
- return { fallbacks };
105
- }
106
- const localFonts = DEFAULT_FALLBACKS[lastFallback];
107
- if (localFonts.length === 0) {
108
- return { fallbacks };
109
- }
110
- if (localFonts.includes(
111
- // @ts-expect-error TS is not smart enough
112
- family.name
113
- )) {
114
- return { fallbacks };
115
- }
116
- const localFontsMappings = localFonts.map((font) => ({
117
- font,
118
- name: `"${family.nameWithHash} fallback: ${font}"`
119
- }));
120
- fallbacks = [.../* @__PURE__ */ new Set([...localFontsMappings.map((m) => m.name), ...fallbacks])];
121
- let css = "";
122
- for (const { font, name } of localFontsMappings) {
123
- for (const { hash, url, data } of fontData) {
124
- css += metrics.generateFontFace({
125
- metrics: await metrics.getMetricsForFamily(family.name, { hash, url, data }),
126
- fallbackMetrics: SYSTEM_METRICS[font],
127
- font,
128
- name,
129
- properties: unifontFontFaceDataToProperties(data)
130
- });
131
- }
132
- }
133
- return { css, fallbacks };
48
+ return GENERIC_FALLBACK_NAMES.includes(str);
134
49
  }
135
50
  function dedupe(arr) {
136
51
  return [...new Set(arr)];
137
52
  }
138
- function resolveVariants({
139
- variants,
140
- root
141
- }) {
142
- return variants.map((variant) => ({
143
- ...variant,
144
- weight: variant.weight.toString(),
145
- src: variant.src.map((value) => {
146
- const isValue = typeof value === "string" || value instanceof URL;
147
- const url = (isValue ? value : value.url).toString();
148
- const tech = isValue ? void 0 : value.tech;
149
- return {
150
- url: fileURLToPath(resolveEntrypoint(root, url)),
151
- tech
152
- };
153
- })
154
- }));
155
- }
156
- async function resolveFontFamily({
157
- family,
158
- generateNameWithHash,
159
- root,
160
- resolveMod
161
- }) {
162
- const nameWithHash = generateNameWithHash(family);
163
- if (family.provider === LOCAL_PROVIDER_NAME) {
164
- return {
165
- ...family,
166
- nameWithHash,
167
- variants: resolveVariants({ variants: family.variants, root }),
168
- fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0
169
- };
170
- }
171
- return {
172
- ...family,
173
- nameWithHash,
174
- provider: await resolveProvider({
175
- root,
176
- resolveMod,
177
- provider: family.provider
178
- }),
179
- weights: family.weights ? dedupe(family.weights.map((weight) => weight.toString())) : void 0,
180
- styles: family.styles ? dedupe(family.styles) : void 0,
181
- subsets: family.subsets ? dedupe(family.subsets) : void 0,
182
- fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0,
183
- unicodeRange: family.unicodeRange ? dedupe(family.unicodeRange) : void 0
184
- };
185
- }
186
53
  function sortObjectByKey(unordered) {
187
54
  const ordered = Object.keys(unordered).sort().reduce((obj, key) => {
188
- obj[key] = unordered[key];
55
+ const value = unordered[key];
56
+ obj[key] = Array.isArray(value) ? value.map((v) => typeof v === "object" && v !== null ? sortObjectByKey(v) : v) : typeof value === "object" && value !== null ? sortObjectByKey(value) : value;
189
57
  return obj;
190
58
  }, {});
191
59
  return ordered;
192
60
  }
193
- function familiesToUnifontProviders({
194
- families,
195
- hashString
196
- }) {
197
- const hashes = /* @__PURE__ */ new Set();
198
- const providers = [];
199
- for (const { provider } of families) {
200
- if (provider === LOCAL_PROVIDER_NAME) {
201
- continue;
202
- }
203
- const unifontProvider = provider.provider(provider.config);
204
- const hash = hashString(
205
- JSON.stringify(
206
- sortObjectByKey({
207
- name: unifontProvider._name,
208
- ...provider.config
209
- })
210
- )
211
- );
212
- unifontProvider._name += `-${hash}`;
213
- provider.name = unifontProvider._name;
214
- if (!hashes.has(hash)) {
215
- hashes.add(hash);
216
- providers.push(unifontProvider);
217
- }
218
- }
219
- return { families, providers };
220
- }
221
61
  function resolveEntrypoint(root, entrypoint) {
222
62
  const require2 = createRequire(root);
223
63
  try {
@@ -226,20 +66,18 @@ function resolveEntrypoint(root, entrypoint) {
226
66
  return new URL(entrypoint, root);
227
67
  }
228
68
  }
69
+ function pickFontFaceProperty(property, { data, family }) {
70
+ return data[property] ?? (family.provider === LOCAL_PROVIDER_NAME ? void 0 : family[property]);
71
+ }
229
72
  export {
230
73
  cache,
231
- extractFontType,
232
- familiesToUnifontProviders,
233
- generateFallbacksCSS,
234
- generateFontFace,
74
+ dedupe,
235
75
  isFontType,
236
76
  isGenericFontFamily,
237
- proxyURL,
238
- renderFontFace,
77
+ pickFontFaceProperty,
239
78
  renderFontSrc,
240
79
  resolveEntrypoint,
241
- resolveFontFamily,
242
80
  sortObjectByKey,
243
- toCSS,
81
+ unifontFontFaceDataToProperties,
244
82
  withoutQuotes
245
83
  };