@diagramers/cli
Version:
Diagramers CLI - Command-line tools for managing Diagramers projects
347 lines ⢠18 kB
JavaScript
;
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