Skip to main content
Glama
universalDiagramOptimizer.ts17.7 kB
/** * Universal Diagram Optimizer for Enhanced Code Map Generator * * Replaces verbose mermaid diagrams with concise text summaries that work across * all programming languages and tech stacks. Achieves maximum token reduction * while preserving essential architectural information. */ import { GraphNode, GraphEdge } from '../graphBuilder.js'; import { UniversalOptimizationConfig } from '../types.js'; import { FileInfo, ImportInfo } from '../codeMapModel.js'; /** * Represents dependency analysis results. */ export interface DependencyAnalysis { totalNodes: number; coreComponents: CoreComponent[]; externalDependencies: string[]; internalModules: string[]; complexityScore: number; architecturalPattern: string; } /** * Represents a core component in the architecture. */ export interface CoreComponent { name: string; role: string; importance: number; connections: number; } /** * Universal diagram optimizer that works across all programming languages. */ export class UniversalDiagramOptimizer { /** * Optimizes import lists by cleaning up unresolved imports and reducing redundancy. * Enhanced with smart consolidation and pattern recognition. */ optimizeImports(imports: ImportInfo[]): ImportInfo[] { if (!imports || imports.length === 0) { return imports; } const optimizedImports: ImportInfo[] = []; const resolved = imports.filter(imp => !this.isUnresolvedImport(imp)); const unresolved = imports.filter(imp => this.isUnresolvedImport(imp)); // Group and consolidate imports const consolidatedSummary = this.consolidateImports(resolved, unresolved); // Add consolidated summary as a single import entry if (consolidatedSummary) { optimizedImports.push({ path: consolidatedSummary, type: 'summary', comment: 'Consolidated import summary', isExternalPackage: false }); } // Only keep the most important resolved imports (top 3) const importantResolved = resolved .filter(imp => this.isImportantImport(imp)) .slice(0, 3); optimizedImports.push(...importantResolved); return optimizedImports; } /** * Consolidates imports into a smart summary with pattern recognition. */ private consolidateImports(resolved: ImportInfo[], unresolved: ImportInfo[]): string { const parts: string[] = []; // Count resolved imports if (resolved.length > 0) { parts.push(`${resolved.length} internal modules`); } // Analyze unresolved imports for patterns if (unresolved.length > 0) { const patterns = this.analyzeUnresolvedPatterns(unresolved); if (patterns.standardLibs > 0) { parts.push(`${patterns.standardLibs} standard libraries`); } if (patterns.frameworks > 0) { parts.push(`${patterns.frameworks} framework dependencies`); } if (patterns.utilities > 0) { parts.push(`${patterns.utilities} utility packages`); } const otherUnresolved = unresolved.length - patterns.standardLibs - patterns.frameworks - patterns.utilities; if (otherUnresolved > 0) { parts.push(`${otherUnresolved} external dependencies`); } } return parts.length > 0 ? parts.join(', ') : ''; } /** * Analyzes unresolved import patterns to categorize them. */ private analyzeUnresolvedPatterns(unresolved: ImportInfo[]): { standardLibs: number; frameworks: number; utilities: number; } { const standardLibPatterns = ['fs', 'path', 'crypto', 'util', 'os', 'http', 'https', 'url', 'events', 'stream']; const frameworkPatterns = ['react', 'vue', 'angular', 'express', 'fastify', 'next', 'nuxt', 'django', 'flask', 'spring']; const utilityPatterns = ['lodash', 'moment', 'axios', 'fetch', 'uuid', 'chalk', 'debug', 'winston']; let standardLibs = 0; let frameworks = 0; let utilities = 0; unresolved.forEach(imp => { const path = imp.path.toLowerCase(); if (standardLibPatterns.some(pattern => path.includes(pattern))) { standardLibs++; } else if (frameworkPatterns.some(pattern => path.includes(pattern))) { frameworks++; } else if (utilityPatterns.some(pattern => path.includes(pattern))) { utilities++; } }); return { standardLibs, frameworks, utilities }; } /** * Determines if an import is important enough to keep in detailed view. */ private isImportantImport(imp: ImportInfo): boolean { const path = imp.path.toLowerCase(); // Keep imports that are likely core to the application const importantPatterns = [ 'config', 'service', 'manager', 'controller', 'handler', 'model', 'schema', 'types', 'interface', 'api' ]; return importantPatterns.some(pattern => path.includes(pattern)) || Boolean(imp.importedItems && imp.importedItems.length > 3); // Many imported items suggests importance } /** * Checks if an import is unresolved (generic "module import" placeholder). */ private isUnresolvedImport(imp: ImportInfo): boolean { return imp.path === 'unknown' || imp.path === 'module import' || imp.path.startsWith('module import') || (imp.path === 'unknown' && (!imp.importedItems || imp.importedItems.length === 0)); } /** * Counts the number of unresolved imports. */ private countUnresolvedImports(imports: ImportInfo[]): number { return imports.filter(imp => this.isUnresolvedImport(imp)).length; } /** * Creates a summary entry for unresolved imports. */ private createUnresolvedImportSummary(count: number): ImportInfo { return { path: `${count} unresolved imports`, type: 'summary', comment: 'These imports could not be resolved to specific module names', isExternalPackage: false }; } /** * Optimizes a FileInfo object by cleaning up its imports. */ optimizeFileInfo(fileInfo: FileInfo): FileInfo { return { ...fileInfo, imports: this.optimizeImports(fileInfo.imports) }; } /** * Optimizes an array of FileInfo objects by cleaning up their imports. */ optimizeFileInfos(fileInfos: FileInfo[]): FileInfo[] { return fileInfos.map(fileInfo => this.optimizeFileInfo(fileInfo)); } /** * Optimizes dependency diagrams based on complexity and configuration. */ optimizeDependencyDiagram( nodes: GraphNode[], edges: GraphEdge[], config: UniversalOptimizationConfig ): string { // Analyze codebase to determine optimization strategy const analysis = this.analyzeDependencyComplexity(nodes, edges); // Maximum aggressive: Always use text summary for maximum token reduction if (config.eliminateVerboseDiagrams || analysis.totalNodes > 20) { return this.generateArchitectureSummary(analysis); } else if (analysis.totalNodes > 10) { return this.generateSimplifiedDiagram(nodes, edges); } else { return this.generateCompactDiagram(nodes, edges); } } /** * Analyzes dependency complexity for optimization decisions. */ private analyzeDependencyComplexity(nodes: GraphNode[], edges: GraphEdge[]): DependencyAnalysis { const coreComponents = this.identifyCoreComponents(nodes, edges); const externalDeps = this.identifyExternalDependencies(nodes); const internalModules = this.identifyInternalModules(nodes); return { totalNodes: nodes.length, coreComponents, externalDependencies: externalDeps, internalModules, complexityScore: this.calculateComplexityScore(nodes, edges), architecturalPattern: this.detectArchitecturePattern(nodes, edges) }; } /** * Generates concise architecture summary (maximum token reduction). */ private generateArchitectureSummary(analysis: DependencyAnalysis): string { const coreComponents = analysis.coreComponents.slice(0, 6); // Top 6 components const externalDeps = analysis.externalDependencies.slice(0, 8); // Top 8 dependencies return `## Architecture Overview **Core Components** (${coreComponents.length}/${analysis.coreComponents.length}): ${coreComponents.map(comp => `- **${comp.name}**: ${comp.role}`).join('\n')} **External Dependencies** (${externalDeps.length}/${analysis.externalDependencies.length}): ${externalDeps.join(', ')} **Architecture Pattern**: ${analysis.architecturalPattern} **Module Organization**: ${analysis.internalModules.length} internal modules `; } /** * Identifies core components based on importance and connections. */ private identifyCoreComponents(nodes: GraphNode[], edges: GraphEdge[]): CoreComponent[] { return nodes .map(node => ({ name: this.extractComponentName(node.id), importance: this.calculateComponentImportance(node, edges), role: this.inferComponentRole(node), connections: this.countConnections(node.id, edges) })) .filter(comp => comp.importance >= 6.0) // Higher threshold for maximum optimization .sort((a, b) => b.importance - a.importance); } /** * Extracts component name (universal across languages). */ private extractComponentName(filePath: string): string { const segments = filePath.split('/').filter(Boolean); const fileName = segments[segments.length - 1]; // Remove common file extensions universally return fileName.replace(/\.(ts|js|py|java|go|rs|php|rb|cpp|cs|kt|swift|dart|scala)$/, ''); } /** * Infers component role based on universal patterns. */ private inferComponentRole(node: GraphNode): string { const path = node.id.toLowerCase(); // Universal role inference based on path patterns if (path.includes('service') || path.includes('api')) return 'Service'; if (path.includes('model') || path.includes('entity')) return 'Data'; if (path.includes('controller') || path.includes('handler')) return 'Handler'; if (path.includes('util') || path.includes('helper')) return 'Utility'; if (path.includes('config') || path.includes('setting')) return 'Config'; if (path.includes('test') || path.includes('spec')) return 'Test'; if (path.includes('component') || path.includes('widget')) return 'UI'; if (path.includes('middleware') || path.includes('interceptor')) return 'Middleware'; // Infer from file name patterns const fileName = this.extractComponentName(node.id).toLowerCase(); if (fileName.includes('manager') || fileName.includes('coordinator')) return 'Manager'; if (fileName.includes('factory') || fileName.includes('builder')) return 'Factory'; if (fileName.includes('adapter') || fileName.includes('wrapper')) return 'Adapter'; return 'Component'; } /** * Calculates component importance score. */ private calculateComponentImportance(node: GraphNode, edges: GraphEdge[]): number { let score = 5.0; // Count incoming and outgoing connections const incomingCount = edges.filter(e => e.to === node.id).length; const outgoingCount = edges.filter(e => e.from === node.id).length; // Boost for high connectivity (hub components) score += Math.min(incomingCount * 0.5, 3.0); score += Math.min(outgoingCount * 0.3, 2.0); // Boost for core architectural components const role = this.inferComponentRole(node); if (['Service', 'Manager', 'Handler'].includes(role)) score += 2.0; if (['Data', 'Config'].includes(role)) score += 1.0; // Boost for main/index files const fileName = this.extractComponentName(node.id).toLowerCase(); if (['index', 'main', 'app', 'server'].includes(fileName)) score += 2.0; return Math.min(score, 10.0); } /** * Counts total connections for a node. */ private countConnections(nodeId: string, edges: GraphEdge[]): number { return edges.filter(e => e.from === nodeId || e.to === nodeId).length; } /** * Identifies external dependencies (universal detection). */ private identifyExternalDependencies(nodes: GraphNode[]): string[] { return nodes .filter(node => this.isExternalDependency(node.id)) .map(node => this.extractDependencyName(node.id)) .filter((dep, index, arr) => arr.indexOf(dep) === index) // Remove duplicates .sort(); } /** * Checks if a node represents an external dependency. */ private isExternalDependency(nodeId: string): boolean { // Universal patterns for external dependencies return nodeId.includes('node_modules') || nodeId.includes('site-packages') || nodeId.includes('vendor') || nodeId.includes('lib') || nodeId.startsWith('@') || !nodeId.includes('/') && !nodeId.includes('\\'); // Simple module names } /** * Extracts dependency name from path. */ private extractDependencyName(nodeId: string): string { if (nodeId.includes('node_modules')) { const parts = nodeId.split('node_modules/')[1]?.split('/'); return parts?.[0]?.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts?.[0] || nodeId; } if (nodeId.includes('site-packages')) { const parts = nodeId.split('site-packages/')[1]?.split('/'); return parts?.[0] || nodeId; } return nodeId; } /** * Identifies internal modules. */ private identifyInternalModules(nodes: GraphNode[]): string[] { return nodes .filter(node => !this.isExternalDependency(node.id)) .map(node => this.extractModulePath(node.id)) .filter((module, index, arr) => arr.indexOf(module) === index) .sort(); } /** * Extracts module path from file path. */ private extractModulePath(filePath: string): string { const segments = filePath.split('/').filter(Boolean); return segments.length > 1 ? segments[0] : filePath; } /** * Calculates overall complexity score. */ private calculateComplexityScore(nodes: GraphNode[], edges: GraphEdge[]): number { const nodeCount = nodes.length; const edgeCount = edges.length; const density = nodeCount > 0 ? edgeCount / nodeCount : 0; return Math.min(nodeCount * 0.1 + density * 2, 10.0); } /** * Detects architectural pattern from dependency structure. */ detectArchitecturePattern(nodes: GraphNode[], edges: GraphEdge[]): string { const analysis = this.analyzeArchitecturalPatterns(nodes, edges); if (analysis.hasLayeredStructure) return 'Layered Architecture'; if (analysis.hasMicroservicePattern) return 'Microservices'; if (analysis.hasMVCPattern) return 'MVC Pattern'; if (analysis.hasModularStructure) return 'Modular Architecture'; if (analysis.hasComponentStructure) return 'Component-Based'; return 'Custom Architecture'; } /** * Analyzes architectural patterns in the codebase. */ private analyzeArchitecturalPatterns(nodes: GraphNode[], _edges: GraphEdge[]): { hasLayeredStructure: boolean; hasMicroservicePattern: boolean; hasMVCPattern: boolean; hasModularStructure: boolean; hasComponentStructure: boolean } { const paths = nodes.map(n => n.id.toLowerCase()); return { hasLayeredStructure: this.detectLayeredStructure(paths), hasMicroservicePattern: this.detectMicroservicePattern(paths), hasMVCPattern: this.detectMVCPattern(paths), hasModularStructure: this.detectModularStructure(paths), hasComponentStructure: this.detectComponentStructure(paths) }; } /** * Detects layered architecture pattern. */ private detectLayeredStructure(paths: string[]): boolean { const layers = ['controller', 'service', 'repository', 'model', 'dao']; const foundLayers = layers.filter(layer => paths.some(path => path.includes(layer)) ); return foundLayers.length >= 3; } /** * Detects microservice pattern. */ private detectMicroservicePattern(paths: string[]): boolean { const serviceIndicators = ['service', 'api', 'gateway', 'proxy']; return serviceIndicators.filter(indicator => paths.some(path => path.includes(indicator)) ).length >= 2; } /** * Detects MVC pattern. */ private detectMVCPattern(paths: string[]): boolean { const mvcComponents = ['controller', 'model', 'view']; return mvcComponents.every(component => paths.some(path => path.includes(component)) ); } /** * Detects modular structure. */ private detectModularStructure(paths: string[]): boolean { const modules = new Set(paths.map(path => path.split('/')[0])); return modules.size >= 3; } /** * Detects component-based structure. */ private detectComponentStructure(paths: string[]): boolean { const componentIndicators = ['component', 'widget', 'element']; return componentIndicators.some(indicator => paths.some(path => path.includes(indicator)) ); } /** * Generates simplified diagram for medium complexity. */ private generateSimplifiedDiagram(nodes: GraphNode[], edges: GraphEdge[]): string { const coreNodes = nodes.slice(0, 15); // Limit to 15 nodes const coreEdges = edges.filter(e => coreNodes.some(n => n.id === e.from) && coreNodes.some(n => n.id === e.to) ); return `## Simplified Architecture **Components**: ${coreNodes.map(n => this.extractComponentName(n.id)).join(', ')} **Connections**: ${coreEdges.length} dependencies `; } /** * Generates compact diagram for small complexity. */ private generateCompactDiagram(nodes: GraphNode[], edges: GraphEdge[]): string { return `## Architecture Diagram **Components** (${nodes.length}): ${nodes.map(n => this.extractComponentName(n.id)).join(', ')} **Dependencies**: ${edges.length} connections `; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freshtechbro/vibe-coder-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server