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

365 lines (364 loc) 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandRegistry = void 0; const events_1 = require("events"); const error_handler_1 = require("../utils/error-handler"); class CommandRegistry extends events_1.EventEmitter { constructor(logger, analytics, config, plugins) { super(); this.logger = logger; this.analytics = analytics; this.config = config; this.plugins = plugins; this.commands = new Map(); this.aliases = new Map(); this.categories = new Map(); this.middleware = []; this.commandHistory = []; } /** * Register a new command */ async register(definition) { this.emit('command:registering', definition); // Validate command definition this.validateCommand(definition); // Check for conflicts if (this.commands.has(definition.name)) { const existing = this.commands.get(definition.name); if (existing.priority !== undefined && definition.priority !== undefined) { if (definition.priority > existing.priority) { this.logger.debug(`Overriding command ${definition.name} due to higher priority`); } else { throw new error_handler_1.ValidationError(`Command ${definition.name} already registered with higher priority`); } } else if (!definition.plugin) { throw new error_handler_1.ValidationError(`Command ${definition.name} already registered`); } } // Register command this.commands.set(definition.name, definition); // Register aliases if (definition.alias) { for (const alias of definition.alias) { if (this.aliases.has(alias)) { throw new error_handler_1.ValidationError(`Alias ${alias} already registered for command ${this.aliases.get(alias)}`); } this.aliases.set(alias, definition.name); } } // Add to category if (definition.category) { if (!this.categories.has(definition.category)) { this.categories.set(definition.category, []); } this.categories.get(definition.category).push(definition); } this.emit('command:registered', definition); this.logger.debug(`Registered command: ${definition.name}`); } /** * Unregister a command */ async unregister(name) { const command = this.commands.get(name); if (!command) { throw new error_handler_1.ValidationError(`Command ${name} not found`); } this.emit('command:unregistering', command); // Remove from commands this.commands.delete(name); // Remove aliases if (command.alias) { for (const alias of command.alias) { this.aliases.delete(alias); } } // Remove from category if (command.category) { const categoryCommands = this.categories.get(command.category); if (categoryCommands) { const index = categoryCommands.indexOf(command); if (index !== -1) { categoryCommands.splice(index, 1); } } } this.emit('command:unregistered', command); this.logger.debug(`Unregistered command: ${name}`); } /** * Get a command by name or alias */ get(nameOrAlias) { const name = this.aliases.get(nameOrAlias) || nameOrAlias; return this.commands.get(name); } /** * Get all commands */ getAll() { return Array.from(this.commands.values()); } /** * Get commands by category */ getByCategory(category) { return this.categories.get(category) || []; } /** * Get all categories */ getCategories() { return Array.from(this.categories.keys()); } /** * Add global middleware */ addMiddleware(middleware) { this.middleware.push(middleware); } /** * Create commander command from definition */ createCommand(program, definition) { const cmd = program .command(definition.name) .description(definition.description); // Add aliases if (definition.alias && definition.alias.length > 0) { for (const alias of definition.alias) { cmd.alias(alias); } } // Add arguments if (definition.arguments) { for (const arg of definition.arguments) { const argString = arg.variadic ? `<${arg.name}...>` : arg.required ? `<${arg.name}>` : `[${arg.name}]`; cmd.argument(argString, arg.description, arg.defaultValue); } } // Add options if (definition.options) { for (const opt of definition.options) { cmd.option(opt.flag, opt.description, opt.defaultValue); // Add choices validation if (opt.choices) { cmd.addHelpText('after', `\n Choices for ${opt.flag}: ${opt.choices.join(', ')}`); } } } // Add examples to help if (definition.examples) { const examplesText = definition.examples .map(ex => ` ${ex.description}\n $ ${ex.command}`) .join('\n\n'); cmd.addHelpText('after', `\nExamples:\n${examplesText}`); } // Set action handler with middleware cmd.action(async (...args) => { const context = this.createContext(definition, cmd, args); await this.executeCommand(context); }); return cmd; } /** * Execute command with middleware */ async executeCommand(context) { const execution = { command: context.command.name, args: context.args, options: context.options, startTime: Date.now(), status: 'running' }; this.commandHistory.push(execution); this.emit('command:executing', context); try { // Run pre middleware await this.runMiddleware(context, 'pre'); // Execute command handler await context.command.handler(context); // Run post middleware await this.runMiddleware(context, 'post'); execution.status = 'success'; execution.endTime = Date.now(); this.emit('command:executed', context); } catch (error) { execution.status = 'error'; execution.endTime = Date.now(); execution.error = error; this.emit('command:error', { context, error }); throw error; } finally { // Track analytics this.analytics.track('command_executed', { command: context.command.name, duration: execution.endTime - execution.startTime, status: execution.status, plugin: context.command.plugin?.name }); } } /** * Run middleware for a phase */ async runMiddleware(context, phase) { // Global middleware const globalMiddleware = this.middleware.filter(m => m.phase === phase); // Command-specific middleware const commandMiddleware = (context.command.middleware || []) .filter(m => m.phase === phase); // Combine and execute const allMiddleware = [...globalMiddleware, ...commandMiddleware]; for (const middleware of allMiddleware) { this.logger.debug(`Running ${phase} middleware: ${middleware.name}`); await middleware.handler(context); } } /** * Create command context */ createContext(definition, cmd, args) { // Parse arguments const parsedArgs = {}; if (definition.arguments) { definition.arguments.forEach((arg, index) => { if (arg.variadic) { parsedArgs[arg.name] = args.slice(index, args.length - 1); } else { parsedArgs[arg.name] = args[index]; } }); } // Get options const options = cmd.opts(); // Create spinner const spinner = this.createSpinner(); return { command: definition, args: parsedArgs, options, program: cmd, logger: this.logger, spinner, analytics: this.analytics, config: this.config, plugins: this.plugins }; } /** * Create spinner instance */ createSpinner() { let ora; let instance; return { start(message) { if (!ora) { ora = require('ora'); } instance = ora(message).start(); }, succeed(message) { if (instance) { instance.succeed(message); instance = null; } }, fail(message) { if (instance) { instance.fail(message); instance = null; } }, info(message) { if (instance) { instance.info(message); instance = null; } }, warn(message) { if (instance) { instance.warn(message); instance = null; } }, stop() { if (instance) { instance.stop(); instance = null; } }, get isSpinning() { return instance?.isSpinning || false; } }; } /** * Validate command definition */ validateCommand(definition) { if (!definition.name) { throw new error_handler_1.ValidationError('Command name is required'); } if (!definition.description) { throw new error_handler_1.ValidationError('Command description is required'); } if (!definition.handler) { throw new error_handler_1.ValidationError('Command handler is required'); } // Validate arguments if (definition.arguments) { let variadicFound = false; for (const arg of definition.arguments) { if (variadicFound) { throw new error_handler_1.ValidationError('Variadic argument must be last'); } if (arg.variadic) { variadicFound = true; } } } // Validate options if (definition.options) { for (const opt of definition.options) { if (!opt.flag || !opt.description) { throw new error_handler_1.ValidationError('Option flag and description are required'); } } } } /** * Get command history */ getHistory() { return [...this.commandHistory]; } /** * Clear command history */ clearHistory() { this.commandHistory = []; } /** * Search commands */ search(query) { const lowerQuery = query.toLowerCase(); return this.getAll().filter(cmd => cmd.name.toLowerCase().includes(lowerQuery) || cmd.description.toLowerCase().includes(lowerQuery) || cmd.keywords?.some((k) => k.toLowerCase().includes(lowerQuery))); } } exports.CommandRegistry = CommandRegistry;