node-font2base64
Version:
Convert font to base64 url or src, and to inject src into style files
402 lines (399 loc) • 13 kB
JavaScript
;
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