UNPKG

node-font2base64

Version:

Convert font to base64 url or src, and to inject src into style files

402 lines (399 loc) 13 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { default: () => src_default, encodeToDataSrc: () => encodeToDataSrc, encodeToDataSrcSync: () => encodeToDataSrcSync, encodeToDataUrl: () => encodeToDataUrl, encodeToDataUrlSync: () => encodeToDataUrlSync, injectBase64: () => injectBase64, injectBase64Sync: () => injectBase64Sync }); module.exports = __toCommonJS(src_exports); var import_fs2 = __toESM(require("fs")); var import_path2 = __toESM(require("path")); var import_file_type = __toESM(require("file-type")); var import_css = __toESM(require("css")); // src/helpers.ts var import_fs = require("fs"); var import_path = require("path"); var isArray = Array.isArray; var isNil = (value) => value === void 0 || value === null; var castArray = (value) => { if (isNil(value)) return []; return isArray(value) ? value : [value]; }; var each = (items, fn, startOffset = 0, endOffset = 0) => { for (let x = startOffset; x < items.length - endOffset; x++) { if (fn(items[x], x, items) === false) break; } }; var eachArray = (items, fn, startOffset = 0, endOffset = 0) => { items = castArray(items); each(items, fn, startOffset, endOffset); }; var promiseMap = (items, fn) => { items = castArray(items); const promises = []; for (let x = 0; x < items.length; x++) { promises.push(fn(items[x], x, items)); } return Promise.all(promises); }; var promisify = (fn) => (...args) => new Promise((resolve, reject) => { fn(...args, (err, data) => { if (err) return reject(err); return resolve(data); }); }); var readFileAsync = promisify(import_fs.readFile); var writeFileAsync = promisify(import_fs.writeFile); var statAsync = promisify(import_fs.stat); var readdirAsync = promisify(import_fs.readdir); var readAllFilesAsync = async (fileOrPath, allowedExts = []) => { const files = []; await promiseMap(fileOrPath, async (fp) => { try { const stat2 = await statAsync(fp); if (stat2.isDirectory()) { const subs = await readdirAsync(fp); const subPaths = subs.map((s) => (0, import_path.join)(fp, s)); const subFiles = await readAllFilesAsync(subPaths, allowedExts); files.push(...subFiles); } else { if (allowedExts.includes((0, import_path.extname)(fp))) files.push(fp); } } catch (e) { } }); return files; }; var readAllFilesSync = (fileOrPath, allowedExts = []) => { const files = []; eachArray(fileOrPath, (fp) => { try { const stat2 = (0, import_fs.statSync)(fp); if (stat2.isDirectory()) { const subs = (0, import_fs.readdirSync)(fp); const subPaths = subs.map((s) => (0, import_path.join)(fp, s)); const subFiles = readAllFilesSync(subPaths, allowedExts); files.push(...subFiles); } else { if (allowedExts.includes((0, import_path.extname)(fp))) files.push(fp); } } catch (e) { } }); return files; }; // src/index.ts var { fromBuffer: fileTypeFromBuffer } = import_file_type.default; var sync; try { sync = require("promise-synchronizer"); } catch (er) { sync = null; } var MAX_PATH_LENGTH = 200; var fontMap = { ".svg": { mediaType: "image/svg+xml", format: "svg" }, ".ttf": { mediaType: "font/truetype", format: "truetype" }, ".otf": { mediaType: "font/opentype", format: "opentype" }, ".eot": { mediaType: "application/vnd.ms-fontobject", format: "embedded-opentype" }, ".sfnt": { mediaType: "application/font-sfnt", format: "sfnt" }, ".woff2": { mediaType: "application/font-woff2", format: "woff2" }, ".woff": { mediaType: "application/font-woff", format: "woff" } }; var _fontTypes = Object.keys(fontMap); var _styleTypes = [".css", ".scss", ".less"]; var _buffToBase64 = (buff) => buff.toString("base64"); var _readBuffer = async (buff) => { const base64 = _buffToBase64(buff); const data = await fileTypeFromBuffer(buff); data.base64 = base64; return data; }; var _readBufferSync = (buff) => { const base64 = _buffToBase64(buff); let data; if (sync) { data = sync(fileTypeFromBuffer(buff)); } else { data = {}; } data.base64 = base64; return data; }; var _toDataUrl = (mediaType, base64) => `data:${mediaType};charset=utf-8;base64,${base64}`; var _toDataSrc = (dataUrl, format) => `url(${dataUrl}) format('${format}')`; var _getMeta = (fpath, ext) => { const naive = import_path2.default.parse(fpath).ext; if (naive === ".svg") return fontMap[naive]; const type = ext && `.${ext}` || naive; return fontMap[type]; }; var toDataUrl = (fpath, { ext, mime, base64 }) => { const meta = _getMeta(fpath, ext); const mediaType = meta.mediaType; return _toDataUrl(mediaType, base64); }; var toDataSrc = (fpath, { ext, mime, base64 }) => { const meta = _getMeta(fpath, ext); if (!meta) return null; const mediaType = meta.mediaType; const format = meta.format; const dataUrl = _toDataUrl(mediaType, base64); return _toDataSrc(dataUrl, format); }; var _encodeToDataUrl = async (fpath) => { const buff = await readFileAsync(fpath); const data = await _readBuffer(buff); return toDataUrl(fpath, data); }; var _encodeToDataUrlSync = (fpath) => { const buff = import_fs2.default.readFileSync(fpath); const data = _readBufferSync(buff); return toDataUrl(fpath, data); }; var _encodeToDataSrc = async (fpath) => { const buff = await readFileAsync(fpath); const data = await _readBuffer(buff); return toDataSrc(fpath, data); }; var _encodeToDataSrcSync = (fpath) => { const buff = import_fs2.default.readFileSync(fpath); const data = _readBufferSync(buff); return toDataSrc(fpath, data); }; var encodeToDataUrl = async (fpath) => { if (isArray(fpath)) return Promise.all(fpath.map(_encodeToDataUrl)); return _encodeToDataUrl(fpath); }; var encodeToDataUrlSync = (fpath) => { if (isArray(fpath)) return fpath.map(_encodeToDataUrlSync); return _encodeToDataUrlSync(fpath); }; var encodeToDataSrc = (fpath) => { if (isArray(fpath)) return Promise.all(fpath.map(_encodeToDataSrcSync)); return _encodeToDataSrc(fpath); }; var encodeToDataSrcSync = (fpath) => { if (isArray(fpath)) return fpath.map(_encodeToDataSrcSync); return _encodeToDataSrcSync(fpath); }; var _extractSrcUrl = (value) => { const rx = /url\('?(.+?)(\??#.+?)?'?\)/g; const arr = rx.exec(value); if (!arr) return value; return arr[1]; }; var _updateCssAst = (content, validator, dataUrlMap, fullpathMatch, cssRoot) => { var _a; const keys = Object.keys(dataUrlMap); const ast = import_css.default.parse(content); let modified = false; each(((_a = ast.stylesheet) == null ? void 0 : _a.rules) || [], (rule) => { if (rule.type === "font-face") { each(rule.declarations || [], (dec) => { var _a2; if (dec.property === "src") { const urls = ((_a2 = dec.value) == null ? void 0 : _a2.split(",")) || []; const nUrls = urls.map((url) => { let nUrl = url; const urlpath = _extractSrcUrl(url); if (urlpath.length > MAX_PATH_LENGTH) return nUrl; const fullmatch = fullpathMatch && cssRoot; const tpathToCompare = fullmatch && import_path2.default.resolve(cssRoot, urlpath) || import_path2.default.basename(urlpath); each(keys, (key) => { const kpathToCompare = fullmatch && import_path2.default.resolve(key) || import_path2.default.basename(key); if (validator(tpathToCompare, kpathToCompare, urlpath, key)) { nUrl = dataUrlMap[key] || ""; modified = true; return false; } return true; }); return nUrl; }); dec.value = nUrls.join(",\n"); } }); } }); const result = { modified }; if (modified) { const newContent = import_css.default.stringify(ast); result.content = newContent; } else { result.content = content; } return result; }; var _defaultValidator = (path1, path2) => path1 === path2; var _generateDataUrlMap = async (fpath, fontTypes) => { const dataUrlMap = {}; try { await promiseMap(await readAllFilesAsync(fpath, fontTypes), async (fp) => { dataUrlMap[fp] = await _encodeToDataSrc(fp); }); } catch (e) { console.error(e); } return dataUrlMap; }; var _generateDataUrlMapSync = (fpath, fontTypes) => { const dataUrlMap = {}; eachArray(readAllFilesSync(fpath, fontTypes), (fp) => { dataUrlMap[fp] = _encodeToDataSrcSync(fp); }); return dataUrlMap; }; var injectBase64 = async (fpath, cpath, { validator = _defaultValidator, fontTypes = _fontTypes, cssTypes = _styleTypes, resave = true, fullpathMatch = false } = {}) => { const dataUrlMap = await _generateDataUrlMap(fpath, fontTypes); const results = []; try { await promiseMap(await readAllFilesAsync(cpath, cssTypes), async (cp) => { const content = await readFileAsync(cp, "utf8"); const result = _updateCssAst(content, validator, dataUrlMap, fullpathMatch, import_path2.default.parse(cp).dir); if (result.modified && resave) { await writeFileAsync(cp, result.content, "utf8"); } result.filepath = cp; results.push(result); }); } catch (err) { console.error(err); } return resave ? true : results; }; var injectBase64Sync = (fpath, cpath, { validator = _defaultValidator, fontTypes = _fontTypes, cssTypes = _styleTypes, resave = true, fullpathMatch = false } = {}) => { const dataUrlMap = _generateDataUrlMapSync(fpath, fontTypes); const results = []; try { eachArray(readAllFilesSync(cpath, cssTypes), (cp) => { const content = import_fs2.default.readFileSync(cp, "utf8"); const result = _updateCssAst(content, validator, dataUrlMap, fullpathMatch, import_path2.default.parse(cp).dir); if (result.modified && resave) { import_fs2.default.writeFileSync(cp, result.content || "", "utf8"); } result.filepath = cp; results.push(result); }); } catch (err) { console.error(err); } return resave ? true : results; }; injectBase64.fromContent = async (fpath, content, { validator = _defaultValidator, fontTypes = _fontTypes, fullpathMatch = false, root = "" } = {}) => { const dataUrlMap = await _generateDataUrlMap(fpath, fontTypes); return _updateCssAst(content, validator, dataUrlMap, fullpathMatch, root); }; injectBase64Sync.fromContent = (fpath, content, { validator = _defaultValidator, fontTypes = _fontTypes, fullpathMatch = false, root = "" } = {}) => { const dataUrlMap = _generateDataUrlMapSync(fpath, fontTypes); return _updateCssAst(content, validator, dataUrlMap, fullpathMatch, root); }; injectBase64.fromBuffer = async (fpath, buffer, options) => { const content = buffer.toString("utf8"); return injectBase64.fromContent(fpath, content, options); }; injectBase64Sync.fromBuffer = (fpath, buffer, options) => { const content = buffer.toString("utf8"); return injectBase64Sync.fromContent(fpath, content, options); }; var src_default = { encodeToDataUrl, encodeToDataSrc, encodeToDataUrlSync, encodeToDataSrcSync, injectBase64, injectBase64Sync }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { encodeToDataSrc, encodeToDataSrcSync, encodeToDataUrl, encodeToDataUrlSync, injectBase64, injectBase64Sync }); /*! * node-font2base64 * Copyright(c) 2023 Junmin Ahn * MIT Licensed */ //# sourceMappingURL=index.js.map