2
0
mirror of https://github.com/iconify/iconify.git synced 2025-01-08 07:48:29 +00:00
iconify/plugins/tailwind/lib/iconify.js
2023-01-11 17:42:21 +02:00

119 lines
3.5 KiB
JavaScript

import { readFileSync } from 'fs';
import { getIconsCSSData } from '@iconify/utils/lib/css/icons';
import { matchIconName } from '@iconify/utils/lib/icon/name';
const missingIconsListError = 'TailwindCSS cannot dynamically find all used icons. Need to pass list of used icons to Iconify plugin.';
/**
* Locate icon set
*/
function locateIconSet(prefix) {
try {
return require.resolve(`@iconify-json/${prefix}/icons.json`);
}
catch { }
try {
return require.resolve(`@iconify/json/json/${prefix}.json`);
}
catch { }
}
/**
* Load icon set
*/
function loadIconSet(prefix) {
const filename = locateIconSet(prefix);
if (filename) {
try {
return JSON.parse(readFileSync(filename, 'utf8'));
}
catch { }
}
}
/**
* Get icon names from list
*/
function getIconNames(icons) {
const prefixes = Object.create(null);
// Add entry
const add = (prefix, name) => {
if (typeof prefix === 'string' &&
prefix.match(matchIconName) &&
typeof name === 'string' &&
name.match(matchIconName)) {
(prefixes[prefix] || (prefixes[prefix] = new Set())).add(name);
}
};
// Comma or space separated string
let iconNames;
if (typeof icons === 'string') {
iconNames = icons.split(/[\s,.]/);
}
else if (icons instanceof Array) {
iconNames = [];
// Split each array entry
icons.forEach((item) => {
item.split(/[\s,.]/).forEach((name) => iconNames.push(name));
});
}
else {
throw new Error(missingIconsListError);
}
// Parse array
if (iconNames?.length) {
iconNames.forEach((icon) => {
if (!icon.trim()) {
return;
}
// Attempt prefix:name split
const nameParts = icon.split(':');
if (nameParts.length === 2) {
add(nameParts[0], nameParts[1]);
return;
}
// Attempt icon class: .icon--{prefix}--{name}
// with or without dot
const classParts = icon.split('--');
if (classParts[0].match(/^\.?icon$/)) {
if (classParts.length === 3) {
add(classParts[1], classParts[2]);
return;
}
if (classParts.length === 2) {
// Partial match
return;
}
}
// Throw error
throw new Error(`Cannot resolve icon: "${icon}"`);
});
}
else {
throw new Error(missingIconsListError);
}
return prefixes;
}
/**
* Get CSS rules for icon
*/
export function getCSSRules(icons, options = {}) {
const rules = Object.create(null);
// Get all icons
const prefixes = getIconNames(icons);
// Parse all icon sets
for (const prefix in prefixes) {
const iconSet = loadIconSet(prefix);
if (!iconSet) {
throw new Error(`Cannot load icon set for "${prefix}"`);
}
const generated = getIconsCSSData(iconSet, Array.from(prefixes[prefix]), options);
const result = generated.common
? [generated.common, ...generated.css]
: generated.css;
result.forEach((item) => {
const selector = item.selector instanceof Array
? item.selector.join(', ')
: item.selector;
rules[selector] = item.rules;
});
}
return rules;
}