Skip to main content
Glama
relationship_mapping.py40.8 kB
""" Relationship Mapping Module Advanced relationship analysis for understanding code architecture, dependencies, and structural patterns across codebases. """ import ast import re from collections import defaultdict from dataclasses import dataclass, field from enum import Enum from functools import lru_cache from typing import Any, Dict, List, Optional, Set # Handle optional dependencies gracefully try: import networkx as nx NETWORKX_AVAILABLE = True except ImportError: NETWORKX_AVAILABLE = False nx = None class RelationshipType(Enum): """Types of relationships between code components.""" INHERITS_FROM = "inherits_from" IMPLEMENTS = "implements" DEPENDS_ON = "depends_on" CALLS = "calls" IMPORTS = "imports" INSTANTIATES = "instantiates" REFERENCES = "references" CONTAINS = "contains" OVERRIDES = "overrides" EXTENDS = "extends" COMPOSES = "composes" AGGREGATES = "aggregates" ASSOCIATES = "associates" class DependencyType(Enum): """Types of dependencies between modules.""" DIRECT = "direct" INDIRECT = "indirect" CYCLICAL = "cyclical" TRANSITIVE = "transitive" WEAK = "weak" STRONG = "strong" class CouplingType(Enum): """Types of coupling between modules.""" CONTENT = "content" # One module depends on internal implementation of another COMMON = "common" # Modules share global data EXTERNAL = "external" # Module depends on interface of another CONTROL = "control" # One module controls flow of another STAMP = "stamp" # Modules share data structure DATA = "data" # Modules communicate via parameters TEMPORAL = "temporal" # Timing dependencies @dataclass class CodeComponent: """Represents a code component (class, function, module, etc.).""" name: str type: str # "class", "function", "module", "variable" file_path: str line_number: int language: str metadata: Dict[str, Any] = field(default_factory=dict) @dataclass class Relationship: """Represents a relationship between two code components.""" source: CodeComponent target: CodeComponent relationship_type: RelationshipType strength: float # 0.0 to 1.0 metadata: Dict[str, Any] = field(default_factory=dict) @dataclass class Dependency: """Represents a dependency between modules.""" source_module: str target_module: str dependency_type: DependencyType path: List[str] = field(default_factory=list) # For indirect dependencies strength: float = 1.0 @dataclass class CouplingAnalysis: """Analysis of coupling between modules.""" source_module: str target_module: str coupling_types: List[CouplingType] coupling_score: float # 0.0 to 1.0, higher = more coupled shared_elements: List[str] impact_score: float # Impact of changes on dependent modules @dataclass class CohesionAnalysis: """Analysis of cohesion within a module.""" module_name: str cohesion_score: float # 0.0 to 1.0, higher = more cohesive responsibility_count: int related_elements: List[str] cohesion_type: str # "functional", "sequential", "communicational", "procedural" @dataclass class CircularDependency: """Represents a circular dependency between modules.""" cycle_path: List[str] dependency_types: List[DependencyType] impact_score: float resolution_suggestions: List[str] @dataclass class RelationshipMap: """Complete relationship map of a codebase.""" components: Dict[str, CodeComponent] = field(default_factory=dict) relationships: List[Relationship] = field(default_factory=list) dependencies: List[Dependency] = field(default_factory=list) coupling_analysis: List[CouplingAnalysis] = field(default_factory=list) cohesion_analysis: List[CohesionAnalysis] = field(default_factory=list) circular_dependencies: List[CircularDependency] = field(default_factory=list) graph: Any = field(default_factory=lambda: None if not NETWORKX_AVAILABLE else nx.DiGraph()) @dataclass class DependencyAnalysis: """Analysis of dependencies between modules.""" direct_dependencies: List[Dependency] indirect_dependencies: List[Dependency] circular_dependencies: List[CircularDependency] transitive_dependencies: List[Dependency] dependency_score: float # Overall dependency complexity score dependencies: List[Dependency] = field(default_factory=list) dependency_matrix: Dict[str, Dict[str, float]] = field(default_factory=dict) critical_paths: List[List[str]] = field(default_factory=list) @dataclass class ControlFlowNode: """Represents a node in control flow graph.""" id: str type: str # "entry", "exit", "condition", "loop", "statement", "function_call" label: str line_number: int condition: Optional[str] = None @dataclass class ControlFlowEdge: """Represents an edge in control flow graph.""" source: str target: str type: str # "true_branch", "false_branch", "unconditional", "exception" condition: Optional[str] = None @dataclass class ControlFlowGraph: """Represents control flow graph of code.""" nodes: List[ControlFlowNode] = field(default_factory=list) edges: List[ControlFlowEdge] = field(default_factory=list) paths: List[List[str]] = field(default_factory=list) cyclomatic_complexity: int = 1 entry_points: List[str] = field(default_factory=list) exit_points: List[str] = field(default_factory=list) def add_node(self, node_id: str, **kwargs): """Add a node to the CFG.""" self.nodes.append(ControlFlowNode( id=node_id, type=kwargs.get('type', 'statement'), label=kwargs.get('label', node_id), line_number=kwargs.get('line_number', 0), condition=kwargs.get('condition') )) @dataclass class DataFlowNode: """Represents a variable or data element.""" name: str type: str scope: str definitions: List[int] = field(default_factory=list) # Line numbers where defined uses: List[int] = field(default_factory=list) # Line numbers where used mutations: List[int] = field(default_factory=list) # Line numbers where modified @dataclass class DataFlowEdge: """Represents data flow dependency.""" source: str # Variable name target: str # Variable name type: str # "definition", "use", "kill" line_number: int @dataclass class DataFlowGraph: """Represents data flow graph of code.""" variables: List[DataFlowNode] = field(default_factory=list) data_dependencies: List[DataFlowEdge] = field(default_factory=list) flow_paths: List[List[str]] = field(default_factory=list) critical_variables: List[str] = field(default_factory=list) data_flow_complexity: float = 0.0 def add_variable(self, variable: str): """Add a variable to the DFG.""" self.variables.append(DataFlowNode( name=variable, type='unknown', scope='global' )) self.critical_variables.append(variable) @dataclass class ArchitecturalPatterns: """Analysis of architectural patterns detected.""" patterns: List[str] = field(default_factory=list) confidence_scores: Dict[str, float] = field(default_factory=dict) pattern_locations: Dict[str, List[str]] = field(default_factory=dict) architectural_style: str = "" layering_violations: List[str] = field(default_factory=list) pattern_consistency: float = 0.0 detected_patterns: List[str] = field(default_factory=list) anti_patterns: List[str] = field(default_factory=list) insights: List[str] = field(default_factory=list) class CodeStructure: """Represents the structure of analyzed code.""" def __init__(self, root_path: str): self.root_path = root_path self.files: Dict[str, str] = {} self.modules: Dict[str, List[CodeComponent]] = defaultdict(list) self.imports: Dict[str, Set[str]] = defaultdict(set) class RelationshipMapper: """Main class for mapping code relationships and architecture.""" def __init__(self) -> None: self.component_cache: Dict[str, CodeComponent] = {} self.relationship_cache: Dict[str, List[Relationship]] = defaultdict(list) def understand_relationships(self, code: str, context: str = "", project_path: Optional[str] = None) -> RelationshipMap: """ Analyze and map relationships in code. Args: code: Source code to analyze context: Analysis context or file path project_path: Root path of the project Returns: Complete relationship map """ # Parse code structure code_structure = self._parse_code_structure(code, context, project_path) # Extract components components = self._extract_components(code_structure) # Build relationship graph relationship_map = self._build_relationship_graph(components, code_structure) # Analyze dependencies dependencies = self._analyze_dependencies(relationship_map, code_structure) # Analyze coupling and cohesion coupling_analysis = self._analyze_coupling(relationship_map, dependencies) cohesion_analysis = self._analyze_cohesion(relationship_map, components) # Detect circular dependencies circular_dependencies = self._detect_circular_dependencies(dependencies) # Build final relationship map final_map = RelationshipMap( components={c.name: c for c in components}, relationships=relationship_map.relationships, dependencies=dependencies, coupling_analysis=coupling_analysis, cohesion_analysis=cohesion_analysis, circular_dependencies=circular_dependencies, graph=relationship_map.graph ) return final_map def analyze_dependencies(self, code_structure: CodeStructure) -> DependencyAnalysis: """ Analyze dependencies between modules. Args: code_structure: Parsed code structure Returns: Complete dependency analysis """ dependencies = [] # Direct dependencies from imports for module, imports in code_structure.imports.items(): for imported_module in imports: dependency = Dependency( source_module=module, target_module=imported_module, dependency_type=DependencyType.DIRECT ) dependencies.append(dependency) # Find indirect dependencies indirect_deps = self._find_indirect_dependencies(dependencies) dependencies.extend(indirect_deps) # Find transitive dependencies transitive_deps = self._find_transitive_dependencies(dependencies) dependencies.extend(transitive_deps) return DependencyAnalysis( direct_dependencies=dependencies, indirect_dependencies=indirect_deps, circular_dependencies=[], transitive_dependencies=transitive_deps, dependency_score=0.0, dependencies=dependencies, dependency_matrix=self._build_dependency_matrix(dependencies), critical_paths=self._identify_critical_paths(dependencies) ) def map_control_flow(self, code: str, language: str = "python") -> ControlFlowGraph: """ Map control flow within code. Args: code: Source code language: Programming language Returns: Control flow graph """ cfg = ControlFlowGraph() if language == "python": try: tree = ast.parse(code) self._build_cfg_from_ast(tree, cfg) except Exception: # Fallback to simple control flow analysis self._build_simple_cfg(code, cfg) return cfg def analyze_data_flow(self, code: str, language: str = "python") -> DataFlowGraph: """ Analyze data flow within code. Args: code: Source code language: Programming language Returns: Data flow graph """ dfg = DataFlowGraph() if language == "python": try: tree = ast.parse(code) self._build_dfg_from_ast(tree, dfg) except Exception: # Fallback to simple data flow analysis self._build_simple_dfg(code, dfg) return dfg def detect_architectural_patterns(self, relationship_map: RelationshipMap) -> ArchitecturalPatterns: """ Detect architectural patterns from relationship analysis. Args: relationship_map: Complete relationship map Returns: Detected architectural patterns """ patterns = ArchitecturalPatterns() # Layered architecture detection if self._detect_layered_architecture(relationship_map): patterns.detected_patterns.append("layered") # MVC architecture detection if self._detect_mvc_architecture(relationship_map): patterns.detected_patterns.append("mvc") # Microservices detection if self._detect_microservices_architecture(relationship_map): patterns.detected_patterns.append("microservices") # Repository pattern detection if self._detect_repository_pattern(relationship_map): patterns.detected_patterns.append("repository") # Anti-patterns detection anti_patterns = self._detect_anti_patterns(relationship_map) patterns.anti_patterns.extend(anti_patterns) # Architectural insights patterns.insights = self._generate_architectural_insights(relationship_map) return patterns # Private helper methods @lru_cache(maxsize=256) def _parse_code_structure(self, code: str, context: str, project_path: Optional[str]) -> CodeStructure: """Parse code and extract structural information.""" structure = CodeStructure(project_path or "") # Store code if context: structure.files[context] = code # Extract imports if context: structure.imports[context] = self._extract_imports(code) # Extract components by parsing try: tree = ast.parse(code) module_name = self._get_module_name(context) for node in ast.walk(tree): if isinstance(node, ast.ClassDef): component = CodeComponent( name=node.name, type="class", file_path=context, line_number=node.lineno, language="python", metadata={"bases": [base.id if isinstance(base, ast.Name) else str(base) for base in node.bases]} ) structure.modules[module_name].append(component) elif isinstance(node, ast.FunctionDef): component = CodeComponent( name=node.name, type="function", file_path=context, line_number=node.lineno, language="python", metadata={"args": [arg.arg for arg in node.args.args]} ) structure.modules[module_name].append(component) except Exception: pass return structure def _extract_components(self, code_structure: CodeStructure) -> List[CodeComponent]: """Extract all code components from structure.""" components = [] for module, module_components in code_structure.modules.items(): components.extend(module_components) return components def _build_relationship_graph(self, components: List[CodeComponent], code_structure: CodeStructure) -> RelationshipMap: """Build graph of relationships between components.""" relationship_map = RelationshipMap() relationship_map.components = {c.name: c for c in components} # Build networkx graph graph = nx.DiGraph() for component in components: graph.add_node(component.name, component=component) relationships: List[Relationship] = [] # Analyze inheritance relationships inheritance_rels = self._analyze_inheritance_relationships(components) relationships.extend(inheritance_rels) # Analyze call relationships call_rels = self._analyze_call_relationships(components, code_structure) relationships.extend(call_rels) # Analyze import relationships import_rels = self._analyze_import_relationships(components, code_structure) relationships.extend(import_rels) # Add relationships to graph for rel in relationships: graph.add_edge(rel.source.name, rel.target.name, relationship_type=rel.relationship_type.value, strength=rel.strength) relationship_map.relationships = relationships relationship_map.graph = graph return relationship_map def _analyze_inheritance_relationships(self, components: List[CodeComponent]) -> List[Relationship]: """Analyze inheritance relationships between components.""" relationships: List[Relationship] = [] for component in components: if component.type == "class": bases = component.metadata.get("bases", []) for base in bases: # Find base component base_component = next((c for c in components if c.name == base), None) if base_component: relationship = Relationship( source=component, target=base_component, relationship_type=RelationshipType.INHERITS_FROM, strength=0.9 ) relationships.append(relationship) return relationships def _analyze_call_relationships(self, components: List[CodeComponent], code_structure: CodeStructure) -> List[Relationship]: """Analyze function/method call relationships.""" relationships: List[Relationship] = [] for component in components: if component.type == "function": # This would require more sophisticated analysis of function bodies # For now, we'll create placeholder relationships pass return relationships def _analyze_import_relationships(self, components: List[CodeComponent], code_structure: CodeStructure) -> List[Relationship]: """Analyze import-based relationships.""" relationships: List[Relationship] = [] for module, imports in code_structure.imports.items(): for imported_module in imports: # Find components in each module source_components = [c for c in components if module in c.file_path] target_components = [c for c in components if imported_module in c.file_path] for source in source_components: for target in target_components: relationship = Relationship( source=source, target=target, relationship_type=RelationshipType.IMPORTS, strength=0.7 ) relationships.append(relationship) return relationships def _analyze_dependencies(self, relationship_map: RelationshipMap, code_structure: CodeStructure) -> List[Dependency]: """Analyze dependencies between modules.""" dependencies = [] # Extract modules from relationship map modules = set() for component in relationship_map.components.values(): module = self._get_module_name(component.file_path) if module: modules.add(module) # Build dependency matrix for relationship in relationship_map.relationships: if relationship.relationship_type in [RelationshipType.IMPORTS, RelationshipType.DEPENDS_ON]: source_module = self._get_module_name(relationship.source.file_path) target_module = self._get_module_name(relationship.target.file_path) if source_module and target_module and source_module != target_module: dependency = Dependency( source_module=source_module, target_module=target_module, dependency_type=DependencyType.DIRECT, strength=relationship.strength ) dependencies.append(dependency) return dependencies def _analyze_coupling(self, relationship_map: RelationshipMap, dependencies: List[Dependency]) -> List[CouplingAnalysis]: """Analyze coupling between modules.""" coupling_analysis = [] # Group dependencies by module pair module_pairs = defaultdict(list) for dep in dependencies: key = (dep.source_module, dep.target_module) module_pairs[key].append(dep) # Analyze coupling for each pair for (source, target), deps in module_pairs.items(): coupling_types = self._determine_coupling_types(deps) coupling_score = self._calculate_coupling_score(deps) shared_elements = self._find_shared_elements(relationship_map, source, target) impact_score = self._calculate_impact_score(deps) analysis = CouplingAnalysis( source_module=source, target_module=target, coupling_types=coupling_types, coupling_score=coupling_score, shared_elements=shared_elements, impact_score=impact_score ) coupling_analysis.append(analysis) return coupling_analysis def _analyze_cohesion(self, relationship_map: RelationshipMap, components: List[CodeComponent]) -> List[CohesionAnalysis]: """Analyze cohesion within modules.""" cohesion_analysis = [] # Group components by module module_components = defaultdict(list) for component in components: module = self._get_module_name(component.file_path) if module: module_components[module].append(component) # Analyze cohesion for each module for module, module_comps in module_components.items(): cohesion_score = self._calculate_cohesion_score(module_comps, relationship_map) responsibility_count = len(module_comps) related_elements = self._find_related_elements(module_comps, relationship_map) cohesion_type = self._determine_cohesion_type(module_comps, relationship_map) analysis = CohesionAnalysis( module_name=module, cohesion_score=cohesion_score, responsibility_count=responsibility_count, related_elements=related_elements, cohesion_type=cohesion_type ) cohesion_analysis.append(analysis) return cohesion_analysis def _detect_circular_dependencies(self, dependencies: List[Dependency]) -> List[CircularDependency]: """Detect circular dependencies between modules.""" circular_deps = [] # Build dependency graph graph = nx.DiGraph() for dep in dependencies: graph.add_edge(dep.source_module, dep.target_module) # Find cycles try: cycles = list(nx.simple_cycles(graph)) except Exception: cycles = [] for cycle in cycles: impact_score = self._calculate_cycle_impact(cycle, dependencies) resolution_suggestions = self._generate_cycle_resolution_suggestions(cycle) circular_dep = CircularDependency( cycle_path=cycle, dependency_types=[DependencyType.CYCLICAL], impact_score=impact_score, resolution_suggestions=resolution_suggestions ) circular_deps.append(circular_dep) return circular_deps def _find_indirect_dependencies(self, dependencies: List[Dependency]) -> List[Dependency]: """Find indirect dependencies through transitive analysis.""" indirect_deps = [] # Build graph for path analysis graph = nx.DiGraph() for dep in dependencies: graph.add_edge(dep.source_module, dep.target_module) # Find all pairs shortest paths try: all_pairs = dict(nx.all_pairs_shortest_path(graph)) except Exception: all_pairs = {} for source in all_pairs: for target in all_pairs[source]: if source != target and len(all_pairs[source][target]) > 2: # This is an indirect dependency path = all_pairs[source][target] indirect_dep = Dependency( source_module=source, target_module=target, dependency_type=DependencyType.INDIRECT, path=path, strength=0.5 # Weaker than direct ) indirect_deps.append(indirect_dep) return indirect_deps def _find_transitive_dependencies(self, dependencies: List[Dependency]) -> List[Dependency]: """Find transitive dependencies.""" transitive_deps = [] # Build dependency graph graph = nx.DiGraph() for dep in dependencies: graph.add_edge(dep.source_module, dep.target_module) # Find transitive closure transitive_closure = nx.transitive_closure(graph) # Add transitive dependencies not in original graph for edge in transitive_closure.edges(): if not graph.has_edge(edge[0], edge[1]): transitive_dep = Dependency( source_module=edge[0], target_module=edge[1], dependency_type=DependencyType.TRANSITIVE, strength=0.3 # Weakest dependency type ) transitive_deps.append(transitive_dep) return transitive_deps def _determine_coupling_types(self, dependencies: List[Dependency]) -> List[CouplingType]: """Determine types of coupling between modules.""" coupling_types = [] # Based on dependency types and patterns for dep in dependencies: if dep.dependency_type == DependencyType.DIRECT: coupling_types.append(CouplingType.EXTERNAL) elif dep.dependency_type == DependencyType.CYCLICAL: coupling_types.append(CouplingType.COMMON) return list(set(coupling_types)) def _calculate_coupling_score(self, dependencies: List[Dependency]) -> float: """Calculate coupling score between modules.""" if not dependencies: return 0.0 # Base score on number and strength of dependencies total_strength = sum(dep.strength for dep in dependencies) normalized_score = min(total_strength / 2.0, 1.0) # Normalize to 0-1 return normalized_score def _find_shared_elements(self, relationship_map: RelationshipMap, source_module: str, target_module: str) -> List[str]: """Find shared elements between modules.""" shared_elements = [] # Find components in each module source_components = [c for c in relationship_map.components.values() if self._get_module_name(c.file_path) == source_module] target_components = [c for c in relationship_map.components.values() if self._get_module_name(c.file_path) == target_module] # Find shared relationships for rel in relationship_map.relationships: if (rel.source in source_components and rel.target in target_components) or \ (rel.source in target_components and rel.target in source_components): shared_elements.append(f"{rel.source.name} -> {rel.target.name}") return shared_elements def _calculate_impact_score(self, dependencies: List[Dependency]) -> float: """Calculate impact score of dependencies.""" if not dependencies: return 0.0 # Higher impact for stronger dependencies total_strength = sum(dep.strength for dep in dependencies) return min(total_strength, 1.0) def _calculate_cohesion_score(self, module_components: List[CodeComponent], relationship_map: RelationshipMap) -> float: """Calculate cohesion score for a module.""" if len(module_components) <= 1: return 1.0 # Count internal relationships internal_relationships = 0 total_relationships = 0 for rel in relationship_map.relationships: if rel.source in module_components: total_relationships += 1 if rel.target in module_components: internal_relationships += 1 # Cohesion = internal relationships / total relationships if total_relationships == 0: return 0.5 # Neutral score return internal_relationships / total_relationships def _find_related_elements(self, module_components: List[CodeComponent], relationship_map: RelationshipMap) -> List[str]: """Find related elements within a module.""" related_elements = [] for component in module_components: # Find relationships to other components in the same module for rel in relationship_map.relationships: if rel.source == component and rel.target in module_components: related_elements.append(f"{component.name} -> {rel.target.name}") return related_elements def _determine_cohesion_type(self, module_components: List[CodeComponent], relationship_map: RelationshipMap) -> str: """Determine the type of cohesion.""" # Simplified cohesion type detection function_count = sum(1 for c in module_components if c.type == "function") class_count = sum(1 for c in module_components if c.type == "class") if function_count > class_count: return "functional" elif class_count > 0: return "sequential" else: return "procedural" def _calculate_cycle_impact(self, cycle: List[str], dependencies: List[Dependency]) -> float: """Calculate impact score of a circular dependency.""" # Longer cycles generally have higher impact base_impact = len(cycle) * 0.2 # Consider dependency strengths cycle_deps = [d for d in dependencies if d.source_module in cycle and d.target_module in cycle] strength_impact = sum(d.strength for d in cycle_deps) * 0.1 return min(base_impact + strength_impact, 1.0) def _generate_cycle_resolution_suggestions(self, cycle: List[str]) -> List[str]: """Generate suggestions for resolving circular dependencies.""" suggestions = [] if len(cycle) == 2: suggestions.append("Extract shared interface to break direct dependency") elif len(cycle) == 3: suggestions.append("Apply dependency inversion principle") else: suggestions.append("Consider refactoring into separate layers") suggestions.append("Use dependency injection to reduce coupling") suggestions.append("Introduce abstraction layer between circular dependencies") return suggestions def _detect_layered_architecture(self, relationship_map: RelationshipMap) -> bool: """Detect if the codebase follows layered architecture.""" # Simplified detection based on import patterns layers = self._identify_layers(relationship_map) return len(layers) >= 3 def _detect_mvc_architecture(self, relationship_map: RelationshipMap) -> bool: """Detect if the codebase follows MVC architecture.""" # Look for model, view, controller patterns has_models = any("model" in c.name.lower() for c in relationship_map.components.values()) has_views = any("view" in c.name.lower() for c in relationship_map.components.values()) has_controllers = any("controller" in c.name.lower() or "handler" in c.name.lower() for c in relationship_map.components.values()) return has_models and has_views and has_controllers def _detect_microservices_architecture(self, relationship_map: RelationshipMap) -> bool: """Detect if the codebase follows microservices architecture.""" # Look for service boundaries and loose coupling modules = set() for component in relationship_map.components.values(): module = self._get_module_name(component.file_path) if module: modules.add(module) # Check for low coupling between modules coupling_count = len([r for r in relationship_map.relationships if r.relationship_type == RelationshipType.IMPORTS]) coupling_ratio = coupling_count / max(len(modules), 1) return coupling_ratio < 2.0 and len(modules) > 3 def _detect_repository_pattern(self, relationship_map: RelationshipMap) -> bool: """Detect if the codebase uses repository pattern.""" # Look for repository classes and data access patterns repositories = [c for c in relationship_map.components.values() if "repository" in c.name.lower()] return len(repositories) > 0 def _detect_anti_patterns(self, relationship_map: RelationshipMap) -> List[str]: """Detect architectural anti-patterns.""" anti_patterns = [] # God object detection large_components = [c for c in relationship_map.components.values() if c.metadata.get("size", 0) > 1000] if large_components: anti_patterns.append("god_object") # Spaghetti code detection circular_deps = relationship_map.circular_dependencies if len(circular_deps) > len(relationship_map.components) * 0.1: anti_patterns.append("spaghetti_code") return anti_patterns def _generate_architectural_insights(self, relationship_map: RelationshipMap) -> List[str]: """Generate architectural insights from relationship analysis.""" insights = [] # Component count insight total_components = len(relationship_map.components) if total_components > 100: insights.append("Large codebase with many components - consider modularization") # Relationship density insight total_relationships = len(relationship_map.relationships) relationship_density = total_relationships / max(total_components, 1) if relationship_density > 5: insights.append("High relationship density - may indicate tight coupling") # Circular dependency insight if relationship_map.circular_dependencies: insights.append("Circular dependencies detected - refactoring recommended") return insights def _extract_imports(self, code: str) -> Set[str]: """Extract imports from code.""" imports = set() # Python import patterns import_patterns = [ r'import\s+(\w+(?:\.\w+)*)', r'from\s+(\w+(?:\.\w+)*)\s+import', ] for pattern in import_patterns: matches = re.findall(pattern, code) imports.update(matches) return imports def _get_module_name(self, file_path: str) -> str: """Extract module name from file path.""" if not file_path: return "" # Remove file extension module = file_path.replace(".py", "").replace(".js", "").replace(".ts", "") # Extract just the module name without path module = module.split("/")[-1].split("\\")[-1] return module def _identify_layers(self, relationship_map: RelationshipMap) -> List[Set[str]]: """Identify architectural layers.""" # Simplified layer identification based on naming conventions layers = defaultdict(set) for component in relationship_map.components.values(): name_lower = component.name.lower() if any(keyword in name_lower for keyword in ["ui", "view", "present"]): layers["presentation"].add(component.name) elif any(keyword in name_lower for keyword in ["controller", "handler", "service"]): layers["business"].add(component.name) elif any(keyword in name_lower for keyword in ["model", "entity", "data"]): layers["data"].add(component.name) else: layers["common"].add(component.name) return [layer for layer in layers.values() if layer] def _build_cfg_from_ast(self, tree: ast.AST, cfg: 'ControlFlowGraph'): """Build control flow graph from AST.""" # Simplified CFG building # This would require more sophisticated implementation pass def _build_simple_cfg(self, code: str, cfg: 'ControlFlowGraph'): """Build simple control flow graph.""" # Very simplified CFG building lines = code.split('\n') for i, line in enumerate(lines): if "if " in line: cfg.add_node(f"line_{i}") elif "for " in line: cfg.add_node(f"line_{i}") elif "while " in line: cfg.add_node(f"line_{i}") def _build_dfg_from_ast(self, tree: ast.AST, dfg: 'DataFlowGraph'): """Build data flow graph from AST.""" # Simplified DFG building # This would require more sophisticated implementation pass def _build_simple_dfg(self, code: str, dfg: 'DataFlowGraph'): """Build simple data flow graph.""" # Very simplified DFG building # Extract variable assignments assignments = re.findall(r'(\w+)\s*=', code) for var in assignments: dfg.add_variable(var) def _build_dependency_matrix(self, dependencies: List[Dependency]) -> Dict[str, Dict[str, float]]: """Build dependency matrix.""" matrix: Dict[str, Dict[str, float]] = defaultdict(dict) for dep in dependencies: matrix[dep.source_module][dep.target_module] = dep.strength return dict(matrix) def _identify_critical_paths(self, dependencies: List[Dependency]) -> List[List[str]]: """Identify critical dependency paths.""" # Simplified critical path identification critical_paths = [] # Find dependencies with high impact high_impact_deps = [d for d in dependencies if d.strength > 0.8] for dep in high_impact_deps: critical_paths.append([dep.source_module, dep.target_module]) return critical_paths

Latest Blog Posts

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/betmoar/FastApply-MCP'

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