MarketAlly.AIPlugin.Extensions/MarketAlly.ProjectDetector/Detectors/DotNetDetectors.cs

595 lines
19 KiB
C#
Executable File

using System;
using System.Linq;
namespace MarketAlly.ProjectDetector.Detectors;
public class TestProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
// Test framework packages are the strongest indicator
if (analysis.HasTestFramework)
{
confidence += 60;
reasons.Add("Has test framework packages");
}
// More specific test file patterns
var testFilePatterns = new[] { ".Test.", ".Tests.", ".Spec.", ".Specs.", "_Test.", "_Tests.", "_Spec.", "_Specs." };
if (analysis.Files.Any(f => testFilePatterns.Any(pattern => f.Contains(pattern, StringComparison.OrdinalIgnoreCase))))
{
confidence += 25;
reasons.Add("Contains test files with standard naming");
}
// Test folder patterns - must be more specific
var testFolderPatterns = new[] { "Tests", "Test", "Specs", "Spec", "UnitTests", "IntegrationTests", "E2ETests" };
if (analysis.Folders.Any(f => testFolderPatterns.Any(pattern => f.Equals(pattern, StringComparison.OrdinalIgnoreCase) ||
f.EndsWith($"/{pattern}", StringComparison.OrdinalIgnoreCase) ||
f.EndsWith($"\\{pattern}", StringComparison.OrdinalIgnoreCase))))
{
confidence += 20;
reasons.Add("Contains dedicated test folders");
}
// Project name ending with .Tests or .Test is a strong indicator
if (analysis.ProjectName != null && (analysis.ProjectName.EndsWith(".Tests", StringComparison.OrdinalIgnoreCase) ||
analysis.ProjectName.EndsWith(".Test", StringComparison.OrdinalIgnoreCase)))
{
confidence += 30;
reasons.Add("Project name indicates test project");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 50,
ProjectType = ProjectType.Tests,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class DatabaseProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
// SQL Server Data Tools project
if (analysis.Files.Any(f => f.EndsWith(".sqlproj", StringComparison.OrdinalIgnoreCase)))
{
confidence += 80;
reasons.Add("SQL Server Data Tools project");
}
// Entity Framework or database packages
var dbPackages = new[]
{
"Microsoft.EntityFrameworkCore", "EntityFramework", "Dapper",
"Microsoft.Data.SqlClient", "Npgsql", "MySql.Data",
"MongoDB.Driver", "RavenDB.Client"
};
if (dbPackages.Any(pkg => analysis.PackageReferences.Any(p => p.Contains(pkg))))
{
confidence += 40;
reasons.Add("Has database packages");
}
// Migration files
if (analysis.Folders.Any(f => f.Contains("Migrations")))
{
confidence += 30;
reasons.Add("Contains Migrations folder");
}
// Database-related naming
if (analysis.Files.Any(f => f.Contains("Migration") || f.Contains("DbContext")))
{
confidence += 25;
reasons.Add("Contains database-related files");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 50,
ProjectType = ProjectType.Database,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class MauiProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.HasMauiSdk || analysis.HasMaui)
{
confidence += 40;
reasons.Add("Has MAUI properties or packages");
}
if (analysis.Folders.Any(f => f.StartsWith("Platforms")))
{
confidence += 30;
reasons.Add("Contains Platforms folder");
}
if (analysis.Files.Any(f => f.Equals("MauiProgram.cs", StringComparison.OrdinalIgnoreCase)))
{
confidence += 20;
reasons.Add("Contains MauiProgram.cs");
}
if (analysis.Files.Any(f => f.Equals("App.xaml", StringComparison.OrdinalIgnoreCase)))
{
confidence += 15;
reasons.Add("Contains App.xaml");
}
if (analysis.Files.Any(f => f.Contains("MauiIcon") || f.Contains("MauiSplashScreen")))
{
confidence += 25;
reasons.Add("Contains MAUI app resources");
}
if (analysis.Files.Any(f => f.Contains("ApplicationTitle") || f.Contains("ApplicationId")))
{
confidence += 20;
reasons.Add("Contains application metadata");
}
// Distinguish between MAUI app and MAUI library
var projectType = ProjectType.MobileApp;
// Enhanced library detection
var isLibrary = IsMauiLibrary(analysis);
if (isLibrary)
{
projectType = ProjectType.Library;
reasons.Add("MAUI class library");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 40,
ProjectType = projectType,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
private bool IsMauiLibrary(ProjectAnalysis analysis)
{
// PRIORITY 1: If it's explicitly executable, it's NOT a library
if (analysis.IsExecutable || analysis.OutputType.Equals("Exe", StringComparison.OrdinalIgnoreCase))
{
return false; // Executable = App, not Library
}
// PRIORITY 2: If it's explicitly a library, it IS a library
if (analysis.IsLibrary || analysis.OutputType.Equals("Library", StringComparison.OrdinalIgnoreCase))
{
return true;
}
// PRIORITY 3: Check for NuGet package generation (strong indicator of library)
if (analysis.PackageReferences.Any(p => p.Contains("GeneratePackageOnBuild")))
{
return true;
}
// PRIORITY 4: Check for package metadata in the file content
var packageMetadataKeywords = new[] { "PackageId", "Authors", "Description", "GeneratePackageOnBuild" };
if (packageMetadataKeywords.Any(keyword =>
analysis.DetectionEvidence.Any(evidence => evidence.Contains(keyword))))
{
return true;
}
// PRIORITY 5: Check for application-specific metadata (indicates app)
var appMetadataKeywords = new[] { "ApplicationTitle", "ApplicationId", "ApplicationVersion" };
if (appMetadataKeywords.Any(keyword =>
analysis.DetectionEvidence.Any(evidence => evidence.Contains(keyword))))
{
return false; // Has app metadata = App, not Library
}
// Default: If no clear indicators, assume it's an app (since it has MAUI)
return false;
}
}
public class BlazorProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.HasBlazor)
{
confidence += 50;
reasons.Add("Has Blazor packages");
}
if (analysis.Files.Any(f => f.EndsWith(".razor", StringComparison.OrdinalIgnoreCase)))
{
confidence += 40;
reasons.Add("Contains Razor components");
}
if (analysis.Files.Any(f => f.Equals("_Imports.razor", StringComparison.OrdinalIgnoreCase)))
{
confidence += 20;
reasons.Add("Contains _Imports.razor");
}
if (analysis.Folders.Any(f => f.Equals("wwwroot", StringComparison.OrdinalIgnoreCase)))
{
confidence += 15;
reasons.Add("Contains wwwroot folder");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 50,
ProjectType = ProjectType.WebApp,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class WebApiProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.HasWebSdk)
{
confidence += 30;
reasons.Add("Uses Microsoft.NET.Sdk.Web");
}
if (analysis.HasAspNetCore)
{
confidence += 20;
reasons.Add("Has ASP.NET Core packages");
}
// API-specific indicators
var apiPackages = new[]
{
"Microsoft.AspNetCore.Mvc", "Microsoft.AspNetCore.OpenApi",
"Swashbuckle", "Microsoft.AspNetCore.Mvc.Api",
"Microsoft.AspNetCore.Mvc.WebApiCompatShim"
};
if (apiPackages.Any(pkg => analysis.PackageReferences.Any(p => p.Contains(pkg))))
{
confidence += 40;
reasons.Add("Has API-specific packages");
}
if (analysis.Files.Any(f => f.Contains("Controller") && f.EndsWith(".cs")))
{
confidence += 30;
reasons.Add("Contains API controllers");
}
if (analysis.Folders.Any(f => f.Equals("Controllers", StringComparison.OrdinalIgnoreCase)))
{
confidence += 25;
reasons.Add("Contains Controllers folder");
}
// Exclude if it has UI components
if (analysis.Files.Any(f => f.EndsWith(".razor") || f.EndsWith(".cshtml")))
{
confidence -= 20;
reasons.Add("Contains UI components (likely WebApp)");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 50,
ProjectType = ProjectType.API,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class WebAppProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.HasWebSdk)
{
confidence += 25;
reasons.Add("Uses Microsoft.NET.Sdk.Web");
}
if (analysis.HasAspNetCore)
{
confidence += 20;
reasons.Add("Has ASP.NET Core packages");
}
// UI components
if (analysis.Files.Any(f => f.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)))
{
confidence += 35;
reasons.Add("Contains Razor views");
}
if (analysis.Folders.Any(f => f.Equals("Views", StringComparison.OrdinalIgnoreCase)))
{
confidence += 25;
reasons.Add("Contains Views folder");
}
if (analysis.Folders.Any(f => f.Equals("wwwroot", StringComparison.OrdinalIgnoreCase)))
{
confidence += 20;
reasons.Add("Contains wwwroot folder");
}
// MVC patterns
if (analysis.Folders.Any(f => f.Equals("Models", StringComparison.OrdinalIgnoreCase)) &&
analysis.Folders.Any(f => f.Equals("Controllers", StringComparison.OrdinalIgnoreCase)))
{
confidence += 15;
reasons.Add("Has MVC structure");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 40,
ProjectType = ProjectType.WebApp,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class DesktopAppProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
var projectType = ProjectType.Other;
// WPF
if (analysis.HasWpf)
{
confidence += 50;
reasons.Add("Has WPF enabled");
projectType = ProjectType.WpfApp;
}
if (analysis.Files.Any(f => f.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) && !analysis.HasMaui))
{
confidence += 30;
reasons.Add("Contains XAML files (non-MAUI)");
projectType = ProjectType.WpfApp;
}
// WinForms
if (analysis.HasWinForms)
{
confidence += 50;
reasons.Add("Has WinForms enabled");
projectType = ProjectType.WinFormsApp;
}
if (analysis.Files.Any(f => f.EndsWith(".Designer.cs", StringComparison.OrdinalIgnoreCase)))
{
confidence += 25;
reasons.Add("Contains WinForms designer files");
projectType = ProjectType.WinFormsApp;
}
// Avalonia
var avaloniaPackages = new[] { "Avalonia", "Avalonia.Desktop", "Avalonia.Themes.Fluent" };
if (avaloniaPackages.Any(pkg => analysis.PackageReferences.Any(p => p.Contains(pkg))))
{
confidence += 50;
reasons.Add("Has Avalonia packages");
projectType = ProjectType.AvaloniaApp;
}
// Desktop SDK
if (analysis.HasDesktopSdk)
{
confidence += 20;
reasons.Add("Uses Windows Desktop SDK");
}
// Windows executable
if (analysis.OutputType.Equals("WinExe", StringComparison.OrdinalIgnoreCase))
{
confidence += 15;
reasons.Add("Windows executable output");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 40,
ProjectType = projectType,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class WorkerServiceProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.HasWorkerSdk)
{
confidence += 60;
reasons.Add("Uses Microsoft.NET.Sdk.Worker");
}
if (analysis.HasWorkerService)
{
confidence += 50;
reasons.Add("Has Worker Service configuration");
}
// Worker service packages
var workerPackages = new[]
{
"Microsoft.Extensions.Hosting", "Microsoft.Extensions.Hosting.WindowsServices",
"Microsoft.Extensions.Hosting.Systemd"
};
if (workerPackages.Any(pkg => analysis.PackageReferences.Any(p => p.Contains(pkg))))
{
confidence += 40;
reasons.Add("Has hosting packages");
}
// Worker patterns - including monitoring services
if (analysis.Files.Any(f => f.Contains("Worker") || f.Contains("BackgroundService") ||
f.Contains("Monitor") || f.Contains("Service")))
{
confidence += 30;
reasons.Add("Contains service-related files");
}
// Project name patterns for services
if (analysis.ProjectName != null &&
(analysis.ProjectName.Contains("monitor", StringComparison.OrdinalIgnoreCase) ||
analysis.ProjectName.Contains("service", StringComparison.OrdinalIgnoreCase) ||
analysis.ProjectName.Contains("worker", StringComparison.OrdinalIgnoreCase)))
{
confidence += 20;
reasons.Add("Project name indicates service");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 50,
ProjectType = ProjectType.Service,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class LibraryProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.IsLibrary)
{
confidence += 40;
reasons.Add("Library output type");
}
// NuGet package metadata
if (analysis.DetectionEvidence.Any(e => e.Contains("GeneratePackageOnBuild")))
{
confidence += 30;
reasons.Add("Generates NuGet package");
}
if (analysis.DetectionEvidence.Any(e => e.Contains("PackageId") || e.Contains("Authors")))
{
confidence += 25;
reasons.Add("Has NuGet metadata");
}
// No executable markers
if (!analysis.IsExecutable && string.IsNullOrEmpty(analysis.OutputType))
{
confidence += 20;
reasons.Add("No executable output");
}
// Common library patterns
if (analysis.Files.Any(f => f.Contains(".Core.") || f.Contains(".Common.") || f.Contains(".Shared.")))
{
confidence += 15;
reasons.Add("Common library naming patterns");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 40,
ProjectType = ProjectType.Library,
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}
public class ConsoleAppProjectDetector : IProjectTypeDetector
{
public ProjectTypeDetectionResult Detect(ProjectAnalysis analysis)
{
var confidence = 0;
var reasons = new List<string>();
if (analysis.OutputType.Equals("Exe", StringComparison.OrdinalIgnoreCase))
{
confidence += 30;
reasons.Add("Console executable output");
}
// Check for Program.cs with Main method pattern
if (analysis.Files.Any(f => f.Equals("Program.cs", StringComparison.OrdinalIgnoreCase)))
{
confidence += 25;
reasons.Add("Contains Program.cs");
}
// No UI frameworks
if (!analysis.HasWpf && !analysis.HasWinForms && !analysis.HasMaui && !analysis.HasBlazor)
{
confidence += 20;
reasons.Add("No UI framework detected");
}
// Console-specific packages
if (analysis.HasCommandLine)
{
confidence += 30;
reasons.Add("Has command line packages");
}
return new ProjectTypeDetectionResult
{
IsMatch = confidence >= 40,
ProjectType = ProjectType.Other, // Console apps typically fall under "Other"
Confidence = Math.Min(confidence, 100),
Reason = string.Join(", ", reasons)
};
}
}