@cf-wasm/og
Version:
Generate Open Graph Images dynamically from HTML/CSS without a browser.
203 lines (202 loc) • 7.09 kB
JavaScript
const require_maps = require("./maps.cjs");
const require_cache = require("./cache.cjs");
const require_errors = require("./errors.cjs");
//#region src/core/font.ts
/** Default user agent for loading css */
const GOOGLE_FONT_CSS_DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1";
/** Google fonts utils */
var GoogleFontsUtils = class {
constructor() {
this._defaultCssLoader = async (cssUrl, userAgent) => {
return (await require_cache.cache.serve(cssUrl, () => fetch(cssUrl, { headers: { "User-Agent": userAgent } }).then((res) => {
if (!res.ok) throw new require_errors.FetchError(`Response was not successful (status: \`${res.status}\`, statusText: \`${res.statusText}\`)`, { response: res });
return res;
}).catch((e) => {
throw new require_errors.FetchError(`An error ocurred while fetching \`${cssUrl}\``, {
cause: e,
response: e instanceof require_errors.FetchError ? e.response : void 0
});
}))).text();
};
this._cssLoader = this._defaultCssLoader;
}
/**
* Loads Google font css
*
* @param cssUrl The Google font css url
* @param userAgent The user agent header to be used
*
* @returns On success, the css as string
*/
async loadCss(cssUrl, userAgent = GOOGLE_FONT_CSS_DEFAULT_USER_AGENT) {
let css = await this._cssLoader(cssUrl, userAgent);
if (typeof css === "undefined") css = await this._defaultCssLoader(cssUrl, userAgent);
else if (typeof css !== "string") throw new Error("Google font css loader return value must resolve to string");
return css;
}
/**
* Sets Google font css loader
*
* @param loader The {@link GoogleFontCssLoader}
*/
setCssLoader(loader) {
if (typeof loader !== "function") throw new TypeError("Argument 1 must be a function.");
this._cssLoader = loader;
}
};
const googleFonts = new GoogleFontsUtils();
/** Constructs Google font css url */
function constructGoogleFontCssUrl(family, { style = "normal", weight = 400, subset = "latin", display, text } = {}) {
if (typeof family !== "string" || family.trim().length === 0) throw new Error("Not a valid font family name was provided");
const params = { family: `${family.replaceAll(" ", "+")}:${style === "italic" ? "ital," : ""}wght@${style === "italic" ? "1," : ""}${weight}` };
if (text) params.text = encodeURIComponent(text);
else params.subset = subset;
if (typeof display === "string") params.display = display;
return `https://fonts.googleapis.com/css2?${Object.keys(params).map((key) => `${key}=${params[key]}`).join("&")}`;
}
/**
* A helper function for loading google fonts as {@link ArrayBuffer}
*
* @param family The name of the font family
* @param param1 Options
*
* @returns A promise which resolved to {@link ArrayBuffer}
*/
async function loadGoogleFont(family, options = {}) {
const cssUrl = constructGoogleFontCssUrl(family, options);
const fromMap = require_maps.FONT_CACHE_MAP.get(cssUrl);
if (fromMap) return fromMap;
const fontUrl = (await googleFonts.loadCss(cssUrl)).match(/src: url\((.+)\) format\('(opentype|truetype)'\)/)?.[1];
if (!fontUrl) throw new Error("The css does not content source for truetype font.");
const buffer = await (await require_cache.cache.serve(fontUrl, () => fetch(fontUrl).then((res) => {
if (!res.ok) throw new require_errors.FetchError(`Response was not successful (status: ${res.status}, statusText: ${res.statusText})`, { response: res });
return res;
}).catch((e) => {
throw new require_errors.FetchError(`An error ocurred while fetching ${fontUrl}`, {
cause: e,
response: e instanceof require_errors.FetchError ? e.response : void 0
});
}))).arrayBuffer();
require_maps.FONT_CACHE_MAP.set(cssUrl, buffer);
return buffer;
}
/** A helper class to load Custom font */
var CustomFont = class {
/**
* Creates an instance of {@link CustomFont}
*
* @param name The name of the font (can be used for font-family css property)
* @param input Font data as `ArrayBuffer` or a promise which resolves to `ArrayBuffer`
* @param options
*/
constructor(name, input, { style = "normal", weight = 400, lang } = {}) {
this.type = "custom";
this.name = name;
this.style = style;
this.weight = weight;
this.input = input;
this.lang = lang;
}
/**
* A promise which resolves to font data as `ArrayBuffer`
*/
get data() {
const fallback = async () => typeof this.input === "function" ? this.input() : this.input;
this.promise = this.promise?.then(null, fallback) ?? fallback();
return this.promise;
}
};
/** A helper class to load Google font */
var GoogleFont = class {
/**
* Creates an instance of {@link GoogleFont}
*
* @param family The name of font family to load
* @param options The {@link GoogleFontOptions}
*/
constructor(family, { name, style = "normal", weight = 400, subset = "latin", text } = {}) {
this.type = "google";
this.name = name || family;
this.style = style;
this.weight = weight;
this.subset = subset;
this.family = family;
this.text = text;
}
/** A promise which resolves to font data as `ArrayBuffer` */
get data() {
const fallback = async () => loadGoogleFont(this.family, {
style: this.style,
weight: this.weight,
subset: this.subset,
text: this.text
});
this.promise = this.promise?.then(null, fallback) ?? fallback();
return this.promise;
}
/**
* Checks whether font can load buffer
*
* @returns On success, true otherwise the error object thrown
*/
async canLoad() {
try {
await this.data;
} catch (e) {
return e;
}
return true;
}
};
/** Default font utils */
var DefaultFont = class {
constructor() {
this._shouldResolve = true;
}
/**
* Sets default font for image rendering
*
* @param input {@link FontInput}
*/
set(input) {
if (!input) throw new TypeError("Argument 1 type is not acceptable");
this._shouldResolve = true;
this._input = input;
}
/**
* Gets default font buffer for image rendering if it is set
*
* @returns A Promise which resolves to ArrayBuffer if default font is set,
* otherwise undefined
*/
async get() {
let buffer;
if (this._shouldResolve && this._input) {
const input = typeof this._input === "function" ? await this._input() : await this._input;
if (input instanceof Response) buffer = await input.arrayBuffer();
else if ("data" in input) buffer = await input.data;
else buffer = input;
} else if (this._data) buffer = this._data;
this._data = buffer;
this._shouldResolve = false;
return buffer;
}
/**
* Check whether default font is set or not
*
* @returns true if default font is set, otherwise false
*/
has() {
return Boolean(this._input);
}
};
const defaultFont = new DefaultFont();
//#endregion
exports.CustomFont = CustomFont;
exports.GOOGLE_FONT_CSS_DEFAULT_USER_AGENT = GOOGLE_FONT_CSS_DEFAULT_USER_AGENT;
exports.GoogleFont = GoogleFont;
exports.constructGoogleFontCssUrl = constructGoogleFontCssUrl;
exports.defaultFont = defaultFont;
exports.googleFonts = googleFonts;
exports.loadGoogleFont = loadGoogleFont;
//# sourceMappingURL=font.cjs.map