You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
2.2 KiB

const fs = require('fs');
function extractGlyphMapFromCss(files, selectorPattern) {
const styleRulePattern =
'(\\.[A-Za-z0-9_.:, \\n\\t-]+)\\{[^}]*content: ?["\\\'](?:\\\\([A-Fa-f0-9]+)|([^"\\\']+))["\\\'][^}]*\\}';
const allStyleRules = new RegExp(styleRulePattern, 'g');
const singleStyleRules = new RegExp(styleRulePattern);
const allSelectors = new RegExp(selectorPattern, 'g');
const singleSelector = new RegExp(selectorPattern);
const extractGlyphFromRule = rule => {
const ruleParts = rule.match(singleStyleRules);
if (ruleParts[2]) {
// Hex value in CSS
return parseInt(ruleParts[2], 16);
}
if (ruleParts[3].length > 1) {
// String value in CSS that we'll keep as a string because it's not a single character
return ruleParts[3];
}
// String value in CSS that we'll convert to a charcode
return ruleParts[3].charCodeAt();
};
const extractSelectorsFromRule = rule => {
const ruleParts = rule.match(singleStyleRules);
const selectors = ruleParts[1].match(allSelectors) || [];
return selectors.map(selector => selector.match(singleSelector)[1]);
};
return (typeof files === 'string' ? [files] : files)
.map(fileName => fs.readFileSync(fileName, { encoding: 'utf8' }))
.map(contents => contents.match(allStyleRules) || [])
.reduce((acc, rules) => acc.concat(rules), [])
.map(rule => {
const glyph = extractGlyphFromRule(rule);
const selectors = extractSelectorsFromRule(rule);
return selectors.map(selector => [selector, glyph]);
})
.reduce(
(acc, glyphs) => Object.assign(acc, Object.fromEntries(glyphs)),
{}
);
}
function escapeRegExp(str) {
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
}
function generateIconSetFromCss(cssFiles, selectorPrefix, template, data = {}) {
const glyphMap = extractGlyphMapFromCss(
cssFiles,
`${escapeRegExp(selectorPrefix)}([A-Za-z0-9_-]+)::?before`
);
const content = JSON.stringify(glyphMap, null, ' ');
if (template) {
const templateVariables = { glyphMap: content, ...data };
return template.replace(/\${([^}]*)}/g, (_, key) => templateVariables[key]);
}
return content;
}
module.exports = generateIconSetFromCss;