Repository: withastro/astro
File: packages/astro/src/assets/fonts/utils.ts (TypeScript)

Code before:
import type {
	FontFamily,
	FontType,
	LocalFontFamily,
	ResolvedFontFamily,
	ResolvedLocalFontFamily,
} from './types.js';

export function toCSS(properties: Record<string, string | undefined>, indent = 2) {
	return Object.entries(properties)
		.filter(([, value]) => Boolean(value))
		.map(([key, value]) => `${' '.repeat(indent)}${key}: ${value};`)
		.join('\n');
}

export function renderFontFace(properties: Record<string, string | undefined>) {
	return `@font-face {\n${toCSS(properties)}\n}\n`;
}

export function generateFontFace(family: string, font: unifont.FontFaceData) {
	return renderFontFace({
		'font-family': family,
		src: renderFontSrc(font.src),
		'font-display': font.display ?? 'swap',
		'unicode-range': font.unicodeRange?.join(','),
		'font-weight': Array.isArray(font.weight) ? font.weight.join(' ') : font.weight?.toString(),
		'font-style': font.style,
		'font-stretch': font.stretch,
		'font-feature-settings': font.featureSettings,
		'font-variation-settings': font.variationSettings,
	});
}

// Source: https://github.com/nuxt/fonts/blob/main/src/css/render.ts#L68-L81
export function renderFontSrc(sources: Exclude<unifont.FontFaceData['src'][number], string>[]) {
	return sources
		.map((src) => {
			if ('url' in src) {
				let rendered = `url("${src.url}")`;
				for (const key of ['format', 'tech'] as const) {
					const value = src[key];
					if (value) {
						rendered += ` ${key}(${value})`;
					}
				}
				return rendered;
			}
			return `local("${src.name}")`;
		})
		.join(', ');
}

Review comment (suggestion):
```suggestion
		'font-weight': Array.isArray(font.weight) ? font.weight.map(s => s.trim()).join(' ') : font.weight?.toString(),
```

nit: we might want to clean the string

Code after:
import type {
	FontFamily,
	FontType,
	LocalFontFamily,
	ResolvedFontFamily,
	ResolvedLocalFontFamily,
} from './types.js';

export function toCSS(properties: Record<string, string | undefined>, indent = 2) {
	return Object.entries(properties)
		.filter(([, value]) => Boolean(value))
		.map(([key, value]) => `${' '.repeat(indent)}${key}: ${value};`)
		.join('\n');
}

export function renderFontFace(properties: Record<string, string | undefined>) {
	return `@font-face {\n\t${toCSS(properties)}\n}\n`;
}

export function generateFontFace(family: string, font: unifont.FontFaceData) {
	return renderFontFace({
		'font-family': family,
		src: renderFontSrc(font.src),
		'font-display': font.display ?? 'swap',
		'unicode-range': font.unicodeRange?.join(','),
		'font-weight': Array.isArray(font.weight) ? font.weight.join(' ') : font.weight?.toString(),
		'font-style': font.style,
		'font-stretch': font.stretch,
		'font-feature-settings': font.featureSettings,
		'font-variation-settings': font.variationSettings,
	});
}

// Source: https://github.com/nuxt/fonts/blob/main/src/css/render.ts#L68-L81
export function renderFontSrc(sources: Exclude<unifont.FontFaceData['src'][number], string>[]) {
	return sources
		.map((src) => {
			if ('url' in src) {
				let rendered = `url("${src.url}")`;
				for (const key of ['format', 'tech'] as const) {
					const value = src[key];
					if (value) {
						rendered += ` ${key}(${value})`;
					}
				}
				return rendered;
			}
			return `local("${src.name}")`;
		})
		.join(', ');
}