UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

538 lines (537 loc) • 23 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.manageWorkspaceDefinition = manageWorkspaceDefinition; const chalk_1 = __importDefault(require("chalk")); const prompts_1 = __importDefault(require("prompts")); const path = __importStar(require("path")); const fs = __importStar(require("fs-extra")); const workspace_schema_1 = require("../utils/workspace-schema"); const error_handler_1 = require("../utils/error-handler"); const DEFAULT_WORKSPACE_FILE = 're-shell.workspaces.yaml'; async function manageWorkspaceDefinition(options = {}) { const { spinner, verbose, json } = options; try { if (options.init) { await initializeWorkspaceDefinition(options, spinner); return; } if (options.validate) { await validateWorkspaceDefinition(options, spinner); return; } if (options.autoDetect) { await autoDetectWorkspaces(options, spinner); return; } if (options.structure) { await validateWorkspaceStructure(options, spinner); return; } if (options.fix) { await fixWorkspaceDefinition(options, spinner); return; } if (options.interactive) { await interactiveWorkspaceManagement(options, spinner); return; } // Default: show workspace definition status await showWorkspaceDefinitionStatus(options, spinner); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Workspace definition operation failed')); throw error; } } async function initializeWorkspaceDefinition(options, spinner) { const outputFile = options.output || options.file || DEFAULT_WORKSPACE_FILE; const outputPath = path.resolve(outputFile); if (spinner) spinner.setText(`Initializing workspace definition: ${outputFile}`); // Check if file already exists if (await fs.pathExists(outputPath) && !options.dryRun) { if (spinner) spinner.stop(); const response = await (0, prompts_1.default)([ { type: 'confirm', name: 'overwrite', message: `Workspace definition already exists at ${outputFile}. Overwrite?`, initial: false } ]); if (!response.overwrite) { console.log(chalk_1.default.yellow('Initialization cancelled.')); return; } } try { // Get project information let projectName = path.basename(process.cwd()); let description = ''; if (!options.dryRun) { if (spinner) spinner.stop(); const response = await (0, prompts_1.default)([ { type: 'text', name: 'name', message: 'Project name:', initial: projectName, validate: (value) => value.trim() ? true : 'Project name is required' }, { type: 'text', name: 'description', message: 'Project description (optional):', } ]); if (!response.name) return; projectName = response.name; description = response.description || ''; } // Create default workspace definition const definition = (0, workspace_schema_1.createDefaultWorkspaceDefinition)(projectName, { description: description || undefined }); if (options.dryRun) { if (spinner) spinner.stop(); console.log(chalk_1.default.cyan('\\nšŸ“‹ Workspace Definition Preview')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(JSON.stringify(definition, null, 2)); return; } // Save the definition await (0, workspace_schema_1.saveWorkspaceDefinition)(definition, outputPath); if (spinner) { spinner.succeed(chalk_1.default.green('Workspace definition initialized')); } console.log(chalk_1.default.green(`\\nāœ… Workspace definition created: ${outputFile}`)); console.log(chalk_1.default.cyan('\\nšŸ“ Next steps:')); console.log(` • Run: re-shell workspace-def auto-detect --merge`); console.log(` • Edit: ${outputFile}`); console.log(` • Validate: re-shell workspace-def validate`); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to initialize workspace definition')); throw error; } } async function validateWorkspaceDefinition(options, spinner) { const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); if (spinner) spinner.setText(`Validating workspace definition: ${inputFile}`); try { // Load and validate definition const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath); const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath)); const result = await validator.validateDefinition(); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } // Display results displayValidationResults(result, inputFile, options.strict || false, options.ignoreWarnings || false); if (!result.valid) { process.exit(1); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Validation failed')); if (error instanceof error_handler_1.ValidationError) { console.error(chalk_1.default.red(`āŒ ${error.message}`)); } else { console.error(chalk_1.default.red(`āŒ Unexpected error: ${error.message}`)); } process.exit(1); } } async function validateWorkspaceStructure(options, spinner) { const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); if (spinner) spinner.setText(`Validating workspace structure: ${inputFile}`); try { const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath); const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath)); const result = await validator.validateWorkspaceStructure(); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } console.log(chalk_1.default.cyan('\\nšŸ—ļø Workspace Structure Validation')); console.log(chalk_1.default.gray('═'.repeat(60))); displayValidationResults(result, inputFile, options.strict || false, options.ignoreWarnings || false); if (!result.valid) { process.exit(1); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Structure validation failed')); throw error; } } async function autoDetectWorkspaces(options, spinner) { const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); if (spinner) spinner.setText('Auto-detecting workspaces...'); try { let definition; // Load existing definition or create default if (await fs.pathExists(inputPath)) { definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath); } else { definition = (0, workspace_schema_1.createDefaultWorkspaceDefinition)(path.basename(process.cwd())); } const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath)); const detectedWorkspaces = await validator.autoDetectWorkspaces(); if (spinner) spinner.stop(); if (detectedWorkspaces.length === 0) { console.log(chalk_1.default.yellow('No workspaces detected based on current patterns and types.')); console.log(chalk_1.default.gray('Consider updating workspace patterns or adding workspaces manually.')); return; } console.log(chalk_1.default.cyan(`\\nšŸ” Auto-Detected Workspaces (${detectedWorkspaces.length})`)); console.log(chalk_1.default.gray('═'.repeat(50))); for (const workspace of detectedWorkspaces) { const typeIcon = getWorkspaceTypeIcon(workspace.type); console.log(`\\n${typeIcon} ${chalk_1.default.cyan(workspace.name)}`); console.log(` Path: ${workspace.path}`); console.log(` Type: ${workspace.type}`); if (workspace.description) { console.log(` Description: ${chalk_1.default.gray(workspace.description)}`); } if (workspace.tags && workspace.tags.length > 0) { console.log(` Tags: ${workspace.tags.map(tag => chalk_1.default.blue(tag)).join(', ')}`); } } if (options.dryRun) { console.log(chalk_1.default.gray('\\n(Dry run - no changes made)')); return; } // Merge with existing definition if requested if (options.merge) { const response = await (0, prompts_1.default)([ { type: 'confirm', name: 'merge', message: `Merge ${detectedWorkspaces.length} detected workspaces with existing definition?`, initial: true } ]); if (response.merge) { // Add detected workspaces to definition for (const workspace of detectedWorkspaces) { definition.workspaces[workspace.name] = workspace; } await (0, workspace_schema_1.saveWorkspaceDefinition)(definition, inputPath); console.log(chalk_1.default.green(`\\nāœ… Merged ${detectedWorkspaces.length} workspaces into ${inputFile}`)); } } else { // Save as new file or replace const outputFile = options.output || inputFile; const newDefinition = { ...definition, workspaces: Object.fromEntries(detectedWorkspaces.map(w => [w.name, w])) }; await (0, workspace_schema_1.saveWorkspaceDefinition)(newDefinition, outputFile); console.log(chalk_1.default.green(`\\nāœ… Saved detected workspaces to ${outputFile}`)); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Auto-detection failed')); throw error; } } async function fixWorkspaceDefinition(options, spinner) { const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); if (spinner) spinner.setText(`Analyzing workspace definition for fixes: ${inputFile}`); try { const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath); const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath)); const result = await validator.validateDefinition(); if (spinner) spinner.stop(); if (result.valid && result.suggestions.length === 0) { console.log(chalk_1.default.green('āœ… No fixes needed - workspace definition is valid')); return; } console.log(chalk_1.default.cyan('\\nšŸ”§ Available Fixes')); console.log(chalk_1.default.gray('═'.repeat(40))); let hasApplicableFixes = false; // Show suggestions that can be auto-fixed for (const suggestion of result.suggestions) { if (suggestion.fix) { hasApplicableFixes = true; console.log(`\\nšŸ’” ${suggestion.message}`); console.log(` Path: ${chalk_1.default.gray(suggestion.path)}`); console.log(` Fix: ${chalk_1.default.green(suggestion.fix)}`); } } if (!hasApplicableFixes) { console.log(chalk_1.default.yellow('No auto-fixable issues found.')); console.log(chalk_1.default.gray('Manual fixes may be required - see validation output.')); return; } if (options.dryRun) { console.log(chalk_1.default.gray('\\n(Dry run - no changes would be made)')); return; } const response = await (0, prompts_1.default)([ { type: 'confirm', name: 'apply', message: 'Apply suggested fixes?', initial: true } ]); if (response.apply) { // TODO: Implement actual fix application console.log(chalk_1.default.yellow('\\nāš ļø Auto-fix implementation coming in next update')); console.log(chalk_1.default.gray('For now, please apply fixes manually based on suggestions above.')); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Fix analysis failed')); throw error; } } async function showWorkspaceDefinitionStatus(options, spinner) { const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); if (spinner) spinner.setText('Checking workspace definition status...'); try { if (!(await fs.pathExists(inputPath))) { if (spinner) spinner.stop(); console.log(chalk_1.default.yellow('\\nāš ļø No workspace definition found')); console.log(chalk_1.default.gray(`Expected: ${inputFile}`)); console.log(chalk_1.default.cyan('\\nšŸš€ Quick start:')); console.log(' re-shell workspace-def init'); console.log(' re-shell workspace-def auto-detect --merge'); return; } const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath); const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath)); const [defResult, structResult] = await Promise.all([ validator.validateDefinition(), validator.validateWorkspaceStructure() ]); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify({ file: inputFile, definition: defResult, structure: structResult, workspaces: Object.keys(definition.workspaces).length }, null, 2)); return; } console.log(chalk_1.default.cyan('\\nšŸ“‹ Workspace Definition Status')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`\\nFile: ${chalk_1.default.cyan(inputFile)}`); console.log(`Version: ${definition.version}`); console.log(`Name: ${definition.name}`); if (definition.description) { console.log(`Description: ${chalk_1.default.gray(definition.description)}`); } console.log(`\\nWorkspaces: ${Object.keys(definition.workspaces).length}`); console.log(`Types: ${Object.keys(definition.types).length}`); console.log(`Patterns: ${definition.patterns.length}`); // Definition validation status const defIcon = defResult.valid ? 'āœ…' : 'āŒ'; const defStatus = defResult.valid ? chalk_1.default.green('Valid') : chalk_1.default.red('Invalid'); console.log(`\\nDefinition: ${defIcon} ${defStatus}`); if (defResult.errors.length > 0) { console.log(` Errors: ${chalk_1.default.red(defResult.errors.length)}`); } if (defResult.warnings.length > 0) { console.log(` Warnings: ${chalk_1.default.yellow(defResult.warnings.length)}`); } // Structure validation status const structIcon = structResult.valid ? 'āœ…' : 'āŒ'; const structStatus = structResult.valid ? chalk_1.default.green('Valid') : chalk_1.default.red('Invalid'); console.log(`Structure: ${structIcon} ${structStatus}`); if (structResult.errors.length > 0) { console.log(` Errors: ${chalk_1.default.red(structResult.errors.length)}`); } if (structResult.warnings.length > 0) { console.log(` Warnings: ${chalk_1.default.yellow(structResult.warnings.length)}`); } console.log(chalk_1.default.cyan('\\nšŸ› ļø Available Commands:')); console.log(' • re-shell workspace-def validate'); console.log(' • re-shell workspace-def structure'); console.log(' • re-shell workspace-def auto-detect'); console.log(' • re-shell workspace-def interactive'); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Status check failed')); throw error; } } async function interactiveWorkspaceManagement(options, spinner) { if (spinner) spinner.stop(); const inputFile = options.file || DEFAULT_WORKSPACE_FILE; const inputPath = path.resolve(inputFile); const exists = await fs.pathExists(inputPath); const response = await (0, prompts_1.default)([ { type: 'select', name: 'action', message: 'What would you like to do?', choices: [ ...(!exists ? [{ title: 'šŸ†• Initialize workspace definition', value: 'init' }] : []), ...(exists ? [ { title: 'āœ… Validate definition', value: 'validate' }, { title: 'šŸ—ļø Validate structure', value: 'structure' }, ] : []), { title: 'šŸ” Auto-detect workspaces', value: 'auto-detect' }, ...(exists ? [ { title: 'šŸ”§ Fix issues', value: 'fix' }, { title: 'šŸ“Š Show status', value: 'status' } ] : []) ] } ]); if (!response.action) return; switch (response.action) { case 'init': await initializeWorkspaceDefinition({ ...options, interactive: false }); break; case 'validate': await validateWorkspaceDefinition({ ...options, interactive: false }); break; case 'structure': await validateWorkspaceStructure({ ...options, interactive: false }); break; case 'auto-detect': await autoDetectWorkspaces({ ...options, interactive: false }); break; case 'fix': await fixWorkspaceDefinition({ ...options, interactive: false }); break; case 'status': await showWorkspaceDefinitionStatus({ ...options, interactive: false }); break; } } // Utility functions function displayValidationResults(result, fileName, strict, ignoreWarnings) { const hasIssues = result.errors.length > 0 || (!ignoreWarnings && result.warnings.length > 0); if (result.valid && !hasIssues) { console.log(chalk_1.default.green(`\\nāœ… ${fileName} is valid`)); if (result.suggestions.length > 0) { console.log(chalk_1.default.cyan(`\\nšŸ’” Suggestions (${result.suggestions.length}):`)); for (const suggestion of result.suggestions) { console.log(` • ${suggestion.message}`); if (suggestion.fix) { console.log(` ${chalk_1.default.green(suggestion.fix)}`); } } } return; } // Show errors if (result.errors.length > 0) { console.log(chalk_1.default.red(`\\nāŒ Errors (${result.errors.length}):`)); for (const error of result.errors) { console.log(` • ${error.message}`); } } // Show warnings if (result.warnings.length > 0 && !ignoreWarnings) { console.log(chalk_1.default.yellow(`\\nāš ļø Warnings (${result.warnings.length}):`)); for (const warning of result.warnings) { const severityIcon = warning.severity === 'high' ? 'šŸ”“' : warning.severity === 'medium' ? '🟔' : 'šŸ”µ'; console.log(` ${severityIcon} ${warning.message}`); if (warning.path) { console.log(` Path: ${chalk_1.default.gray(warning.path)}`); } } } // Show suggestions if (result.suggestions.length > 0) { console.log(chalk_1.default.cyan(`\\nšŸ’” Suggestions (${result.suggestions.length}):`)); for (const suggestion of result.suggestions) { console.log(` • ${suggestion.message}`); if (suggestion.fix) { console.log(` ${chalk_1.default.green(suggestion.fix)}`); } } } if (strict && result.warnings.length > 0) { console.log(chalk_1.default.red('\\nāŒ Validation failed (strict mode enabled)')); } } function getWorkspaceTypeIcon(type) { const icons = { app: 'šŸ“±', package: 'šŸ“¦', lib: 'šŸ“š', tool: 'šŸ”§', service: 'āš™ļø', website: '🌐' }; return icons[type] || 'šŸ“„'; }