UNPKG

@diagramers/cli

Version:

Diagramers CLI - Command-line tools for managing Diagramers projects

347 lines • 18 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DeployCommand = void 0; const commander_1 = require("commander"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const yaml = __importStar(require("js-yaml")); class DeployCommand { constructor() { this.program = new commander_1.Command('deploy'); this.setupCommands(); } setupCommands() { this.program .description('Manage deployment configuration and module communication'); // Generate config command this.program .command('generate-config') .description('Generate deployment configuration file') .option('-o, --output <path>', 'Output path for config file', './diagramers.yml') .option('-s, --scan', 'Scan for available modules and auto-configure them') .option('-p, --port <port>', 'Default port for local modules', '3000') .option('--host <host>', 'Default host for local modules', 'localhost') .action(async (options) => { await this.generateConfig(options); }); // Show status command this.program .command('status') .description('Show deployment status from config file') .action(async () => { await this.showStatus(); }); // Add external module command this.program .command('add-external') .description('Add external module configuration') .requiredOption('-m, --module <name>', 'Module name') .requiredOption('-h, --host <host>', 'Module host') .requiredOption('-p, --port <port>', 'Module port') .option('--protocol <protocol>', 'Protocol (http/https)', 'http') .option('--auth-type <type>', 'Authentication type (api_key/bearer/basic)') .option('--auth-header <header>', 'Authentication header') .option('--auth-value <value>', 'Authentication value') .option('--auth-token <token>', 'Authentication token') .action(async (options) => { await this.addExternalModule(options); }); // Scan modules command this.program .command('scan-modules') .description('Scan project for available modules and show configuration') .option('-p, --port <port>', 'Default port for local modules', '3000') .option('--host <host>', 'Default host for local modules', 'localhost') .action(async (options) => { await this.scanModules(options); }); } async showStatus() { try { const configPath = path.join(process.cwd(), 'diagramers.yml'); if (!fs.existsSync(configPath)) { console.log('āŒ No diagramers.yml configuration file found'); console.log('šŸ’” Run: diagramers deploy generate-config to create one'); return; } const configContent = fs.readFileSync(configPath, 'utf8'); const config = yaml.load(configContent); console.log('\nšŸ“Š Deployment Configuration Status\n'); // Show local modules if (config.modules && Object.keys(config.modules).length > 0) { console.log('šŸ  Local Modules:'); console.log('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'); console.log('│ Module │ Server │ Deploy │ Port │'); console.log('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'); for (const [name, moduleConfig] of Object.entries(config.modules)) { const serverConfig = config.servers[moduleConfig.server]; console.log(`│ ${name.padEnd(11)} │ ${moduleConfig.server.padEnd(12)} │ ${moduleConfig.deploy.padEnd(7)} │ ${serverConfig.port.toString().padEnd(10)} │`); } console.log('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n'); } // Show external modules if (config.external_modules && Object.keys(config.external_modules).length > 0) { console.log('🌐 External Modules:'); console.log('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'); console.log('│ Module │ URL │ Auth Type │'); console.log('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'); for (const [name, externalConfig] of Object.entries(config.external_modules)) { const url = `${externalConfig.protocol || 'http'}://${externalConfig.host}:${externalConfig.port}`; const authType = externalConfig.auth?.type || 'None'; console.log(`│ ${name.padEnd(11)} │ ${url.padEnd(27)} │ ${authType.padEnd(11)} │`); } console.log('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n'); } console.log('šŸ“ Configuration file: diagramers.yml'); console.log('šŸ”§ Use diagramers deploy add-external to add external modules\n'); } catch (error) { console.error('āŒ Error showing status:', error.message); } } async addExternalModule(options) { try { const configPath = path.join(process.cwd(), 'diagramers.yml'); if (!fs.existsSync(configPath)) { console.log('āŒ No diagramers.yml configuration file found'); console.log('šŸ’” Run: diagramers deploy generate-config to create one first'); return; } const configContent = fs.readFileSync(configPath, 'utf8'); const config = yaml.load(configContent); if (!config.external_modules) { config.external_modules = {}; } const externalConfig = { server: options.module + '-server', host: options.host, port: parseInt(options.port), protocol: options.protocol, health_check: `${options.protocol}://${options.host}:${options.port}/health`, timeout: 10000 }; // Add authentication if provided if (options.authType) { externalConfig.auth = { type: options.authType, header: options.authHeader, value: options.authValue, token: options.authToken }; } config.external_modules[options.module] = externalConfig; // Save updated config const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120, noRefs: true }); fs.writeFileSync(configPath, yamlContent, 'utf8'); console.log(`āœ… External module '${options.module}' added successfully!`); console.log(`🌐 URL: ${options.protocol}://${options.host}:${options.port}`); console.log(`šŸ“ Configuration saved to diagramers.yml`); } catch (error) { console.error('āŒ Error adding external module:', error.message); } } async generateConfig(options) { try { let config; if (options.scan) { console.log('šŸ” Scanning for available modules...'); const scannedModules = await this.scanProjectModules(options.host || 'localhost', parseInt(options.port) || 3000); config = { servers: { 'main-server': { host: options.host || 'localhost', port: parseInt(options.port) || 3000, environment: 'development', protocol: 'http' } }, modules: scannedModules, external_modules: {} }; console.log(`āœ… Found ${Object.keys(scannedModules).length} modules`); } else { config = { servers: { 'main-server': { host: options.host || 'localhost', port: parseInt(options.port) || 3000, environment: 'development', protocol: 'http' } }, modules: {}, external_modules: {} }; } const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120, noRefs: true }); fs.writeFileSync(options.output, yamlContent, 'utf8'); console.log(`āœ… Configuration file generated: ${options.output}`); if (options.scan) { console.log('šŸ“ Auto-configured local modules based on project structure'); console.log('šŸ”§ Edit the file to customize module settings or add external modules'); } else { console.log('šŸ“ Edit the file to configure your modules and external services'); console.log('šŸ’” Use --scan flag to auto-detect and configure local modules'); } } catch (error) { console.error('āŒ Error generating config:', error.message); } } async scanModules(options) { try { console.log('šŸ” Scanning project for available modules...\n'); const modules = await this.scanProjectModules(options.host || 'localhost', parseInt(options.port) || 3000); if (Object.keys(modules).length === 0) { console.log('āŒ No modules found in the project'); console.log('šŸ’” Make sure you have modules in src/modules/ directory'); return; } console.log('šŸ“¦ Available Modules:\n'); console.log('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'); console.log('│ Module │ Server │ Deploy │ Port │'); console.log('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'); for (const [name, moduleConfig] of Object.entries(modules)) { console.log(`│ ${name.padEnd(11)} │ ${moduleConfig.server.padEnd(12)} │ ${moduleConfig.deploy.padEnd(7)} │ ${(options.port || 3000).toString().padEnd(10)} │`); } console.log('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n'); console.log('šŸ’” To generate configuration with these modules:'); console.log(` diagramers deploy generate-config --scan --port ${options.port || 3000}`); } catch (error) { console.error('āŒ Error scanning modules:', error.message); } } async scanProjectModules(host, port) { const modules = {}; const modulesPath = path.join(process.cwd(), 'src', 'modules'); if (!fs.existsSync(modulesPath)) { return modules; } const moduleDirs = fs.readdirSync(modulesPath, { withFileTypes: true }) .filter(dirent => dirent.isDirectory()) .map(dirent => dirent.name); for (const moduleName of moduleDirs) { const modulePath = path.join(modulesPath, moduleName); // Check if it's a valid module by looking for key files const hasService = fs.existsSync(path.join(modulePath, 'services', `${moduleName}.service.ts`)); const hasController = fs.existsSync(path.join(modulePath, 'controllers', `${moduleName}.controller.ts`)); const hasRoutes = fs.existsSync(path.join(modulePath, 'routes', `${moduleName}.routes.ts`)); // Also check for any service file (in case naming is different) const serviceFiles = fs.existsSync(path.join(modulePath, 'services')) ? fs.readdirSync(path.join(modulePath, 'services')).filter(f => f.endsWith('.service.ts')) : []; // Also check for any controller file const controllerFiles = fs.existsSync(path.join(modulePath, 'controllers')) ? fs.readdirSync(path.join(modulePath, 'controllers')).filter(f => f.endsWith('.controller.ts')) : []; // Also check for any routes file const routesFiles = fs.existsSync(path.join(modulePath, 'routes')) ? fs.readdirSync(path.join(modulePath, 'routes')).filter(f => f.endsWith('.routes.ts')) : []; if (hasService || hasController || hasRoutes || serviceFiles.length > 0 || controllerFiles.length > 0 || routesFiles.length > 0) { // Determine dependencies by scanning imports const dependencies = await this.scanModuleDependencies(moduleName, modulePath); modules[moduleName] = { deploy: 'shared', server: 'main-server', dependencies: dependencies, communication: { type: 'local', timeout: 5000 } }; } } return modules; } async scanModuleDependencies(moduleName, modulePath) { const dependencies = []; // Check service files for imports const servicePath = path.join(modulePath, 'services', `${moduleName}.service.ts`); if (fs.existsSync(servicePath)) { const serviceContent = fs.readFileSync(servicePath, 'utf8'); const moduleImports = this.extractModuleImports(serviceContent); dependencies.push(...moduleImports); } // Check controller files for imports const controllerPath = path.join(modulePath, 'controllers', `${moduleName}.controller.ts`); if (fs.existsSync(controllerPath)) { const controllerContent = fs.readFileSync(controllerPath, 'utf8'); const moduleImports = this.extractModuleImports(controllerContent); dependencies.push(...moduleImports); } // Remove duplicates and self-references return [...new Set(dependencies)].filter(dep => dep !== moduleName); } extractModuleImports(content) { const imports = []; // Look for import statements that reference other modules const importRegex = /import.*from.*['"](\.\.\/)*modules\/([^\/'"]+)/g; let match; while ((match = importRegex.exec(content)) !== null) { const moduleName = match[2]; if (moduleName && !imports.includes(moduleName)) { imports.push(moduleName); } } // Also look for service calls that might indicate dependencies const serviceCallRegex = /this\.(\w+)Service/g; while ((match = serviceCallRegex.exec(content)) !== null) { const serviceName = match[1]; if (serviceName && !imports.includes(serviceName)) { imports.push(serviceName); } } return imports; } getCommand() { return this.program; } } exports.DeployCommand = DeployCommand; //# sourceMappingURL=deploy.js.map