Primera versión del plugin
This commit is contained in:
863
build-icons-json.js
Normal file
863
build-icons-json.js
Normal file
@@ -0,0 +1,863 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// ================= CONFIGURACIÓN =================
|
||||
const CONFIG = {
|
||||
// Rutas de entrada (archivos procesados)
|
||||
PROCESSED_METADATA: path.join(__dirname, 'assets', 'processed', 'metadata.json'),
|
||||
PROCESSED_STYLES: path.join(__dirname, 'assets', 'processed', 'styles.json'),
|
||||
PROCESSED_CATEGORIES: path.join(__dirname, 'assets', 'processed', 'categories.json'),
|
||||
|
||||
// Rutas de salida (plugin)
|
||||
OUTPUT_ICONS: path.join(__dirname, 'assets', 'icons.json'),
|
||||
OUTPUT_DYNAMIC_CSS: path.join(__dirname, 'assets', 'dynamic-styles.css'),
|
||||
OUTPUT_CUSTOM_CSS: path.join(__dirname, 'assets', 'custom-styles.css'),
|
||||
|
||||
// Configuración del plugin
|
||||
PLUGIN_NAME: 'FontAwesome Pro',
|
||||
VERSION: '2.0.0'
|
||||
};
|
||||
|
||||
// ================= ESTILOS POSIBLES =================
|
||||
const ALL_STYLES = [
|
||||
// Estilos clásicos
|
||||
{
|
||||
id: 'solid',
|
||||
name: 'Solid',
|
||||
prefix: 'fas',
|
||||
class: 'fas',
|
||||
weight: 900,
|
||||
pro: true,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Pro',
|
||||
file: 'fa-solid-900.woff2'
|
||||
},
|
||||
{
|
||||
id: 'regular',
|
||||
name: 'Regular',
|
||||
prefix: 'far',
|
||||
class: 'far',
|
||||
weight: 400,
|
||||
pro: true,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Pro',
|
||||
file: 'fa-regular-400.woff2'
|
||||
},
|
||||
{
|
||||
id: 'light',
|
||||
name: 'Light',
|
||||
prefix: 'fal',
|
||||
class: 'fal',
|
||||
weight: 300,
|
||||
pro: true,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Pro',
|
||||
file: 'fa-light-300.woff2'
|
||||
},
|
||||
{
|
||||
id: 'thin',
|
||||
name: 'Thin',
|
||||
prefix: 'fat',
|
||||
class: 'fat',
|
||||
weight: 100,
|
||||
pro: true,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Pro',
|
||||
file: 'fa-thin-100.woff2'
|
||||
},
|
||||
{
|
||||
id: 'duotone',
|
||||
name: 'Duotone',
|
||||
prefix: 'fad',
|
||||
class: 'fad',
|
||||
weight: 900,
|
||||
pro: true,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Duotone',
|
||||
file: 'fa-duotone-900.woff2'
|
||||
},
|
||||
|
||||
// Estilos Sharp
|
||||
{
|
||||
id: 'sharp-solid',
|
||||
name: 'Sharp Solid',
|
||||
prefix: 'fass',
|
||||
class: 'fass',
|
||||
weight: 900,
|
||||
pro: true,
|
||||
sharp: true,
|
||||
family: 'Font Awesome 6 Sharp',
|
||||
file: 'fa-sharp-solid-900.woff2'
|
||||
},
|
||||
{
|
||||
id: 'sharp-regular',
|
||||
name: 'Sharp Regular',
|
||||
prefix: 'fasr',
|
||||
class: 'fasr',
|
||||
weight: 400,
|
||||
pro: true,
|
||||
sharp: true,
|
||||
family: 'Font Awesome 6 Sharp',
|
||||
file: 'fa-sharp-regular-400.woff2'
|
||||
},
|
||||
{
|
||||
id: 'sharp-light',
|
||||
name: 'Sharp Light',
|
||||
prefix: 'fasl',
|
||||
class: 'fasl',
|
||||
weight: 300,
|
||||
pro: true,
|
||||
sharp: true,
|
||||
family: 'Font Awesome 6 Sharp',
|
||||
file: 'fa-sharp-light-300.woff2'
|
||||
},
|
||||
{
|
||||
id: 'sharp-thin',
|
||||
name: 'Sharp Thin',
|
||||
prefix: 'fast',
|
||||
class: 'fast',
|
||||
weight: 100,
|
||||
pro: true,
|
||||
sharp: true,
|
||||
family: 'Font Awesome 6 Sharp',
|
||||
file: 'fa-sharp-thin-100.woff2'
|
||||
},
|
||||
{
|
||||
id: 'sharp-duotone',
|
||||
name: 'Sharp Duotone',
|
||||
prefix: 'fasd',
|
||||
class: 'fasd',
|
||||
weight: 900,
|
||||
pro: true,
|
||||
sharp: true,
|
||||
family: 'Font Awesome 6 Sharp Duotone',
|
||||
file: 'fa-sharp-duotone-900.woff2'
|
||||
},
|
||||
|
||||
// Brands
|
||||
{
|
||||
id: 'brands',
|
||||
name: 'Brands',
|
||||
prefix: 'fab',
|
||||
class: 'fab',
|
||||
weight: 400,
|
||||
pro: false,
|
||||
sharp: false,
|
||||
family: 'Font Awesome 6 Brands',
|
||||
file: 'fa-brands-400.woff2'
|
||||
}
|
||||
];
|
||||
|
||||
// Estilos detectados (se llenará automáticamente)
|
||||
let DETECTED_STYLES = [];
|
||||
|
||||
// ================= FUNCIONES PRINCIPALES =================
|
||||
|
||||
/**
|
||||
* Verificar si los archivos procesados existen
|
||||
*/
|
||||
function checkProcessedFiles() {
|
||||
console.log('🔍 Verificando archivos procesados...\n');
|
||||
|
||||
const requiredFiles = [
|
||||
{ path: CONFIG.PROCESSED_METADATA, name: 'metadata.json' },
|
||||
{ path: CONFIG.PROCESSED_STYLES, name: 'styles.json' },
|
||||
{ path: CONFIG.PROCESSED_CATEGORIES, name: 'categories.json' }
|
||||
];
|
||||
|
||||
let allExist = true;
|
||||
|
||||
requiredFiles.forEach(file => {
|
||||
if (fs.existsSync(file.path)) {
|
||||
const stats = fs.statSync(file.path);
|
||||
console.log(` ✅ ${file.name}: ${(stats.size / 1024).toFixed(2)} KB`);
|
||||
} else {
|
||||
console.log(` ❌ ${file.name}: NO ENCONTRADO`);
|
||||
allExist = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!allExist) {
|
||||
console.log('\n⚠️ Archivos procesados no encontrados.');
|
||||
console.log(' Ejecuta primero: npm run extract');
|
||||
console.log(' O: npm run build (que ejecuta extract automáticamente)');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
return allExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detectar estilos disponibles automáticamente
|
||||
*/
|
||||
function detectAvailableStyles() {
|
||||
console.log('🔍 Detectando estilos disponibles...\n');
|
||||
|
||||
const webfontsDir = path.join(__dirname, 'assets', 'fontawesome', 'webfonts');
|
||||
|
||||
if (!fs.existsSync(webfontsDir)) {
|
||||
console.error('❌ Carpeta de webfonts no encontrada:', webfontsDir);
|
||||
console.log(' Asegúrate de copiar los archivos de FontAwesome Pro');
|
||||
return [];
|
||||
}
|
||||
|
||||
const availableStyles = [];
|
||||
const fontFiles = fs.readdirSync(webfontsDir);
|
||||
|
||||
ALL_STYLES.forEach(style => {
|
||||
const expectedFile = style.file;
|
||||
const fontPath = path.join(webfontsDir, expectedFile);
|
||||
|
||||
// Verificar archivo principal (.woff2)
|
||||
if (fs.existsSync(fontPath)) {
|
||||
availableStyles.push(style);
|
||||
console.log(` ✅ ${style.name.padEnd(20)} ${expectedFile}`);
|
||||
} else {
|
||||
// Verificar variantes
|
||||
const variants = ['.ttf', '.eot', '.woff'].map(ext =>
|
||||
expectedFile.replace('.woff2', ext)
|
||||
);
|
||||
|
||||
const foundVariant = variants.find(variant =>
|
||||
fs.existsSync(path.join(webfontsDir, variant))
|
||||
);
|
||||
|
||||
if (foundVariant) {
|
||||
availableStyles.push(style);
|
||||
console.log(` ✅ ${style.name.padEnd(20)} ${foundVariant} (variante)`);
|
||||
} else {
|
||||
console.log(` ⚠️ ${style.name.padEnd(20)} No encontrado`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log(`📊 RESUMEN: ${availableStyles.length} de ${ALL_STYLES.length} estilos detectados`);
|
||||
|
||||
// Estadísticas
|
||||
const classicCount = availableStyles.filter(s => !s.sharp && s.id !== 'brands').length;
|
||||
const sharpCount = availableStyles.filter(s => s.sharp).length;
|
||||
const brandsCount = availableStyles.filter(s => s.id === 'brands').length;
|
||||
|
||||
console.log(` • Clásicos: ${classicCount}/5`);
|
||||
console.log(` • Sharp: ${sharpCount}/5`);
|
||||
console.log(` • Brands: ${brandsCount}/1`);
|
||||
console.log('='.repeat(60) + '\n');
|
||||
|
||||
return availableStyles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar metadata procesado
|
||||
*/
|
||||
function loadProcessedMetadata() {
|
||||
try {
|
||||
console.log('📥 Cargando metadata procesado...');
|
||||
|
||||
if (!fs.existsSync(CONFIG.PROCESSED_METADATA)) {
|
||||
throw new Error(`Archivo no encontrado: ${CONFIG.PROCESSED_METADATA}`);
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(CONFIG.PROCESSED_METADATA, 'utf8');
|
||||
const data = JSON.parse(content);
|
||||
|
||||
if (!data.icons || typeof data.icons !== 'object') {
|
||||
throw new Error('Estructura de metadata inválida');
|
||||
}
|
||||
|
||||
console.log(`✅ Metadata cargado: ${Object.keys(data.icons).length} íconos`);
|
||||
|
||||
// Convertir objeto a array
|
||||
const iconsArray = Object.values(data.icons);
|
||||
|
||||
// Filtrar íconos que tienen estilos disponibles
|
||||
const filteredIcons = iconsArray.filter(icon => {
|
||||
if (!icon.styles || !Array.isArray(icon.styles)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verificar si al menos un estilo está disponible
|
||||
return icon.styles.some(style =>
|
||||
DETECTED_STYLES.some(s => s.id === style)
|
||||
);
|
||||
});
|
||||
|
||||
console.log(`📊 Íconos con estilos disponibles: ${filteredIcons.length}/${iconsArray.length}`);
|
||||
|
||||
return filteredIcons;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error cargando metadata procesado:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar información de estilos procesada
|
||||
*/
|
||||
function loadProcessedStylesInfo() {
|
||||
try {
|
||||
if (!fs.existsSync(CONFIG.PROCESSED_STYLES)) {
|
||||
console.log('⚠️ Archivo de estilos procesado no encontrado');
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(CONFIG.PROCESSED_STYLES, 'utf8');
|
||||
const data = JSON.parse(content);
|
||||
|
||||
if (!data.styles || typeof data.styles !== 'object') {
|
||||
console.log('⚠️ Estructura de estilos inválida');
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('✅ Información de estilos cargada');
|
||||
return data.styles;
|
||||
|
||||
} catch (error) {
|
||||
console.log('⚠️ Error cargando información de estilos:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar categorías procesadas
|
||||
*/
|
||||
function loadProcessedCategories() {
|
||||
try {
|
||||
if (!fs.existsSync(CONFIG.PROCESSED_CATEGORIES)) {
|
||||
console.log('⚠️ Archivo de categorías procesado no encontrado');
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(CONFIG.PROCESSED_CATEGORIES, 'utf8');
|
||||
const data = JSON.parse(content);
|
||||
|
||||
if (!data.categories || !Array.isArray(data.categories)) {
|
||||
console.log('⚠️ Estructura de categorías inválida');
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`✅ Categorías cargadas: ${data.categories.length}`);
|
||||
return data.categories;
|
||||
|
||||
} catch (error) {
|
||||
console.log('⚠️ Error cargando categorías:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar CSS dinámico basado en estilos detectados
|
||||
*/
|
||||
function generateDynamicCSS(styles) {
|
||||
console.log('🎨 Generando CSS dinámico...');
|
||||
|
||||
let cssContent = `/* ============================================\n`;
|
||||
cssContent += ` FontAwesome Dynamic Styles\n`;
|
||||
cssContent += ` Generado: ${new Date().toISOString()}\n`;
|
||||
cssContent += ` Estilos detectados: ${styles.length}\n`;
|
||||
cssContent += `============================================ */\n\n`;
|
||||
|
||||
// Agrupar por familia de fuentes
|
||||
const families = {};
|
||||
styles.forEach(style => {
|
||||
if (!families[style.family]) {
|
||||
families[style.family] = [];
|
||||
}
|
||||
families[style.family].push(style);
|
||||
});
|
||||
|
||||
// Generar @font-face para cada familia
|
||||
Object.entries(families).forEach(([familyName, familyStyles]) => {
|
||||
cssContent += `/* ${familyName} */\n`;
|
||||
|
||||
familyStyles.forEach(style => {
|
||||
const fontWeight = style.weight;
|
||||
const fontFile = style.file;
|
||||
const fontPath = `../webfonts/${fontFile}`;
|
||||
|
||||
cssContent += `@font-face {\n`;
|
||||
cssContent += ` font-family: '${familyName}';\n`;
|
||||
cssContent += ` font-style: normal;\n`;
|
||||
cssContent += ` font-weight: ${fontWeight};\n`;
|
||||
cssContent += ` font-display: block;\n`;
|
||||
cssContent += ` src: url("${fontPath}") format("woff2");\n`;
|
||||
cssContent += `}\n\n`;
|
||||
});
|
||||
});
|
||||
|
||||
// Reglas de clase para cada estilo
|
||||
cssContent += `/* Reglas de clase */\n`;
|
||||
styles.forEach(style => {
|
||||
cssContent += `.${style.prefix} {\n`;
|
||||
cssContent += ` font-family: '${style.family}';\n`;
|
||||
cssContent += ` font-weight: ${style.weight};\n`;
|
||||
cssContent += `}\n`;
|
||||
});
|
||||
|
||||
// Variables CSS para Duotone
|
||||
const hasDuotone = styles.some(s => s.id.includes('duotone'));
|
||||
if (hasDuotone) {
|
||||
cssContent += `\n/* Variables para Duotone */\n`;
|
||||
cssContent += `.fad, .fasd {\n`;
|
||||
cssContent += ` --fa-primary-color: currentColor;\n`;
|
||||
cssContent += ` --fa-secondary-color: rgba(0, 0, 0, 0.4);\n`;
|
||||
cssContent += ` --fa-primary-opacity: 1;\n`;
|
||||
cssContent += ` --fa-secondary-opacity: 0.4;\n`;
|
||||
cssContent += `}\n`;
|
||||
}
|
||||
|
||||
// Guardar archivo
|
||||
fs.writeFileSync(CONFIG.OUTPUT_DYNAMIC_CSS, cssContent, 'utf8');
|
||||
console.log(`✅ CSS dinámico generado: ${CONFIG.OUTPUT_DYNAMIC_CSS}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar CSS personalizado para características avanzadas
|
||||
*/
|
||||
function generateCustomCSS() {
|
||||
console.log('🎨 Generando CSS personalizado...');
|
||||
|
||||
const cssContent = `/* ============================================\n`;
|
||||
cssContent += ` FontAwesome Custom Styles\n`;
|
||||
cssContent += ` Características avanzadas: Color, Tamaño, Animaciones\n`;
|
||||
cssContent += ` Generado: ${new Date().toISOString()}\n`;
|
||||
cssContent += `============================================ */\n\n`;
|
||||
|
||||
// Tamaños personalizados
|
||||
cssContent += `/* Tamaños */\n`;
|
||||
const sizes = [
|
||||
{ class: 'fa-xs', size: '0.75em' },
|
||||
{ class: 'fa-sm', size: '0.875em' },
|
||||
{ class: 'fa-lg', size: '1.33em' },
|
||||
{ class: 'fa-xl', size: '1.75em' },
|
||||
{ class: 'fa-2x', size: '2em' },
|
||||
{ class: 'fa-3x', size: '3em' },
|
||||
{ class: 'fa-4x', size: '4em' },
|
||||
{ class: 'fa-5x', size: '5em' },
|
||||
{ class: 'fa-6x', size: '6em' },
|
||||
{ class: 'fa-7x', size: '7em' },
|
||||
{ class: 'fa-8x', size: '8em' },
|
||||
{ class: 'fa-9x', size: '9em' },
|
||||
{ class: 'fa-10x', size: '10em' }
|
||||
];
|
||||
|
||||
sizes.forEach(({ class: sizeClass, size }) => {
|
||||
cssContent += `.${sizeClass} { font-size: ${size} !important; }\n`;
|
||||
});
|
||||
|
||||
// Animaciones
|
||||
cssContent += `\n/* Animaciones */\n`;
|
||||
cssContent += `.fa-spin { animation: fa-spin 2s linear infinite; }\n`;
|
||||
cssContent += `.fa-pulse { animation: fa-spin 1s steps(8) infinite; }\n`;
|
||||
cssContent += `.fa-beat { animation: fa-beat 1s ease infinite; }\n`;
|
||||
cssContent += `.fa-fade { animation: fa-fade 2s ease infinite; }\n`;
|
||||
cssContent += `.fa-bounce { animation: fa-bounce 1s ease infinite; }\n`;
|
||||
cssContent += `.fa-flip { animation: fa-flip 2s ease infinite; }\n`;
|
||||
cssContent += `.fa-shake { animation: fa-shake 1s ease infinite; }\n`;
|
||||
|
||||
// Keyframes para animaciones
|
||||
cssContent += `\n/* Keyframes */\n`;
|
||||
cssContent += `@keyframes fa-beat {\n`;
|
||||
cssContent += ` 0%, 90% { transform: scale(1); }\n`;
|
||||
cssContent += ` 45% { transform: scale(1.1); }\n`;
|
||||
cssContent += `}\n\n`;
|
||||
|
||||
cssContent += `@keyframes fa-fade {\n`;
|
||||
cssContent += ` 0%, 100% { opacity: 1; }\n`;
|
||||
cssContent += ` 50% { opacity: 0.5; }\n`;
|
||||
cssContent += `}\n\n`;
|
||||
|
||||
cssContent += `@keyframes fa-bounce {\n`;
|
||||
cssContent += ` 0%, 100% { transform: translateY(0); }\n`;
|
||||
cssContent += ` 50% { transform: translateY(-5px); }\n`;
|
||||
cssContent += `}\n\n`;
|
||||
|
||||
cssContent += `@keyframes fa-flip {\n`;
|
||||
cssContent += ` 0% { transform: perspective(400px) rotateY(0); }\n`;
|
||||
cssContent += ` 100% { transform: perspective(400px) rotateY(360deg); }\n`;
|
||||
cssContent += `}\n\n`;
|
||||
|
||||
cssContent += `@keyframes fa-shake {\n`;
|
||||
cssContent += ` 0%, 100% { transform: translateX(0); }\n`;
|
||||
cssContent += ` 25% { transform: translateX(-3px); }\n`;
|
||||
cssContent += ` 75% { transform: translateX(3px); }\n`;
|
||||
cssContent += `}\n`;
|
||||
|
||||
// Colores temáticos
|
||||
cssContent += `\n/* Colores temáticos */\n`;
|
||||
const themeColors = [
|
||||
{ class: 'fa-primary', color: 'var(--ls-link-text-color, #0451a5)' },
|
||||
{ class: 'fa-success', color: '#10b981' },
|
||||
{ class: 'fa-danger', color: '#ef4444' },
|
||||
{ class: 'fa-warning', color: '#f59e0b' },
|
||||
{ class: 'fa-info', color: '#3b82f6' },
|
||||
{ class: 'fa-purple', color: '#8b5cf6' },
|
||||
{ class: 'fa-pink', color: '#ec4899' },
|
||||
{ class: 'fa-gray', color: '#6b7280' },
|
||||
{ class: 'fa-black', color: '#000000' },
|
||||
{ class: 'fa-white', color: '#ffffff' }
|
||||
];
|
||||
|
||||
themeColors.forEach(({ class: colorClass, color }) => {
|
||||
cssContent += `.${colorClass} { color: ${color} !important; }\n`;
|
||||
});
|
||||
|
||||
// Efectos especiales
|
||||
cssContent += `\n/* Efectos especiales */\n`;
|
||||
cssContent += `.fa-shadow { filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2)); }\n`;
|
||||
cssContent += `.fa-shadow-lg { filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3)); }\n`;
|
||||
cssContent += `.fa-glow { filter: drop-shadow(0 0 8px currentColor); }\n`;
|
||||
|
||||
// Gradientes
|
||||
cssContent += `.fa-gradient {\n`;
|
||||
cssContent += ` background: linear-gradient(45deg, #8b5cf6, #3b82f6);\n`;
|
||||
cssContent += ` -webkit-background-clip: text;\n`;
|
||||
cssContent += ` -webkit-text-fill-color: transparent;\n`;
|
||||
cssContent += ` background-clip: text;\n`;
|
||||
cssContent += `}\n`;
|
||||
|
||||
// Guardar archivo
|
||||
fs.writeFileSync(CONFIG.OUTPUT_CUSTOM_CSS, cssContent, 'utf8');
|
||||
console.log(`✅ CSS personalizado generado: ${CONFIG.OUTPUT_CUSTOM_CSS}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crear base de datos final
|
||||
*/
|
||||
function createDatabase(icons, categories, stylesInfo) {
|
||||
console.log('📊 Creando base de datos final...');
|
||||
|
||||
// Preparar estilos para la base de datos
|
||||
const dbStyles = DETECTED_STYLES.map(style => {
|
||||
const styleInfoData = stylesInfo && stylesInfo[style.id] ? stylesInfo[style.id] : {};
|
||||
return {
|
||||
id: style.id,
|
||||
name: style.name,
|
||||
prefix: style.prefix,
|
||||
class: style.class,
|
||||
weight: style.weight,
|
||||
pro: style.pro,
|
||||
sharp: style.sharp,
|
||||
available: true,
|
||||
count: styleInfoData.count || 0,
|
||||
percentage: styleInfoData.percentage || '0.0'
|
||||
};
|
||||
});
|
||||
|
||||
// Actualizar conteos en categorías
|
||||
const updatedCategories = categories ? categories.map(category => {
|
||||
if (category.id === 'all') {
|
||||
return { ...category, count: icons.length };
|
||||
} else if (category.type === 'fontawesome') {
|
||||
// Contar íconos en esta categoría
|
||||
const count = icons.filter(icon =>
|
||||
icon.categories && icon.categories.includes(category.id)
|
||||
).length;
|
||||
return { ...category, count };
|
||||
}
|
||||
return category;
|
||||
}) : getDefaultCategories(icons.length);
|
||||
|
||||
// Crear estructura final
|
||||
const database = {
|
||||
meta: {
|
||||
generated: new Date().toISOString(),
|
||||
fontawesomeVersion: '6.0.0',
|
||||
pluginVersion: CONFIG.VERSION,
|
||||
totalIcons: icons.length,
|
||||
totalCategories: updatedCategories.length,
|
||||
detectedStyles: DETECTED_STYLES.length,
|
||||
stylesAvailable: DETECTED_STYLES.map(s => s.id),
|
||||
proIcons: icons.filter(icon =>
|
||||
icon.styles && icon.styles.some(style =>
|
||||
['solid', 'regular', 'light', 'thin', 'duotone',
|
||||
'sharp-solid', 'sharp-regular', 'sharp-light', 'sharp-thin', 'sharp-duotone']
|
||||
.includes(style)
|
||||
)
|
||||
).length,
|
||||
freeIcons: icons.filter(icon =>
|
||||
icon.styles && icon.styles.includes('brands')
|
||||
).length
|
||||
},
|
||||
icons: icons.map(icon => ({
|
||||
id: icon.id,
|
||||
name: icon.name,
|
||||
label: icon.label,
|
||||
categories: icon.categories || ['uncategorized'],
|
||||
styles: icon.styles || [],
|
||||
searchTerms: icon.searchTerms || [],
|
||||
unicode: icon.unicode || '',
|
||||
version: icon.version || '6.0.0',
|
||||
free: (icon.styles && icon.styles.includes('brands')) || false,
|
||||
pro: icon.styles && icon.styles.some(style =>
|
||||
['solid', 'regular', 'light', 'thin', 'duotone',
|
||||
'sharp-solid', 'sharp-regular', 'sharp-light', 'sharp-thin', 'sharp-duotone']
|
||||
.includes(style)
|
||||
)
|
||||
})),
|
||||
categories: updatedCategories,
|
||||
styles: dbStyles,
|
||||
search: {
|
||||
languages: ['en', 'es'],
|
||||
synonyms: true
|
||||
},
|
||||
features: {
|
||||
colorCustomization: true,
|
||||
sizeCustomization: true,
|
||||
animations: true,
|
||||
transformations: true,
|
||||
presets: true
|
||||
}
|
||||
};
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener categorías por defecto
|
||||
*/
|
||||
function getDefaultCategories(totalIcons) {
|
||||
return [
|
||||
{
|
||||
id: 'all',
|
||||
name: 'Todos los Íconos',
|
||||
icon: 'fas fa-th',
|
||||
count: totalIcons,
|
||||
type: 'special'
|
||||
},
|
||||
{
|
||||
id: 'favorites',
|
||||
name: 'Favoritos',
|
||||
icon: 'fas fa-star',
|
||||
count: 0,
|
||||
type: 'special'
|
||||
},
|
||||
{
|
||||
id: 'recent',
|
||||
name: 'Recientes',
|
||||
icon: 'fas fa-history',
|
||||
count: 0,
|
||||
type: 'special'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Guardar base de datos
|
||||
*/
|
||||
function saveDatabase(database) {
|
||||
try {
|
||||
// Asegurar directorio
|
||||
const assetsDir = path.dirname(CONFIG.OUTPUT_ICONS);
|
||||
if (!fs.existsSync(assetsDir)) {
|
||||
fs.mkdirSync(assetsDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Guardar JSON
|
||||
fs.writeFileSync(
|
||||
CONFIG.OUTPUT_ICONS,
|
||||
JSON.stringify(database, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
console.log(`✅ Base de datos guardada: ${CONFIG.OUTPUT_ICONS}`);
|
||||
console.log(`📊 Tamaño: ${(fs.statSync(CONFIG.OUTPUT_ICONS).size / 1024 / 1024).toFixed(2)} MB`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error guardando base de datos:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar base de datos de ejemplo
|
||||
*/
|
||||
function generateSampleDatabase() {
|
||||
console.log('📝 Generando base de datos de ejemplo...');
|
||||
|
||||
const sampleIcons = [
|
||||
{
|
||||
id: "home",
|
||||
name: "home",
|
||||
label: "Home",
|
||||
categories: ["household", "buildings"],
|
||||
styles: ["solid", "regular", "light"],
|
||||
searchTerms: ["casa", "hogar", "inicio"],
|
||||
unicode: "f015",
|
||||
version: "6.0.0",
|
||||
free: true,
|
||||
pro: true
|
||||
},
|
||||
{
|
||||
id: "user",
|
||||
name: "user",
|
||||
label: "User",
|
||||
categories: ["users-people"],
|
||||
styles: ["solid", "regular"],
|
||||
searchTerms: ["persona", "perfil", "cuenta"],
|
||||
unicode: "f007",
|
||||
version: "6.0.0",
|
||||
free: true,
|
||||
pro: true
|
||||
}
|
||||
];
|
||||
|
||||
const sampleStyles = DETECTED_STYLES.length > 0 ?
|
||||
DETECTED_STYLES.slice(0, 3) :
|
||||
ALL_STYLES.slice(0, 3);
|
||||
|
||||
const database = {
|
||||
meta: {
|
||||
generated: new Date().toISOString(),
|
||||
fontawesomeVersion: "6.0.0",
|
||||
pluginVersion: CONFIG.VERSION,
|
||||
totalIcons: sampleIcons.length,
|
||||
totalCategories: 3,
|
||||
detectedStyles: sampleStyles.length,
|
||||
proIcons: sampleIcons.length,
|
||||
freeIcons: 0,
|
||||
note: "BASE DE DATOS DE EJEMPLO - Ejecuta 'npm run build' para generar la versión completa"
|
||||
},
|
||||
icons: sampleIcons,
|
||||
categories: [
|
||||
{ id: "all", name: "Todos los Íconos", icon: "fas fa-th", count: sampleIcons.length, type: "special" },
|
||||
{ id: "household", name: "Hogar", icon: "fas fa-home", count: 1, type: "fontawesome" },
|
||||
{ id: "users-people", name: "Personas", icon: "fas fa-user", count: 1, type: "fontawesome" }
|
||||
],
|
||||
styles: sampleStyles.map(s => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
prefix: s.prefix,
|
||||
class: s.class,
|
||||
available: true
|
||||
}))
|
||||
};
|
||||
|
||||
saveDatabase(database);
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Función principal
|
||||
*/
|
||||
async function generateIconDatabase() {
|
||||
console.log('🎨 ' + '='.repeat(60));
|
||||
console.log(' GENERADOR DE BASE DE DATOS FONTAWESOME PRO');
|
||||
console.log(' Versión: ' + CONFIG.VERSION);
|
||||
console.log('='.repeat(60) + '\n');
|
||||
|
||||
try {
|
||||
// 1. Verificar archivos procesados
|
||||
const hasProcessedFiles = checkProcessedFiles();
|
||||
|
||||
if (!hasProcessedFiles) {
|
||||
console.log('⚠️ Ejecutando en modo fallback (sin archivos procesados)...');
|
||||
console.log(' Para mejor rendimiento, ejecuta: npm run extract');
|
||||
}
|
||||
|
||||
// 2. Detectar estilos disponibles
|
||||
DETECTED_STYLES = detectAvailableStyles();
|
||||
|
||||
if (DETECTED_STYLES.length === 0) {
|
||||
console.warn('⚠️ No se detectaron estilos. Generando base de datos de ejemplo...');
|
||||
return generateSampleDatabase();
|
||||
}
|
||||
|
||||
// 3. Generar CSS
|
||||
generateDynamicCSS(DETECTED_STYLES);
|
||||
generateCustomCSS();
|
||||
|
||||
// 4. Cargar datos procesados
|
||||
let icons, stylesInfo, categories;
|
||||
|
||||
if (hasProcessedFiles) {
|
||||
icons = loadProcessedMetadata();
|
||||
stylesInfo = loadProcessedStylesInfo();
|
||||
categories = loadProcessedCategories();
|
||||
|
||||
if (!icons || icons.length === 0) {
|
||||
throw new Error('No se pudieron cargar íconos del metadata procesado');
|
||||
}
|
||||
} else {
|
||||
// Modo fallback: cargar metadata original
|
||||
console.log('📥 Cargando metadata original (modo fallback)...');
|
||||
const metadataPath = path.join(__dirname, 'assets', 'fontawesome', 'metadata', 'icons.json');
|
||||
|
||||
if (!fs.existsSync(metadataPath)) {
|
||||
throw new Error('No se encontró metadata original. ¿Copiaste los archivos de FontAwesome?');
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(metadataPath, 'utf8');
|
||||
const rawMetadata = JSON.parse(content);
|
||||
|
||||
// Procesar íconos básicamente
|
||||
icons = Object.values(rawMetadata).map(icon => ({
|
||||
id: icon.name || Object.keys(rawMetadata).find(key => rawMetadata[key] === icon),
|
||||
name: icon.name || '',
|
||||
label: icon.label || '',
|
||||
categories: icon.categories || ['uncategorized'],
|
||||
styles: icon.styles || [],
|
||||
searchTerms: [],
|
||||
unicode: icon.unicode || '',
|
||||
version: icon.version || '6.0.0'
|
||||
}));
|
||||
|
||||
categories = getDefaultCategories(icons.length);
|
||||
}
|
||||
|
||||
// 5. Crear base de datos
|
||||
console.log('\n📊 Creando estructura de datos...');
|
||||
const database = createDatabase(icons, categories, stylesInfo);
|
||||
|
||||
// 6. Guardar
|
||||
saveDatabase(database);
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('✅ ¡GENERACIÓN COMPLETADA EXITOSAMENTE!');
|
||||
console.log('='.repeat(60));
|
||||
console.log(`📊 Total íconos: ${database.icons.length}`);
|
||||
console.log(`📁 Categorías: ${database.categories.length}`);
|
||||
console.log(`🎨 Estilos: ${database.meta.detectedStyles}`);
|
||||
console.log(`📍 Archivos generados:`);
|
||||
console.log(` • ${CONFIG.OUTPUT_ICONS}`);
|
||||
console.log(` • ${CONFIG.OUTPUT_DYNAMIC_CSS}`);
|
||||
console.log(` • ${CONFIG.OUTPUT_CUSTOM_CSS}`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
// Mostrar resumen de estilos
|
||||
console.log('\n🎨 ESTILOS DISPONIBLES:');
|
||||
database.styles.forEach(style => {
|
||||
if (style.available) {
|
||||
console.log(` • ${style.name.padEnd(15)}: ${style.count || 0} íconos`);
|
||||
}
|
||||
});
|
||||
|
||||
return database;
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ ERROR CRÍTICO:', error.message);
|
||||
console.log('\n🔄 Generando base de datos de ejemplo...');
|
||||
return generateSampleDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
// ================= EJECUCIÓN =================
|
||||
const args = process.argv.slice(2);
|
||||
const isSampleMode = args.includes('--sample');
|
||||
|
||||
if (require.main === module) {
|
||||
if (isSampleMode) {
|
||||
generateSampleDatabase();
|
||||
} else {
|
||||
generateIconDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
// Exportar
|
||||
module.exports = {
|
||||
generateIconDatabase,
|
||||
generateSampleDatabase,
|
||||
CONFIG,
|
||||
ALL_STYLES
|
||||
};
|
||||
Reference in New Issue
Block a user