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 };