@darksnow-ui/commander
Version:
Command pattern implementation with React hooks for building command palettes and keyboard-driven UIs
338 lines (269 loc) • 9.4 kB
Markdown
# Commander Algorithm - Arquitetura e Funcionamento
## 📋 Visão Geral
O **Commander** é o motor central do sistema - uma classe que implementa o padrão Command com funcionalidades enterprise. É responsável por gerenciar, executar e organizar comandos de forma eficiente e escalável.
## 🏗️ Arquitetura Core
### Estruturas de Dados Principais
```typescript
class Commander {
private commands = new Map<CommandKey, Command>() // O(1) lookup por chave
private executionHistory: ExecutionContext[] = [] // Buffer circular
private recentCommands = new Map<CommandKey, Command>() // LRU cache
private listeners = new Map<string, EventListener[]>() // Pub/Sub system
public maxHistorySize = 100 // Limite do histórico
public maxRecentSize = 10 // Limite de comandos recentes
}
```
**Decisões de Design:**
- **Map para comandos**: Lookup O(1) vs Array O(n)
- **Buffer circular para histórico**: Memória limitada, performance consistente
- **LRU para recentes**: Acesso rápido aos comandos mais usados
- **Map para eventos**: Múltiplos listeners por evento
## ⚙️ Algoritmos de Execução
### 1. Command Execution Pipeline
```
invoke(key, input, source) →
├── 1. Command Lookup (O(1))
├── 2. Availability Check (O(1) ou Promise)
├── 3. Event: "command:executing"
├── 4. Handler Execution (com timeout)
├── 5. History Tracking
├── 6. Recent Commands Update
└── 7. Event: "command:completed" | "command:failed"
```
**Características:**
- **Timeout Protection**: Execução limitada por tempo
- **Error Handling**: Try/catch com wrapping em CommandExecutionError
- **Event Tracking**: Full lifecycle observability
- **Source Tracking**: "api", "palette", "shortcut"
### 2. Search Algorithm
```typescript
async search(query: string, options?: SearchOptions): Promise<SearchResult[]>
```
**Algoritmo de Scoring Hierárquico:**
```
Para cada comando:
├── 1. Filtros (categoria, owner, tags)
├── 2. Availability Check (se includeUnavailable = false)
├── 3. Score Calculation:
│ ├── Label exact match: 100 pontos
│ ├── Label partial match: 80 pontos
│ ├── Description match: 60 pontos
│ ├── Tags match: 40 pontos
│ ├── SearchKeywords match: 50 pontos
│ └── Fuzzy matching: 1-30 pontos
├── 4. Sort by score (desc)
└── 5. Limit results
```
**Complexidade:** O(n × m) onde n = comandos, m = termos de busca
### 3. History Management
**Buffer Circular Implementation:**
```typescript
private addToHistory(context: ExecutionContext) {
this.executionHistory.unshift(context)
if (this.executionHistory.length > this.maxHistorySize) {
this.executionHistory = this.executionHistory.slice(0, this.maxHistorySize)
}
}
```
**Recent Commands (LRU):**
```typescript
private updateRecentCommands(command: Command) {
// Remove se já existe (move para frente)
this.recentCommands.delete(command.key)
// Adiciona no início
this.recentCommands.set(command.key, command)
// Mantém tamanho máximo
if (this.recentCommands.size > this.maxRecentSize) {
const firstKey = this.recentCommands.keys().next().value
this.recentCommands.delete(firstKey)
}
}
```
## 🎯 Sistema de Eventos (Pub/Sub)
### Event Lifecycle
```
Command Execution:
├── command:executing → { command, input, source, startTime }
├── command:completed → { command, input, result, duration }
└── command:failed → { command, input, error, duration }
Command Management:
├── command:added → { command }
└── command:removed → { command }
```
### Event System Implementation
```typescript
listen(event: string, callback: Function, options?: { once?: boolean }) {
const listener = { callback, once: options?.once || false }
if (!this.listeners.has(event)) {
this.listeners.set(event, [])
}
this.listeners.get(event)!.push(listener)
return listener // Para remoção posterior
}
private emit(event: string, ...args: any[]) {
const listeners = this.listeners.get(event) || []
listeners.forEach(listener => {
try {
listener.callback(...args)
} catch (error) {
console.error(`Event listener error for "${event}":`, error)
}
})
// Remove listeners "once"
this.listeners.set(event, listeners.filter(l => !l.once))
}
```
## 🔍 Command Lookup e Filtering
### 1. Basic Lookup
```typescript
has(key: CommandKey): boolean {
return this.commands.has(key) // O(1)
}
getCommand(key: CommandKey): Command | undefined {
return this.commands.get(key) // O(1)
}
```
### 2. Filtered Queries
```typescript
getAvailableCommands(options?: FilterOptions): Promise<Command[]> {
return Promise.all(
Array.from(this.commands.values())
.filter(cmd => matchesFilters(cmd, options))
.map(async cmd => ({
command: cmd,
available: await this.isCommandAvailable(cmd)
}))
).then(results =>
results
.filter(r => r.available)
.map(r => r.command)
)
}
```
### 3. Category Organization
```typescript
getCommandsByCategory(): Map<CommandCategory, Command[]> {
const categories = new Map<CommandCategory, Command[]>()
for (const command of this.commands.values()) {
const category = command.category || 'custom'
if (!categories.has(category)) {
categories.set(category, [])
}
categories.get(category)!.push(command)
}
return categories
}
```
## ⚡ Performance Optimizations
### 1. Lazy Evaluation
- **Availability checks**: Só executados quando necessário
- **Event emission**: Só dispara se há listeners
- **History**: Só mantém registros necessários
### 2. Memory Management
- **History circular**: Evita vazamentos de memória
- **Recent commands LRU**: Tamanho limitado
- **Event cleanup**: Remove listeners "once" automaticamente
### 3. Search Optimizations
- **Early filtering**: Aplica filtros antes do scoring
- **Limit results**: Para busca prematura
- **Cache availability**: Para comandos que não mudam
## 🛡️ Error Handling
### Error Types
```typescript
// Comando não encontrado
class CommandNotFoundError extends Error
// Comando indisponível (when() = false)
class CommandUnavailableError extends Error
// Timeout na execução
class CommandTimeoutError extends Error
// Erro durante execução
class CommandExecutionError extends Error {
constructor(message: string, public cause?: Error)
}
```
### Execution Safety
```typescript
async attempt<T>(key: CommandKey, input?: any): Promise<ExecutionResult<T>> {
try {
const result = await this.invoke<T>(key, input)
return { success: true, result, error: null }
} catch (error) {
return {
success: false,
result: null,
error: error instanceof Error ? error : new Error(String(error))
}
}
}
```
## 📊 Statistics e Monitoring
### Stats Collection
```typescript
getStats() {
return {
totalCommands: this.commands.size,
categories: new Set(Array.from(this.commands.values()).map(c => c.category || 'custom')).size,
executionHistory: this.executionHistory.length,
recentCommands: this.recentCommands.size,
listeners: Array.from(this.listeners.values()).reduce((sum, arr) => sum + arr.length, 0)
}
}
```
## 🎛️ Command Invoker Pattern
### Invoker Creation
```typescript
createInvoker<TInput, TOutput>(key: CommandKey): CommandInvoker<TInput, TOutput> {
return {
exists: () => this.has(key),
isAvailable: () => this.isCommandAvailable(this.getCommand(key)!),
getCommand: () => this.getCommand(key),
invoke: (input?: TInput) => this.invoke<TOutput>(key, input),
attempt: (input?: TInput) => this.attempt<TOutput>(key, input)
}
}
```
## 🏆 Características Enterprise
### 1. Scalability
- **Suporta 500+ comandos** sem degradação
- **O(1) lookups** para operações críticas
- **Memory bounded** com histórico circular
### 2. Observability
- **Comprehensive events** para monitoring
- **Execution tracking** com timing
- **Error reporting** estruturado
### 3. Reliability
- **Timeout protection** contra comandos travados
- **Error isolation** entre comandos
- **Graceful degradation** com availability checks
### 4. Maintainability
- **Clear separation** entre storage e logic
- **Consistent API** para todas as operações
- **Extensive testing** coverage
## 🚀 Algoritmo de Inicialização
```typescript
constructor() {
// 1. Initialize data structures
this.commands = new Map()
this.executionHistory = []
this.recentCommands = new Map()
this.listeners = new Map()
// 2. Set default configuration
this.maxHistorySize = 100
this.maxRecentSize = 10
// 3. Ready to accept commands
}
```
## 📈 Complexity Analysis
| Operation | Time Complexity | Space Complexity |
|-----------|----------------|------------------|
| `add(command)` | O(1) | O(1) |
| `remove(key)` | O(1) | O(1) |
| `has(key)` | O(1) | O(1) |
| `invoke(key)` | O(1) + handler | O(1) |
| `search(query)` | O(n × m) | O(n) |
| `getAvailableCommands()` | O(n) | O(n) |
| `getCommandsByCategory()` | O(n) | O(n) |
**Onde:**
- n = número de comandos
- m = número de termos na busca
O Commander foi projetado para ser **eficiente, confiável e escalável**, implementando as melhores práticas de algoritmos e estruturas de dados para sistemas enterprise.