added fonts

This commit is contained in:
2025-07-02 11:28:41 +02:00
parent 4134e3a234
commit 142d2986b6
9079 changed files with 1498421 additions and 2 deletions
@@ -0,0 +1,18 @@
import type { Font } from 'fontkit';
import type { AdjustFontFallback } from 'next/font';
/**
* Given a font file and category, calculate the fallback font override values.
* The returned values can be used to generate a CSS @font-face declaration.
*
* For example:
* @font-face {
* font-family: local-font;
* src: local(Arial);
* size-adjust: 90%;
* }
*
* Read more about this technique in these texts by the Google Aurora team:
* https://developer.chrome.com/blog/font-fallbacks/
* https://docs.google.com/document/d/e/2PACX-1vRsazeNirATC7lIj2aErSHpK26hZ6dA9GsQ069GEbq5fyzXEhXbvByoftSfhG82aJXmrQ_sJCPBqcx_/pub
*/
export declare function getFallbackMetricsFromFontFile(font: Font, category?: string): AdjustFontFallback;
@@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFallbackMetricsFromFontFile = void 0;
// The font metadata of the fallback fonts, retrieved with fontkit on system font files
// The average width is calculated with the calcAverageWidth function below
const DEFAULT_SANS_SERIF_FONT = {
name: 'Arial',
azAvgWidth: 934.5116279069767,
unitsPerEm: 2048,
};
const DEFAULT_SERIF_FONT = {
name: 'Times New Roman',
azAvgWidth: 854.3953488372093,
unitsPerEm: 2048,
};
/**
* Calculate the average character width of a font file.
* Used to calculate the size-adjust property by comparing the fallback average with the loaded font average.
*/
function calcAverageWidth(font) {
try {
/**
* Finding the right characters to use when calculating the average width is tricky.
* We can't just use the average width of all characters, because we have to take letter frequency into account.
* We also have to take word length into account, because the font's space width usually differ a lot from other characters.
* The goal is to find a string that'll give you a good average width, given most texts in most languages.
*
* TODO: Currently only works for the latin alphabet. Support more languages by finding the right characters for additional languages.
*
* The used characters were decided through trial and error with letter frequency and word length tables as a guideline.
* E.g. https://en.wikipedia.org/wiki/Letter_frequency
*/
const avgCharacters = 'aaabcdeeeefghiijklmnnoopqrrssttuvwxyz ';
// Check if the font file has all the characters we need to calculate the average width
const hasAllChars = font
.glyphsForString(avgCharacters)
.flatMap((glyph) => glyph.codePoints)
.every((codePoint) => font.hasGlyphForCodePoint(codePoint));
if (!hasAllChars)
return undefined;
const widths = font
.glyphsForString(avgCharacters)
.map((glyph) => glyph.advanceWidth);
const totalWidth = widths.reduce((sum, width) => sum + width, 0);
return totalWidth / widths.length;
}
catch {
// Could not calculate average width from the font file, skip size-adjust
return undefined;
}
}
function formatOverrideValue(val) {
return Math.abs(val * 100).toFixed(2) + '%';
}
/**
* Given a font file and category, calculate the fallback font override values.
* The returned values can be used to generate a CSS @font-face declaration.
*
* For example:
* @font-face {
* font-family: local-font;
* src: local(Arial);
* size-adjust: 90%;
* }
*
* Read more about this technique in these texts by the Google Aurora team:
* https://developer.chrome.com/blog/font-fallbacks/
* https://docs.google.com/document/d/e/2PACX-1vRsazeNirATC7lIj2aErSHpK26hZ6dA9GsQ069GEbq5fyzXEhXbvByoftSfhG82aJXmrQ_sJCPBqcx_/pub
*/
function getFallbackMetricsFromFontFile(font, category = 'serif') {
const fallbackFont = category === 'serif' ? DEFAULT_SERIF_FONT : DEFAULT_SANS_SERIF_FONT;
const azAvgWidth = calcAverageWidth(font);
const { ascent, descent, lineGap, unitsPerEm } = font;
const fallbackFontAvgWidth = fallbackFont.azAvgWidth / fallbackFont.unitsPerEm;
let sizeAdjust = azAvgWidth
? azAvgWidth / unitsPerEm / fallbackFontAvgWidth
: 1;
return {
ascentOverride: formatOverrideValue(ascent / (unitsPerEm * sizeAdjust)),
descentOverride: formatOverrideValue(descent / (unitsPerEm * sizeAdjust)),
lineGapOverride: formatOverrideValue(lineGap / (unitsPerEm * sizeAdjust)),
fallbackFont: fallbackFont.name,
sizeAdjust: formatOverrideValue(sizeAdjust),
};
}
exports.getFallbackMetricsFromFontFile = getFallbackMetricsFromFontFile;
+21
View File
@@ -0,0 +1,21 @@
import type { CssVariable, Display, NextFont, NextFontWithVariable } from '../types';
type LocalFont<T extends CssVariable | undefined = undefined> = {
src: string | Array<{
path: string;
weight?: string;
style?: string;
}>;
display?: Display;
weight?: string;
style?: string;
adjustFontFallback?: 'Arial' | 'Times New Roman' | false;
fallback?: string[];
preload?: boolean;
variable?: T;
declarations?: Array<{
prop: string;
value: string;
}>;
};
export default function localFont<T extends CssVariable | undefined = undefined>(options: LocalFont<T>): T extends undefined ? NextFont : NextFontWithVariable;
export {};
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function localFont(options) {
throw new Error();
}
exports.default = localFont;
+3
View File
@@ -0,0 +1,3 @@
import type { FontLoader } from 'next/font';
declare const nextFontLocalFontLoader: FontLoader;
export default nextFontLocalFontLoader;
+75
View File
@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-ignore
// eslint-disable-next-line import/no-extraneous-dependencies
let fontFromBuffer;
try {
const mod = require('../fontkit').default;
fontFromBuffer = mod.default || mod;
}
catch { }
const util_1 = require("util");
const pick_font_file_for_fallback_generation_1 = require("./pick-font-file-for-fallback-generation");
const get_fallback_metrics_from_font_file_1 = require("./get-fallback-metrics-from-font-file");
const validate_local_font_function_call_1 = require("./validate-local-font-function-call");
const nextFontLocalFontLoader = async ({ functionName, variableName, data, emitFontFile, resolve, loaderContext, }) => {
const { src, display, fallback, preload, variable, adjustFontFallback, declarations, weight: defaultWeight, style: defaultStyle, } = (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)(functionName, data[0]);
// Load all font files and emit them to the .next output directory
// Also generate a @font-face CSS for each font file
const fontFiles = await Promise.all(src.map(async ({ path, style, weight, ext, format }) => {
const resolved = await resolve(path);
const fileBuffer = await (0, util_1.promisify)(loaderContext.fs.readFile)(resolved);
const fontUrl = emitFontFile(fileBuffer, ext, preload, typeof adjustFontFallback === 'undefined' || !!adjustFontFallback);
// Try to load font metadata from the font file using fontkit.
// The data is used to calculate the fallback font override values.
let fontMetadata;
try {
fontMetadata = fontFromBuffer === null || fontFromBuffer === void 0 ? void 0 : fontFromBuffer(fileBuffer);
}
catch (e) {
console.error(`Failed to load font file: ${resolved}\n${e}`);
}
// Get all values that should be added to the @font-face declaration
const fontFaceProperties = [
...(declarations
? declarations.map(({ prop, value }) => [prop, value])
: []),
['font-family', variableName],
['src', `url(${fontUrl}) format('${format}')`],
['font-display', display],
...((weight !== null && weight !== void 0 ? weight : defaultWeight)
? [['font-weight', weight !== null && weight !== void 0 ? weight : defaultWeight]]
: []),
...((style !== null && style !== void 0 ? style : defaultStyle)
? [['font-style', style !== null && style !== void 0 ? style : defaultStyle]]
: []),
];
// Generate the @font-face CSS from the font-face properties
const css = `@font-face {\n${fontFaceProperties
.map(([property, value]) => `${property}: ${value};`)
.join('\n')}\n}\n`;
return {
css,
fontMetadata,
weight,
style,
};
}));
// Calculate the fallback font override values using the font file metadata
let adjustFontFallbackMetrics;
if (adjustFontFallback !== false) {
const fallbackFontFile = (0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)(fontFiles);
if (fallbackFontFile.fontMetadata) {
adjustFontFallbackMetrics = (0, get_fallback_metrics_from_font_file_1.getFallbackMetricsFromFontFile)(fallbackFontFile.fontMetadata, adjustFontFallback === 'Times New Roman' ? 'serif' : 'sans-serif');
}
}
return {
css: fontFiles.map(({ css }) => css).join('\n'),
fallbackFonts: fallback,
weight: src.length === 1 ? src[0].weight : undefined,
style: src.length === 1 ? src[0].style : undefined,
variable,
adjustFontFallback: adjustFontFallbackMetrics,
};
};
exports.default = nextFontLocalFontLoader;
+1
View File
@@ -0,0 +1 @@
export {};
+228
View File
@@ -0,0 +1,228 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const loader_1 = __importDefault(require("./loader"));
describe('next/font/local loader', () => {
describe('generated CSS', () => {
test('Default CSS', async () => {
const { css } = await (0, loader_1.default)({
functionName: '',
data: [{ src: './my-font.woff2' }],
emitFontFile: () => '/_next/static/media/my-font.woff2',
resolve: jest.fn(),
isDev: false,
isServer: true,
variableName: 'myFont',
loaderContext: {
fs: {
readFile: (_, cb) => cb(null, 'fontdata'),
},
},
});
expect(css).toMatchInlineSnapshot(`
"@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
}
"
`);
});
test('Weight and style', async () => {
const { css } = await (0, loader_1.default)({
functionName: '',
data: [{ src: './my-font.woff2', weight: '100 900', style: 'italic' }],
emitFontFile: () => '/_next/static/media/my-font.woff2',
resolve: jest.fn(),
isDev: false,
isServer: true,
variableName: 'myFont',
loaderContext: {
fs: {
readFile: (_, cb) => cb(null, 'fontdata'),
},
},
});
expect(css).toMatchInlineSnapshot(`
"@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 100 900;
font-style: italic;
}
"
`);
});
test('Other properties', async () => {
const { css } = await (0, loader_1.default)({
functionName: '',
data: [
{
src: './my-font.woff2',
declarations: [
{ prop: 'font-feature-settings', value: '"smcp" on' },
{ prop: 'ascent-override', value: '90%' },
],
},
],
emitFontFile: () => '/_next/static/media/my-font.woff2',
resolve: jest.fn(),
isDev: false,
isServer: true,
variableName: 'myFont',
loaderContext: {
fs: {
readFile: (_, cb) => cb(null, 'fontdata'),
},
},
});
expect(css).toMatchInlineSnapshot(`
"@font-face {
font-feature-settings: "smcp" on;
ascent-override: 90%;
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
}
"
`);
});
test('Multiple weights default style', async () => {
const { css } = await (0, loader_1.default)({
functionName: '',
data: [
{
style: 'italic',
src: [
{
path: './fonts/font1.woff2',
weight: '100',
},
{
path: './fonts/font2.woff2',
weight: '400',
},
{
path: './fonts/font3.woff2',
weight: '700',
},
{
path: './fonts/font2.woff2',
weight: '400',
style: 'normal',
},
],
adjustFontFallback: false,
},
],
emitFontFile: () => `/_next/static/media/my-font.woff2`,
resolve: jest.fn(),
isDev: false,
isServer: true,
variableName: 'myFont',
loaderContext: {
fs: {
readFile: (path, cb) => cb(null, path),
},
},
});
expect(css).toMatchInlineSnapshot(`
"@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 100;
font-style: italic;
}
@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
"
`);
});
test('Multiple styles default weight', async () => {
const { css } = await (0, loader_1.default)({
functionName: '',
data: [
{
weight: '400',
src: [
{
path: './fonts/font1.woff2',
style: 'normal',
},
{
path: './fonts/font3.woff2',
style: 'italic',
},
{
path: './fonts/font2.woff2',
weight: '700',
},
],
adjustFontFallback: false,
},
],
emitFontFile: () => `/_next/static/media/my-font.woff2`,
resolve: jest.fn(),
isDev: false,
isServer: true,
variableName: 'myFont',
loaderContext: {
fs: {
readFile: (path, cb) => cb(null, path),
},
},
});
expect(css).toMatchInlineSnapshot(`
"@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: myFont;
src: url(/_next/static/media/my-font.woff2) format('woff2');
font-display: swap;
font-weight: 700;
}
"
`);
});
});
});
@@ -0,0 +1,13 @@
/**
* If multiple font files are provided for a font family, we need to pick one to use for the automatic fallback generation.
* This function returns the font file that is most likely to be used for the bulk of the text on a page.
*
* There are some assumptions here about the text on a page when picking the font file:
* - Most of the text will have normal weight, use the one closest to 400
* - Most of the text will have normal style, prefer normal over italic
* - If two font files have the same distance from normal weight, the thinner one will most likely be the bulk of the text
*/
export declare function pickFontFileForFallbackGeneration<T extends {
style?: string;
weight?: string;
}>(fontFiles: T[]): T;
@@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.pickFontFileForFallbackGeneration = void 0;
const next_font_error_1 = require("../next-font-error");
const NORMAL_WEIGHT = 400;
const BOLD_WEIGHT = 700;
/**
* Convert the weight string to a number so it can be used for comparison.
* Weights can be defined as a number, 'normal' or 'bold'. https://developer.mozilla.org/docs/Web/CSS/@font-face/font-weight
*/
function getWeightNumber(weight) {
return weight === 'normal'
? NORMAL_WEIGHT
: weight === 'bold'
? BOLD_WEIGHT
: Number(weight);
}
/**
* Get the distance from normal (400) weight for the provided weight.
* If it's not a variable font we can just return the distance.
* If it's a variable font we need to compare its weight range to 400.
*/
function getDistanceFromNormalWeight(weight) {
if (!weight)
return 0;
// If it's a variable font the weight is defined with two numbers "100 900", rather than just one "400"
const [firstWeight, secondWeight] = weight
.trim()
.split(/ +/)
.map(getWeightNumber);
if (Number.isNaN(firstWeight) || Number.isNaN(secondWeight)) {
(0, next_font_error_1.nextFontError)(`Invalid weight value in src array: \`${weight}\`.\nExpected \`normal\`, \`bold\` or a number.`);
}
// If the weight doesn't have have a second value, it's not a variable font
// If that's the case, just return the distance from normal weight
if (!secondWeight) {
return firstWeight - NORMAL_WEIGHT;
}
// Normal weight is within variable font range
if (firstWeight <= NORMAL_WEIGHT && secondWeight >= NORMAL_WEIGHT) {
return 0;
}
// Normal weight is outside variable font range
// Return the distance of normal weight to the variable font range
const firstWeightDistance = firstWeight - NORMAL_WEIGHT;
const secondWeightDistance = secondWeight - NORMAL_WEIGHT;
if (Math.abs(firstWeightDistance) < Math.abs(secondWeightDistance)) {
return firstWeightDistance;
}
return secondWeightDistance;
}
/**
* If multiple font files are provided for a font family, we need to pick one to use for the automatic fallback generation.
* This function returns the font file that is most likely to be used for the bulk of the text on a page.
*
* There are some assumptions here about the text on a page when picking the font file:
* - Most of the text will have normal weight, use the one closest to 400
* - Most of the text will have normal style, prefer normal over italic
* - If two font files have the same distance from normal weight, the thinner one will most likely be the bulk of the text
*/
function pickFontFileForFallbackGeneration(fontFiles) {
return fontFiles.reduce((usedFontFile, currentFontFile) => {
if (!usedFontFile)
return currentFontFile;
const usedFontDistance = getDistanceFromNormalWeight(usedFontFile.weight);
const currentFontDistance = getDistanceFromNormalWeight(currentFontFile.weight);
// Prefer normal style if they have the same weight
if (usedFontDistance === currentFontDistance &&
(typeof currentFontFile.style === 'undefined' ||
currentFontFile.style === 'normal')) {
return currentFontFile;
}
const absUsedDistance = Math.abs(usedFontDistance);
const absCurrentDistance = Math.abs(currentFontDistance);
// Use closest absolute distance to normal weight
if (absCurrentDistance < absUsedDistance)
return currentFontFile;
// Prefer the thinner font if both have the same absolute distance from normal weight
if (absUsedDistance === absCurrentDistance &&
currentFontDistance < usedFontDistance) {
return currentFontFile;
}
return usedFontFile;
});
}
exports.pickFontFileForFallbackGeneration = pickFontFileForFallbackGeneration;
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,113 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const pick_font_file_for_fallback_generation_1 = require("./pick-font-file-for-fallback-generation");
describe('pickFontFileForFallbackGeneration', () => {
it('should pick the weight closest to 400', () => {
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{
weight: '300',
},
{
weight: '600',
},
])).toEqual({
weight: '300',
});
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ weight: '200' },
{
weight: '500',
},
])).toEqual({
weight: '500',
});
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{
weight: 'normal',
},
{
weight: '700',
},
])).toEqual({
weight: 'normal',
});
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{
weight: 'bold',
},
{
weight: '900',
},
])).toEqual({
weight: 'bold',
});
});
it('should pick the thinner weight if both have the same distance to 400', () => {
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{
weight: '300',
},
{
weight: '500',
},
])).toEqual({
weight: '300',
});
});
it('should pick variable range closest to 400', () => {
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{
weight: '100 300',
},
{
weight: '600 900',
},
])).toEqual({
weight: '100 300',
});
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ weight: '100 200' },
{
weight: '500 800',
},
])).toEqual({
weight: '500 800',
});
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ weight: '100 900' },
{
weight: '300 399',
},
])).toEqual({
weight: '100 900',
});
});
it('should prefer normal style over italic', () => {
expect((0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ weight: '400', style: 'normal' },
{ weight: '400', style: 'italic' },
])).toEqual({ weight: '400', style: 'normal' });
});
it('should error on invalid weight in array', async () => {
expect(() => (0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ path: './font1.woff2', weight: 'normal bold' },
{ path: './font2.woff2', weight: '400 bold' },
{ path: './font3.woff2', weight: 'normal 700' },
{ path: './font4.woff2', weight: '100 abc' },
])).toThrowErrorMatchingInlineSnapshot(`
"Invalid weight value in src array: \`100 abc\`.
Expected \`normal\`, \`bold\` or a number."
`);
});
test('Invalid variable weight in array', async () => {
expect(() => (0, pick_font_file_for_fallback_generation_1.pickFontFileForFallbackGeneration)([
{ path: './font1.woff2', weight: 'normal bold' },
{ path: './font2.woff2', weight: '400 bold' },
{ path: './font3.woff2', weight: 'normal 700' },
{ path: './font4.woff2', weight: '100 abc' },
])).toThrowErrorMatchingInlineSnapshot(`
"Invalid weight value in src array: \`100 abc\`.
Expected \`normal\`, \`bold\` or a number."
`);
});
});
@@ -0,0 +1,25 @@
type FontOptions = {
src: Array<{
path: string;
weight?: string;
style?: string;
ext: string;
format: string;
}>;
display: string;
weight?: string;
style?: string;
fallback?: string[];
preload: boolean;
variable?: string;
adjustFontFallback?: string | false;
declarations?: Array<{
prop: string;
value: string;
}>;
};
/**
* Validate the data recieved from next-swc next-transform-font on next/font/local calls
*/
export declare function validateLocalFontFunctionCall(functionName: string, fontData: any): FontOptions;
export {};
@@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateLocalFontFunctionCall = void 0;
const constants_1 = require("../constants");
const format_available_values_1 = require("../format-available-values");
const next_font_error_1 = require("../next-font-error");
const extToFormat = {
woff: 'woff',
woff2: 'woff2',
ttf: 'truetype',
otf: 'opentype',
eot: 'embedded-opentype',
};
/**
* Validate the data recieved from next-swc next-transform-font on next/font/local calls
*/
function validateLocalFontFunctionCall(functionName, fontData) {
if (functionName) {
(0, next_font_error_1.nextFontError)(`next/font/local has no named exports`);
}
let { src, display = 'swap', weight, style, fallback, preload = true, variable, adjustFontFallback, declarations, } = fontData || {};
if (!constants_1.allowedDisplayValues.includes(display)) {
(0, next_font_error_1.nextFontError)(`Invalid display value \`${display}\`.\nAvailable display values: ${(0, format_available_values_1.formatAvailableValues)(constants_1.allowedDisplayValues)}`);
}
if (!src) {
(0, next_font_error_1.nextFontError)('Missing required `src` property');
}
if (!Array.isArray(src)) {
src = [{ path: src, weight, style }];
}
else {
if (src.length === 0) {
(0, next_font_error_1.nextFontError)('Unexpected empty `src` array.');
}
}
src = src.map((fontFile) => {
var _a;
const ext = (_a = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFile.path)) === null || _a === void 0 ? void 0 : _a[1];
if (!ext) {
(0, next_font_error_1.nextFontError)(`Unexpected file \`${fontFile.path}\``);
}
return {
...fontFile,
ext,
format: extToFormat[ext],
};
});
if (Array.isArray(declarations)) {
declarations.forEach((declaration) => {
if ([
'font-family',
'src',
'font-display',
'font-weight',
'font-style',
].includes(declaration === null || declaration === void 0 ? void 0 : declaration.prop)) {
(0, next_font_error_1.nextFontError)(`Invalid declaration prop: \`${declaration.prop}\``);
}
});
}
return {
src,
display,
weight,
style,
fallback,
preload,
variable,
adjustFontFallback,
declarations,
};
}
exports.validateLocalFontFunctionCall = validateLocalFontFunctionCall;
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const validate_local_font_function_call_1 = require("./validate-local-font-function-call");
describe('validateLocalFontFunctionCall', () => {
test('Not using default export', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('Named', {})).toThrowErrorMatchingInlineSnapshot(`"next/font/local has no named exports"`);
});
test('Missing src', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('', {})).toThrowErrorMatchingInlineSnapshot(`"Missing required \`src\` property"`);
});
test('Invalid file extension', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('', { src: './font/font-file.abc' })).toThrowErrorMatchingInlineSnapshot(`"Unexpected file \`./font/font-file.abc\`"`);
});
test('Invalid display value', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('', {
src: './font-file.woff2',
display: 'invalid',
})).toThrowErrorMatchingInlineSnapshot(`
"Invalid display value \`invalid\`.
Available display values: \`auto\`, \`block\`, \`swap\`, \`fallback\`, \`optional\`"
`);
});
test('Invalid declaration', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('', {
src: './font-file.woff2',
declarations: [{ prop: 'src', value: '/hello.woff2' }],
})).toThrowErrorMatchingInlineSnapshot(`"Invalid declaration prop: \`src\`"`);
});
test('Empty src array', async () => {
expect(() => (0, validate_local_font_function_call_1.validateLocalFontFunctionCall)('', {
src: [],
})).toThrowErrorMatchingInlineSnapshot(`"Unexpected empty \`src\` array."`);
});
});