fontawesome-subset
Version:
Utility to create subsets for FontAwesome and FontAwesome Pro.
128 lines (127 loc) • 6.49 kB
JavaScript
;
/**
* Author: Logan Graham <loganparkergraham@gmail.com>
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fontawesomeSubset = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const mkdirp_1 = require("mkdirp");
const subset_font_1 = __importDefault(require("subset-font"));
const yaml_1 = __importDefault(require("yaml"));
const utils_1 = require("./utils");
const constants_1 = require("./constants");
/**
* This function will take an object of glyph names and output a subset of the standard fonts optimized in size for
* use on websites / external resources.
*
* @param subset Array or Object containing glyph / font family names.
* @param outputDir Directory output generated webfonts.
* @param options Object of options / tweaks for further customization. Defaults to 'Free' package.
*/
function fontawesomeSubset(subset, outputDir, options = {}) {
const { package: packageType = "free", targetFormats = ["woff2", "sfnt"] } = options;
// Maps style to actual font name / file name.
const fontTypes = Object.keys(constants_1.STYLE_FONT_MAP);
let packageLocation;
// Check to see if the user has either free, or pro installed.
try {
packageLocation = require.resolve(`@fortawesome/fontawesome-${packageType}`);
}
catch (e) {
console.error(`Unable to resolve the module '@fortawesome/fontawesome-${packageType}'. Double-check that you have your preferred fontawesome package installed as a dependency and the package type passed into the options if using Pro features.\n\n\`fontawesomeSubset(..., ..., { package: 'pro' })\``);
return Promise.resolve(false);
}
// Check that we have at least one target format for output
if (!Array.isArray(targetFormats) || targetFormats.length === 0) {
console.error("One or more target formats are required. Exiting.");
return Promise.resolve(false);
}
const fontMeta = (0, path_1.resolve)(packageLocation, "../../metadata/icons.yml");
const fontFamilyMeta = (0, path_1.resolve)(packageLocation, "../../metadata/icon-families.yml");
const fontFiles = (0, path_1.resolve)(packageLocation, "../../webfonts");
// If 'subset' is set to array, turn into object defaulted for 'solid' use (fontawesome free)
if (Array.isArray(subset)) {
subset = { solid: subset };
}
const iconMeta = yaml_1.default.parse((0, fs_1.readFileSync)(fontMeta, "utf8"));
const iconFamilyMeta = (0, fs_1.existsSync)(fontFamilyMeta)
? yaml_1.default.parse((0, fs_1.readFileSync)(fontFamilyMeta, "utf8"))
: null;
const entries = Object.entries(subset);
const promises = [];
const iconErrors = {};
for (const [key, icons] of entries) {
// Skip if current font family is not found in font_map.
if (fontTypes.indexOf(key) === -1) {
continue;
}
// Bail early if icons isn't set, isn't an array, or is empty
if (!Array.isArray(icons) || icons.length === 0) {
continue;
}
const fontFamily = key;
const fontFileName = constants_1.STYLE_FONT_MAP[fontFamily];
const fontFilePath = (0, path_1.resolve)(fontFiles, `./${fontFileName}.ttf`);
if (!(0, fs_1.existsSync)((0, path_1.resolve)(fontFilePath))) {
console.warn(`Unable to find font file for requested font style '${fontFamily}'. Skipping.`);
(0, utils_1.addIconError)(iconErrors, fontFamily, icons);
continue;
}
// Pull unicode characters from fontawesome yml, aggregating into array
const unicodeCharacters = [];
for (const icon of icons) {
let foundIcon;
if (iconFamilyMeta) {
foundIcon = (0, utils_1.findIconByName)(iconFamilyMeta, icon);
// Skip if the icon isn't found in our icon yaml
if (!foundIcon || !(0, utils_1.iconHasStyle)(foundIcon, fontFamily, packageType)) {
(0, utils_1.addIconError)(iconErrors, fontFamily, icon);
continue;
}
}
else {
foundIcon = (0, utils_1.findIconByName)(iconMeta, icon);
// Skip if the icon isn't found in our icon yaml
if (!foundIcon || !foundIcon.styles.includes(fontFamily)) {
(0, utils_1.addIconError)(iconErrors, fontFamily, icon);
continue;
}
}
const charCode = foundIcon.unicode;
unicodeCharacters.push(String.fromCodePoint(parseInt(charCode, 16)));
// Duotone secondary char codes are prefixed with a `10` for the secondary color
if (fontFamily === "duotone") {
unicodeCharacters.push(String.fromCodePoint(parseInt(`10${charCode}`, 16)));
}
}
mkdirp_1.mkdirp.sync((0, path_1.resolve)(outputDir));
const fontData = (0, fs_1.readFileSync)(fontFilePath);
const outputFile = (0, path_1.resolve)(outputDir, fontFileName);
// Loop over our requested output formats, and generate our subsets
for (const targetFormat of targetFormats) {
promises.push((0, subset_font_1.default)(fontData, unicodeCharacters.join(" "), {
targetFormat: targetFormat,
}).then((data) => {
(0, fs_1.writeFileSync)(`${outputFile}.${constants_1.OUTPUT_FORMAT_MAP[targetFormat]}`, data);
}));
}
}
return Promise.all(promises).then(() => {
const iconErrorArray = Object.entries(iconErrors).map(([style, missing_icons]) => ({
style,
missing_icons,
}));
if (iconErrorArray.length > 0) {
console.warn(`\nOne or more icons were not found in the icon metadata. Check that the icon is available in your version, tier, and that you are requesting the correct style.`);
console.table(iconErrorArray);
console.warn("See https://fontawesome.com/icons/ for icons, styles, and version availability.");
return false;
}
return true;
});
}
exports.fontawesomeSubset = fontawesomeSubset;