UNPKG

acs-framework-cli

Version:

🚀 CLI inteligente para configurar automáticamente el Augmented Context Standard (ACS) Framework. Context-as-Code que convierte tu conocimiento en un activo versionado.

360 lines (297 loc) 11.1 kB
#!/usr/bin/env node /** * large-project-handler.js - Manejador especializado para proyectos grandes * * Detecta y maneja casos especiales como: * - Proyectos con múltiples stacks * - Monorepos * - Proyectos legacy complejos * - Proyectos sin configuración inicial */ const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); class LargeProjectHandler { constructor(targetDir) { this.targetDir = targetDir; this.complexity = 'simple'; this.detectedPatterns = []; this.warnings = []; this.recommendations = []; } async analyzeProjectComplexity() { console.log(chalk.yellow('🔍 Analizando complejidad del proyecto...')); const analysis = { fileCount: 0, directoryCount: 0, configFiles: [], multipleTechStacks: false, isMonorepo: false, hasLegacyCode: false, estimatedSize: 'small' }; try { // Contar archivos y directorios (con límite para evitar bloqueos) analysis.directoryCount = await this.countDirectories(); analysis.fileCount = await this.estimateFileCount(); // Detectar archivos de configuración múltiples analysis.configFiles = await this.detectConfigFiles(); // Detectar monorepo analysis.isMonorepo = await this.detectMonorepo(); // Detectar múltiples stacks tecnológicos analysis.multipleTechStacks = await this.detectMultipleTechStacks(); // Detectar código legacy analysis.hasLegacyCode = await this.detectLegacyPatterns(); // Determinar tamaño estimado analysis.estimatedSize = this.estimateProjectSize(analysis); this.complexity = this.determineComplexity(analysis); console.log(chalk.blue(`📊 Proyecto detectado como: ${this.complexity.toUpperCase()}`)); return analysis; } catch (error) { console.log(chalk.red('⚠️ Error analizando proyecto:', error.message)); return analysis; } } async countDirectories() { try { const items = await fs.readdir(this.targetDir); let count = 0; for (const item of items.slice(0, 50)) { // Limitar para evitar bloqueos if (item.startsWith('.') && item !== '.context') continue; const itemPath = path.join(this.targetDir, item); const stat = await fs.stat(itemPath); if (stat.isDirectory() && !['node_modules', '.git', 'vendor'].includes(item)) { count++; } } return count; } catch (error) { return 0; } } async estimateFileCount() { try { // Estimación rápida sin recorrer todo el árbol const { execSync } = require('child_process'); const result = execSync( 'find . -type f -not -path "./node_modules/*" -not -path "./.git/*" -not -path "./vendor/*" | wc -l', { cwd: this.targetDir, encoding: 'utf8', timeout: 5000 } ); return parseInt(result.trim()); } catch (error) { // Fallback: contar solo archivos en root try { const items = await fs.readdir(this.targetDir); return items.filter(item => !item.startsWith('.') && fs.statSync(path.join(this.targetDir, item)).isFile()).length; } catch (e) { return 0; } } } async detectConfigFiles() { const configFiles = [ 'package.json', 'composer.json', 'requirements.txt', 'go.mod', 'Cargo.toml', 'pom.xml', 'build.gradle', 'CMakeLists.txt', 'Makefile', 'docker-compose.yml', 'Dockerfile', 'docker-compose.yaml', 'tsconfig.json', 'babel.config.js', 'webpack.config.js', 'vite.config.js', 'next.config.js', 'nuxt.config.js', 'angular.json', 'pubspec.yaml', 'Package.swift', 'project.clj' ]; const foundFiles = []; for (const configFile of configFiles) { if (await fs.pathExists(path.join(this.targetDir, configFile))) { foundFiles.push(configFile); } } return foundFiles; } async detectMonorepo() { // Detectar patrones de monorepo const monorepoIndicators = [ 'lerna.json', 'nx.json', 'rush.json', 'pnpm-workspace.yaml', 'packages/', 'apps/', 'libs/', 'modules/', 'services/' ]; for (const indicator of monorepoIndicators) { if (await fs.pathExists(path.join(this.targetDir, indicator))) { this.detectedPatterns.push(`Monorepo pattern: ${indicator}`); return true; } } // Detectar múltiples package.json try { const { execSync } = require('child_process'); const result = execSync( 'find . -name "package.json" -not -path "./node_modules/*" | wc -l', { cwd: this.targetDir, encoding: 'utf8', timeout: 3000 } ); const packageJsonCount = parseInt(result.trim()); if (packageJsonCount > 1) { this.detectedPatterns.push(`Multiple package.json files: ${packageJsonCount}`); return true; } } catch (error) { // Ignore } return false; } async detectMultipleTechStacks() { const techStacks = []; // Detectar JavaScript/Node.js if (await fs.pathExists(path.join(this.targetDir, 'package.json'))) { techStacks.push('JavaScript/Node.js'); } // Detectar PHP if (await fs.pathExists(path.join(this.targetDir, 'composer.json'))) { techStacks.push('PHP'); } // Detectar Python if (await fs.pathExists(path.join(this.targetDir, 'requirements.txt')) || await fs.pathExists(path.join(this.targetDir, 'Pipfile')) || await fs.pathExists(path.join(this.targetDir, 'pyproject.toml'))) { techStacks.push('Python'); } // Detectar Go if (await fs.pathExists(path.join(this.targetDir, 'go.mod'))) { techStacks.push('Go'); } // Detectar Rust if (await fs.pathExists(path.join(this.targetDir, 'Cargo.toml'))) { techStacks.push('Rust'); } // Detectar Java if (await fs.pathExists(path.join(this.targetDir, 'pom.xml')) || await fs.pathExists(path.join(this.targetDir, 'build.gradle'))) { techStacks.push('Java'); } if (techStacks.length > 1) { this.detectedPatterns.push(`Multiple tech stacks: ${techStacks.join(', ')}`); return true; } return false; } async detectLegacyPatterns() { const legacyIndicators = [ // Archivos legacy comunes 'bower.json', 'gulpfile.js', 'Gruntfile.js', '.bowerrc', // Directorios legacy 'bower_components/', // Versiones muy viejas en package.json ]; for (const indicator of legacyIndicators) { if (await fs.pathExists(path.join(this.targetDir, indicator))) { this.detectedPatterns.push(`Legacy pattern: ${indicator}`); return true; } } // Detectar versiones muy viejas en package.json try { const packagePath = path.join(this.targetDir, 'package.json'); if (await fs.pathExists(packagePath)) { const pkg = await fs.readJson(packagePath); // Detectar versiones muy viejas de frameworks populares const deps = { ...pkg.dependencies, ...pkg.devDependencies }; if (deps.react && deps.react.includes('15.')) { this.detectedPatterns.push('Legacy React version detected'); return true; } if (deps.angular && deps.angular.includes('1.')) { this.detectedPatterns.push('Legacy AngularJS detected'); return true; } } } catch (error) { // Ignore } return false; } estimateProjectSize(analysis) { if (analysis.fileCount > 10000 || analysis.directoryCount > 50) { return 'large'; } else if (analysis.fileCount > 1000 || analysis.directoryCount > 20) { return 'medium'; } return 'small'; } determineComplexity(analysis) { let complexityScore = 0; if (analysis.isMonorepo) complexityScore += 3; if (analysis.multipleTechStacks) complexityScore += 2; if (analysis.hasLegacyCode) complexityScore += 2; if (analysis.estimatedSize === 'large') complexityScore += 2; if (analysis.estimatedSize === 'medium') complexityScore += 1; if (analysis.configFiles.length > 5) complexityScore += 1; if (complexityScore >= 5) { return 'complex'; } else if (complexityScore >= 3) { return 'moderate'; } return 'simple'; } generateComplexityRecommendations() { const recommendations = []; if (this.complexity === 'complex') { recommendations.push({ type: 'critical', message: 'Proyecto complejo detectado - considera documentar por módulos/servicios', action: 'Crear documentación ACS para cada submódulo principal' }); recommendations.push({ type: 'warning', message: 'Considera usar acs-validate frecuentemente durante el setup', action: 'Ejecutar acs-validate después de cada sección completada' }); } if (this.detectedPatterns.some(p => p.includes('Monorepo'))) { recommendations.push({ type: 'info', message: 'Monorepo detectado - cada package puede necesitar su propia documentación', action: 'Ejecutar acs-init en cada directorio de package principal' }); } if (this.detectedPatterns.some(p => p.includes('Multiple tech stacks'))) { recommendations.push({ type: 'warning', message: 'Múltiples tecnologías detectadas - asegúrate de documentar todas', action: 'Incluir versiones específicas de cada stack en RULES.md' }); } if (this.detectedPatterns.some(p => p.includes('Legacy'))) { recommendations.push({ type: 'warning', message: 'Código legacy detectado - documenta planes de migración', action: 'Agregar sección de "Technical Debt" en ARCHITECTURE.md' }); } return recommendations; } async showComplexityWarnings() { if (this.complexity === 'complex') { console.log(chalk.yellow('\n⚠️ PROYECTO COMPLEJO DETECTADO')); console.log(chalk.gray(' Este proyecto tiene alta complejidad. Recomendaciones:')); const recommendations = this.generateComplexityRecommendations(); recommendations.forEach(rec => { const icon = rec.type === 'critical' ? '🚨' : rec.type === 'warning' ? '⚠️' : '💡'; console.log(chalk.yellow(` ${icon} ${rec.message}`)); console.log(chalk.gray(` → ${rec.action}`)); }); console.log(chalk.cyan('\n💡 Tip: Puedes ejecutar acs-init en subdirectorios para documentación modular')); } if (this.detectedPatterns.length > 0) { console.log(chalk.blue('\n📋 Patrones detectados:')); this.detectedPatterns.forEach(pattern => { console.log(chalk.gray(` • ${pattern}`)); }); } } } module.exports = LargeProjectHandler;