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
JavaScript
/**
* 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;