220 lines
8.9 KiB
JavaScript
220 lines
8.9 KiB
JavaScript
|
|
"use strict";
|
||
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
|
|
};
|
||
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
|
exports.getFontAxes = exports.fetchFontFile = exports.fetchCSSFromGoogleFonts = exports.getUrl = exports.validateData = void 0;
|
||
|
|
const fs_1 = __importDefault(require("fs"));
|
||
|
|
// @ts-ignore
|
||
|
|
const node_fetch_1 = __importDefault(require("next/dist/compiled/node-fetch"));
|
||
|
|
const utils_1 = require("../utils");
|
||
|
|
const font_data_json_1 = __importDefault(require("./font-data.json"));
|
||
|
|
const allowedDisplayValues = ['auto', 'block', 'swap', 'fallback', 'optional'];
|
||
|
|
const formatValues = (values) => values.map((val) => `\`${val}\``).join(', ');
|
||
|
|
function validateData(functionName, data) {
|
||
|
|
let { weight, style, display = 'optional', preload = true, axes, fallback, adjustFontFallback = true, variable, subsets, } = data[0] || {};
|
||
|
|
if (functionName === '') {
|
||
|
|
(0, utils_1.nextFontError)(`@next/font/google has no default export`);
|
||
|
|
}
|
||
|
|
const fontFamily = functionName.replace(/_/g, ' ');
|
||
|
|
const fontFamilyData = font_data_json_1.default[fontFamily];
|
||
|
|
const fontWeights = fontFamilyData === null || fontFamilyData === void 0 ? void 0 : fontFamilyData.weights;
|
||
|
|
if (!fontWeights) {
|
||
|
|
(0, utils_1.nextFontError)(`Unknown font \`${fontFamily}\``);
|
||
|
|
}
|
||
|
|
const fontStyles = fontFamilyData.styles;
|
||
|
|
const weights = !weight
|
||
|
|
? []
|
||
|
|
: [...new Set(Array.isArray(weight) ? weight : [weight])];
|
||
|
|
const styles = !style
|
||
|
|
? []
|
||
|
|
: [...new Set(Array.isArray(style) ? style : [style])];
|
||
|
|
if (weights.length === 0) {
|
||
|
|
// Set variable as default, throw if not available
|
||
|
|
if (fontWeights.includes('variable')) {
|
||
|
|
weights.push('variable');
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
(0, utils_1.nextFontError)(`Missing weight for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(fontWeights)}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (weights.length > 1 && weights.includes('variable')) {
|
||
|
|
(0, utils_1.nextFontError)(`Unexpected \`variable\` in weight array for font \`${fontFamily}\`. You only need \`variable\`, it includes all available weights.`);
|
||
|
|
}
|
||
|
|
weights.forEach((selectedWeight) => {
|
||
|
|
if (!fontWeights.includes(selectedWeight)) {
|
||
|
|
(0, utils_1.nextFontError)(`Unknown weight \`${selectedWeight}\` for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(fontWeights)}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (styles.length === 0) {
|
||
|
|
if (fontStyles.length === 1) {
|
||
|
|
styles.push(fontStyles[0]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
styles.push('normal');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
styles.forEach((selectedStyle) => {
|
||
|
|
if (!fontStyles.includes(selectedStyle)) {
|
||
|
|
(0, utils_1.nextFontError)(`Unknown style \`${selectedStyle}\` for font \`${fontFamily}\`.\nAvailable styles: ${formatValues(fontStyles)}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (!allowedDisplayValues.includes(display)) {
|
||
|
|
(0, utils_1.nextFontError)(`Invalid display value \`${display}\` for font \`${fontFamily}\`.\nAvailable display values: ${formatValues(allowedDisplayValues)}`);
|
||
|
|
}
|
||
|
|
if (weights[0] !== 'variable' && axes) {
|
||
|
|
(0, utils_1.nextFontError)('Axes can only be defined for variable fonts');
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
fontFamily,
|
||
|
|
weights,
|
||
|
|
styles,
|
||
|
|
display,
|
||
|
|
preload,
|
||
|
|
selectedVariableAxes: axes,
|
||
|
|
fallback,
|
||
|
|
adjustFontFallback,
|
||
|
|
variable,
|
||
|
|
subsets,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
exports.validateData = validateData;
|
||
|
|
function getUrl(fontFamily, axes, display) {
|
||
|
|
var _a, _b;
|
||
|
|
// Variants are all combinations of weight and style, each variant will result in a separate font file
|
||
|
|
const variants = [];
|
||
|
|
if (axes.wght) {
|
||
|
|
for (const wgth of axes.wght) {
|
||
|
|
if (!axes.ital) {
|
||
|
|
variants.push([['wght', wgth], ...((_a = axes.variableAxes) !== null && _a !== void 0 ? _a : [])]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
for (const ital of axes.ital) {
|
||
|
|
variants.push([
|
||
|
|
['ital', ital],
|
||
|
|
['wght', wgth],
|
||
|
|
...((_b = axes.variableAxes) !== null && _b !== void 0 ? _b : []),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (axes.variableAxes) {
|
||
|
|
// Variable fonts might not have a range of weights, just add optional variable axes in that case
|
||
|
|
variants.push([...axes.variableAxes]);
|
||
|
|
}
|
||
|
|
// Google api requires the axes to be sorted, starting with lowercase words
|
||
|
|
if (axes.variableAxes) {
|
||
|
|
variants.forEach((variant) => {
|
||
|
|
variant.sort(([a], [b]) => {
|
||
|
|
const aIsLowercase = a.charCodeAt(0) > 96;
|
||
|
|
const bIsLowercase = b.charCodeAt(0) > 96;
|
||
|
|
if (aIsLowercase && !bIsLowercase)
|
||
|
|
return -1;
|
||
|
|
if (bIsLowercase && !aIsLowercase)
|
||
|
|
return 1;
|
||
|
|
return a > b ? 1 : -1;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
let url = `https://fonts.googleapis.com/css2?family=${fontFamily.replace(/ /g, '+')}`;
|
||
|
|
if (variants.length > 0) {
|
||
|
|
url = `${url}:${variants[0].map(([key]) => key).join(',')}@${variants
|
||
|
|
.map((variant) => variant.map(([, val]) => val).join(','))
|
||
|
|
.sort()
|
||
|
|
.join(';')}`;
|
||
|
|
}
|
||
|
|
url = `${url}&display=${display}`;
|
||
|
|
return url;
|
||
|
|
}
|
||
|
|
exports.getUrl = getUrl;
|
||
|
|
async function fetchCSSFromGoogleFonts(url, fontFamily) {
|
||
|
|
let mockedResponse;
|
||
|
|
if (process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES) {
|
||
|
|
const mockFile = require(process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES);
|
||
|
|
mockedResponse = mockFile[url];
|
||
|
|
if (!mockedResponse) {
|
||
|
|
(0, utils_1.nextFontError)('Missing mocked response for URL: ' + url);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
let cssResponse;
|
||
|
|
if (mockedResponse) {
|
||
|
|
cssResponse = mockedResponse;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
const res = await (0, node_fetch_1.default)(url, {
|
||
|
|
headers: {
|
||
|
|
// The file format is based off of the user agent, make sure woff2 files are fetched
|
||
|
|
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
|
||
|
|
},
|
||
|
|
});
|
||
|
|
if (!res.ok) {
|
||
|
|
(0, utils_1.nextFontError)(`Failed to fetch font \`${fontFamily}\`.\nURL: ${url}`);
|
||
|
|
}
|
||
|
|
cssResponse = await res.text();
|
||
|
|
}
|
||
|
|
return cssResponse;
|
||
|
|
}
|
||
|
|
exports.fetchCSSFromGoogleFonts = fetchCSSFromGoogleFonts;
|
||
|
|
async function fetchFontFile(url) {
|
||
|
|
if (process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES) {
|
||
|
|
if (url.startsWith('/')) {
|
||
|
|
return fs_1.default.readFileSync(url);
|
||
|
|
}
|
||
|
|
return Buffer.from(url);
|
||
|
|
}
|
||
|
|
const arrayBuffer = await (0, node_fetch_1.default)(url).then((r) => r.arrayBuffer());
|
||
|
|
return Buffer.from(arrayBuffer);
|
||
|
|
}
|
||
|
|
exports.fetchFontFile = fetchFontFile;
|
||
|
|
function getFontAxes(fontFamily, weights, styles, selectedVariableAxes) {
|
||
|
|
const allAxes = font_data_json_1.default[fontFamily].axes;
|
||
|
|
const hasItalic = styles.includes('italic');
|
||
|
|
const hasNormal = styles.includes('normal');
|
||
|
|
const ital = hasItalic ? [...(hasNormal ? ['0'] : []), '1'] : undefined;
|
||
|
|
// Weights will always contain one element if it's a variable font
|
||
|
|
if (weights[0] === 'variable') {
|
||
|
|
if (selectedVariableAxes) {
|
||
|
|
const defineAbleAxes = allAxes
|
||
|
|
.map(({ tag }) => tag)
|
||
|
|
.filter((tag) => tag !== 'wght');
|
||
|
|
if (defineAbleAxes.length === 0) {
|
||
|
|
(0, utils_1.nextFontError)(`Font \`${fontFamily}\` has no definable \`axes\``);
|
||
|
|
}
|
||
|
|
if (!Array.isArray(selectedVariableAxes)) {
|
||
|
|
(0, utils_1.nextFontError)(`Invalid axes value for font \`${fontFamily}\`, expected an array of axes.\nAvailable axes: ${formatValues(defineAbleAxes)}`);
|
||
|
|
}
|
||
|
|
selectedVariableAxes.forEach((key) => {
|
||
|
|
if (!defineAbleAxes.some((tag) => tag === key)) {
|
||
|
|
(0, utils_1.nextFontError)(`Invalid axes value \`${key}\` for font \`${fontFamily}\`.\nAvailable axes: ${formatValues(defineAbleAxes)}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
let weightAxis;
|
||
|
|
let variableAxes;
|
||
|
|
for (const { tag, min, max } of allAxes) {
|
||
|
|
if (tag === 'wght') {
|
||
|
|
weightAxis = `${min}..${max}`;
|
||
|
|
}
|
||
|
|
else if (selectedVariableAxes === null || selectedVariableAxes === void 0 ? void 0 : selectedVariableAxes.includes(tag)) {
|
||
|
|
if (!variableAxes) {
|
||
|
|
variableAxes = [];
|
||
|
|
}
|
||
|
|
variableAxes.push([tag, `${min}..${max}`]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
wght: weightAxis ? [weightAxis] : undefined,
|
||
|
|
ital,
|
||
|
|
variableAxes,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return {
|
||
|
|
ital,
|
||
|
|
wght: weights,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
exports.getFontAxes = getFontAxes;
|