using MarketAlly.AIPlugin; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.MSBuild; using System.Collections.Generic; using System.Threading.Tasks; using System.IO; using System.Linq; using System.Text.Json; using System.Text.RegularExpressions; using System.Xml.Linq; using Microsoft.Extensions.Logging; using System.Text; namespace MarketAlly.AIPlugin.Analysis.Plugins { [AIPlugin("ModularMap", "Generates visual dependency maps and analyzes modular architecture patterns")] public class ModularMapPlugin : IAIPlugin { private readonly ILogger? _logger; public ModularMapPlugin(ILogger? logger = null) { _logger = logger; } [AIParameter("Full path to the project or solution directory", required: true)] public string ProjectPath { get; set; } = string.Empty; [AIParameter("Map output format: json, mermaid, cytoscape, graphviz", required: false)] public string OutputFormat { get; set; } = "json"; [AIParameter("Include external dependencies (NuGet packages)", required: false)] public bool IncludeExternalDependencies { get; set; } = false; [AIParameter("Include internal project references only", required: false)] public bool InternalOnly { get; set; } = true; [AIParameter("Analyze coupling and cohesion metrics", required: false)] public bool AnalyzeCoupling { get; set; } = true; [AIParameter("Generate architectural insights and recommendations", required: false)] public bool GenerateInsights { get; set; } = true; [AIParameter("Maximum dependency depth to analyze", required: false)] public int MaxDepth { get; set; } = 5; [AIParameter("Filter by namespace pattern (e.g., 'MyCompany.*')", required: false)] public string NamespaceFilter { get; set; } = string.Empty; [AIParameter("Include method-level dependencies", required: false)] public bool IncludeMethodLevel { get; set; } = false; [AIParameter("Output file path for the map", required: false)] public string OutputPath { get; set; } = string.Empty; [AIParameter("Enable advanced module identification and grouping", required: false)] public bool EnableModuleGrouping { get; set; } = true; [AIParameter("Module grouping strategy: namespace, folder, feature, auto", required: false)] public string ModuleGroupingStrategy { get; set; } = "auto"; [AIParameter("Detect platform-specific modules", required: false)] public bool DetectPlatformModules { get; set; } = true; [AIParameter("Include module entry points and public interfaces", required: false)] public bool IncludeEntryPoints { get; set; } = true; [AIParameter("Generate reusable module definitions", required: false)] public bool GenerateModuleDefinitions { get; set; } = true; public IReadOnlyDictionary SupportedParameters => new Dictionary { ["projectPath"] = typeof(string), ["outputFormat"] = typeof(string), ["includeExternalDependencies"] = typeof(bool), ["internalOnly"] = typeof(bool), ["analyzeCoupling"] = typeof(bool), ["generateInsights"] = typeof(bool), ["maxDepth"] = typeof(int), ["namespaceFilter"] = typeof(string), ["includeMethodLevel"] = typeof(bool), ["outputPath"] = typeof(string), ["detectPatterns"] = typeof(bool), ["enableModuleGrouping"] = typeof(bool), ["moduleGroupingStrategy"] = typeof(string), ["detectPlatformModules"] = typeof(bool), ["includeEntryPoints"] = typeof(bool), ["generateModuleDefinitions"] = typeof(bool), ["generateScaffoldingMetadata"] = typeof(bool), ["includeLlmDescriptions"] = typeof(bool), ["analyzeModuleTags"] = typeof(bool), ["includeModuleFlags"] = typeof(bool) }; public async Task ExecuteAsync(IReadOnlyDictionary parameters) { try { // Extract parameters string projectPath = parameters["projectPath"].ToString() ?? string.Empty; string outputFormat = parameters.GetValueOrDefault("outputFormat", "json")?.ToString() ?? "json"; bool includeExternal = Convert.ToBoolean(parameters.GetValueOrDefault("includeExternalDependencies", false)); bool internalOnly = Convert.ToBoolean(parameters.GetValueOrDefault("internalOnly", true)); bool analyzeCoupling = Convert.ToBoolean(parameters.GetValueOrDefault("analyzeCoupling", true)); bool generateInsights = Convert.ToBoolean(parameters.GetValueOrDefault("generateInsights", true)); int maxDepth = Convert.ToInt32(parameters.GetValueOrDefault("maxDepth", 5)); string? namespaceFilter = parameters.GetValueOrDefault("namespaceFilter", string.Empty)?.ToString(); bool includeMethodLevel = Convert.ToBoolean(parameters.GetValueOrDefault("includeMethodLevel", false)); string? outputPath = parameters.GetValueOrDefault("outputPath", string.Empty)?.ToString(); bool detectPatterns = Convert.ToBoolean(parameters.GetValueOrDefault("detectPatterns", true)); bool enableModuleGrouping = Convert.ToBoolean(parameters.GetValueOrDefault("enableModuleGrouping", true)); string moduleGroupingStrategy = parameters.GetValueOrDefault("moduleGroupingStrategy", "auto")?.ToString() ?? "auto"; bool detectPlatformModules = Convert.ToBoolean(parameters.GetValueOrDefault("detectPlatformModules", true)); bool includeEntryPoints = Convert.ToBoolean(parameters.GetValueOrDefault("includeEntryPoints", true)); bool generateModuleDefinitions = Convert.ToBoolean(parameters.GetValueOrDefault("generateModuleDefinitions", true)); bool generateScaffoldingMetadata = Convert.ToBoolean(parameters.GetValueOrDefault("generateScaffoldingMetadata", true)); bool includeLlmDescriptions = Convert.ToBoolean(parameters.GetValueOrDefault("includeLlmDescriptions", true)); bool analyzeModuleTags = Convert.ToBoolean(parameters.GetValueOrDefault("analyzeModuleTags", true)); bool includeModuleFlags = Convert.ToBoolean(parameters.GetValueOrDefault("includeModuleFlags", true)); // Validate project path if (!Directory.Exists(projectPath) && !File.Exists(projectPath)) { return new AIPluginResult( new DirectoryNotFoundException($"Project path not found: {projectPath}"), "Invalid project path" ); } _logger?.LogInformation("Starting modular map analysis for {ProjectPath}", projectPath); // Analyze project structure var analysisResult = await AnalyzeProjectStructureAsync(projectPath, new AnalysisOptions { IncludeExternalDependencies = includeExternal, InternalOnly = internalOnly, MaxDepth = maxDepth, NamespaceFilter = namespaceFilter, IncludeMethodLevel = includeMethodLevel, EnableModuleGrouping = enableModuleGrouping, ModuleGroupingStrategy = moduleGroupingStrategy, DetectPlatformModules = detectPlatformModules, IncludeEntryPoints = includeEntryPoints, GenerateModuleDefinitions = generateModuleDefinitions, GenerateScaffoldingMetadata = generateScaffoldingMetadata, IncludeLlmDescriptions = includeLlmDescriptions, AnalyzeModuleTags = analyzeModuleTags, IncludeModuleFlags = includeModuleFlags }); // Generate modular structure if requested var modularStructure = enableModuleGrouping ? await GenerateModularStructureAsync(analysisResult, options: new ModularOptions { GroupingStrategy = moduleGroupingStrategy, DetectPlatformModules = detectPlatformModules, IncludeEntryPoints = includeEntryPoints, GenerateScaffoldingMetadata = generateScaffoldingMetadata, IncludeLlmDescriptions = includeLlmDescriptions, AnalyzeModuleTags = analyzeModuleTags, IncludeModuleFlags = includeModuleFlags }) : null; // Generate dependency map (enhanced with modular structure if available) var dependencyMap = await GenerateDependencyMapAsync(analysisResult, outputFormat, modularStructure); // Analyze coupling metrics if requested var couplingMetrics = analyzeCoupling ? await AnalyzeCouplingMetricsAsync(analysisResult) : null; // Detect architectural patterns if requested var architecturalPatterns = detectPatterns ? await DetectArchitecturalPatternsAsync(analysisResult) : null; // Generate insights and recommendations var insights = generateInsights ? await GenerateArchitecturalInsightsAsync(analysisResult, couplingMetrics, architecturalPatterns) : null; // Save output file if path provided string? savedPath = null; if (!string.IsNullOrEmpty(outputPath)) { savedPath = await SaveMapToFileAsync(dependencyMap, outputPath, outputFormat); } var result = new { ProjectPath = projectPath, OutputFormat = outputFormat, DependencyMap = dependencyMap, ModularStructure = modularStructure, CouplingMetrics = couplingMetrics, ArchitecturalPatterns = architecturalPatterns, Insights = insights, Statistics = new { TotalModules = modularStructure?.Modules?.Count ?? analysisResult.Modules.Count, TotalLogicalModules = modularStructure?.Modules?.Count ?? 0, TotalDependencies = analysisResult.Dependencies.Count, MaxDepthReached = analysisResult.MaxDepthReached, ExternalDependencies = analysisResult.ExternalDependencies.Count, PlatformSpecificModules = modularStructure?.Modules?.Count(m => m.PlatformSpecific) ?? 0 }, OutputPath = savedPath }; _logger?.LogInformation("Modular map analysis completed successfully"); return new AIPluginResult(result, "Modular map generation completed successfully"); } catch (Exception ex) { _logger?.LogError(ex, "Failed to generate modular map"); return new AIPluginResult(ex, $"Failed to generate modular map: {ex.Message}"); } } private async Task AnalyzeProjectStructureAsync(string projectPath, AnalysisOptions options) { var result = new ProjectAnalysisResult { ProjectPath = projectPath }; var processedProjects = new HashSet(); var projectQueue = new Queue<(string path, int depth)>(); try { // Find initial projects to analyze var initialProjects = await DiscoverProjectsAsync(projectPath); foreach (var project in initialProjects) { projectQueue.Enqueue((project, 0)); } // Process projects with depth limiting while (projectQueue.Count > 0) { var (currentPath, depth) = projectQueue.Dequeue(); if (depth > options.MaxDepth || processedProjects.Contains(currentPath)) continue; processedProjects.Add(currentPath); result.MaxDepthReached = Math.Max(result.MaxDepthReached, depth); var module = await AnalyzeProjectAsync(currentPath, options); if (module != null && ShouldIncludeModule(module, options)) { result.Modules.Add(module); // Add project references to queue for deeper analysis var projectRefs = await GetProjectReferencesAsync(currentPath); foreach (var refPath in projectRefs) { if (!processedProjects.Contains(refPath)) { projectQueue.Enqueue((refPath, depth + 1)); } } } } // Build dependency relationships result.Dependencies = await BuildDependencyGraphAsync(result.Modules, options); // Analyze external dependencies if requested if (options.IncludeExternalDependencies) { result.ExternalDependencies = await AnalyzeExternalDependenciesAsync(result.Modules); } _logger?.LogInformation("Analyzed {ModuleCount} modules with {DependencyCount} dependencies", result.Modules.Count, result.Dependencies.Count); return result; } catch (Exception ex) { _logger?.LogError(ex, "Error analyzing project structure"); throw; } } private async Task> DiscoverProjectsAsync(string path) { var projects = new List(); if (File.Exists(path)) { var extension = Path.GetExtension(path).ToLower(); if (extension == ".sln") { // Parse solution file projects.AddRange(await ParseSolutionFileAsync(path)); } else if (extension == ".csproj" || extension == ".vbproj" || extension == ".fsproj") { projects.Add(path); } } else if (Directory.Exists(path)) { // Search for project files var projectFiles = Directory.GetFiles(path, "*.csproj", SearchOption.AllDirectories) .Concat(Directory.GetFiles(path, "*.vbproj", SearchOption.AllDirectories)) .Concat(Directory.GetFiles(path, "*.fsproj", SearchOption.AllDirectories)); projects.AddRange(projectFiles); // Also check for solution files var solutionFiles = Directory.GetFiles(path, "*.sln", SearchOption.TopDirectoryOnly); foreach (var sln in solutionFiles) { projects.AddRange(await ParseSolutionFileAsync(sln)); } } return projects.Distinct().ToList(); } private async Task> ParseSolutionFileAsync(string solutionPath) { var projects = new List(); var solutionDir = Path.GetDirectoryName(solutionPath); var content = await File.ReadAllTextAsync(solutionPath); var projectRegex = new Regex(@"Project\(""\{[^}]+\}""\)\s*=\s*""[^""]*"",\s*""([^""]+)"",\s*""\{[^}]+\}"""); foreach (Match match in projectRegex.Matches(content)) { var relativePath = match.Groups[1].Value; var absolutePath = Path.GetFullPath(Path.Combine(solutionDir ?? string.Empty, relativePath)); if (File.Exists(absolutePath) && IsProjectFile(absolutePath)) { projects.Add(absolutePath); } } return projects; } private bool IsProjectFile(string path) { var extension = Path.GetExtension(path).ToLower(); return extension == ".csproj" || extension == ".vbproj" || extension == ".fsproj"; } private async Task AnalyzeProjectAsync(string projectPath, AnalysisOptions options) { try { var projectName = Path.GetFileNameWithoutExtension(projectPath); var projectDir = Path.GetDirectoryName(projectPath) ?? string.Empty; // Parse project file var projectXml = await File.ReadAllTextAsync(projectPath); var doc = XDocument.Parse(projectXml); // Get project type and target framework var projectType = DetermineProjectType(doc); var targetFramework = doc.Descendants("TargetFramework").FirstOrDefault()?.Value ?? doc.Descendants("TargetFrameworks").FirstOrDefault()?.Value?.Split(';').FirstOrDefault() ?? "unknown"; // Analyze source code var sourceFiles = Directory.GetFiles(projectDir, "*.cs", SearchOption.AllDirectories) .Where(f => !f.Contains("bin") && !f.Contains("obj")) .ToList(); var namespaces = new HashSet(); var classes = new List(); var totalLines = 0; foreach (var file in sourceFiles) { try { var sourceCode = await File.ReadAllTextAsync(file); totalLines += sourceCode.Split('\n').Length; var tree = CSharpSyntaxTree.ParseText(sourceCode); var root = await tree.GetRootAsync(); // Extract namespaces var namespaceDeclarations = root.DescendantNodes().OfType(); foreach (var ns in namespaceDeclarations) { if (ns.Name != null) namespaces.Add(ns.Name.ToString()); } // Extract classes var classDeclarations = root.DescendantNodes().OfType(); foreach (var cls in classDeclarations) { classes.Add(cls.Identifier.ValueText); } } catch (Exception ex) { _logger?.LogWarning("Failed to parse file {File}: {Error}", file, ex.Message); } } var primaryNamespace = namespaces.FirstOrDefault() ?? projectName; return new ModuleInfo { Name = projectName, Namespace = primaryNamespace, Type = projectType, LineCount = totalLines, ClassCount = classes.Count, TargetFramework = targetFramework, ProjectPath = projectPath, SourceFiles = sourceFiles, Namespaces = namespaces.ToList(), Classes = classes }; } catch (Exception ex) { _logger?.LogWarning("Failed to analyze project {Project}: {Error}", projectPath, ex.Message); return null; } } private string DetermineProjectType(XDocument projectDoc) { var outputType = projectDoc.Descendants("OutputType").FirstOrDefault()?.Value?.ToLower(); var useWebSdk = projectDoc.Root?.Attribute("Sdk")?.Value?.Contains("Web") == true; var hasPackageRefs = projectDoc.Descendants("PackageReference").Any(); return outputType switch { "exe" when useWebSdk => "WebAPI", "exe" => "Console", "library" when useWebSdk => "WebLibrary", "library" => "Library", "winexe" => "WinForms", _ when useWebSdk => "Web", _ => "Library" }; } private bool ShouldIncludeModule(ModuleInfo module, AnalysisOptions options) { if (string.IsNullOrEmpty(options.NamespaceFilter)) return true; var pattern = options.NamespaceFilter.Replace("*", ".*"); var regex = new Regex(pattern, RegexOptions.IgnoreCase); return module.Namespaces.Any(ns => regex.IsMatch(ns)); } private async Task> GetProjectReferencesAsync(string projectPath) { var references = new List(); try { var projectXml = await File.ReadAllTextAsync(projectPath); var doc = XDocument.Parse(projectXml); var projectDir = Path.GetDirectoryName(projectPath) ?? string.Empty; var projectRefs = doc.Descendants("ProjectReference"); foreach (var projRef in projectRefs) { var include = projRef.Attribute("Include")?.Value; if (!string.IsNullOrEmpty(include)) { var absolutePath = Path.GetFullPath(Path.Combine(projectDir, include)); if (File.Exists(absolutePath)) { references.Add(absolutePath); } } } } catch (Exception ex) { _logger?.LogWarning("Failed to get project references for {Project}: {Error}", projectPath, ex.Message); } return references; } private async Task> BuildDependencyGraphAsync(List modules, AnalysisOptions options) { var dependencies = new List(); var modulesByPath = modules.ToDictionary(m => m.ProjectPath, m => m); foreach (var module in modules) { try { // Get project references var projectRefs = await GetProjectReferencesAsync(module.ProjectPath); foreach (var refPath in projectRefs) { if (modulesByPath.TryGetValue(refPath, out var targetModule)) { var strength = await CalculateDependencyStrength(module, targetModule, options); dependencies.Add(new DependencyInfo { From = module.Name, To = targetModule.Name, Type = "ProjectReference", Strength = strength, ReferenceCount = await CountReferences(module, targetModule) }); } } // Analyze using statements for namespace dependencies if method-level analysis is enabled if (options.IncludeMethodLevel) { var namespaceDependencies = await AnalyzeNamespaceDependencies(module, modules); dependencies.AddRange(namespaceDependencies); } } catch (Exception ex) { _logger?.LogWarning("Failed to build dependencies for {Module}: {Error}", module.Name, ex.Message); } } return dependencies; } private async Task CalculateDependencyStrength(ModuleInfo from, ModuleInfo to, AnalysisOptions options) { try { var referenceCount = await CountReferences(from, to); return referenceCount switch { > 50 => "Strong", > 10 => "Medium", _ => "Weak" }; } catch { return "Unknown"; } } private async Task CountReferences(ModuleInfo from, ModuleInfo to) { int count = 0; foreach (var sourceFile in from.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); // Count using directives var usingDirectives = root.DescendantNodes().OfType(); foreach (var usingDirective in usingDirectives) { var namespaceName = usingDirective.Name?.ToString(); if (to.Namespaces.Any(ns => namespaceName?.StartsWith(ns) == true)) { count++; } } // Count qualified name references var identifierNames = root.DescendantNodes().OfType(); foreach (var identifier in identifierNames) { if (to.Classes.Contains(identifier.Identifier.ValueText)) { count++; } } } catch (Exception ex) { _logger?.LogWarning("Failed to count references in {File}: {Error}", sourceFile, ex.Message); } } return count; } private async Task> AnalyzeNamespaceDependencies(ModuleInfo module, List allModules) { var dependencies = new List(); var targetModulesByNamespace = allModules .SelectMany(m => m.Namespaces.Select(ns => new { Namespace = ns, Module = m })) .GroupBy(x => x.Namespace) .ToDictionary(g => g.Key, g => g.Select(x => x.Module).ToList()); foreach (var sourceFile in module.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); var usingDirectives = root.DescendantNodes().OfType(); foreach (var usingDirective in usingDirectives) { var namespaceName = usingDirective.Name?.ToString(); if (!string.IsNullOrEmpty(namespaceName) && targetModulesByNamespace.ContainsKey(namespaceName)) { foreach (var targetModule in targetModulesByNamespace[namespaceName]) { if (targetModule.Name != module.Name) { var existing = dependencies.FirstOrDefault(d => d.From == module.Name && d.To == targetModule.Name && d.Type == "NamespaceReference"); if (existing == null) { dependencies.Add(new DependencyInfo { From = module.Name, To = targetModule.Name, Type = "NamespaceReference", Strength = "Weak", ReferenceCount = 1 }); } else { existing.ReferenceCount++; } } } } } } catch (Exception ex) { _logger?.LogWarning("Failed to analyze namespace dependencies in {File}: {Error}", sourceFile, ex.Message); } } return dependencies; } private async Task> AnalyzeExternalDependenciesAsync(List modules) { var externalDeps = new List(); var depsByName = new Dictionary(); foreach (var module in modules) { try { var projectXml = await File.ReadAllTextAsync(module.ProjectPath); var doc = XDocument.Parse(projectXml); var packageRefs = doc.Descendants("PackageReference"); foreach (var packageRef in packageRefs) { var name = packageRef.Attribute("Include")?.Value; var version = packageRef.Attribute("Version")?.Value ?? packageRef.Element("Version")?.Value; if (!string.IsNullOrEmpty(name)) { if (!depsByName.TryGetValue(name, out var existingDep)) { existingDep = new ExternalDependencyInfo { Name = name, Version = version ?? "unknown", Type = "NuGet" }; depsByName[name] = existingDep; externalDeps.Add(existingDep); } existingDep.UsedBy.Add(module.Name); } } } catch (Exception ex) { _logger?.LogWarning("Failed to analyze external dependencies for {Module}: {Error}", module.Name, ex.Message); } } return externalDeps; } private async Task AnalyzeCouplingMetricsAsync(ProjectAnalysisResult analysis) { var metrics = new CouplingMetrics(); var moduleMetrics = new Dictionary(); // Calculate coupling metrics for each module foreach (var module in analysis.Modules) { var afferentCoupling = analysis.Dependencies.Count(d => d.To == module.Name); var efferentCoupling = analysis.Dependencies.Count(d => d.From == module.Name); var totalCoupling = afferentCoupling + efferentCoupling; var instability = totalCoupling == 0 ? 0 : (double)efferentCoupling / totalCoupling; // Calculate abstractness (simplified - ratio of interfaces/abstract classes) var abstractness = await CalculateAbstractnessAsync(module); // Distance from main sequence: D = |A + I - 1| var distance = Math.Abs(abstractness + instability - 1); var moduleCoupling = new ModuleCouplingMetrics { AfferentCoupling = afferentCoupling, EfferentCoupling = efferentCoupling, Instability = instability, Abstractness = abstractness, Distance = distance }; moduleMetrics[module.Name] = moduleCoupling; metrics.InstabilityScores[module.Name] = instability; } // Calculate overall metrics metrics.OverallCouplingScore = moduleMetrics.Values.Average(m => m.Distance); // Identify highly coupled modules (instability > 0.7) metrics.HighlyCoupledModules = moduleMetrics .Where(kvp => kvp.Value.Instability > 0.7) .Select(kvp => kvp.Key) .ToList(); // Identify loosely coupled modules (instability < 0.3) metrics.LooselyCoupledModules = moduleMetrics .Where(kvp => kvp.Value.Instability < 0.3) .Select(kvp => kvp.Key) .ToList(); // Detect circular dependencies metrics.CircularDependencies = await DetectCircularDependenciesAsync(analysis); // Generate recommendations metrics.Recommendations = GenerateCouplingRecommendations(moduleMetrics, metrics); await Task.CompletedTask; return metrics; } private async Task CalculateAbstractnessAsync(ModuleInfo module) { int totalTypes = 0; int abstractTypes = 0; foreach (var sourceFile in module.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); // Count classes and interfaces var classDeclarations = root.DescendantNodes().OfType(); var interfaceDeclarations = root.DescendantNodes().OfType(); foreach (var classDecl in classDeclarations) { totalTypes++; if (classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword))) { abstractTypes++; } } foreach (var interfaceDecl in interfaceDeclarations) { totalTypes++; abstractTypes++; // Interfaces are considered abstract } } catch (Exception ex) { _logger?.LogWarning("Failed to calculate abstractness for {File}: {Error}", sourceFile, ex.Message); } } return totalTypes == 0 ? 0 : (double)abstractTypes / totalTypes; } private async Task> DetectCircularDependenciesAsync(ProjectAnalysisResult analysis) { var circularDeps = new List(); var graph = new Dictionary>(); // Build adjacency list foreach (var module in analysis.Modules) { graph[module.Name] = new List(); } foreach (var dependency in analysis.Dependencies) { if (graph.ContainsKey(dependency.From)) { graph[dependency.From].Add(dependency.To); } } // Use DFS to detect cycles var visited = new HashSet(); var recursionStack = new HashSet(); foreach (var module in analysis.Modules) { if (!visited.Contains(module.Name)) { var cycles = await DetectCyclesAsync(module.Name, graph, visited, recursionStack, new List()); circularDeps.AddRange(cycles); } } return circularDeps.Distinct().ToList(); } private async Task> DetectCyclesAsync(string node, Dictionary> graph, HashSet visited, HashSet recursionStack, List currentPath) { var cycles = new List(); visited.Add(node); recursionStack.Add(node); currentPath.Add(node); if (graph.ContainsKey(node)) { foreach (var neighbor in graph[node]) { if (!visited.Contains(neighbor)) { var subCycles = await DetectCyclesAsync(neighbor, graph, visited, recursionStack, new List(currentPath)); cycles.AddRange(subCycles); } else if (recursionStack.Contains(neighbor)) { // Found a cycle var cycleStart = currentPath.IndexOf(neighbor); var cycle = currentPath.Skip(cycleStart).Append(neighbor); cycles.Add(string.Join(" -> ", cycle)); } } } recursionStack.Remove(node); return cycles; } private List GenerateCouplingRecommendations(Dictionary moduleMetrics, CouplingMetrics metrics) { var recommendations = new List(); // High coupling recommendations foreach (var highlyCouple in metrics.HighlyCoupledModules) { if (moduleMetrics.TryGetValue(highlyCouple, out var coupling)) { if (coupling.EfferentCoupling > coupling.AfferentCoupling) { recommendations.Add($"Module '{highlyCouple}' has high efferent coupling ({coupling.EfferentCoupling}). Consider extracting interfaces or breaking into smaller modules."); } else { recommendations.Add($"Module '{highlyCouple}' has high afferent coupling ({coupling.AfferentCoupling}). This module is heavily depended upon - ensure it has a stable interface."); } } } // Distance from main sequence recommendations foreach (var moduleMetric in moduleMetrics) { if (moduleMetric.Value.Distance > 0.7) { if (moduleMetric.Value.Abstractness < 0.3 && moduleMetric.Value.Instability > 0.7) { recommendations.Add($"Module '{moduleMetric.Key}' is in the 'Zone of Pain' (concrete and unstable). Consider increasing abstraction through interfaces."); } else if (moduleMetric.Value.Abstractness > 0.7 && moduleMetric.Value.Instability < 0.3) { recommendations.Add($"Module '{moduleMetric.Key}' is in the 'Zone of Uselessness' (abstract but not used). Consider removing unused abstractions."); } } } // Circular dependency recommendations if (metrics.CircularDependencies.Any()) { recommendations.Add($"Found {metrics.CircularDependencies.Count} circular dependencies. Consider dependency inversion or extracting common interfaces."); } // General recommendations if (metrics.OverallCouplingScore > 0.6) { recommendations.Add("Overall coupling is high. Consider applying SOLID principles and dependency injection patterns."); } return recommendations; } private async Task DetectArchitecturalPatternsAsync(ProjectAnalysisResult analysis) { var patterns = new ArchitecturalPatterns(); var layerScores = new Dictionary(); // Detect layered architecture var layeredScore = await DetectLayeredArchitectureAsync(analysis); layerScores["Layered"] = layeredScore; // Detect clean architecture var cleanScore = await DetectCleanArchitectureAsync(analysis); layerScores["Clean"] = cleanScore; // Detect hexagonal architecture var hexagonalScore = await DetectHexagonalArchitectureAsync(analysis); layerScores["Hexagonal"] = hexagonalScore; // Detect microservices patterns var microservicesScore = await DetectMicroservicesPatternAsync(analysis); layerScores["Microservices"] = microservicesScore; // Find the pattern with highest confidence var bestPattern = layerScores.OrderByDescending(kvp => kvp.Value).First(); patterns.DetectedPattern = bestPattern.Key; patterns.Confidence = bestPattern.Value; // Generate layer definitions based on detected pattern patterns.LayerDefinitions = await GenerateLayerDefinitionsAsync(analysis, bestPattern.Key); // Detect pattern violations patterns.PatternViolations = await DetectPatternViolationsAsync(analysis, bestPattern.Key, patterns.LayerDefinitions); // Generate suggestions patterns.Suggestions = GeneratePatternSuggestions(analysis, bestPattern.Key, patterns.PatternViolations); return patterns; } private async Task DetectLayeredArchitectureAsync(ProjectAnalysisResult analysis) { double score = 0; var moduleNames = analysis.Modules.Select(m => m.Name.ToLower()).ToList(); // Check for common layer naming patterns var layerPatterns = new Dictionary { ["presentation"] = new[] { "web", "api", "mvc", "ui", "frontend", "presentation" }, ["business"] = new[] { "business", "service", "logic", "application", "app" }, ["data"] = new[] { "data", "dal", "repository", "persistence", "infrastructure" } }; var foundLayers = new HashSet(); foreach (var module in analysis.Modules) { var moduleName = module.Name.ToLower(); var namespaces = module.Namespaces.Select(ns => ns.ToLower()); foreach (var layer in layerPatterns) { if (layer.Value.Any(pattern => moduleName.Contains(pattern) || namespaces.Any(ns => ns.Contains(pattern)))) { foundLayers.Add(layer.Key); score += 0.3; } } } // Check dependency flow (should be top-down in layered architecture) var dependencyViolations = 0; var layerOrder = new[] { "presentation", "business", "data" }; foreach (var dependency in analysis.Dependencies) { var fromLayer = DetermineLayer(dependency.From, analysis.Modules); var toLayer = DetermineLayer(dependency.To, analysis.Modules); var fromIndex = Array.IndexOf(layerOrder, fromLayer); var toIndex = Array.IndexOf(layerOrder, toLayer); if (fromIndex >= 0 && toIndex >= 0 && fromIndex < toIndex) { dependencyViolations++; } } // Penalize for dependency violations if (analysis.Dependencies.Count > 0) { var violationRatio = (double)dependencyViolations / analysis.Dependencies.Count; score -= violationRatio * 0.4; } // Bonus for having all three layers if (foundLayers.Count >= 3) { score += 0.3; } await Task.CompletedTask; return Math.Max(0, Math.Min(1, score)); } private async Task DetectCleanArchitectureAsync(ProjectAnalysisResult analysis) { double score = 0; var moduleNames = analysis.Modules.Select(m => m.Name.ToLower()).ToList(); // Check for clean architecture naming patterns var cleanPatterns = new Dictionary { ["domain"] = new[] { "domain", "entities", "core" }, ["application"] = new[] { "application", "usecases", "services" }, ["infrastructure"] = new[] { "infrastructure", "persistence", "external" }, ["presentation"] = new[] { "web", "api", "ui", "controllers" } }; var foundLayers = new HashSet(); foreach (var module in analysis.Modules) { var moduleName = module.Name.ToLower(); var namespaces = module.Namespaces.Select(ns => ns.ToLower()); foreach (var layer in cleanPatterns) { if (layer.Value.Any(pattern => moduleName.Contains(pattern) || namespaces.Any(ns => ns.Contains(pattern)))) { foundLayers.Add(layer.Key); score += 0.25; } } } // Check for dependency rule compliance (dependencies point inward) var violationCount = 0; var layerDependencyRules = new Dictionary { ["domain"] = new string[0], // Domain should have no dependencies ["application"] = new[] { "domain" }, ["infrastructure"] = new[] { "domain", "application" }, ["presentation"] = new[] { "application", "domain" } }; foreach (var dependency in analysis.Dependencies) { var fromLayer = DetermineCleanLayer(dependency.From, analysis.Modules); var toLayer = DetermineCleanLayer(dependency.To, analysis.Modules); if (!string.IsNullOrEmpty(fromLayer) && !string.IsNullOrEmpty(toLayer)) { var allowedDependencies = layerDependencyRules.GetValueOrDefault(fromLayer, new string[0]); if (!allowedDependencies.Contains(toLayer)) { violationCount++; } } } // Penalize violations if (analysis.Dependencies.Count > 0) { var violationRatio = (double)violationCount / analysis.Dependencies.Count; score -= violationRatio * 0.5; } await Task.CompletedTask; return Math.Max(0, Math.Min(1, score)); } private async Task DetectHexagonalArchitectureAsync(ProjectAnalysisResult analysis) { double score = 0; // Check for hexagonal architecture patterns var hexPatterns = new Dictionary { ["core"] = new[] { "core", "domain", "business" }, ["ports"] = new[] { "ports", "interfaces", "contracts" }, ["adapters"] = new[] { "adapters", "infrastructure", "external" } }; var foundComponents = new HashSet(); foreach (var module in analysis.Modules) { var moduleName = module.Name.ToLower(); var namespaces = module.Namespaces.Select(ns => ns.ToLower()); foreach (var component in hexPatterns) { if (component.Value.Any(pattern => moduleName.Contains(pattern) || namespaces.Any(ns => ns.Contains(pattern)))) { foundComponents.Add(component.Key); score += 0.33; } } } // Look for interface segregation (ports pattern) var interfaceCount = 0; var totalClasses = 0; foreach (var module in analysis.Modules) { foreach (var sourceFile in module.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); interfaceCount += root.DescendantNodes().OfType().Count(); totalClasses += root.DescendantNodes().OfType().Count(); } catch { // Ignore parsing errors } } } // High interface-to-class ratio suggests ports and adapters if (totalClasses > 0) { var interfaceRatio = (double)interfaceCount / totalClasses; if (interfaceRatio > 0.3) { score += 0.2; } } return Math.Max(0, Math.Min(1, score)); } private async Task DetectMicroservicesPatternAsync(ProjectAnalysisResult analysis) { double score = 0; // Check for microservices indicators var servicePatterns = new[] { "service", "api", "microservice", "ms" }; var serviceCount = 0; foreach (var module in analysis.Modules) { var moduleName = module.Name.ToLower(); if (servicePatterns.Any(pattern => moduleName.Contains(pattern)) && (module.Type == "WebAPI" || module.Type == "Console")) { serviceCount++; score += 0.2; } } // Multiple independent services suggest microservices if (serviceCount >= 3) { score += 0.3; } // Low coupling between services is good for microservices var serviceDependencies = analysis.Dependencies.Where(d => IsService(d.From, analysis.Modules) && IsService(d.To, analysis.Modules)).Count(); if (serviceCount > 0) { var serviceCouplingRatio = (double)serviceDependencies / (serviceCount * serviceCount); if (serviceCouplingRatio < 0.2) { score += 0.3; } } await Task.CompletedTask; return Math.Max(0, Math.Min(1, score)); } private bool IsService(string moduleName, List modules) { var module = modules.FirstOrDefault(m => m.Name == moduleName); return module != null && (module.Type == "WebAPI" || module.Type == "Console") && new[] { "service", "api", "microservice", "ms" }.Any(pattern => module.Name.ToLower().Contains(pattern)); } private string DetermineLayer(string moduleName, List modules) { var module = modules.FirstOrDefault(m => m.Name == moduleName); if (module == null) return "unknown"; var name = module.Name.ToLower(); var namespaces = module.Namespaces.Select(ns => ns.ToLower()); if (new[] { "web", "api", "mvc", "ui", "presentation" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "presentation"; if (new[] { "business", "service", "logic", "application" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "business"; if (new[] { "data", "dal", "repository", "persistence" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "data"; return "unknown"; } private string? DetermineCleanLayer(string moduleName, List modules) { var module = modules.FirstOrDefault(m => m.Name == moduleName); if (module == null) return null; var name = module.Name.ToLower(); var namespaces = module.Namespaces.Select(ns => ns.ToLower()); if (new[] { "domain", "entities", "core" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "domain"; if (new[] { "application", "usecases", "services" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "application"; if (new[] { "infrastructure", "persistence", "external" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "infrastructure"; if (new[] { "web", "api", "ui", "controllers" }.Any(p => name.Contains(p) || namespaces.Any(ns => ns.Contains(p)))) return "presentation"; return null; } private async Task>> GenerateLayerDefinitionsAsync(ProjectAnalysisResult analysis, string patternType) { var layers = new Dictionary>(); switch (patternType.ToLower()) { case "layered": layers["Presentation"] = analysis.Modules.Where(m => DetermineLayer(m.Name, analysis.Modules) == "presentation").Select(m => m.Name).ToList(); layers["Business"] = analysis.Modules.Where(m => DetermineLayer(m.Name, analysis.Modules) == "business").Select(m => m.Name).ToList(); layers["Data"] = analysis.Modules.Where(m => DetermineLayer(m.Name, analysis.Modules) == "data").Select(m => m.Name).ToList(); break; case "clean": layers["Domain"] = analysis.Modules.Where(m => DetermineCleanLayer(m.Name, analysis.Modules) == "domain").Select(m => m.Name).ToList(); layers["Application"] = analysis.Modules.Where(m => DetermineCleanLayer(m.Name, analysis.Modules) == "application").Select(m => m.Name).ToList(); layers["Infrastructure"] = analysis.Modules.Where(m => DetermineCleanLayer(m.Name, analysis.Modules) == "infrastructure").Select(m => m.Name).ToList(); layers["Presentation"] = analysis.Modules.Where(m => DetermineCleanLayer(m.Name, analysis.Modules) == "presentation").Select(m => m.Name).ToList(); break; case "hexagonal": layers["Core"] = analysis.Modules.Where(m => m.Name.ToLower().Contains("core") || m.Name.ToLower().Contains("domain")).Select(m => m.Name).ToList(); layers["Ports"] = analysis.Modules.Where(m => m.Name.ToLower().Contains("interface") || m.Name.ToLower().Contains("contract")).Select(m => m.Name).ToList(); layers["Adapters"] = analysis.Modules.Where(m => m.Name.ToLower().Contains("adapter") || m.Name.ToLower().Contains("infrastructure")).Select(m => m.Name).ToList(); break; case "microservices": layers["Services"] = analysis.Modules.Where(m => IsService(m.Name, analysis.Modules)).Select(m => m.Name).ToList(); layers["Shared"] = analysis.Modules.Where(m => !IsService(m.Name, analysis.Modules)).Select(m => m.Name).ToList(); break; } await Task.CompletedTask; return layers; } private async Task> DetectPatternViolationsAsync(ProjectAnalysisResult analysis, string patternType, Dictionary> layers) { var violations = new List(); switch (patternType.ToLower()) { case "layered": violations.AddRange(await DetectLayeredViolationsAsync(analysis, layers)); break; case "clean": violations.AddRange(await DetectCleanViolationsAsync(analysis, layers)); break; case "hexagonal": violations.AddRange(await DetectHexagonalViolationsAsync(analysis, layers)); break; case "microservices": violations.AddRange(await DetectMicroservicesViolationsAsync(analysis, layers)); break; } return violations; } private async Task> DetectLayeredViolationsAsync(ProjectAnalysisResult analysis, Dictionary> layers) { var violations = new List(); var layerOrder = new[] { "Presentation", "Business", "Data" }; foreach (var dependency in analysis.Dependencies) { var fromLayer = GetModuleLayer(dependency.From, layers); var toLayer = GetModuleLayer(dependency.To, layers); if (!string.IsNullOrEmpty(fromLayer) && !string.IsNullOrEmpty(toLayer)) { var fromIndex = Array.IndexOf(layerOrder, fromLayer); var toIndex = Array.IndexOf(layerOrder, toLayer); if (fromIndex >= 0 && toIndex >= 0 && fromIndex < toIndex) { violations.Add($"{fromLayer} layer module '{dependency.From}' should not depend on {toLayer} layer module '{dependency.To}'"); } } } await Task.CompletedTask; return violations; } private async Task> DetectCleanViolationsAsync(ProjectAnalysisResult analysis, Dictionary> layers) { var violations = new List(); var dependencyRules = new Dictionary { ["Domain"] = new string[0], ["Application"] = new[] { "Domain" }, ["Infrastructure"] = new[] { "Domain", "Application" }, ["Presentation"] = new[] { "Application", "Domain" } }; foreach (var dependency in analysis.Dependencies) { var fromLayer = GetModuleLayer(dependency.From, layers); var toLayer = GetModuleLayer(dependency.To, layers); if (!string.IsNullOrEmpty(fromLayer) && !string.IsNullOrEmpty(toLayer)) { var allowedDependencies = dependencyRules.GetValueOrDefault(fromLayer, new string[0]); if (!allowedDependencies.Contains(toLayer)) { violations.Add($"Clean Architecture violation: {fromLayer} module '{dependency.From}' should not depend on {toLayer} module '{dependency.To}'"); } } } await Task.CompletedTask; return violations; } private async Task> DetectHexagonalViolationsAsync(ProjectAnalysisResult analysis, Dictionary> layers) { var violations = new List(); // Core should not depend on Adapters foreach (var dependency in analysis.Dependencies) { var fromLayer = GetModuleLayer(dependency.From, layers); var toLayer = GetModuleLayer(dependency.To, layers); if (fromLayer == "Core" && toLayer == "Adapters") { violations.Add($"Hexagonal Architecture violation: Core module '{dependency.From}' should not depend on Adapter module '{dependency.To}'"); } } await Task.CompletedTask; return violations; } private async Task> DetectMicroservicesViolationsAsync(ProjectAnalysisResult analysis, Dictionary> layers) { var violations = new List(); // Services should have minimal dependencies on other services var serviceToServiceDeps = analysis.Dependencies.Where(d => layers["Services"].Contains(d.From) && layers["Services"].Contains(d.To)).ToList(); if (serviceToServiceDeps.Count > layers["Services"].Count * 0.3) { violations.Add($"High coupling between microservices detected: {serviceToServiceDeps.Count} inter-service dependencies"); } foreach (var serviceDep in serviceToServiceDeps) { violations.Add($"Service coupling: '{serviceDep.From}' depends on '{serviceDep.To}' - consider async messaging or shared data contracts"); } await Task.CompletedTask; return violations; } private string GetModuleLayer(string moduleName, Dictionary> layers) { return layers.FirstOrDefault(kvp => kvp.Value.Contains(moduleName)).Key; } private List GeneratePatternSuggestions(ProjectAnalysisResult analysis, string patternType, List violations) { var suggestions = new List(); switch (patternType.ToLower()) { case "layered": suggestions.Add("Ensure dependencies flow downward: Presentation -> Business -> Data"); suggestions.Add("Consider using dependency injection to invert control between layers"); if (violations.Any()) suggestions.Add("Extract interfaces to break inappropriate layer dependencies"); break; case "clean": suggestions.Add("Keep the Domain layer free of external dependencies"); suggestions.Add("Use dependency inversion principle for Infrastructure dependencies"); suggestions.Add("Consider using MediatR pattern for Application layer orchestration"); break; case "hexagonal": suggestions.Add("Define clear port interfaces for external integrations"); suggestions.Add("Keep business logic in the core, isolated from infrastructure concerns"); suggestions.Add("Use adapter pattern for external service integrations"); break; case "microservices": suggestions.Add("Minimize direct dependencies between services"); suggestions.Add("Consider using message queues or event-driven communication"); suggestions.Add("Implement proper service boundaries based on business domains"); break; } return suggestions; } private async Task GenerateArchitecturalInsightsAsync( ProjectAnalysisResult analysis, CouplingMetrics? coupling, ArchitecturalPatterns? patterns) { var insights = new ArchitecturalInsights(); // Calculate overall architecture score var patternScore = patterns?.Confidence ?? 0; var couplingScore = coupling != null ? (1 - coupling.OverallCouplingScore) : 0; var complexityScore = CalculateComplexityScore(analysis); insights.OverallArchitectureScore = (patternScore + couplingScore + complexityScore) / 3 * 10; // Identify strength areas insights.StrengthAreas = new List(); if (patternScore > 0.7) insights.StrengthAreas.Add($"Good adherence to {patterns?.DetectedPattern ?? "unknown"} architectural pattern"); if (coupling?.CircularDependencies?.Count == 0) insights.StrengthAreas.Add("No circular dependencies detected"); if (coupling?.LooselyCoupledModules?.Count > coupling?.HighlyCoupledModules?.Count) insights.StrengthAreas.Add("Good overall module decoupling"); if (analysis.Modules.Any(m => m.Type == "Library")) insights.StrengthAreas.Add("Good separation of concerns with dedicated library modules"); // Identify improvement areas insights.ImprovementAreas = new List(); if (coupling?.HighlyCoupledModules?.Count > 0) insights.ImprovementAreas.Add($"High coupling in modules: {string.Join(", ", coupling.HighlyCoupledModules!)}"); if (patterns?.PatternViolations?.Count > 0) insights.ImprovementAreas.Add($"Architectural pattern violations detected ({patterns.PatternViolations!.Count} issues)"); if (coupling?.CircularDependencies?.Count > 0) insights.ImprovementAreas.Add($"Circular dependencies need resolution ({coupling.CircularDependencies!.Count} cycles)"); // Generate refactoring opportunities insights.RefactoringOpportunities = await GenerateRefactoringOpportunitiesAsync(analysis, coupling, patterns); // Generate design pattern suggestions insights.DesignPatternSuggestions = GenerateDesignPatternSuggestions(analysis, coupling, patterns); return insights; } private double CalculateComplexityScore(ProjectAnalysisResult analysis) { if (analysis.Modules.Count == 0) return 0; var avgLinesPerModule = analysis.Modules.Average(m => m.LineCount); var avgClassesPerModule = analysis.Modules.Average(m => m.ClassCount); var dependencyRatio = analysis.Dependencies.Count / (double)analysis.Modules.Count; // Normalize scores (lower is better for complexity) var linesScore = Math.Max(0, 1 - (avgLinesPerModule / 10000)); // Penalize modules > 10k lines var classesScore = Math.Max(0, 1 - (avgClassesPerModule / 50)); // Penalize modules > 50 classes var dependencyScore = Math.Max(0, 1 - (dependencyRatio / 5)); // Penalize > 5 deps per module return (linesScore + classesScore + dependencyScore) / 3; } private async Task> GenerateRefactoringOpportunitiesAsync( ProjectAnalysisResult analysis, CouplingMetrics? coupling, ArchitecturalPatterns? patterns) { var opportunities = new List(); // Large module refactoring var largeModules = analysis.Modules.Where(m => m.LineCount > 5000 || m.ClassCount > 30).ToList(); foreach (var module in largeModules) { opportunities.Add(new RefactoringOpportunity { Type = "Split Large Module", Target = module.Name, Benefit = "Improved maintainability and reduced complexity", Effort = module.LineCount > 10000 ? "High" : "Medium", Priority = "Medium" }); } // High coupling refactoring if (coupling?.HighlyCoupledModules != null) { foreach (var coupledModule in coupling.HighlyCoupledModules) { opportunities.Add(new RefactoringOpportunity { Type = "Reduce Coupling", Target = coupledModule, Benefit = "Improved testability and flexibility", Effort = "Medium", Priority = "High" }); } } // Circular dependency refactoring if (coupling?.CircularDependencies?.Count > 0) { opportunities.Add(new RefactoringOpportunity { Type = "Break Circular Dependencies", Target = "Multiple modules", Benefit = "Simplified dependency graph and better modularity", Effort = "High", Priority = "High" }); } // Pattern-specific refactoring if (patterns?.PatternViolations?.Count > 0) { opportunities.Add(new RefactoringOpportunity { Type = $"Fix {patterns?.DetectedPattern ?? "architectural"} Pattern Violations", Target = "Architecture", Benefit = "Better architectural consistency and maintainability", Effort = "Medium", Priority = "Medium" }); } await Task.CompletedTask; return opportunities; } private List GenerateDesignPatternSuggestions( ProjectAnalysisResult analysis, CouplingMetrics? coupling, ArchitecturalPatterns? patterns) { var suggestions = new List(); // Repository pattern for data access var dataModules = analysis.Modules.Where(m => m.Name.ToLower().Contains("data") || m.Name.ToLower().Contains("repository") || m.Name.ToLower().Contains("dal")).ToList(); if (dataModules.Any()) { suggestions.Add("Consider implementing Repository pattern for data access abstraction"); } // Factory pattern for high coupling if (coupling?.HighlyCoupledModules?.Count > 0) { suggestions.Add("Consider Factory or Abstract Factory patterns to reduce coupling in object creation"); } // Observer pattern for event handling var eventModules = analysis.Modules.Where(m => m.Name.ToLower().Contains("event") || m.Name.ToLower().Contains("notification") || m.Classes.Any(c => c.ToLower().Contains("event"))).ToList(); if (eventModules.Any()) { suggestions.Add("Consider Observer or Mediator patterns for event-driven communication"); } // Strategy pattern for business logic var businessModules = analysis.Modules.Where(m => m.Name.ToLower().Contains("business") || m.Name.ToLower().Contains("service") || m.Name.ToLower().Contains("logic")).ToList(); if (businessModules.Any()) { suggestions.Add("Consider Strategy pattern for varying business logic implementations"); } // Dependency Injection for tight coupling if (coupling?.OverallCouplingScore > 0.6) { suggestions.Add("Implement Dependency Injection container to improve testability and flexibility"); } // Command pattern for API modules var apiModules = analysis.Modules.Where(m => m.Type == "WebAPI" || m.Name.ToLower().Contains("api") || m.Name.ToLower().Contains("controller")).ToList(); if (apiModules.Any()) { suggestions.Add("Consider Command/Query pattern (CQRS) for API request handling"); } // Facade pattern for complex subsystems var complexModules = analysis.Modules.Where(m => m.ClassCount > 20).ToList(); if (complexModules.Any()) { suggestions.Add("Consider Facade pattern to simplify interfaces to complex subsystems"); } return suggestions; } private async Task SaveMapToFileAsync(object map, string outputPath, string format) { var directory = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } string content = format.ToLower() switch { "json" => JsonSerializer.Serialize(map, new JsonSerializerOptions { WriteIndented = true }), "mermaid" => map.ToString() ?? string.Empty, "cytoscape" => JsonSerializer.Serialize(map, new JsonSerializerOptions { WriteIndented = true }), "graphviz" => map.ToString() ?? string.Empty, _ => JsonSerializer.Serialize(map, new JsonSerializerOptions { WriteIndented = true }) }; await File.WriteAllTextAsync(outputPath, content); return outputPath; } private string GenerateMermaidDiagram(ProjectAnalysisResult analysis) { var mermaid = new StringBuilder(); mermaid.AppendLine("graph TD"); // Add nodes with styling foreach (var module in analysis.Modules) { var nodeStyle = module.Type switch { "WebAPI" => ":::webapi", "Library" => ":::library", "Console" => ":::console", _ => "" }; mermaid.AppendLine($" {SanitizeNodeName(module.Name)}[\"{module.Name}
({module.Type})\"] {nodeStyle}"); } // Add dependencies foreach (var dependency in analysis.Dependencies) { var arrow = dependency.Strength switch { "Strong" => "-->", "Medium" => "-.->", _ => "-->" }; var label = dependency.ReferenceCount > 1 ? $"|{dependency.ReferenceCount}|" : ""; mermaid.AppendLine($" {SanitizeNodeName(dependency.From)} {arrow} {SanitizeNodeName(dependency.To)} {label}"); } // Add styling mermaid.AppendLine(); mermaid.AppendLine(" classDef webapi fill:#e1f5fe,stroke:#0277bd,stroke-width:2px"); mermaid.AppendLine(" classDef library fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px"); mermaid.AppendLine(" classDef console fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px"); return mermaid.ToString(); } private string SanitizeNodeName(string name) { return Regex.Replace(name ?? string.Empty, @"[^a-zA-Z0-9_]", "_"); } private object GenerateCytoscapeJson(ProjectAnalysisResult analysis) { return new { elements = new { nodes = analysis.Modules.Select(m => new { data = new { id = m.Name, label = m.Name, type = m.Type, lineCount = m.LineCount, classCount = m.ClassCount, @namespace = m.Namespace } }), edges = analysis.Dependencies.Select(d => new { data = new { source = d.From, target = d.To, type = d.Type, strength = d.Strength, weight = d.ReferenceCount } }) }, style = new object[] { new { selector = "node", style = new { content = "data(label)", width = "mapData(lineCount, 0, 10000, 20, 80)", height = "mapData(classCount, 0, 50, 20, 60)", backgroundColor = "#0074D9" } }, new { selector = "edge", style = new { width = "mapData(weight, 1, 10, 1, 5)", lineColor = "#333", targetArrowColor = "#333", targetArrowShape = "triangle" } } }, layout = new { name = "dagre", directed = true, rankDir = "TB" } }; } private string GenerateGraphvizDot(ProjectAnalysisResult analysis) { var dot = new StringBuilder(); dot.AppendLine("digraph ModularMap {"); dot.AppendLine(" rankdir=TB;"); dot.AppendLine(" node [shape=box, style=filled];"); dot.AppendLine(" edge [fontsize=10];"); // Add nodes with colors based on type foreach (var module in analysis.Modules) { var color = module.Type switch { "WebAPI" => "lightblue", "Library" => "lightgreen", "Console" => "lightyellow", _ => "lightgray" }; var label = $"{module.Name}\\n({module.Type})\\n{module.LineCount} lines"; dot.AppendLine($" \"{module.Name}\" [label=\"{label}\", fillcolor={color}];"); } // Add edges foreach (var dependency in analysis.Dependencies) { var style = dependency.Strength switch { "Strong" => "solid", "Medium" => "dashed", _ => "dotted" }; var label = dependency.ReferenceCount > 1 ? $"[label=\"{dependency.ReferenceCount}\"]" : ""; dot.AppendLine($" \"{dependency.From}\" -> \"{dependency.To}\" [style={style}] {label};"); } dot.AppendLine("}"); return dot.ToString(); } private async Task GenerateModularStructureAsync(ProjectAnalysisResult analysis, ModularOptions options) { var modularStructure = new ModularStructure { GeneratedAt = DateTime.UtcNow, GroupingStrategy = options.GroupingStrategy }; try { // Step 1: Identify logical modules based on grouping strategy var logicalModules = await IdentifyLogicalModulesAsync(analysis, options); // Step 2: Analyze dependencies between modules var moduleDependencies = await AnalyzeModuleDependenciesAsync(logicalModules, analysis); // Step 3: Detect platform-specific modules if (options.DetectPlatformModules) { await DetectPlatformSpecificModulesAsync(logicalModules, analysis); } // Step 4: Identify entry points and public interfaces if (options.IncludeEntryPoints) { await IdentifyModuleEntryPointsAsync(logicalModules, analysis); } // Step 5: Generate scaffolding metadata if (options.GenerateScaffoldingMetadata) { await GenerateScaffoldingMetadataAsync(logicalModules, analysis, options); } // Step 6: Analyze module tags and capabilities if (options.AnalyzeModuleTags) { await AnalyzeModuleTagsAsync(logicalModules, analysis); } // Step 7: Generate LLM descriptions if (options.IncludeLlmDescriptions) { await GenerateLlmDescriptionsAsync(logicalModules, analysis); } // Step 8: Set module flags if (options.IncludeModuleFlags) { await SetModuleFlagsAsync(logicalModules, analysis); } // Step 9: Build the final modular structure modularStructure.Modules = logicalModules; modularStructure.ModuleDependencies = moduleDependencies; modularStructure.ReusabilityAnalysis = await AnalyzeModuleReusabilityAsync(logicalModules, moduleDependencies); _logger?.LogInformation("Generated modular structure with {ModuleCount} logical modules", logicalModules.Count); return modularStructure; } catch (Exception ex) { _logger?.LogError(ex, "Failed to generate modular structure"); throw; } } private async Task> IdentifyLogicalModulesAsync(ProjectAnalysisResult analysis, ModularOptions options) { var modules = new List(); var namespaceGroups = new Dictionary>(); // Collect all namespaces from all projects var allNamespaces = analysis.Modules .SelectMany(m => m.Namespaces) .Where(ns => !string.IsNullOrEmpty(ns)) .Distinct() .ToList(); switch (options.GroupingStrategy.ToLower()) { case "namespace": modules = await GroupByNamespacePatternAsync(allNamespaces, analysis); break; case "folder": modules = await GroupByFolderStructureAsync(analysis); break; case "feature": modules = await GroupByFeatureDetectionAsync(allNamespaces, analysis); break; case "auto": default: modules = await AutoDetectModulesAsync(allNamespaces, analysis); break; } await Task.CompletedTask; return modules; } private async Task> GroupByNamespacePatternAsync(List namespaces, ProjectAnalysisResult analysis) { var modules = new List(); var moduleGroups = new Dictionary>(); foreach (var ns in namespaces) { // Extract module name from namespace patterns var moduleName = ExtractModuleNameFromNamespace(ns); if (!moduleGroups.ContainsKey(moduleName)) { moduleGroups[moduleName] = new List(); } moduleGroups[moduleName].Add(ns); } foreach (var group in moduleGroups) { var module = new LogicalModule { Name = group.Key, Namespaces = group.Value, ModuleType = DetermineModuleType(group.Value), PlatformSpecific = false, // Will be detected later Platforms = new List() }; // Find related source files module.SourceFiles = analysis.Modules .Where(m => m.Namespaces.Any(ns => group.Value.Contains(ns))) .SelectMany(m => m.SourceFiles) .Distinct() .ToList(); modules.Add(module); } await Task.CompletedTask; return modules; } private async Task> GroupByFolderStructureAsync(ProjectAnalysisResult analysis) { var modules = new List(); var folderGroups = new Dictionary>(); foreach (var project in analysis.Modules) { var projectDir = Path.GetDirectoryName(project.ProjectPath) ?? string.Empty; var subFolders = project.SourceFiles .Select(f => Path.GetDirectoryName(f) ?? string.Empty) .Where(d => !string.IsNullOrEmpty(d) && d != projectDir) .Select(d => Path.GetRelativePath(projectDir, d).Split(Path.DirectorySeparatorChar)[0]) .Distinct() .ToList(); foreach (var folder in subFolders) { if (!folderGroups.ContainsKey(folder)) { folderGroups[folder] = new List(); } var folderNamespaces = project.Namespaces .Where(ns => ns.Contains(folder, StringComparison.OrdinalIgnoreCase)) .ToList(); folderGroups[folder].AddRange(folderNamespaces); } } foreach (var group in folderGroups.Where(g => g.Value.Any())) { var module = new LogicalModule { Name = group.Key, Namespaces = group.Value.Distinct().ToList(), ModuleType = DetermineModuleType(group.Value), PlatformSpecific = false }; module.SourceFiles = analysis.Modules .SelectMany(m => m.SourceFiles) .Where(f => Path.GetDirectoryName(f)?.Contains(group.Key, StringComparison.OrdinalIgnoreCase) == true) .ToList(); modules.Add(module); } await Task.CompletedTask; return modules; } private async Task> GroupByFeatureDetectionAsync(List namespaces, ProjectAnalysisResult analysis) { var modules = new List(); var featurePatterns = new Dictionary { ["Authentication"] = new[] { "auth", "login", "identity", "security", "token" }, ["Trading"] = new[] { "trading", "trade", "market", "order", "portfolio", "broker" }, ["Charting"] = new[] { "chart", "graph", "plot", "visualization", "technical" }, ["Messaging"] = new[] { "message", "notification", "push", "alert", "communication" }, ["Data"] = new[] { "data", "repository", "storage", "database", "persistence" }, ["UI"] = new[] { "view", "ui", "interface", "controls", "widgets", "pages" }, ["API"] = new[] { "api", "service", "client", "endpoint", "request" }, ["Utilities"] = new[] { "util", "helper", "common", "shared", "extension" }, ["Platform"] = new[] { "platform", "ios", "android", "windows", "macos" }, ["Configuration"] = new[] { "config", "setting", "preference", "option" }, ["Sync"] = new[] { "sync", "synchronization", "backup", "cloud" }, ["Reports"] = new[] { "report", "analytics", "statistics", "metrics" } }; var featureGroups = new Dictionary>(); foreach (var ns in namespaces) { var nsLower = ns.ToLower(); var matchedFeature = "Utilities"; // Default foreach (var feature in featurePatterns) { if (feature.Value.Any(pattern => nsLower.Contains(pattern))) { matchedFeature = feature.Key; break; } } if (!featureGroups.ContainsKey(matchedFeature)) { featureGroups[matchedFeature] = new List(); } featureGroups[matchedFeature].Add(ns); } foreach (var group in featureGroups.Where(g => g.Value.Any())) { var module = new LogicalModule { Name = group.Key, Namespaces = group.Value, ModuleType = DetermineModuleType(group.Value), PlatformSpecific = group.Key == "Platform" }; module.SourceFiles = analysis.Modules .Where(m => m.Namespaces.Any(ns => group.Value.Contains(ns))) .SelectMany(m => m.SourceFiles) .Distinct() .ToList(); modules.Add(module); } await Task.CompletedTask; return modules; } private async Task> AutoDetectModulesAsync(List namespaces, ProjectAnalysisResult analysis) { // Combine multiple strategies for auto-detection var namespaceModules = await GroupByNamespacePatternAsync(namespaces, analysis); var featureModules = await GroupByFeatureDetectionAsync(namespaces, analysis); // Merge and deduplicate based on namespace overlap var mergedModules = new List(); var processedNamespaces = new HashSet(); // Prioritize feature-based grouping foreach (var featureModule in featureModules) { if (featureModule.Namespaces.Any(ns => !processedNamespaces.Contains(ns))) { mergedModules.Add(featureModule); foreach (var ns in featureModule.Namespaces) { processedNamespaces.Add(ns); } } } // Add remaining namespaces as separate modules foreach (var nsModule in namespaceModules) { var unprocessedNamespaces = nsModule.Namespaces .Where(ns => !processedNamespaces.Contains(ns)) .ToList(); if (unprocessedNamespaces.Any()) { var module = new LogicalModule { Name = nsModule.Name, Namespaces = unprocessedNamespaces, ModuleType = nsModule.ModuleType, PlatformSpecific = nsModule.PlatformSpecific }; module.SourceFiles = analysis.Modules .Where(m => m.Namespaces.Any(ns => unprocessedNamespaces.Contains(ns))) .SelectMany(m => m.SourceFiles) .Distinct() .ToList(); mergedModules.Add(module); } } return mergedModules; } private string ExtractModuleNameFromNamespace(string namespaceName) { var parts = namespaceName.Split('.'); // Look for common module indicators var moduleIndicators = new[] { "Services", "Data", "UI", "API", "Core", "Helpers", "Utils", "Models", "Views", "Controllers" }; parts.Reverse(); foreach (var part in parts) { if (moduleIndicators.Contains(part, StringComparer.OrdinalIgnoreCase)) { return part; } } // Look for feature names (third part usually contains feature name) if (parts.Length >= 3) { return parts[2]; } // Fall back to last meaningful part return parts.LastOrDefault(p => !string.IsNullOrEmpty(p) && p.Length > 2) ?? "Unknown"; } private string DetermineModuleType(List namespaces) { var allNamespaces = string.Join(" ", namespaces).ToLower(); if (allNamespaces.Contains("service") || allNamespaces.Contains("api")) return "Service"; if (allNamespaces.Contains("data") || allNamespaces.Contains("repository")) return "Data"; if (allNamespaces.Contains("ui") || allNamespaces.Contains("view") || allNamespaces.Contains("page")) return "UI"; if (allNamespaces.Contains("model") || allNamespaces.Contains("entity")) return "Model"; if (allNamespaces.Contains("helper") || allNamespaces.Contains("util")) return "Utility"; if (allNamespaces.Contains("platform") || allNamespaces.Contains("ios") || allNamespaces.Contains("android")) return "Platform"; return "Library"; } private async Task> AnalyzeModuleDependenciesAsync(List modules, ProjectAnalysisResult analysis) { var dependencies = new List(); foreach (var fromModule in modules) { foreach (var toModule in modules) { if (fromModule.Name == toModule.Name) continue; var dependencyCount = await CountModuleDependencies(fromModule, toModule, analysis); if (dependencyCount > 0) { dependencies.Add(new ModuleDependency { From = fromModule.Name, To = toModule.Name, DependencyType = "Internal", ReferenceCount = dependencyCount, DependencyStrength = CalculateDependencyStrength(dependencyCount) }); } } } return dependencies; } private async Task CountModuleDependencies(LogicalModule fromModule, LogicalModule toModule, ProjectAnalysisResult analysis) { int count = 0; foreach (var sourceFile in fromModule.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); // Count using directives pointing to target module var usingDirectives = root.DescendantNodes().OfType(); foreach (var usingDirective in usingDirectives) { var namespaceName = usingDirective.Name?.ToString(); if (toModule.Namespaces.Any(ns => namespaceName?.StartsWith(ns) == true)) { count++; } } // Count type references var identifierNames = root.DescendantNodes().OfType(); foreach (var identifier in identifierNames) { // This is a simplified check - in practice, you'd want semantic analysis var identifierText = identifier.Identifier.ValueText; if (toModule.Namespaces.Any(ns => ns.EndsWith(identifierText))) { count++; } } } catch (Exception ex) { _logger?.LogWarning("Failed to analyze dependencies in {File}: {Error}", sourceFile, ex.Message); } } return count; } private string CalculateDependencyStrength(int referenceCount) { return referenceCount switch { > 20 => "Strong", > 5 => "Medium", _ => "Weak" }; } private async Task DetectPlatformSpecificModulesAsync(List modules, ProjectAnalysisResult analysis) { var platformPatterns = new Dictionary { ["iOS"] = new[] { "ios", "iphone", "ipad", "xamarin.ios", "uikit", "foundation" }, ["Android"] = new[] { "android", "xamarin.android", "androidx", "google.android" }, ["Windows"] = new[] { "windows", "win32", "uwp", "winui", "wpf" }, ["macOS"] = new[] { "macos", "osx", "appkit", "xamarin.mac" }, ["Web"] = new[] { "blazor", "web", "browser", "javascript" } }; foreach (var module in modules) { var moduleContent = string.Join(" ", module.Namespaces).ToLower(); foreach (var platform in platformPatterns) { if (platform.Value.Any(pattern => moduleContent.Contains(pattern))) { module.PlatformSpecific = true; module.Platforms.Add(platform.Key); } } // Check source files for platform-specific references foreach (var sourceFile in module.SourceFiles.Take(10)) // Sample to avoid performance issues { try { var content = await File.ReadAllTextAsync(sourceFile); var contentLower = content.ToLower(); foreach (var platform in platformPatterns) { if (platform.Value.Any(pattern => contentLower.Contains(pattern)) && !module.Platforms.Contains(platform.Key)) { module.PlatformSpecific = true; module.Platforms.Add(platform.Key); } } } catch (Exception ex) { _logger?.LogWarning("Failed to analyze platform specificity in {File}: {Error}", sourceFile, ex.Message); } } } } private async Task IdentifyModuleEntryPointsAsync(List modules, ProjectAnalysisResult analysis) { foreach (var module in modules) { var entryPoints = new List(); var publicInterfaces = new List(); foreach (var sourceFile in module.SourceFiles) { try { var content = await File.ReadAllTextAsync(sourceFile); var tree = CSharpSyntaxTree.ParseText(content); var root = await tree.GetRootAsync(); // Find public classes that could be entry points var publicClasses = root.DescendantNodes().OfType() .Where(c => c.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))); foreach (var publicClass in publicClasses) { var className = publicClass.Identifier.ValueText; // Entry point heuristics if (className.EndsWith("Service") || className.EndsWith("Manager") || className.EndsWith("Controller") || className.EndsWith("Client") || className.EndsWith("Facade") || className.EndsWith("Gateway")) { entryPoints.Add($"{Path.GetFileName(sourceFile)}:{className}"); } } // Find public interfaces var publicInterfaces_temp = root.DescendantNodes().OfType() .Where(i => i.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))); foreach (var publicInterface in publicInterfaces_temp) { var interfaceName = publicInterface.Identifier.ValueText; publicInterfaces.Add($"{Path.GetFileName(sourceFile)}:{interfaceName}"); } } catch (Exception ex) { _logger?.LogWarning("Failed to identify entry points in {File}: {Error}", sourceFile, ex.Message); } } module.EntryPoints = entryPoints; module.PublicInterfaces = publicInterfaces; } } private async Task AnalyzeModuleReusabilityAsync(List modules, List dependencies) { var analysis = new ReusabilityAnalysis(); foreach (var module in modules) { var incomingDeps = dependencies.Count(d => d.To == module.Name); var outgoingDeps = dependencies.Count(d => d.From == module.Name); var totalDeps = incomingDeps + outgoingDeps; var reusabilityScore = CalculateReusabilityScore(module, incomingDeps, outgoingDeps); var moduleReusability = new ModuleReusability { ModuleName = module.Name, ReusabilityScore = reusabilityScore, IncomingDependencies = incomingDeps, OutgoingDependencies = outgoingDeps, PlatformSpecific = module.PlatformSpecific, HasPublicInterfaces = module.PublicInterfaces.Any(), RecommendedFor = GenerateReusabilityRecommendations(module, reusabilityScore) }; analysis.ModuleReusability.Add(moduleReusability); // Categorize modules if (reusabilityScore > 0.8 && !module.PlatformSpecific) { analysis.HighlyReusableModules.Add(module.Name); } else if (module.PlatformSpecific) { analysis.PlatformSpecificModules.Add(module.Name); } else if (outgoingDeps > incomingDeps * 2) { analysis.UtilityModules.Add(module.Name); } } await Task.CompletedTask; return analysis; } private double CalculateReusabilityScore(LogicalModule module, int incomingDeps, int outgoingDeps) { double score = 0.5; // Base score // Factors that increase reusability if (module.PublicInterfaces.Any()) score += 0.2; if (!module.PlatformSpecific) score += 0.2; if (incomingDeps > 0) score += Math.Min(0.3, incomingDeps * 0.1); if (module.ModuleType == "Utility" || module.ModuleType == "Service") score += 0.1; // Factors that decrease reusability if (outgoingDeps > 5) score -= Math.Min(0.3, (outgoingDeps - 5) * 0.05); if (module.PlatformSpecific) score -= 0.2; return Math.Max(0, Math.Min(1, score)); } private List GenerateReusabilityRecommendations(LogicalModule module, double reusabilityScore) { var recommendations = new List(); if (reusabilityScore > 0.8) { recommendations.Add("Highly reusable - excellent candidate for shared libraries"); recommendations.Add("Consider packaging as NuGet package for cross-project use"); } else if (reusabilityScore > 0.6) { recommendations.Add("Good reusability potential with minor improvements"); if (!module.PublicInterfaces.Any()) recommendations.Add("Add public interfaces to improve API design"); } else { recommendations.Add("Limited reusability - consider refactoring if needed elsewhere"); if (module.PlatformSpecific) recommendations.Add("Platform-specific - abstract platform dependencies for reusability"); } return recommendations; } private Task GenerateDependencyMapAsync(ProjectAnalysisResult analysis, string format) { var result = format.ToLower() switch { "mermaid" => GenerateMermaidDiagram(analysis), "cytoscape" => GenerateCytoscapeJson(analysis), "graphviz" => GenerateGraphvizDot(analysis), _ => GenerateJsonMap(analysis) }; return Task.FromResult(result); } private object GenerateJsonMap(ProjectAnalysisResult analysis) { return new { metadata = new { generatedAt = DateTime.UtcNow, projectPath = analysis.ProjectPath, totalModules = analysis.Modules.Count, totalDependencies = analysis.Dependencies.Count }, nodes = analysis.Modules.Select(m => new { id = m.Name, label = m.Name, @namespace = m.Namespace, type = m.Type, lineCount = m.LineCount, classCount = m.ClassCount, targetFramework = m.TargetFramework, namespaces = m.Namespaces, projectPath = m.ProjectPath }), edges = analysis.Dependencies.Select(d => new { source = d.From, target = d.To, type = d.Type, strength = d.Strength, referenceCount = d.ReferenceCount }), externalDependencies = analysis.ExternalDependencies.Select(ed => new { name = ed.Name, version = ed.Version, type = ed.Type, usedBy = ed.UsedBy }) }; } private object GenerateModularJsonMap(ModularStructure modularStructure) { return new { metadata = new { generatedAt = modularStructure.GeneratedAt, groupingStrategy = modularStructure.GroupingStrategy, totalLogicalModules = modularStructure.Modules.Count, totalModuleDependencies = modularStructure.ModuleDependencies.Count, scaffoldingCompatible = true, llmOptimized = true }, modules = modularStructure.Modules.Select(m => new { // Core module information name = m.Name, namespaces = m.Namespaces, moduleType = m.ModuleType, platformSpecific = m.PlatformSpecific, platforms = m.Platforms, entryPoints = m.EntryPoints, publicInterfaces = m.PublicInterfaces, externalDependencies = m.ExternalDependencies, // Dependencies and relationships dependsOn = modularStructure.ModuleDependencies .Where(d => d.From == m.Name) .Select(d => d.To) .ToList(), usedBy = modularStructure.ModuleDependencies .Where(d => d.To == m.Name) .Select(d => d.From) .ToList(), // Metrics sourceFileCount = m.SourceFiles.Count, reusabilityScore = modularStructure.ReusabilityAnalysis?.ModuleReusability .FirstOrDefault(r => r.ModuleName == m.Name)?.ReusabilityScore ?? 0, // New generation-focused properties tags = m.Tags, // Module flags for CLI/LLM usage optional = m.ModuleFlags?.Optional ?? true, defaultIncluded = m.ModuleFlags?.DefaultIncluded ?? false, coreModule = m.ModuleFlags?.CoreModule ?? false, experimentalFeature = m.ModuleFlags?.ExperimentalFeature ?? false, requiresConfiguration = m.ModuleFlags?.RequiresConfiguration ?? false, hasBreakingChanges = m.ModuleFlags?.HasBreakingChanges ?? false, // Scaffolding metadata scaffoldable = m.ScaffoldingMetadata?.Scaffoldable ?? false, minimumDependencies = m.ScaffoldingMetadata?.MinimumDependencies ?? new List(), lastUpdated = m.ScaffoldingMetadata?.LastUpdated ?? DateTime.UtcNow, isDeprecated = m.ScaffoldingMetadata?.IsDeprecated ?? false, complexityScore = m.ScaffoldingMetadata?.ComplexityScore ?? 0, setupInstructions = m.ScaffoldingMetadata?.SetupInstructions ?? new List(), configurationFiles = m.ScaffoldingMetadata?.ConfigurationFiles ?? new List(), requiredEnvironmentVariables = m.ScaffoldingMetadata?.RequiredEnvironmentVariables ?? new List(), // LLM-friendly descriptions promptDescription = m.LlmMetadata?.PromptDescription ?? $"The {m.Name} module provides {m.ModuleType.ToLower()} functionality.", usageExample = m.LlmMetadata?.UsageExample ?? "", integrationNotes = m.LlmMetadata?.IntegrationNotes ?? new List(), commonUseCases = m.LlmMetadata?.CommonUseCases ?? new List(), alternativeModules = m.LlmMetadata?.AlternativeModules ?? new List() }), moduleDependencies = modularStructure.ModuleDependencies.Select(d => new { from = d.From, to = d.To, dependencyType = d.DependencyType, referenceCount = d.ReferenceCount, dependencyStrength = d.DependencyStrength }), reusabilityAnalysis = new { highlyReusableModules = modularStructure.ReusabilityAnalysis?.HighlyReusableModules ?? new List(), platformSpecificModules = modularStructure.ReusabilityAnalysis?.PlatformSpecificModules ?? new List(), utilityModules = modularStructure.ReusabilityAnalysis?.UtilityModules ?? new List(), moduleReusability = modularStructure.ReusabilityAnalysis?.ModuleReusability?.Select(r => new { moduleName = r.ModuleName, reusabilityScore = r.ReusabilityScore, incomingDependencies = r.IncomingDependencies, outgoingDependencies = r.OutgoingDependencies, platformSpecific = r.PlatformSpecific, hasPublicInterfaces = r.HasPublicInterfaces, recommendedFor = r.RecommendedFor }).Cast().ToList() ?? new List() }, // New generation-focused analysis scaffoldingGuide = new { coreModules = modularStructure.Modules .Where(m => m.ModuleFlags?.CoreModule == true) .Select(m => m.Name) .ToList(), optionalModules = modularStructure.Modules .Where(m => m.ModuleFlags?.Optional == true) .Select(m => new { name = m.Name, tags = m.Tags }) .ToList(), platformModules = modularStructure.Modules .Where(m => m.PlatformSpecific) .GroupBy(m => m.Platforms.FirstOrDefault() ?? "Unknown") .ToDictionary(g => g.Key, g => g.Select(m => m.Name).ToList()), deprecatedModules = modularStructure.Modules .Where(m => m.ScaffoldingMetadata?.IsDeprecated == true) .Select(m => m.Name) .ToList() }, llmPromptData = new { totalModules = modularStructure.Modules.Count, modulesByCategory = modularStructure.Modules .GroupBy(m => m.ModuleType) .ToDictionary(g => g.Key, g => g.Select(m => new { name = m.Name, description = m.LlmMetadata?.PromptDescription ?? "", tags = m.Tags, optional = m.ModuleFlags?.Optional ?? true }).ToList()), commonCombinations = GenerateCommonModuleCombinations(modularStructure.Modules), quickStartModules = modularStructure.Modules .Where(m => m.ModuleFlags?.DefaultIncluded == true) .Select(m => m.Name) .ToList() } }; } private List GenerateCommonModuleCombinations(List modules) { var combinations = new List(); // Web API combination var webApiModules = modules.Where(m => m.Tags.Contains("api") || m.Tags.Contains("auth") || m.Tags.Contains("database")) .Select(m => m.Name).ToList(); if (webApiModules.Any()) { combinations.Add(new { name = "Web API Stack", modules = webApiModules, useCase = "RESTful API development" }); } // Mobile app combination var mobileModules = modules.Where(m => m.Tags.Contains("ui") || m.Tags.Contains("auth") || m.Tags.Contains("offline") || m.Tags.Contains("notification")) .Select(m => m.Name).ToList(); if (mobileModules.Any()) { combinations.Add(new { name = "Mobile App Stack", modules = mobileModules, useCase = "Cross-platform mobile application" }); } // Analytics combination var analyticsModules = modules.Where(m => m.Tags.Contains("analytics") || m.Tags.Contains("logging") || m.Tags.Contains("database")) .Select(m => m.Name).ToList(); if (analyticsModules.Any()) { combinations.Add(new { name = "Analytics Stack", modules = analyticsModules, useCase = "Data tracking and analysis" }); } return combinations; } private async Task GenerateScaffoldingMetadataAsync(List modules, ProjectAnalysisResult analysis, ModularOptions options) { foreach (var module in modules) { try { // Analyze module complexity and dependencies var moduleDependencies = await AnalyzeModuleDependencyComplexity(module, modules, analysis); // Determine if module is scaffoldable module.ScaffoldingMetadata = new ScaffoldingMetadata { Scaffoldable = DetermineIfScaffoldable(module), MinimumDependencies = moduleDependencies.Where(d => d.IsRequired).Select(d => d.ModuleName).ToList(), LastUpdated = await GetModuleLastUpdated(module), IsDeprecated = await CheckIfDeprecated(module), ComplexityScore = CalculateModuleComplexity(module), SetupInstructions = GenerateSetupInstructions(module), ConfigurationFiles = await IdentifyConfigurationFiles(module), RequiredEnvironmentVariables = await IdentifyRequiredEnvironmentVariables(module) }; } catch (Exception ex) { _logger?.LogWarning("Failed to generate scaffolding metadata for module {Module}: {Error}", module.Name, ex.Message); } } } private async Task AnalyzeModuleTagsAsync(List modules, ProjectAnalysisResult analysis) { var tagPatterns = new Dictionary { ["auth"] = new[] { "authentication", "login", "oauth", "jwt", "identity", "security", "token" }, ["navigation"] = new[] { "navigation", "routing", "menu", "page", "route" }, ["offline"] = new[] { "offline", "cache", "sync", "storage", "local" }, ["firebase"] = new[] { "firebase", "firestore", "messaging", "analytics", "crashlytics" }, ["database"] = new[] { "database", "sql", "entity", "repository", "orm" }, ["api"] = new[] { "api", "http", "rest", "client", "service", "endpoint" }, ["ui"] = new[] { "ui", "view", "component", "control", "widget", "page" }, ["notification"] = new[] { "notification", "push", "alert", "message" }, ["analytics"] = new[] { "analytics", "tracking", "metrics", "telemetry" }, ["payment"] = new[] { "payment", "billing", "stripe", "paypal", "checkout" }, ["media"] = new[] { "image", "video", "audio", "camera", "photo" }, ["location"] = new[] { "location", "gps", "map", "geolocation" }, ["social"] = new[] { "social", "share", "facebook", "twitter", "instagram" }, ["testing"] = new[] { "test", "mock", "stub", "unit", "integration" }, ["logging"] = new[] { "log", "logger", "diagnostic", "debug", "trace" }, ["configuration"] = new[] { "config", "setting", "preference", "option" }, ["crypto"] = new[] { "crypto", "encryption", "hash", "cipher", "secure" }, ["network"] = new[] { "network", "connectivity", "reachability", "internet" } }; foreach (var module in modules) { var tags = new HashSet(); var moduleContent = string.Join(" ", module.Namespaces).ToLower(); // Add class names and comments for better tag detection var allContent = moduleContent; foreach (var sourceFile in module.SourceFiles.Take(10)) // Limit for performance { try { var content = await File.ReadAllTextAsync(sourceFile); allContent += " " + content.ToLower(); } catch { // Ignore file read errors } } foreach (var tagPattern in tagPatterns) { if (tagPattern.Value.Any(pattern => allContent.Contains(pattern))) { tags.Add(tagPattern.Key); } } // Add module type as a tag tags.Add(module.ModuleType.ToLower()); // Add platform tags if platform-specific if (module.PlatformSpecific) { foreach (var platform in module.Platforms) { tags.Add(platform.ToLower()); } } module.Tags = tags.ToList(); } } private async Task GenerateLlmDescriptionsAsync(List modules, ProjectAnalysisResult analysis) { foreach (var module in modules) { try { var description = await GenerateModuleDescription(module, analysis); module.LlmMetadata = new LlmMetadata { PromptDescription = description, UsageExample = GenerateUsageExample(module), IntegrationNotes = GenerateIntegrationNotes(module), CommonUseCases = GenerateCommonUseCases(module), AlternativeModules = await FindAlternativeModules(module, modules) }; } catch (Exception ex) { _logger?.LogWarning("Failed to generate LLM description for module {Module}: {Error}", module.Name, ex.Message); } } } private async Task SetModuleFlagsAsync(List modules, ProjectAnalysisResult analysis) { foreach (var module in modules) { module.ModuleFlags = new ModuleFlags { Optional = DetermineIfOptional(module), DefaultIncluded = DetermineDefaultIncluded(module), CoreModule = DetermineIfCoreModule(module, modules), ExperimentalFeature = await CheckIfExperimental(module), RequiresConfiguration = await CheckIfRequiresConfiguration(module), HasBreakingChanges = await CheckForBreakingChanges(module) }; } } // Helper methods for scaffolding metadata private bool DetermineIfScaffoldable(LogicalModule module) { // Modules are scaffoldable if they have clear interfaces and aren't too complex return module.PublicInterfaces.Any() && !module.Name.ToLower().Contains("legacy") && !module.Name.ToLower().Contains("deprecated"); } private Task GetModuleLastUpdated(LogicalModule module) { try { var latestDate = DateTime.MinValue; foreach (var file in module.SourceFiles.Take(10)) // Sample for performance { if (File.Exists(file)) { var fileInfo = new FileInfo(file); if (fileInfo.LastWriteTime > latestDate) { latestDate = fileInfo.LastWriteTime; } } } return Task.FromResult(latestDate == DateTime.MinValue ? DateTime.UtcNow : latestDate); } catch { return Task.FromResult(DateTime.UtcNow); } } private async Task CheckIfDeprecated(LogicalModule module) { try { foreach (var file in module.SourceFiles.Take(5)) { var content = await File.ReadAllTextAsync(file); if (content.ToLower().Contains("deprecated") || content.ToLower().Contains("obsolete") || content.Contains("[Obsolete")) { return true; } } return false; } catch { return false; } } private double CalculateModuleComplexity(LogicalModule module) { // Simple complexity calculation based on various factors double complexity = 0; complexity += module.SourceFiles.Count * 0.1; // File count factor complexity += module.PublicInterfaces.Count * 0.2; // Interface complexity complexity += module.EntryPoints.Count * 0.15; // Entry point complexity complexity += module.Namespaces.Count * 0.05; // Namespace spread if (module.PlatformSpecific) complexity += 0.3; // Platform complexity return Math.Min(1.0, complexity); // Cap at 1.0 } private List GenerateSetupInstructions(LogicalModule module) { var instructions = new List(); instructions.Add($"1. Add reference to {module.Name} module"); if (module.PublicInterfaces.Any()) { instructions.Add($"2. Register services/interfaces in DI container"); } if (module.PlatformSpecific) { instructions.Add($"3. Configure platform-specific settings for {string.Join(", ", module.Platforms)}"); } if (module.Tags.Contains("configuration")) { instructions.Add($"4. Update configuration files with required settings"); } instructions.Add($"5. Initialize {module.Name} in application startup"); return instructions; } private Task> IdentifyConfigurationFiles(LogicalModule module) { var configFiles = new List(); var configPatterns = new[] { "config", "settings", "appsettings", "web.config", ".json", ".xml", ".yml", ".yaml" }; foreach (var file in module.SourceFiles) { var fileName = Path.GetFileName(file).ToLower(); if (configPatterns.Any(pattern => fileName.Contains(pattern))) { configFiles.Add(fileName); } } return Task.FromResult(configFiles.Distinct().ToList()); } private async Task> IdentifyRequiredEnvironmentVariables(LogicalModule module) { var envVars = new HashSet(); var envPatterns = new[] { "Environment.GetEnvironmentVariable", "Environment.GetVariable", "Environment[", "GetEnvironmentVariable", "env.", "process.env" }; foreach (var file in module.SourceFiles.Take(10)) { try { var content = await File.ReadAllTextAsync(file); foreach (var pattern in envPatterns) { if (content.Contains(pattern)) { // Simple extraction - could be enhanced with regex var lines = content.Split('\n').Where(l => l.Contains(pattern)); foreach (var line in lines) { var envVarMatch = ExtractEnvironmentVariableName(line); if (!string.IsNullOrEmpty(envVarMatch)) { envVars.Add(envVarMatch); } } } } } catch { // Ignore file read errors } } return envVars.ToList(); } private string? ExtractEnvironmentVariableName(string line) { // Simple extraction - looks for quoted strings after environment variable calls var patterns = new[] { @"Environment\.GetEnvironmentVariable\(\s*""([^""]+)""", @"Environment\[\s*""([^""]+)""", @"process\.env\.([A-Z_]+)", @"env\.([A-Z_]+)" }; foreach (var pattern in patterns) { var match = System.Text.RegularExpressions.Regex.Match(line, pattern); if (match.Success) { return match.Groups[1].Value; } } return null; } private async Task GenerateModuleDescription(LogicalModule module, ProjectAnalysisResult analysis) { var description = $"The '{module.Name}' module is a {module.ModuleType.ToLower()} component that "; // Add functionality description based on tags var functionDescriptions = new List(); if (module.Tags.Contains("auth")) functionDescriptions.Add("handles user authentication and authorization"); if (module.Tags.Contains("api")) functionDescriptions.Add("provides API integration and data communication"); if (module.Tags.Contains("ui")) functionDescriptions.Add("manages user interface components and interactions"); if (module.Tags.Contains("database")) functionDescriptions.Add("manages data persistence and database operations"); if (module.Tags.Contains("analytics")) functionDescriptions.Add("tracks user behavior and application metrics"); if (module.Tags.Contains("notification")) functionDescriptions.Add("manages push notifications and messaging"); if (functionDescriptions.Any()) { description += string.Join(", ", functionDescriptions); } else { description += $"provides {module.ModuleType.ToLower()} functionality"; } // Add platform information if (module.PlatformSpecific) { description += $" specifically for {string.Join(" and ", module.Platforms)} platforms"; } // Add dependency information if (module.EntryPoints.Any()) { description += $". Main entry points include {string.Join(", ", module.EntryPoints.Take(3))}"; } description += "."; await Task.CompletedTask; return description; } private string GenerateUsageExample(LogicalModule module) { if (module.EntryPoints.Any()) { var mainEntry = module.EntryPoints.First(); var serviceName = mainEntry.Split(':').Last(); return $"// Example usage:\nvar {serviceName.ToLower()} = new {serviceName}();\n// Use {serviceName.ToLower()} for {module.ModuleType.ToLower()} operations"; } return $"// Register {module.Name} module in your DI container\nservices.Add{module.Name}();"; } private List GenerateIntegrationNotes(LogicalModule module) { var notes = new List(); if (module.PlatformSpecific) { notes.Add($"Platform-specific module - requires {string.Join(", ", module.Platforms)} runtime"); } if (module.Tags.Contains("configuration")) { notes.Add("Requires configuration setup before use"); } if (module.Tags.Contains("api")) { notes.Add("May require API keys or authentication tokens"); } if (module.Tags.Contains("database")) { notes.Add("Requires database connection configuration"); } return notes; } private List GenerateCommonUseCases(LogicalModule module) { var useCases = new List(); foreach (var tag in module.Tags.Take(5)) { var useCase = tag switch { "auth" => "User login and session management", "api" => "External service integration and data synchronization", "ui" => "Building responsive user interfaces", "database" => "Data storage and retrieval operations", "analytics" => "User behavior tracking and reporting", "notification" => "Real-time user notifications", "payment" => "Processing financial transactions", "media" => "Image and video processing", _ => $"General {tag} functionality" }; useCases.Add(useCase); } return useCases; } private async Task> FindAlternativeModules(LogicalModule module, List allModules) { var alternatives = new List(); // Find modules with similar tags foreach (var otherModule in allModules) { if (otherModule.Name == module.Name) continue; var commonTags = module.Tags.Intersect(otherModule.Tags).Count(); if (commonTags >= 2) // At least 2 common tags { alternatives.Add(otherModule.Name); } } await Task.CompletedTask; return alternatives.Take(3).ToList(); // Limit to top 3 alternatives } private bool DetermineIfOptional(LogicalModule module) { // Core functionality modules are not optional var coreModules = new[] { "core", "data", "api", "auth", "main" }; return !coreModules.Any(core => module.Name.ToLower().Contains(core)) && !module.Tags.Contains("auth") && module.ModuleType != "Service"; } private bool DetermineDefaultIncluded(LogicalModule module) { // Include core modules and commonly used utilities by default return module.Tags.Contains("auth") || module.Tags.Contains("api") || module.Tags.Contains("ui") || module.ModuleType == "Service" || module.Name.ToLower().Contains("core"); } private bool DetermineIfCoreModule(LogicalModule module, List allModules) { // A module is core if many other modules depend on it var dependents = allModules.Count(m => m.Namespaces.Any(ns => module.Namespaces.Any(mns => ns.StartsWith(mns)))); return dependents > allModules.Count * 0.3 || // More than 30% of modules depend on it module.Name.ToLower().Contains("core") || module.Tags.Contains("auth"); } private async Task CheckIfExperimental(LogicalModule module) { try { foreach (var file in module.SourceFiles.Take(5)) { var content = await File.ReadAllTextAsync(file); if (content.ToLower().Contains("experimental") || content.ToLower().Contains("preview") || content.ToLower().Contains("beta")) { return true; } } return false; } catch { return false; } } private async Task CheckIfRequiresConfiguration(LogicalModule module) { return module.Tags.Contains("configuration") || module.Tags.Contains("api") || module.Tags.Contains("database") || module.PlatformSpecific || (await IdentifyConfigurationFiles(module)).Any(); } private async Task CheckForBreakingChanges(LogicalModule module) { try { foreach (var file in module.SourceFiles.Take(5)) { var content = await File.ReadAllTextAsync(file); if (content.Contains("BREAKING") || content.Contains("breaking change") || content.Contains("incompatible")) { return true; } } return false; } catch { return false; } } private async Task> AnalyzeModuleDependencyComplexity(LogicalModule module, List allModules, ProjectAnalysisResult analysis) { var dependencies = new List(); foreach (var otherModule in allModules) { if (otherModule.Name == module.Name) continue; var dependencyCount = await CountModuleDependencies(module, otherModule, analysis); if (dependencyCount > 0) { dependencies.Add(new ModuleDependencyInfo { ModuleName = otherModule.Name, IsRequired = dependencyCount > 5 || otherModule.Tags.Contains("auth"), // Heuristic ComplexityImpact = CalculateDependencyComplexity(dependencyCount, otherModule) }); } } return dependencies; } private double CalculateDependencyComplexity(int dependencyCount, LogicalModule targetModule) { double complexity = dependencyCount * 0.1; if (targetModule.PlatformSpecific) complexity += 0.3; if (targetModule.Tags.Contains("api")) complexity += 0.2; return Math.Min(1.0, complexity); } public class AnalysisOptions { public bool IncludeExternalDependencies { get; set; } public bool InternalOnly { get; set; } public int MaxDepth { get; set; } public string? NamespaceFilter { get; set; } public bool IncludeMethodLevel { get; set; } public bool EnableModuleGrouping { get; set; } public string ModuleGroupingStrategy { get; set; } = string.Empty; public bool DetectPlatformModules { get; set; } public bool IncludeEntryPoints { get; set; } public bool GenerateModuleDefinitions { get; set; } public bool GenerateScaffoldingMetadata { get; set; } public bool IncludeLlmDescriptions { get; set; } public bool AnalyzeModuleTags { get; set; } public bool IncludeModuleFlags { get; set; } } public class ModularStructure { public DateTime GeneratedAt { get; set; } public string GroupingStrategy { get; set; } = string.Empty; public List Modules { get; set; } = new(); public List ModuleDependencies { get; set; } = new(); public ReusabilityAnalysis ReusabilityAnalysis { get; set; } = new(); } public class ModuleDependency { public string From { get; set; } = string.Empty; public string To { get; set; } = string.Empty; public string DependencyType { get; set; } = string.Empty; public int ReferenceCount { get; set; } public string DependencyStrength { get; set; } = string.Empty; } public class ReusabilityAnalysis { public List HighlyReusableModules { get; set; } = new(); public List PlatformSpecificModules { get; set; } = new(); public List UtilityModules { get; set; } = new(); public List ModuleReusability { get; set; } = new(); } public class ModuleReusability { public string ModuleName { get; set; } = string.Empty; public double ReusabilityScore { get; set; } public int IncomingDependencies { get; set; } public int OutgoingDependencies { get; set; } public bool PlatformSpecific { get; set; } public bool HasPublicInterfaces { get; set; } public List RecommendedFor { get; set; } = new(); } // Update the GenerateDependencyMapAsync method to handle modular structure private Task GenerateDependencyMapAsync(ProjectAnalysisResult analysis, string format, ModularStructure? modularStructure = null) { // If we have modular structure, use it for enhanced visualization if (modularStructure != null) { var result = format.ToLower() switch { "mermaid" => GenerateModularMermaidDiagram(modularStructure), "cytoscape" => GenerateModularCytoscapeJson(modularStructure), "graphviz" => GenerateModularGraphvizDot(modularStructure), _ => GenerateModularJsonMap(modularStructure) }; return Task.FromResult(result); } // Fall back to project-level analysis var fallbackResult = format.ToLower() switch { "mermaid" => GenerateMermaidDiagram(analysis), "cytoscape" => GenerateCytoscapeJson(analysis), "graphviz" => GenerateGraphvizDot(analysis), _ => GenerateJsonMap(analysis) }; return Task.FromResult(fallbackResult); } private string GenerateModularMermaidDiagram(ModularStructure modularStructure) { var mermaid = new StringBuilder(); mermaid.AppendLine("graph TD"); // Add nodes with enhanced styling based on module properties foreach (var module in modularStructure.Modules) { var nodeStyle = GetModuleStyle(module); var platformInfo = module.PlatformSpecific ? $"
[{string.Join(",", module.Platforms)}]" : ""; mermaid.AppendLine($" {SanitizeNodeName(module.Name)}[\"{module.Name}
({module.ModuleType}){platformInfo}\"] {nodeStyle}"); } // Add dependencies with enhanced information foreach (var dependency in modularStructure.ModuleDependencies) { var arrow = dependency.DependencyStrength switch { "Strong" => "==>", "Medium" => "-->", _ => "-..->" }; var label = dependency.ReferenceCount > 1 ? $"|{dependency.ReferenceCount}|" : ""; mermaid.AppendLine($" {SanitizeNodeName(dependency.From)} {arrow} {SanitizeNodeName(dependency.To)} {label}"); } // Add enhanced styling mermaid.AppendLine(); mermaid.AppendLine(" classDef service fill:#e3f2fd,stroke:#1976d2,stroke-width:2px"); mermaid.AppendLine(" classDef ui fill:#fce4ec,stroke:#c2185b,stroke-width:2px"); mermaid.AppendLine(" classDef data fill:#e8f5e8,stroke:#388e3c,stroke-width:2px"); mermaid.AppendLine(" classDef platform fill:#fff3e0,stroke:#f57c00,stroke-width:2px"); mermaid.AppendLine(" classDef utility fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px"); return mermaid.ToString(); } private string GetModuleStyle(LogicalModule module) { return module.ModuleType.ToLower() switch { "service" => ":::service", "ui" => ":::ui", "data" => ":::data", "platform" => ":::platform", "utility" => ":::utility", _ => "" }; } private object GenerateModularCytoscapeJson(ModularStructure modularStructure) { return new { elements = new { nodes = modularStructure.Modules.Select(m => new { data = new { id = m.Name, label = m.Name, moduleType = m.ModuleType, platformSpecific = m.PlatformSpecific, platforms = string.Join(",", m.Platforms), entryPointCount = m.EntryPoints.Count, interfaceCount = m.PublicInterfaces.Count, sourceFileCount = m.SourceFiles.Count, reusabilityScore = modularStructure.ReusabilityAnalysis?.ModuleReusability .FirstOrDefault(r => r.ModuleName == m.Name)?.ReusabilityScore ?? 0 } }), edges = modularStructure.ModuleDependencies.Select(d => new { data = new { source = d.From, target = d.To, dependencyType = d.DependencyType, dependencyStrength = d.DependencyStrength, weight = d.ReferenceCount } }) }, style = new object[] { new { selector = "node", style = new { content = "data(label)", width = "mapData(sourceFileCount, 1, 50, 30, 100)", height = "mapData(entryPointCount, 0, 10, 30, 80)", backgroundColor = "mapData(reusabilityScore, 0, 1, #ff6b6b, #51cf66)", borderWidth = "mapData(interfaceCount, 0, 5, 1, 5)", borderColor = "#333" } }, new { selector = "node[platformSpecific = 'true']", style = new { shape = "diamond" } }, new { selector = "edge", style = new { width = "mapData(weight, 1, 20, 2, 8)", lineColor = "mapData(weight, 1, 20, #ddd, #333)", targetArrowColor = "mapData(weight, 1, 20, #ddd, #333)", targetArrowShape = "triangle", curveStyle = "bezier" } } }, layout = new { name = "cose", directed = true, padding = 20, nodeRepulsion = 400000, idealEdgeLength = 100, edgeElasticity = 100 } }; } private string GenerateModularGraphvizDot(ModularStructure modularStructure) { var dot = new StringBuilder(); dot.AppendLine("digraph ModularMap {"); dot.AppendLine(" rankdir=TB;"); dot.AppendLine(" node [shape=box, style=filled];"); dot.AppendLine(" edge [fontsize=10];"); dot.AppendLine(); // Group modules by type for better layout var modulesByType = modularStructure.Modules.GroupBy(m => m.ModuleType); foreach (var typeGroup in modulesByType) { dot.AppendLine($" subgraph cluster_{typeGroup.Key.ToLower()} {{"); dot.AppendLine($" label=\"{typeGroup.Key} Modules\";"); dot.AppendLine(" style=rounded;"); foreach (var module in typeGroup) { var color = GetGraphvizColor(module); var shape = module.PlatformSpecific ? "diamond" : "box"; var platformInfo = module.PlatformSpecific ? $"\\n[{string.Join(",", module.Platforms)}]" : ""; var label = $"{module.Name}\\n({module.ModuleType}){platformInfo}\\n{module.SourceFiles.Count} files"; dot.AppendLine($" \"{module.Name}\" [label=\"{label}\", fillcolor={color}, shape={shape}];"); } dot.AppendLine(" }"); dot.AppendLine(); } // Add edges with enhanced styling foreach (var dependency in modularStructure.ModuleDependencies) { var style = dependency.DependencyStrength switch { "Strong" => "bold", "Medium" => "solid", _ => "dashed" }; var color = dependency.DependencyStrength switch { "Strong" => "red", "Medium" => "blue", _ => "gray" }; var label = dependency.ReferenceCount > 1 ? $"[label=\"{dependency.ReferenceCount}\"]" : ""; dot.AppendLine($" \"{dependency.From}\" -> \"{dependency.To}\" [style={style}, color={color}] {label};"); } dot.AppendLine("}"); return dot.ToString(); } private string GetGraphvizColor(LogicalModule module) { return module.ModuleType.ToLower() switch { "service" => "lightblue", "ui" => "lightpink", "data" => "lightgreen", "platform" => "orange", "utility" => "lightyellow", _ => "lightgray" }; } // Update the main execution method to use the new GenerateDependencyMapAsync signature // (This would go in the ExecuteAsync method where GenerateDependencyMapAsync is called) // var dependencyMap = await GenerateDependencyMapAsync(analysisResult, outputFormat, modularStructure); } // Supporting data structures public class AnalysisOptions { public bool IncludeExternalDependencies { get; set; } public bool InternalOnly { get; set; } public int MaxDepth { get; set; } public string? NamespaceFilter { get; set; } public bool IncludeMethodLevel { get; set; } } public class ProjectAnalysisResult { public string ProjectPath { get; set; } = string.Empty; public List Modules { get; set; } = new(); public List Dependencies { get; set; } = new(); public List ExternalDependencies { get; set; } = new(); public int MaxDepthReached { get; set; } } public class ModuleInfo { public string Name { get; set; } = string.Empty; public string Namespace { get; set; } = string.Empty; public string Type { get; set; } = string.Empty; // Library, WebAPI, Console, etc. public int LineCount { get; set; } public int ClassCount { get; set; } public string TargetFramework { get; set; } = string.Empty; public string ProjectPath { get; set; } = string.Empty; public List SourceFiles { get; set; } = new(); public List Namespaces { get; set; } = new(); public List Classes { get; set; } = new(); } public class DependencyInfo { public string From { get; set; } = string.Empty; public string To { get; set; } = string.Empty; public string Type { get; set; } = string.Empty; // ProjectReference, PackageReference, NamespaceReference public string Strength { get; set; } = string.Empty; // Strong, Medium, Weak public int ReferenceCount { get; set; } } public class ExternalDependencyInfo { public string Name { get; set; } = string.Empty; public string Version { get; set; } = string.Empty; public string Type { get; set; } = string.Empty; // NuGet, Framework public List UsedBy { get; set; } = new(); } public class CouplingMetrics { public double OverallCouplingScore { get; set; } public List HighlyCoupledModules { get; set; } = new(); public List LooselyCoupledModules { get; set; } = new(); public Dictionary InstabilityScores { get; set; } = new(); public List CircularDependencies { get; set; } = new(); public List Recommendations { get; set; } = new(); } public class ModuleCouplingMetrics { public int AfferentCoupling { get; set; } public int EfferentCoupling { get; set; } public double Instability { get; set; } public double Abstractness { get; set; } public double Distance { get; set; } } public class ArchitecturalPatterns { public string DetectedPattern { get; set; } = string.Empty; public double Confidence { get; set; } public List PatternViolations { get; set; } = new(); public Dictionary> LayerDefinitions { get; set; } = new(); public List Suggestions { get; set; } = new(); } public class ArchitecturalInsights { public double OverallArchitectureScore { get; set; } public List StrengthAreas { get; set; } = new(); public List ImprovementAreas { get; set; } = new(); public List RefactoringOpportunities { get; set; } = new(); public List DesignPatternSuggestions { get; set; } = new(); } public class RefactoringOpportunity { public string Type { get; set; } = string.Empty; public string Target { get; set; } = string.Empty; public string Benefit { get; set; } = string.Empty; public string Effort { get; set; } = string.Empty; // Low, Medium, High public string Priority { get; set; } = string.Empty; // Low, Medium, High } public class LogicalModule { public string Name { get; set; } = string.Empty; public List Namespaces { get; set; } = new(); public string ModuleType { get; set; } = string.Empty; public bool PlatformSpecific { get; set; } public List Platforms { get; set; } = new(); public List EntryPoints { get; set; } = new(); public List PublicInterfaces { get; set; } = new(); public List ExternalDependencies { get; set; } = new(); public List SourceFiles { get; set; } = new(); // Add these missing properties public List Tags { get; set; } = new(); public ScaffoldingMetadata ScaffoldingMetadata { get; set; } = new(); public LlmMetadata LlmMetadata { get; set; } = new(); public ModuleFlags ModuleFlags { get; set; } = new(); } // Add these missing properties to the existing ModularOptions class public class ModularOptions { public string GroupingStrategy { get; set; } = string.Empty; public bool DetectPlatformModules { get; set; } public bool IncludeEntryPoints { get; set; } // Add these missing properties public bool GenerateScaffoldingMetadata { get; set; } public bool IncludeLlmDescriptions { get; set; } public bool AnalyzeModuleTags { get; set; } public bool IncludeModuleFlags { get; set; } } // Add these missing classes public class ScaffoldingMetadata { public bool Scaffoldable { get; set; } public List MinimumDependencies { get; set; } = new(); public DateTime LastUpdated { get; set; } public bool IsDeprecated { get; set; } public double ComplexityScore { get; set; } public List SetupInstructions { get; set; } = new(); public List ConfigurationFiles { get; set; } = new(); public List RequiredEnvironmentVariables { get; set; } = new(); } public class LlmMetadata { public string PromptDescription { get; set; } = string.Empty; public string UsageExample { get; set; } = string.Empty; public List IntegrationNotes { get; set; } = new(); public List CommonUseCases { get; set; } = new(); public List AlternativeModules { get; set; } = new(); } public class ModuleFlags { public bool Optional { get; set; } public bool DefaultIncluded { get; set; } public bool CoreModule { get; set; } public bool ExperimentalFeature { get; set; } public bool RequiresConfiguration { get; set; } public bool HasBreakingChanges { get; set; } } public class ModuleDependencyInfo { public string ModuleName { get; set; } = string.Empty; public bool IsRequired { get; set; } public double ComplexityImpact { get; set; } } }