using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Analysis.Plugins { public class CompilationManager { public CompilationManager() { } public async Task ValidateCompilationAsync(string solutionPath) { var result = new CompilationResult { StartTime = DateTime.UtcNow, SolutionPath = solutionPath }; try { // Use dotnet build to validate compilation var processInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = $"build \"{solutionPath}\" --verbosity quiet --nologo", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processInfo); if (process == null) { throw new InvalidOperationException("Failed to start dotnet build process"); } var output = await process.StandardOutput.ReadToEndAsync(); var error = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); result.ExitCode = process.ExitCode; result.BuildOutput = output; result.BuildErrors = error; // Parse compilation results result.Status = process.ExitCode == 0 ? CompilationStatus.Success : CompilationStatus.Failed; // Use existing parsing logic from WarningsAnalysisPlugin result.Warnings = ParseWarningsFromBuildOutput(output + error); result.Errors = ParseErrorsFromBuildOutput(output + error); result.ErrorCount = result.Errors.Count; result.WarningCount = result.Warnings.Count; // Adjust status based on warnings if (result.Status == CompilationStatus.Success && result.WarningCount > 0) { result.Status = CompilationStatus.Warning; } } catch (Exception ex) { result.Status = CompilationStatus.Failed; result.ErrorMessage = ex.Message; } finally { result.EndTime = DateTime.UtcNow; result.Duration = result.EndTime - result.StartTime; } return result; } private List ParseWarningsFromBuildOutput(string buildOutput) { var warnings = new List(); var lines = buildOutput.Split('\n', StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (line.Contains("warning", StringComparison.OrdinalIgnoreCase)) { var warning = TryParseDiagnosticLine(line.Trim(), "warning"); if (warning != null) { warnings.Add(warning); } } } return warnings; } private List ParseErrorsFromBuildOutput(string buildOutput) { var errors = new List(); var lines = buildOutput.Split('\n', StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (line.Contains("error", StringComparison.OrdinalIgnoreCase) && !line.Contains("warning", StringComparison.OrdinalIgnoreCase)) { var error = TryParseDiagnosticLine(line.Trim(), "error"); if (error != null) { errors.Add(error); } } } return errors; } private CompilationDiagnostic? TryParseDiagnosticLine(string line, string type) { var patterns = new[] { @"(.+?)\((\d+),(\d+)\):\s*warning\s+([A-Z]+\d+):\s*(.+)", @"warning\s+([A-Z]+\d+):\s*(.+)\s*\[(.+?)\]" }; foreach (var pattern in patterns) { var match = System.Text.RegularExpressions.Regex.Match(line, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase); if (match.Success) { if (match.Groups.Count >= 5 && !string.IsNullOrEmpty(match.Groups[1].Value)) { return new CompilationDiagnostic { File = Path.GetFileName(match.Groups[1].Value), Line = int.TryParse(match.Groups[2].Value, out var parsedLine) ? parsedLine : 0, Column = int.TryParse(match.Groups[3].Value, out var parsedCol) ? parsedCol : 0, Code = match.Groups[4].Value, Message = match.Groups[5].Value.Trim(), Type = "warning" }; } else if (match.Groups.Count >= 3) { return new CompilationDiagnostic { Code = match.Groups[1].Value, Message = match.Groups[2].Value.Trim(), File = match.Groups.Count > 3 ? Path.GetFileName(match.Groups[3].Value) : "Unknown", Type = "warning" }; } } } return null; } } public class CompilationResult { public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } public TimeSpan Duration { get; set; } public string SolutionPath { get; set; } = string.Empty; public CompilationStatus Status { get; set; } public int ExitCode { get; set; } public int ErrorCount { get; set; } public int WarningCount { get; set; } public int? PreviousErrorCount { get; set; } public string BuildOutput { get; set; } = string.Empty; public string BuildErrors { get; set; } = string.Empty; public string ErrorMessage { get; set; } = string.Empty; public List Errors { get; set; } = new(); public List Warnings { get; set; } = new(); } public enum CompilationStatus { Success, Warning, Failed } }