UNPKG

vtex-css-sanitizer-cli

Version:

Herramienta CLI para eliminar CSS y blockClass no utilizados en proyectos VTEX IO.

122 lines (121 loc) 6.62 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.fixCommand = fixCommand; const file_finder_1 = require("../utils/file-finder"); const json_processor_1 = require("../utils/json-processor"); const css_processor_1 = require("../utils/css-processor"); const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const postcss_1 = __importDefault(require("postcss")); const prompts_1 = __importDefault(require("prompts")); const report_generator_1 = require("../utils/report-generator"); async function fixCommand(projectPath) { console.log(`\n🔧 Iniciando proceso de limpieza interactiva en: ${path_1.default.resolve(projectPath)}`); // --- 1. Análisis (sin cambios) --- const jsonFiles = (0, file_finder_1.findJsonFiles)(projectPath); const cssFiles = (0, file_finder_1.findCssFiles)(projectPath); const declaredBlockClassesMap = await (0, json_processor_1.extractBlockClasses)(jsonFiles); const usedCssSuffixesMap = await (0, css_processor_1.extractCssSuffixes)(cssFiles); const declaredBlockClasses = new Set(declaredBlockClassesMap.keys()); const usedCssSuffixes = new Set(usedCssSuffixesMap.keys()); const unusedSuffixes = new Set([...usedCssSuffixes].filter(suffix => !declaredBlockClasses.has(suffix))); if (unusedSuffixes.size === 0) { console.log('\n✅ ¡Genial! No se encontraron reglas CSS para eliminar. ¡El proyecto ya está limpio!'); return; } console.log(`\n🔎 Se han encontrado reglas CSS con sufijos potencialmente no utilizados. Vamos a revisarlas una por una.`); console.log('------------------------------------------------------------------'); const deletedRules = []; const keptRules = []; let totalRulesRemoved = 0; // --- 2. Procesamiento Interactivo con CONTADOR --- const totalFiles = cssFiles.length; for (let fileIndex = 0; fileIndex < totalFiles; fileIndex++) { const filePath = cssFiles[fileIndex]; const originalContent = await promises_1.default.readFile(filePath, 'utf-8'); const root = postcss_1.default.parse(originalContent); const candidates = (0, css_processor_1.identifyRulesForDeletion)(root, unusedSuffixes); if (candidates.length === 0) { continue; } // Arreglos temporales para los cambios del archivo actual const fileDeletedRules = []; const fileKeptRules = []; let rulesRemovedInFile = 0; let userCancelled = false; for (let i = 0; i < candidates.length; i++) { const rule = candidates[i]; const relativePath = path_1.default.relative(projectPath, filePath); const ruleAsString = rule.toString(); console.clear(); console.log(`[ Progreso: Archivo ${fileIndex + 1} de ${totalFiles} ]`); console.log(`------------------------------------------------------------------`); console.log(`Revisando Archivo: ${relativePath}`); console.log(`Candidato ${i + 1} de ${candidates.length}`); console.log('------------------------------------------------------------------'); console.log('Se encontró la siguiente regla CSS que podría no estar en uso:'); console.log('\n\x1b[33m%s\x1b[0m', ruleAsString); const response = await (0, prompts_1.default)({ type: 'confirm', name: 'shouldDelete', message: '¿Deseas eliminar esta regla CSS?', initial: true }); if (response.shouldDelete === undefined) { console.log('\n🛑 Proceso de limpieza cancelado por el usuario.'); userCancelled = true; break; // Sale del bucle de reglas para este archivo } if (response.shouldDelete) { // Se opera sobre la regla, pero el reporte se guarda temporalmente fileDeletedRules.push({ rule: ruleAsString, filePath }); rule.remove(); rulesRemovedInFile++; console.log('\x1b[31m%s\x1b[0m', '🗑️ Regla eliminada.'); } else { fileKeptRules.push({ rule: ruleAsString, filePath }); console.log('\x1b[32m%s\x1b[0m', '👍 Regla conservada.'); } console.log('------------------------------------------------------------------'); } // Si el usuario canceló, se detiene todo el proceso. if (userCancelled) { if (deletedRules.length > 0 || keptRules.length > 0) { await (0, report_generator_1.generateFixReport)(projectPath, deletedRules, keptRules); console.log(`\n📄 Informe parcial de limpieza guardado con los cambios de los archivos **anteriores**.`); } return; } // Si se completó el archivo y hubo cambios, se escriben en el disco. if (rulesRemovedInFile > 0) { const newContent = root.toString(); await promises_1.default.writeFile(filePath, newContent, 'utf-8'); console.log(`\n💾 Se guardaron los cambios en ${path_1.default.relative(projectPath, filePath)}. Se eliminaron ${rulesRemovedInFile} reglas.`); totalRulesRemoved += rulesRemovedInFile; await (0, prompts_1.default)({ type: 'invisible', name: 'continue', message: 'Presiona Enter para continuar con el siguiente archivo...' }); } // Solo si el archivo se procesó por completo, se añaden las acciones al reporte final. deletedRules.push(...fileDeletedRules); keptRules.push(...fileKeptRules); } console.clear(); if (totalRulesRemoved > 0) { console.log(`\n✅ Proceso completado. Se eliminaron un total de ${totalRulesRemoved} reglas CSS.`); } else { console.log(`\n✅ Proceso completado. No se realizó ninguna eliminación.`); } if (deletedRules.length > 0 || keptRules.length > 0) { try { const reportPath = await (0, report_generator_1.generateFixReport)(projectPath, deletedRules, keptRules); console.log(`\n📄 Informe de limpieza guardado en: ${path_1.default.relative(projectPath, reportPath)}`); } catch (error) { console.error('\n❌ Ocurrió un error al guardar el informe de limpieza:', error); } } }