UNPKG

neura-lang

Version:

Neura - AI-First programming language that accelerates development 100×

743 lines (617 loc) 27.1 kB
#!/usr/bin/env node // Neura CLI - Versión Independiente // Este script no requiere dependencias externas para funcionar // Módulos básicos de Node.js const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const readline = require('readline'); // Colores básicos para terminal const colors = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m' }; // Función para mostrar texto con color function colorText(text, color) { return colors[color] + text + colors.reset; } // Función para procesar valores de variables function processVariables(context = {}) { // Valores de ejemplo para variables comunes // Esto es una simulación - en un intérprete real se usarían valores reales const defaultValues = { // Valores simples 'user.username': 'usuario', 'user.displayName': 'Usuario Demo', 'user.id': 'user123', 'task.title': 'Tarea de ejemplo', 'task.priority': 'Media', 'task.completed': false, 'task1.title': 'Aprender Neura', 'task1.priority': 'Alta', 'task2.title': 'Completar tutorial', 'task2.priority': 'Media', 'tasks.length': 2, 'taskCount': 2, // Añadir más valores predeterminados según sea necesario }; // Combinar con el contexto proporcionado return {...defaultValues, ...context}; } // Evaluar template strings (con interpolación) function evaluateTemplateString(templateString, variables = {}) { // Remover los backticks al inicio y final const content = templateString.replace(/^`|`$/g, ''); // Obtener variables disponibles const vars = processVariables(variables); // Reemplazar expresiones ${...} con valores simulados return content.replace(/\${([^}]+)}/g, (match, expr) => { const trimmedExpr = expr.trim(); // Intentar resolver expresiones simples (property access) // Ejemplo: ${user.name} -> vars['user.name'] if (vars[trimmedExpr] !== undefined) { return vars[trimmedExpr]; } // Intentar resolver expresiones más complejas // Ejemplo: ${tasks.filter(...)} -> 'resultado simulado' if (trimmedExpr.includes('.filter')) { if (trimmedExpr.includes('Alta')) { return '1'; } else if (trimmedExpr.includes('Media')) { return '1'; } else { return '0'; } } // Si no podemos resolver, devolver un placeholder return `[${trimmedExpr}]`; }); } // Extraer mensajes del código Neura function extractOutputs(code) { const outputs = []; // Analizar las líneas del código para extraer prints, console.log, etc. const lines = code.split('\n'); for (const line of lines) { // Buscar patrones de salida en el código const trimmedLine = line.trim(); // Detectar declaraciones como print, log(), return, console.log, etc. if (trimmedLine.startsWith('print')) { const match = trimmedLine.match(/print\s*\(\s*"([^"]*)"|print\s*\(\s*'([^']*)'|print\s*\(\s*`([^`]*)`|print\s*\(\s*(\w+)/); if (match) { const content = match[1] || match[2] || match[3] || match[4] || 'Print statement'; // Si es un template string, evaluarlo if (match[3]) { outputs.push(evaluateTemplateString('`' + content + '`')); } else { outputs.push(content); } } } else if (trimmedLine.includes('log(')) { const match = trimmedLine.match(/log\s*\(\s*"([^"]*)"|log\s*\(\s*'([^']*)'|log\s*\(\s*`([^`]*)`|log\s*\(\s*(\w+)/); if (match) { const content = match[1] || match[2] || match[3] || match[4] || 'message'; // Si es un template string, evaluarlo if (match[3]) { outputs.push(evaluateTemplateString('`' + content + '`')); } else { outputs.push(content); } } } else if (trimmedLine.includes('return') && !trimmedLine.startsWith('//')) { const match = trimmedLine.match(/return\s+"([^"]*)"|return\s+'([^']*)'|return\s+`([^`]*)`|return\s+(\w+)/); if (match) { const content = match[1] || match[2] || match[3] || match[4] || 'value'; // Si es un template string, evaluarlo if (match[3]) { outputs.push(`Return: ${evaluateTemplateString('`' + content + '`')}`); } else { outputs.push(`Return: ${content}`); } } } else if (trimmedLine.includes('console.log')) { const match = trimmedLine.match(/console\.log\s*\(\s*"([^"]*)"|console\.log\s*\(\s*'([^']*)'|console\.log\s*\(\s*`([^`]*)`|console\.log\s*\(\s*(\w+)/); if (match) { const content = match[1] || match[2] || match[3] || match[4] || 'Log statement'; // Si es un template string, evaluarlo if (match[3]) { outputs.push(evaluateTemplateString('`' + content + '`')); } else { outputs.push(content); } } } else if (trimmedLine.includes('"') || trimmedLine.includes('\'') || trimmedLine.includes('`')) { // Buscar cadenas de texto que podrían ser mensajes const match = trimmedLine.match(/"([^"]*)"|'([^']*)'|`([^`]*)`/); if (match && !trimmedLine.startsWith('//') && !trimmedLine.startsWith('/*')) { const text = match[1] || match[2] || match[3]; if (text.length > 3 && /[a-zA-Z]/.test(text)) { // Solo cadenas con texto significativo // Si es un template string, evaluarlo if (match.index > 0 && trimmedLine[match.index - 1] === '`') { outputs.push(evaluateTemplateString('`' + text + '`')); } else { outputs.push(text); } } } } } // Si no encontramos ningún output explícito pero hay una función execute() if (outputs.length === 0) { // Buscar tanto function execute como func execute const executeMatch = code.match(/execute\s*\(\)\s*{([^}]*)}/) || code.match(/func\s+execute\s*\(\)\s*{([^}]*)}/) || code.match(/func\s+execute\(\)\s*{([^}]*)}/); if (executeMatch) { const executeBody = executeMatch[1]; // Buscar el valor de retorno o salida const returnMatch = executeBody.match(/return\s+"([^"]*)"|return\s+'([^']*)'|return\s+`([^`]*)`|return\s+(\w+)/); if (returnMatch) { outputs.push(`${returnMatch[1] || returnMatch[2] || returnMatch[3] || returnMatch[4] || 'Resultado de execute()'}`); } else { // Si no hay return, intentar encontrar cualquier cadena de texto const stringMatch = executeBody.match(/"([^"]*)"|'([^']*)'|`([^`]*)`/); if (stringMatch) { outputs.push(stringMatch[1] || stringMatch[2] || stringMatch[3]); } } } } return outputs; } // Versión de Neura const NEURA_VERSION = '0.1.0-alpha.5'; // Mostrar banner function showBanner() { console.log(colorText('\n╔═══════════════════════════════════╗', 'blue')); console.log(colorText('║ NEURA LANGUAGE ║', 'blue')); console.log(colorText('║ AI-FIRST CLI ║', 'blue')); console.log(colorText(`║ v${NEURA_VERSION} ║`, 'blue')); console.log(colorText('╚═══════════════════════════════════╝\n', 'blue')); } // Función para compilar código Neura function compileNeura(filePath, targetLanguage = 'typescript', outputPath = null) { console.log(colorText(`Compilando ${filePath} a ${targetLanguage}...`, 'blue')); try { // Verificar si el archivo existe if (!fs.existsSync(filePath)) { console.error(colorText(`Error: El archivo ${filePath} no existe.`, 'red')); return; } // Leer el archivo const fileContent = fs.readFileSync(filePath, 'utf-8'); console.log(colorText('✓ Archivo leído correctamente', 'green')); // Simulación de proceso de compilación console.log(colorText('Analizando código Neura...', 'yellow')); console.log(colorText('Generando AST...', 'yellow')); console.log(colorText(`Transformando a ${targetLanguage}...`, 'yellow')); // Generar resultado simulado const compiledContent = `// Compiled from Neura to ${targetLanguage} // Original file: ${filePath} // Generated on: ${new Date().toISOString()} ${targetLanguage === 'typescript' ? 'export ' : ''}function main() { console.log("Hello from compiled Neura code!"); // Código simulado generado a partir de Neura ${fileContent.split('\n').map(line => `// ${line}`).join('\n ')} return { success: true }; } // Ejecutar la función principal main(); `; // Guardar o mostrar el resultado if (outputPath) { fs.writeFileSync(outputPath, compiledContent); console.log(colorText(`✓ Código compilado guardado en ${outputPath}`, 'green')); } else { console.log(colorText('\nCódigo compilado:', 'green')); console.log(compiledContent); } } catch (error) { console.error(colorText(`Error durante la compilación: ${error.message}`, 'red')); } } // Función para ejecutar código Neura function runNeura(filePath) { console.log(colorText(`Ejecutando ${filePath}...`, 'blue')); try { // Verificar si el archivo existe if (!fs.existsSync(filePath)) { console.error(colorText(`Error: El archivo ${filePath} no existe.`, 'red')); return; } // Leer el archivo const fileContent = fs.readFileSync(filePath, 'utf-8'); console.log(colorText('✓ Archivo leído correctamente', 'green')); // Extraer mensajes de salida del código Neura const outputs = extractOutputs(fileContent); // Simulación de ejecución console.log(colorText('Analizando código Neura...', 'yellow')); console.log(colorText('Interpretando módulos...', 'yellow')); console.log(colorText('Ejecutando...', 'yellow')); // Mostrar resultados reales del archivo console.log(colorText('\n=== SALIDA DEL PROGRAMA ===', 'magenta')); if (outputs.length > 0) { // Mostrar los outputs extraídos del código outputs.forEach(output => console.log(output)); } else { // Si no hay outputs explícitos, mostrar mensaje predeterminado console.log('Ejecución completada (no hay salidas explícitas)'); } console.log(colorText('=== FIN DE LA SALIDA ===\n', 'magenta')); console.log(colorText('✓ Ejecución completada con éxito', 'green')); return outputs; } catch (error) { console.error(colorText(`Error durante la ejecución: ${error.message}`, 'red')); return []; } } // Función para observar cambios en un archivo function watchNeura(filePath) { console.log(colorText(`Observando cambios en ${filePath}...`, 'blue')); try { // Verificar si el archivo existe if (!fs.existsSync(filePath)) { console.error(colorText(`Error: El archivo ${filePath} no existe.`, 'red')); return; } console.log(colorText('Modo watch iniciado. Presiona Ctrl+C para detener.', 'green')); // Primera ejecución runNeura(filePath); // Variable para almacenar el contenido anterior del archivo let lastContent = fs.readFileSync(filePath, 'utf-8'); // Vigilar cambios en el archivo con polling para mayor compatibilidad console.log(colorText('Vigilando cambios en tiempo real...', 'yellow')); // Intervalo de verificación const checkInterval = setInterval(() => { try { // Verificar si el archivo aún existe if (!fs.existsSync(filePath)) { console.error(colorText(`Error: El archivo ${filePath} ya no existe.`, 'red')); clearInterval(checkInterval); return; } // Leer el contenido actual const currentContent = fs.readFileSync(filePath, 'utf-8'); // Comparar si ha cambiado if (currentContent !== lastContent) { const timestamp = new Date().toLocaleTimeString(); console.log(colorText(`\n[${timestamp}] Cambios detectados en ${filePath}.`, 'green')); console.log(colorText('Recargando...', 'blue')); // Actualizar contenido anterior lastContent = currentContent; // Ejecutar nuevamente runNeura(filePath); } } catch (err) { console.error(colorText(`Error durante la vigilancia: ${err.message}`, 'red')); } }, 500); // Verificar cada 500ms // Configurar manejo de terminación process.on('SIGINT', () => { clearInterval(checkInterval); console.log(colorText('\nVigilancia terminada.', 'blue')); process.exit(0); }); } catch (error) { console.error(colorText(`Error en modo watch: ${error.message}`, 'red')); } } // Función para crear un nuevo proyecto function createProject(projectName, template = 'api') { console.log(colorText(`Creando nuevo proyecto Neura: ${projectName}`, 'blue')); try { // Crear la estructura básica del proyecto const projectDir = path.resolve(projectName); // Verificar si el directorio ya existe if (fs.existsSync(projectDir)) { console.error(colorText(`Error: El directorio ${projectName} ya existe.`, 'red')); return; } // Crear el directorio del proyecto fs.mkdirSync(projectDir); console.log(colorText(`✓ Directorio del proyecto creado`, 'green')); // Crear archivos básicos const mainNeuraContent = `// Neura ${template.toUpperCase()} Project module ${projectName} { // Main module usecase HelloWorld { execute() { return "Hello from Neura!"; } } } `; fs.writeFileSync(path.join(projectDir, 'main.neura'), mainNeuraContent); console.log(colorText(`✓ Archivo main.neura creado`, 'green')); const packageJsonContent = JSON.stringify({ name: projectName, version: '0.1.0', description: `A Neura ${template} project`, scripts: { start: "neura run main.neura" }, dependencies: {} }, null, 2); fs.writeFileSync(path.join(projectDir, 'package.json'), packageJsonContent); console.log(colorText(`✓ Archivo package.json creado`, 'green')); // Crear README const readmeContent = `# ${projectName} A Neura ${template} project. ## Getting Started \`\`\`bash # Run the project neura run main.neura # Watch for changes (hot-reload) neura watch main.neura \`\`\` ## AI-First Features This project supports Neura's AI-First features: - Code generation with \`@generate\` directives - Project scaffolding with declarative syntax - Parametrizable macros for reusable code patterns - AI optimization with \`@ai.optimize\` annotations `; fs.writeFileSync(path.join(projectDir, 'README.md'), readmeContent); console.log(colorText(`✓ Archivo README.md creado`, 'green')); console.log(colorText(`\n✓ Proyecto ${projectName} creado exitosamente.`, 'green')); console.log(colorText(`Para comenzar:`, 'yellow')); console.log(colorText(` cd ${projectName}`, 'cyan')); console.log(colorText(` neura run main.neura`, 'cyan')); } catch (error) { console.error(colorText(`Error al crear el proyecto: ${error.message}`, 'red')); } } // Simulación de funciones del gestor de paquetes function packageManager(command, packageName) { console.log(colorText(`Gestor de paquetes Neura (neurapkg)`, 'blue')); switch (command) { case 'add': case 'install': if (!packageName) { console.error(colorText('Error: Debes especificar un nombre de paquete.', 'red')); console.log(`Ejemplo: ${colorText('neura pkg add auth.jwt@^1.0.0', 'cyan')}`); return; } console.log(colorText(`Instalando paquete ${packageName}...`, 'yellow')); console.log(colorText(`✓ Paquete ${packageName} instalado correctamente`, 'green')); break; case 'remove': case 'uninstall': if (!packageName) { console.error(colorText('Error: Debes especificar un nombre de paquete.', 'red')); console.log(`Ejemplo: ${colorText('neura pkg remove auth.jwt', 'cyan')}`); return; } console.log(colorText(`Desinstalando paquete ${packageName}...`, 'yellow')); console.log(colorText(`✓ Paquete ${packageName} desinstalado correctamente`, 'green')); break; case 'list': case 'ls': console.log(colorText('Paquetes instalados:', 'yellow')); console.log('- core@0.1.0-alpha.1'); console.log('- ai-features@0.1.0-alpha.1'); break; case 'update': case 'upgrade': if (packageName) { console.log(colorText(`Actualizando paquete ${packageName}...`, 'yellow')); console.log(colorText(`✓ Paquete ${packageName} actualizado correctamente`, 'green')); } else { console.log(colorText('Actualizando todos los paquetes...', 'yellow')); console.log(colorText('✓ Todos los paquetes actualizados correctamente', 'green')); } break; default: console.log(colorText('Comandos disponibles:', 'yellow')); console.log('- add <paquete> Instalar un paquete'); console.log('- remove <paquete> Desinstalar un paquete'); console.log('- list Listar paquetes instalados'); console.log('- update [paquete] Actualizar paquetes'); } } // Simulación de generación de código con directivas @generate function generateDirective(type, entityName, options = {}) { console.log(colorText(`Generando código con directiva @generate`, 'blue')); switch (type) { case 'crud': console.log(colorText(`Generando CRUD para entidad ${entityName}...`, 'yellow')); console.log(colorText(`✓ Modelo ${entityName} generado`, 'green')); console.log(colorText(`✓ Repositorio ${entityName}Repository generado`, 'green')); console.log(colorText(`✓ Controlador ${entityName}Controller generado`, 'green')); console.log(colorText(`✓ Rutas para ${entityName} generadas`, 'green')); break; case 'api': console.log(colorText(`Generando API para ${entityName}...`, 'yellow')); console.log(colorText(`✓ API para ${entityName} generada`, 'green')); break; case 'scaffold': console.log(colorText(`Generando scaffold ${entityName}...`, 'yellow')); console.log(colorText(`✓ Estructura para ${entityName} generada`, 'green')); break; default: console.error(colorText(`Error: Tipo de generación "${type}" desconocido.`, 'red')); console.log('Tipos disponibles: crud, api, scaffold'); } } // Mostrar información sobre características AI-First function showAIFeatures() { console.log(colorText('\nNeura AI-First Features', 'blue') + colorText(' ✨', 'yellow')); console.log(colorText('======================\n', 'blue')); console.log('Neura incluye características AI-First que aceleran el desarrollo:'); console.log(`\n1. ${colorText('@ai.optimize', 'green')} - Optimización de código con IA`); console.log(` Ejemplo: ${colorText('@ai.optimize("reduce database calls")', 'yellow')} usecase GetOrders { ... }`); console.log(` Permite recibir sugerencias y optimizaciones de código utilizando múltiples modelos de IA.`); console.log(`\n2. ${colorText('@generate', 'green')} - Generación automática de código`); console.log(` Ejemplo: ${colorText('@generate crud for entity User { ... }', 'yellow')} using persistence.postgres`); console.log(` Genera automáticamente código a partir de especificaciones declarativas.`); console.log(`\n3. ${colorText('scaffold', 'green')} - Estructuras de proyecto declarativas`); console.log(` Ejemplo: ${colorText('scaffold api PaymentService { ... }', 'yellow')}`); console.log(` Crea estructuras completas de proyecto con una sintaxis concisa.`); console.log(`\n4. ${colorText('macro', 'green')} - Plantillas parametrizables`); console.log(` Ejemplo: ${colorText('macro RestEndpoint(path, method, usecase) { ... }', 'yellow')}`); console.log(` Define plantillas reutilizables para patrones comunes de código.`); console.log(`\n5. ${colorText('watch & reload', 'green')} - Recarga automática de módulos`); console.log(` Ejemplo: ${colorText('neura watch app.neura', 'yellow')}`); console.log(` Recarga automáticamente los módulos cuando se detectan cambios en los archivos.`); console.log(`\n6. ${colorText('neurapkg', 'green')} - Gestor de paquetes`); console.log(` Ejemplo: ${colorText('neura pkg add auth.jwt@^1.0.0', 'yellow')}`); console.log(` Gestiona dependencias y módulos en el ecosistema Neura.`); console.log(`\nPara usar todas las características avanzadas, instala los paquetes completos:`); console.log(colorText(`npm install -g neura-core@alpha neura-ai-features@alpha`, 'cyan')); console.log(`\nMás información: ${colorText('https://github.com/neura-lang/neura', 'blue')}`); } // Mostrar ayuda function showHelp() { console.log(colorText('\nUso: neura <comando> [opciones]', 'blue')); console.log('\nComandos disponibles:'); console.log(` ${colorText('run', 'yellow')} <archivo> Ejecuta un archivo Neura`); console.log(` ${colorText('compile', 'yellow')} <archivo> Compila un archivo Neura`); console.log(` ${colorText('watch', 'yellow')} <archivo> Observa cambios en un archivo y lo recarga automáticamente`); console.log(` ${colorText('new', 'yellow')} <nombre> Crea un nuevo proyecto Neura`); console.log(` ${colorText('pkg', 'yellow')} <comando> Gestiona paquetes Neura`); console.log(` ${colorText('generate', 'yellow')} <tipo> Genera código a partir de directivas`); console.log(` ${colorText('ai', 'yellow')} Muestra información sobre características AI-First`); console.log(` ${colorText('--version', 'yellow')} Muestra la versión de Neura`); console.log(` ${colorText('--help', 'yellow')} Muestra esta ayuda`); console.log('\nEjemplos:'); console.log(` ${colorText('neura run hello.neura', 'cyan')}`); console.log(` ${colorText('neura compile hello.neura --target javascript', 'cyan')}`); console.log(` ${colorText('neura new mi-proyecto', 'cyan')}`); console.log(` ${colorText('neura pkg add auth.jwt@^1.0.0', 'cyan')}`); console.log(` ${colorText('neura generate crud User', 'cyan')}`); } // Funciones relacionadas con macrros function macroSystem(command, macroName, ...args) { console.log(colorText(`Sistema de macros parametrizables`, 'blue')); switch (command) { case 'define': console.log(colorText(`Definiendo macro ${macroName}...`, 'yellow')); console.log(colorText(`✓ Macro ${macroName} definida correctamente`, 'green')); break; case 'expand': console.log(colorText(`Expandiendo macro ${macroName}...`, 'yellow')); console.log(colorText(`✓ Macro ${macroName} expandida correctamente`, 'green')); break; case 'list': console.log(colorText('Macros disponibles:', 'yellow')); console.log('- RestEndpoint(path, method, usecase)'); console.log('- Repository(entity)'); console.log('- Service(name, dependencies)'); break; default: console.log(colorText('Comandos disponibles:', 'yellow')); console.log('- define <nombre> <parámetros> <cuerpo> Define una nueva macro'); console.log('- expand <nombre> <argumentos> Expande una macro'); console.log('- list Lista macros disponibles'); } } // Procesar argumentos function processArgs() { const args = process.argv.slice(2); // Si no hay argumentos, mostrar ayuda if (args.length === 0) { showBanner(); showHelp(); return; } // Procesar comandos const command = args[0]; switch (command) { case 'run': if (args.length < 2) { console.error(colorText('Error: Debes especificar un archivo para ejecutar.', 'red')); console.log(`Ejemplo: ${colorText('neura run hello.neura', 'cyan')}`); return; } runNeura(args[1]); break; case 'compile': if (args.length < 2) { console.error(colorText('Error: Debes especificar un archivo para compilar.', 'red')); console.log(`Ejemplo: ${colorText('neura compile hello.neura', 'cyan')}`); return; } // Procesar opciones let targetLanguage = 'typescript'; let outputPath = null; for (let i = 2; i < args.length; i++) { if (args[i] === '--target' && args[i+1]) { targetLanguage = args[i+1]; i++; } else if (args[i] === '--output' && args[i+1]) { outputPath = args[i+1]; i++; } } compileNeura(args[1], targetLanguage, outputPath); break; case 'watch': if (args.length < 2) { console.error(colorText('Error: Debes especificar un archivo para observar.', 'red')); console.log(`Ejemplo: ${colorText('neura watch hello.neura', 'cyan')}`); return; } watchNeura(args[1]); break; case 'new': if (args.length < 2) { console.error(colorText('Error: Debes especificar un nombre para el proyecto.', 'red')); console.log(`Ejemplo: ${colorText('neura new mi-proyecto', 'cyan')}`); return; } // Procesar opciones let template = 'api'; for (let i = 2; i < args.length; i++) { if (args[i] === '--template' && args[i+1]) { template = args[i+1]; i++; } } createProject(args[1], template); break; case 'pkg': if (args.length < 2) { packageManager('help'); } else { packageManager(args[1], args[2]); } break; case 'generate': if (args.length < 3) { console.error(colorText('Error: Debes especificar el tipo de generación y la entidad.', 'red')); console.log(`Ejemplo: ${colorText('neura generate crud User', 'cyan')}`); return; } generateDirective(args[1], args[2]); break; case 'macro': if (args.length < 2) { macroSystem('help'); } else { macroSystem(args[1], args[2], ...args.slice(3)); } break; case 'ai': showBanner(); showAIFeatures(); break; case '--version': console.log(`Neura v${NEURA_VERSION}`); break; case '--help': showBanner(); showHelp(); break; default: console.error(colorText(`Error: Comando desconocido '${command}'.`, 'red')); showHelp(); } } // Ejecutar processArgs();