using MarketAlly.AIPlugin; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Refactoring.Plugins { [AIPlugin("ReadmeGenerator", "Generates comprehensive README.md files for projects and solutions with intelligent content analysis")] public class ReadmeGeneratorPlugin : IAIPlugin { [AIParameter("Path to project directory or solution file", required: true)] public string ProjectPath { get; set; } [AIParameter("Type of project: auto, library, application, tool, maui", required: false)] public string ProjectType { get; set; } = "auto"; [AIParameter("Include API documentation section", required: false)] public bool IncludeApiDocs { get; set; } = true; [AIParameter("Include architecture diagrams", required: false)] public bool IncludeArchitecture { get; set; } = true; [AIParameter("Include setup and installation instructions", required: false)] public bool IncludeSetup { get; set; } = true; [AIParameter("Include usage examples", required: false)] public bool IncludeExamples { get; set; } = true; [AIParameter("Apply changes and create README.md file", required: false)] public bool ApplyChanges { get; set; } = false; [AIParameter("Maximum file size in characters for analysis (default: 50000)", required: false)] public int MaxFileSize { get; set; } = 50000; [AIParameter("Use intelligent AI-powered description generation", required: false)] public bool UseIntelligentDescription { get; set; } = false; [AIParameter("Intelligent description override (if provided, skips AI generation)", required: false)] public string IntelligentDescription { get; set; } = ""; public IReadOnlyDictionary SupportedParameters => new Dictionary { ["projectPath"] = typeof(string), ["projectpath"] = typeof(string), ["projectType"] = typeof(string), ["projecttype"] = typeof(string), ["includeApiDocs"] = typeof(bool), ["includeapidocs"] = typeof(bool), ["includeArchitecture"] = typeof(bool), ["includearchitecture"] = typeof(bool), ["includeSetup"] = typeof(bool), ["includesetup"] = typeof(bool), ["includeExamples"] = typeof(bool), ["includeexamples"] = typeof(bool), ["applyChanges"] = typeof(bool), ["applychanges"] = typeof(bool), ["maxFileSize"] = typeof(int), ["maxfilesize"] = typeof(int), ["maxFilesToAnalyze"] = typeof(int), ["maxfilestoanalyze"] = typeof(int), ["useIntelligentDescription"] = typeof(bool), ["useintelligentdescription"] = typeof(bool), ["intelligentDescription"] = typeof(string), ["intelligentdescription"] = typeof(string) }; public async Task ExecuteAsync(IReadOnlyDictionary parameters) { try { // Extract parameters string projectPath = GetParameterValue(parameters, "projectPath", "projectpath")?.ToString(); string projectType = GetParameterValue(parameters, "projectType", "projecttype")?.ToString()?.ToLower() ?? "auto"; bool includeApiDocs = GetBoolParameter(parameters, "includeApiDocs", "includeapidocs", true); bool includeArchitecture = GetBoolParameter(parameters, "includeArchitecture", "includearchitecture", true); bool includeSetup = GetBoolParameter(parameters, "includeSetup", "includesetup", true); bool includeExamples = GetBoolParameter(parameters, "includeExamples", "includeexamples", true); bool applyChanges = GetBoolParameter(parameters, "applyChanges", "applychanges", false); int maxFileSize = GetIntParameter(parameters, "maxFileSize", "maxfilesize", 50000); int maxFilesToAnalyze = GetIntParameter(parameters, "maxFilesToAnalyze", "maxfilestoanalyze", 20); bool useIntelligentDescription = GetBoolParameter(parameters, "useIntelligentDescription", "useintelligentdescription", false); string intelligentDescription = GetParameterValue(parameters, "intelligentDescription", "intelligentdescription")?.ToString() ?? ""; if (!Directory.Exists(projectPath) && !File.Exists(projectPath)) { return new AIPluginResult(new DirectoryNotFoundException($"Path not found: {projectPath}"), "Invalid project path"); } // Phase 1: Analyze project structure and extract metadata var analysisResult = await AnalyzeProjectStructure(projectPath, projectType, maxFileSize, maxFilesToAnalyze); if (!analysisResult.Success) { return new AIPluginResult(new Exception(analysisResult.Error), analysisResult.Error); } // Phase 2: Generate README content using structured analysis var readmeContent = await GenerateReadmeContent( analysisResult, includeApiDocs, includeArchitecture, includeSetup, includeExamples, useIntelligentDescription ? intelligentDescription : null ); // Apply changes if requested if (applyChanges) { var readmePath = Path.Combine( Directory.Exists(projectPath) ? projectPath : Path.GetDirectoryName(projectPath), "README.md" ); // Create backup if file exists if (File.Exists(readmePath)) { var backupPath = $"{readmePath}.{DateTime.Now:yyyyMMdd_HHmmss}.bak"; File.Copy(readmePath, backupPath); } await File.WriteAllTextAsync(readmePath, readmeContent); return new AIPluginResult(new { Message = "README.md generated successfully", ProjectPath = projectPath, ReadmePath = readmePath, ProjectType = analysisResult.DetectedProjectType, FilesAnalyzed = analysisResult.FilesAnalyzed, ContentLength = readmeContent.Length, Sections = analysisResult.IncludedSections, ChangesApplied = true, Timestamp = DateTime.UtcNow }); } else { return new AIPluginResult(new { Message = "README.md content generated (preview mode)", ProjectPath = projectPath, ProjectType = analysisResult.DetectedProjectType, FilesAnalyzed = analysisResult.FilesAnalyzed, ContentLength = readmeContent.Length, Sections = analysisResult.IncludedSections, PreviewContent = readmeContent, ChangesApplied = false, Timestamp = DateTime.UtcNow }); } } catch (Exception ex) { return new AIPluginResult(ex, $"README generation failed: {ex.Message}"); } } private async Task AnalyzeProjectStructure(string projectPath, string projectType, int maxFileSize, int maxFilesToAnalyze) { var result = new ProjectAnalysisResult(); try { // Determine if it's a solution or single project if (File.Exists(projectPath) && projectPath.EndsWith(".sln")) { result = await AnalyzeSolution(projectPath, maxFileSize, maxFilesToAnalyze); } else if (Directory.Exists(projectPath)) { result = await AnalyzeDirectory(projectPath, projectType, maxFileSize, maxFilesToAnalyze); } else if (File.Exists(projectPath) && projectPath.EndsWith(".csproj")) { result = await AnalyzeProject(projectPath, projectType, maxFileSize, maxFilesToAnalyze); } result.Success = true; return result; } catch (Exception ex) { result.Success = false; result.Error = ex.Message; return result; } } private async Task AnalyzeSolution(string solutionPath, int maxFileSize, int maxFilesToAnalyze) { var result = new ProjectAnalysisResult { ProjectName = Path.GetFileNameWithoutExtension(solutionPath), ProjectPath = Path.GetDirectoryName(solutionPath), IsSolution = true }; // Parse solution file var solutionContent = await File.ReadAllTextAsync(solutionPath); var projectMatches = Regex.Matches(solutionContent, @"Project\(""[^""]+\""\)\s*=\s*""([^""]+)"",\s*""([^""]+)"""); foreach (Match match in projectMatches) { var projectName = match.Groups[1].Value; var projectRelativePath = match.Groups[2].Value; var projectFullPath = Path.Combine(Path.GetDirectoryName(solutionPath), projectRelativePath); if (File.Exists(projectFullPath) && projectFullPath.EndsWith(".csproj")) { var projectAnalysis = await AnalyzeProject(projectFullPath, "auto", maxFileSize, maxFilesToAnalyze / 2); result.SubProjects.Add(projectAnalysis); } } // Aggregate analysis result.DetectedProjectType = DetermineOverallProjectType(result.SubProjects); result.KeyFiles = result.SubProjects.SelectMany(p => p.KeyFiles).Take(maxFilesToAnalyze).ToList(); result.PublicApis = result.SubProjects.SelectMany(p => p.PublicApis).ToList(); result.Dependencies = result.SubProjects.SelectMany(p => p.Dependencies).Distinct().ToList(); result.FilesAnalyzed = result.SubProjects.Sum(p => p.FilesAnalyzed); return result; } private async Task AnalyzeDirectory(string directoryPath, string projectType, int maxFileSize, int maxFilesToAnalyze) { var result = new ProjectAnalysisResult { ProjectPath = directoryPath, ProjectName = Path.GetFileName(directoryPath) }; // Look for project files var projectFiles = Directory.GetFiles(directoryPath, "*.csproj", SearchOption.TopDirectoryOnly); if (projectFiles.Any()) { return await AnalyzeProject(projectFiles.First(), projectType, maxFileSize, maxFilesToAnalyze); } // Analyze as general directory result.DetectedProjectType = "application"; await AnalyzeCodeFiles(directoryPath, result, maxFileSize, maxFilesToAnalyze); return result; } private async Task AnalyzeProject(string projectPath, string projectType, int maxFileSize, int maxFilesToAnalyze) { var result = new ProjectAnalysisResult { ProjectPath = Path.GetDirectoryName(projectPath), ProjectName = Path.GetFileNameWithoutExtension(projectPath) }; // Parse project file var projectContent = await File.ReadAllTextAsync(projectPath); result.TargetFramework = ExtractTargetFramework(projectContent); result.Dependencies = ExtractPackageReferences(projectContent); // Detect project type result.DetectedProjectType = projectType == "auto" ? DetectProjectType(projectContent, result.ProjectName) : projectType; // Analyze code files await AnalyzeCodeFiles(result.ProjectPath, result, maxFileSize, maxFilesToAnalyze); return result; } private async Task AnalyzeCodeFiles(string directoryPath, ProjectAnalysisResult result, int maxFileSize, int maxFilesToAnalyze) { var csharpFiles = Directory.GetFiles(directoryPath, "*.cs", SearchOption.AllDirectories) .Where(f => !ShouldExcludeFile(f)) .Take(maxFilesToAnalyze) .ToList(); var prioritizedFiles = PrioritizeFiles(csharpFiles, result.DetectedProjectType); foreach (var file in prioritizedFiles) { try { var fileInfo = new FileInfo(file); if (fileInfo.Length > maxFileSize) continue; var content = await File.ReadAllTextAsync(file); var syntaxTree = CSharpSyntaxTree.ParseText(content); var root = syntaxTree.GetRoot(); // Extract key information var fileAnalysis = AnalyzeCodeFile(file, root, content); result.KeyFiles.Add(fileAnalysis); result.PublicApis.AddRange(ExtractPublicApi(root)); result.FilesAnalyzed++; } catch (Exception) { // Skip problematic files } } // Detect additional features result.HasTests = csharpFiles.Any(f => f.Contains("Test", StringComparison.OrdinalIgnoreCase)); result.HasDocumentation = Directory.GetFiles(directoryPath, "*.md", SearchOption.AllDirectories).Any(); } private List PrioritizeFiles(List files, string projectType) { var prioritized = new List(); // High priority patterns based on project type var highPriorityPatterns = projectType switch { "library" => new[] { "Plugin", "Service", "Manager", "Factory", "Builder", "Repository", "Interface" }, "application" => new[] { "Program", "Main", "Startup", "Controller", "Service", "App" }, "maui" => new[] { "App", "MainPage", "AppShell", "MauiProgram", "Platform" }, "tool" => new[] { "Program", "Main", "Command", "Tool", "Cli" }, _ => new[] { "Program", "Main", "Service", "Controller", "Manager" } }; // Add high priority files first foreach (var pattern in highPriorityPatterns) { prioritized.AddRange(files.Where(f => Path.GetFileName(f).Contains(pattern, StringComparison.OrdinalIgnoreCase))); } // Add remaining files prioritized.AddRange(files.Except(prioritized)); return prioritized.Distinct().ToList(); } private CodeFileAnalysis AnalyzeCodeFile(string filePath, SyntaxNode root, string content) { var analysis = new CodeFileAnalysis { FilePath = filePath, FileName = Path.GetFileName(filePath), LineCount = content.Split('\n').Length }; // Extract classes and interfaces var classes = root.DescendantNodes().OfType(); var interfaces = root.DescendantNodes().OfType(); analysis.Classes = classes.Select(c => c.Identifier.ValueText).ToList(); analysis.Interfaces = interfaces.Select(i => i.Identifier.ValueText).ToList(); // Extract key patterns analysis.HasAttributes = root.DescendantNodes().OfType().Any(); analysis.HasAsyncMethods = root.DescendantNodes().OfType() .Any(m => m.Modifiers.Any(mod => mod.IsKind(SyntaxKind.AsyncKeyword))); // Extract namespace var namespaceDecl = root.DescendantNodes().OfType().FirstOrDefault(); analysis.Namespace = namespaceDecl?.Name.ToString(); return analysis; } private List ExtractPublicApi(SyntaxNode root) { var apis = new List(); var publicMethods = root.DescendantNodes().OfType() .Where(m => m.Modifiers.Any(mod => mod.IsKind(SyntaxKind.PublicKeyword))) .Where(m => !IsConstructor(m) && !IsPropertyAccessor(m)); // Filter out constructors and property accessors foreach (var method in publicMethods) { var className = GetContainingClassName(method); var methodName = method.Identifier.ValueText; // Skip duplicate ExecuteAsync methods - only include one per class if (methodName == "ExecuteAsync" && apis.Any(a => a.Name == "ExecuteAsync" && a.ClassName == className)) continue; apis.Add(new ApiMethod { Name = methodName, ClassName = className, ReturnType = method.ReturnType.ToString(), Parameters = method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier.ValueText}").ToList(), IsAsync = method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)), Summary = ExtractDocumentationSummary(method), IsPluginMethod = methodName == "ExecuteAsync" && className.Contains("Plugin") }); } // Group and prioritize meaningful methods return apis.GroupBy(a => $"{a.ClassName}.{a.Name}") .Select(g => g.First()) // Remove exact duplicates .Where(a => !IsBoilerplateMethod(a)) .OrderBy(a => a.IsPluginMethod ? 0 : 1) // Plugin methods first .ThenBy(a => a.ClassName) .ThenBy(a => a.Name) .ToList(); } private bool IsConstructor(MethodDeclarationSyntax method) { return method.Identifier.ValueText == method.Parent?.ChildTokens() .FirstOrDefault(t => t.IsKind(SyntaxKind.IdentifierToken)).ValueText; } private bool IsPropertyAccessor(MethodDeclarationSyntax method) { return method.Parent is AccessorDeclarationSyntax; } private string GetContainingClassName(MethodDeclarationSyntax method) { var classDecl = method.FirstAncestorOrSelf(); return classDecl?.Identifier.ValueText ?? "Unknown"; } private bool IsBoilerplateMethod(ApiMethod method) { var boilerplateMethods = new[] { "ToString", "GetHashCode", "Equals", "GetType" }; return boilerplateMethods.Contains(method.Name); } private string ExtractDocumentationSummary(SyntaxNode node) { var docComment = node.GetLeadingTrivia() .FirstOrDefault(t => t.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia)); if (docComment.IsKind(SyntaxKind.None)) return null; var commentText = docComment.ToString(); var summaryMatch = Regex.Match(commentText, @"\s*(.*?)\s*", RegexOptions.Singleline); return summaryMatch.Success ? summaryMatch.Groups[1].Value.Trim().Replace("///", "").Trim() : null; } private string DetectProjectType(string projectContent, string projectName) { if (projectContent.Contains("true")) return "maui"; if (projectContent.Contains("Exe") || projectName.ToLower().Contains("console") || projectName.ToLower().Contains("tool") || projectName.ToLower().Contains("cli")) return "tool"; if (projectContent.Contains("Microsoft.AspNetCore") || projectContent.Contains("Microsoft.Extensions.Hosting")) return "application"; if (projectContent.Contains("Library") || projectName.ToLower().Contains("library") || projectName.ToLower().Contains("plugin")) return "library"; return "application"; } private string DetermineOverallProjectType(List projects) { if (projects.Any(p => p.DetectedProjectType == "maui")) return "maui"; var types = projects.Select(p => p.DetectedProjectType).ToList(); return types.GroupBy(t => t).OrderByDescending(g => g.Count()).First().Key; } private string ExtractTargetFramework(string projectContent) { var match = Regex.Match(projectContent, @"(.*?)"); return match.Success ? match.Groups[1].Value : "Unknown"; } private List ExtractMauiPlatforms(string targetFramework) { var platforms = new List(); if (string.IsNullOrEmpty(targetFramework) || targetFramework == "Unknown") return platforms; // Split multiple target frameworks var frameworks = targetFramework.Split(';', ',') .Select(f => f.Trim()) .Where(f => !string.IsNullOrEmpty(f)); foreach (var framework in frameworks) { var platform = framework.ToLower() switch { var f when f.Contains("android") => "Android", var f when f.Contains("ios") => "iOS", var f when f.Contains("windows") => "Windows", var f when f.Contains("maccatalyst") => "macOS (Mac Catalyst)", var f when f.Contains("tizen") => "Tizen", _ => null }; if (platform != null && !platforms.Contains(platform)) { platforms.Add(platform); } } return platforms; } private List ExtractPackageReferences(string projectContent) { var matches = Regex.Matches(projectContent, @"().Select(m => m.Groups[1].Value).ToList(); } private bool ShouldExcludeFile(string filePath) { var fileName = Path.GetFileName(filePath); var excludePatterns = new[] { ".Designer.cs", ".generated.cs", ".g.cs", "AssemblyInfo.cs", "GlobalAssemblyInfo.cs", "TemporaryGeneratedFile", ".AssemblyAttributes.cs" }; return excludePatterns.Any(pattern => fileName.Contains(pattern, StringComparison.OrdinalIgnoreCase)); } private async Task GenerateReadmeContent( ProjectAnalysisResult analysis, bool includeApiDocs, bool includeArchitecture, bool includeSetup, bool includeExamples, string intelligentDescription = null) { var template = GetTemplate(analysis.DetectedProjectType); var content = new StringBuilder(); // Handle MAUI platforms section var platformsSection = ""; if (analysis.DetectedProjectType == "maui") { var platforms = ExtractMauiPlatforms(analysis.TargetFramework); if (platforms.Any()) { platformsSection = "## Supported Platforms\n\n" + string.Join("\n", platforms.Select(p => $"- {p}")) + "\n\n"; } } // Replace template variables var processedTemplate = template .Replace("{{PROJECT_NAME}}", analysis.ProjectName) .Replace("{{PROJECT_TYPE}}", FormatProjectType(analysis.DetectedProjectType)) .Replace("{{TARGET_FRAMEWORK}}", analysis.TargetFramework) .Replace("{{DESCRIPTION}}", intelligentDescription ?? GenerateDescription(analysis)) .Replace("{{PLATFORMS_SECTION}}", platformsSection); content.AppendLine(processedTemplate); // Add sections based on parameters if (includeSetup) { content.AppendLine(GenerateSetupSection(analysis)); } if (includeExamples) { content.AppendLine(GenerateExamplesSection(analysis)); } // Only show API docs for libraries and plugins - not for applications/tools/MAUI apps if (includeApiDocs && analysis.PublicApis.Any() && ShouldIncludeApiDocs(analysis.DetectedProjectType)) { content.AppendLine(GenerateApiDocumentation(analysis)); } if (includeArchitecture) { content.AppendLine(GenerateArchitectureSection(analysis)); } // Add additional sections content.AppendLine(GenerateDependenciesSection(analysis)); content.AppendLine(GenerateContributingSection(analysis)); return content.ToString(); } private string GetTemplate(string projectType) { return projectType switch { "library" => GetLibraryTemplate(), "maui" => GetMauiTemplate(), "tool" => GetToolTemplate(), _ => GetApplicationTemplate() }; } private string GetLibraryTemplate() { return @"# {{PROJECT_NAME}} A {{PROJECT_TYPE}} for .NET {{TARGET_FRAMEWORK}}. ## Overview {{DESCRIPTION}} ## Features - Modern .NET {{TARGET_FRAMEWORK}} implementation - Comprehensive API surface - Well-documented public interfaces - Unit tested and production ready "; } private string GetMauiTemplate() { return @"# {{PROJECT_NAME}} A cross-platform application built with .NET MAUI. ## Overview {{DESCRIPTION}} {{PLATFORMS_SECTION}} ## Features - Cross-platform native UI - Shared business logic - Modern .NET implementation "; } private string GetToolTemplate() { return @"# {{PROJECT_NAME}} A command-line tool built with .NET {{TARGET_FRAMEWORK}}. ## Overview {{DESCRIPTION}} ## Features - Cross-platform CLI tool - Modern .NET {{TARGET_FRAMEWORK}} implementation - Comprehensive command set - Built-in help and documentation "; } private string GetApplicationTemplate() { return @"# {{PROJECT_NAME}} A .NET {{TARGET_FRAMEWORK}} application. ## Overview {{DESCRIPTION}} ## Features - Modern .NET {{TARGET_FRAMEWORK}} implementation - Scalable architecture - Comprehensive functionality - Production ready "; } private string GenerateDescription(ProjectAnalysisResult analysis) { var features = new List(); if (analysis.PublicApis.Any()) features.Add($"Provides {analysis.PublicApis.Count} public API methods"); if (analysis.Dependencies.Any()) features.Add($"Integrates with {analysis.Dependencies.Count} external packages"); if (analysis.HasTests) features.Add("includes comprehensive test coverage"); if (analysis.IsSolution) features.Add($"multi-project solution with {analysis.SubProjects.Count} projects"); var description = $"This {analysis.DetectedProjectType} "; if (features.Any()) { description += string.Join(", ", features) + "."; } else { description += "provides essential functionality for your .NET applications."; } return description; } private string GenerateSetupSection(ProjectAnalysisResult analysis) { var setup = new StringBuilder(); setup.AppendLine("## Installation"); setup.AppendLine(); if (analysis.DetectedProjectType == "library") { setup.AppendLine("### Package Manager"); setup.AppendLine("```"); setup.AppendLine($"Install-Package {analysis.ProjectName}"); setup.AppendLine("```"); setup.AppendLine(); setup.AppendLine("### .NET CLI"); setup.AppendLine("```bash"); setup.AppendLine($"dotnet add package {analysis.ProjectName}"); setup.AppendLine("```"); } else if (analysis.DetectedProjectType == "tool") { setup.AppendLine("### Install as Global Tool"); setup.AppendLine("```bash"); setup.AppendLine($"dotnet tool install -g {analysis.ProjectName}"); setup.AppendLine("```"); setup.AppendLine(); setup.AppendLine("### Local Installation"); setup.AppendLine("```bash"); setup.AppendLine("git clone "); setup.AppendLine($"cd {analysis.ProjectName}"); setup.AppendLine("dotnet build"); setup.AppendLine("dotnet run"); setup.AppendLine("```"); } else if (analysis.DetectedProjectType == "maui") { setup.AppendLine("### Prerequisites"); var platforms = ExtractMauiPlatforms(analysis.TargetFramework); var netVersion = ExtractNetVersion(analysis.TargetFramework); setup.AppendLine($"- .NET {netVersion} SDK"); setup.AppendLine("- .NET MAUI workload"); if (platforms.Contains("Android")) setup.AppendLine("- Android SDK (for Android development)"); if (platforms.Contains("iOS")) setup.AppendLine("- Xcode (for iOS development)"); if (platforms.Contains("Windows")) setup.AppendLine("- Windows App SDK (for Windows development)"); setup.AppendLine(); setup.AppendLine("### Build and Run"); setup.AppendLine("```bash"); setup.AppendLine("git clone "); setup.AppendLine($"cd {analysis.ProjectName}"); setup.AppendLine("dotnet restore"); setup.AppendLine("dotnet build"); if (platforms.Count == 1) { var platform = platforms.First().ToLower().Replace(" (mac catalyst)", ""); setup.AppendLine($"dotnet run --framework net{netVersion}-{platform}"); } else { setup.AppendLine("# Run on specific platform:"); foreach (var platform in platforms.Take(3)) // Show top 3 platforms { var platformCode = platform.ToLower() switch { "android" => "android", "ios" => "ios", "windows" => "windows10.0.19041.0", "macos (mac catalyst)" => "maccatalyst", "tizen" => "tizen", _ => platform.ToLower() }; setup.AppendLine($"# dotnet run --framework net{netVersion}-{platformCode}"); } } setup.AppendLine("```"); } else { setup.AppendLine("### Prerequisites"); var netVersion = ExtractNetVersion(analysis.TargetFramework); setup.AppendLine($"- .NET {netVersion} SDK"); setup.AppendLine(); setup.AppendLine("### Build and Run"); setup.AppendLine("```bash"); setup.AppendLine("git clone "); setup.AppendLine($"cd {analysis.ProjectName}"); setup.AppendLine("dotnet restore"); setup.AppendLine("dotnet build"); setup.AppendLine("dotnet run"); setup.AppendLine("```"); } return setup.ToString(); } private bool ShouldIncludeApiDocs(string projectType) { return projectType switch { "library" => true, // Libraries have public APIs for consumers "application" => false, // Applications are for end users, not developers "tool" => false, // CLI tools focus on usage, not internal APIs "maui" => false, // MAUI apps are end-user applications _ => false // Default to false for unknown types }; } private string ExtractNetVersion(string targetFramework) { if (string.IsNullOrEmpty(targetFramework)) return "8.0"; // Extract version from frameworks like "net9.0-android;net9.0-ios" var match = Regex.Match(targetFramework, @"net(\d+\.\d+)"); return match.Success ? match.Groups[1].Value : "8.0"; } private string GenerateExamplesSection(ProjectAnalysisResult analysis) { var examples = new StringBuilder(); examples.AppendLine("## Usage Examples"); examples.AppendLine(); if (analysis.DetectedProjectType == "library" && analysis.PublicApis.Any()) { // Check if this is a plugin-based architecture var pluginClasses = analysis.KeyFiles .SelectMany(f => f.Classes) .Where(c => c.Contains("Plugin")) .Take(5) .ToList(); if (pluginClasses.Any()) { examples.AppendLine("### Plugin Registration and Usage"); examples.AppendLine(); examples.AppendLine("```csharp"); examples.AppendLine("using " + (analysis.KeyFiles.FirstOrDefault()?.Namespace ?? analysis.ProjectName) + ";"); examples.AppendLine(); examples.AppendLine("// Register plugins"); examples.AppendLine("var registry = new AIPluginRegistry();"); foreach (var pluginClass in pluginClasses) { examples.AppendLine($"registry.RegisterPlugin(new {pluginClass}());"); } examples.AppendLine(); examples.AppendLine("// Execute plugin functionality"); var firstPlugin = pluginClasses.FirstOrDefault()?.Replace("Plugin", ""); if (!string.IsNullOrEmpty(firstPlugin)) { examples.AppendLine($"var result = await registry.CallFunctionAsync(\"{firstPlugin}\", new Dictionary"); examples.AppendLine("{"); // Use actual parameters from the plugin if available var pluginApi = analysis.PublicApis.FirstOrDefault(a => a.ClassName == pluginClasses.First()); if (pluginApi != null && pluginApi.Parameters.Any()) { var sampleParam = pluginApi.Parameters.First().Split(' ').Last(); // Get parameter name var paramType = pluginApi.Parameters.First().Split(' ').First(); // Get parameter type var sampleValue = paramType.ToLower() switch { "string" => "\"example.cs\"", "bool" => "true", "int" => "42", _ => "\"value\"" }; examples.AppendLine($" [\"{sampleParam}\"] = {sampleValue}"); } else { examples.AppendLine(" // Parameters specific to the plugin"); } examples.AppendLine("});"); } examples.AppendLine("```"); // Add batch processing example if multiple plugins if (pluginClasses.Count > 1) { examples.AppendLine(); examples.AppendLine("### Batch Processing"); examples.AppendLine(); examples.AppendLine("```csharp"); examples.AppendLine("// Process with multiple plugins"); var pluginNames = pluginClasses.Select(p => p.Replace("Plugin", "")).Take(3); examples.AppendLine($"var operations = new[] {{ \"{string.Join("\", \"", pluginNames)}\" }};"); examples.AppendLine("foreach (var operation in operations)"); examples.AppendLine("{"); examples.AppendLine(" var result = await registry.CallFunctionAsync(operation, parameters);"); examples.AppendLine(" // Process result"); examples.AppendLine("}"); examples.AppendLine("```"); } } else { // For non-plugin libraries, only show examples if we have actual meaningful APIs var meaningfulApis = analysis.PublicApis .Where(a => !IsBoilerplateMethod(a)) .Where(a => !string.IsNullOrEmpty(a.ClassName)) .GroupBy(a => a.ClassName) .Take(2) .ToList(); if (meaningfulApis.Any()) { examples.AppendLine("### Basic Usage"); examples.AppendLine(); examples.AppendLine("```csharp"); examples.AppendLine("using " + (analysis.KeyFiles.FirstOrDefault()?.Namespace ?? analysis.ProjectName) + ";"); examples.AppendLine(); foreach (var classGroup in meaningfulApis) { var className = classGroup.Key; var firstMethod = classGroup.First(); examples.AppendLine($"// Using {className}"); examples.AppendLine($"var {className.ToLower()} = new {className}();"); if (firstMethod.IsAsync) { examples.AppendLine($"var result = await {className.ToLower()}.{firstMethod.Name}({GenerateExampleParams(firstMethod.Parameters)});"); } else { examples.AppendLine($"var result = {className.ToLower()}.{firstMethod.Name}({GenerateExampleParams(firstMethod.Parameters)});"); } examples.AppendLine(); } examples.AppendLine("```"); } // If no meaningful APIs found, don't show a usage section at all } } else if (analysis.DetectedProjectType == "tool") { examples.AppendLine("### Command Line Usage"); examples.AppendLine(); examples.AppendLine("```bash"); examples.AppendLine($"# Install the tool"); examples.AppendLine($"dotnet tool install -g {analysis.ProjectName}"); examples.AppendLine(); examples.AppendLine($"# Basic usage"); examples.AppendLine($"{analysis.ProjectName.ToLower()} --help"); examples.AppendLine(); examples.AppendLine($"# Process files"); examples.AppendLine($"{analysis.ProjectName.ToLower()} process --input file.txt --output result.txt"); examples.AppendLine("```"); } // For other project types with no clear APIs, don't show usage examples at all return examples.ToString(); } private string GenerateExampleParams(List parameters) { if (!parameters.Any()) return ""; return string.Join(", ", parameters.Select(param => { var parts = param.Split(' '); var type = parts[0].ToLower(); return type switch { "string" => "\"example\"", "int" => "42", "bool" => "true", "double" or "decimal" => "3.14", _ => "null" }; })); } private string GenerateApiDocumentation(ProjectAnalysisResult analysis) { var api = new StringBuilder(); api.AppendLine("## API Reference"); api.AppendLine(); if (!analysis.PublicApis.Any()) { api.AppendLine("*API documentation will be generated when public methods are detected.*"); return api.ToString(); } // Group APIs by class, but with better organization var groupedApis = analysis.PublicApis .GroupBy(a => a.ClassName ?? "General") .Where(g => g.Any(m => !string.IsNullOrEmpty(m.Name))) .Take(8) // Limit to top 8 classes .ToList(); foreach (var group in groupedApis) { var className = group.Key; var methods = group.Where(m => !string.IsNullOrEmpty(m.Name)).Take(6).ToList(); // Limit methods per class if (!methods.Any()) continue; api.AppendLine($"### {className}"); api.AppendLine(); foreach (var method in methods) { // Create meaningful descriptions for plugin methods var description = GenerateMethodDescription(method, className); if (!string.IsNullOrEmpty(description)) { api.AppendLine($"#### {method.Name}"); api.AppendLine(); api.AppendLine(description); api.AppendLine(); } api.AppendLine("```csharp"); var signature = $"{method.ReturnType} {method.Name}("; if (method.Parameters.Any()) { signature += string.Join(", ", method.Parameters); } signature += ")"; api.AppendLine(signature); api.AppendLine("```"); api.AppendLine(); } } return api.ToString(); } private string GenerateMethodDescription(ApiMethod method, string className) { // Use existing summary if available if (!string.IsNullOrEmpty(method.Summary)) { return method.Summary; } // Generate intelligent descriptions based on patterns if (method.IsPluginMethod && className.Contains("Plugin")) { return GeneratePluginDescription(className, method.Name); } // Generate description based on method name patterns return GenerateMethodDescriptionFromName(method.Name, className); } private string GeneratePluginDescription(string className, string methodName) { if (methodName == "ExecuteAsync" && className.Contains("Plugin")) { return className.Replace("Plugin", "") switch { "CodeAnalysis" => "Analyzes code structure, complexity metrics, and identifies refactoring opportunities.", "EnhancedDocumentationGenerator" => "Generates comprehensive XML documentation with AI-powered intelligent descriptions.", "CodeFormatter" => "Formats code according to specified style guidelines and conventions.", "NamingConvention" => "Analyzes and suggests improvements for variable, method, and class naming.", "BatchRefactor" => "Orchestrates multiple refactoring operations across entire projects or solutions.", "ReadmeGenerator" => "Generates comprehensive README documentation by analyzing project structure and code.", _ => $"Executes {className.Replace("Plugin", "").ToLower()} operations on the specified code or project." }; } return ""; } private string GenerateMethodDescriptionFromName(string methodName, string className) { // Generate descriptions based on common method name patterns if (methodName.StartsWith("Generate")) return $"Generates content or artifacts based on the provided parameters."; if (methodName.StartsWith("Analyze")) return $"Performs analysis on the specified input and returns detailed results."; if (methodName.StartsWith("Process")) return $"Processes the input data and applies transformations or operations."; if (methodName.StartsWith("Create")) return $"Creates new instances or artifacts based on the specified configuration."; if (methodName.StartsWith("Execute")) return $"Executes the primary operation of the {className} component."; if (methodName.StartsWith("Validate")) return $"Validates input parameters and returns validation results."; if (methodName.StartsWith("Get")) return $"Retrieves information or data from the {className} component."; if (methodName.StartsWith("Set")) return $"Sets or updates configuration values in the {className} component."; return ""; // Don't generate description for unclear methods } private string GenerateArchitectureSection(ProjectAnalysisResult analysis) { var arch = new StringBuilder(); arch.AppendLine("## Architecture"); arch.AppendLine(); if (analysis.IsSolution) { arch.AppendLine("### Solution Structure"); arch.AppendLine(); foreach (var project in analysis.SubProjects) { arch.AppendLine($"- **{project.ProjectName}**: {project.DetectedProjectType}"); } arch.AppendLine(); } arch.AppendLine("### Key Components"); arch.AppendLine(); var componentTypes = analysis.KeyFiles .SelectMany(f => f.Classes.Concat(f.Interfaces)) .GroupBy(GetComponentType) .ToList(); foreach (var group in componentTypes) { arch.AppendLine($"- **{group.Key}**: {group.Count()} components"); } if (analysis.DetectedProjectType == "maui") { arch.AppendLine(); arch.AppendLine("### MAUI Architecture"); arch.AppendLine(); arch.AppendLine("```"); arch.AppendLine("┌─────────────────┐"); arch.AppendLine("│ Shared UI │"); arch.AppendLine("├─────────────────┤"); arch.AppendLine("│ Business Logic │"); arch.AppendLine("├─────────────────┤"); arch.AppendLine("│ Platform APIs │"); arch.AppendLine("└─────────────────┘"); arch.AppendLine("```"); } return arch.ToString(); } private string GetComponentType(string className) { var lower = className.ToLower(); if (lower.Contains("service")) return "Services"; if (lower.Contains("controller")) return "Controllers"; if (lower.Contains("repository")) return "Repositories"; if (lower.Contains("manager")) return "Managers"; if (lower.Contains("factory")) return "Factories"; if (lower.Contains("builder")) return "Builders"; if (lower.Contains("plugin")) return "Plugins"; if (lower.Contains("handler")) return "Handlers"; if (lower.Contains("provider")) return "Providers"; if (lower.Contains("helper")) return "Helpers"; if (lower.Contains("util")) return "Utilities"; if (lower.StartsWith("i") && char.IsUpper(className[1])) return "Interfaces"; return "Core Classes"; } private string GenerateDependenciesSection(ProjectAnalysisResult analysis) { if (!analysis.Dependencies.Any()) return ""; var deps = new StringBuilder(); deps.AppendLine("## Dependencies"); deps.AppendLine(); var majorDeps = analysis.Dependencies .Where(d => !d.StartsWith("System.") && !d.StartsWith("Microsoft.Extensions.")) .Take(10) .ToList(); if (majorDeps.Any()) { deps.AppendLine("### Major Dependencies"); deps.AppendLine(); foreach (var dep in majorDeps) { deps.AppendLine($"- {dep}"); } deps.AppendLine(); } deps.AppendLine($"### Target Framework"); if (analysis.DetectedProjectType == "maui") { var netVersion = ExtractNetVersion(analysis.TargetFramework); var platforms = ExtractMauiPlatforms(analysis.TargetFramework); deps.AppendLine($"- .NET {netVersion}"); if (platforms.Any()) { deps.AppendLine($"- Platforms: {string.Join(", ", platforms)}"); } } else { var netVersion = ExtractNetVersion(analysis.TargetFramework); deps.AppendLine($"- .NET {netVersion}"); } deps.AppendLine(); return deps.ToString(); } private string GenerateContributingSection(ProjectAnalysisResult analysis) { var contrib = new StringBuilder(); contrib.AppendLine("## Contributing"); contrib.AppendLine(); contrib.AppendLine("1. Fork the repository"); contrib.AppendLine("2. Create a feature branch"); contrib.AppendLine("3. Make your changes"); contrib.AppendLine("4. Add tests if applicable"); contrib.AppendLine("5. Submit a pull request"); contrib.AppendLine(); if (analysis.HasTests) { contrib.AppendLine("### Running Tests"); contrib.AppendLine(); contrib.AppendLine("```bash"); contrib.AppendLine("dotnet test"); contrib.AppendLine("```"); contrib.AppendLine(); } contrib.AppendLine("## License"); contrib.AppendLine(); contrib.AppendLine("This project is licensed under the MIT License - see the LICENSE file for details."); contrib.AppendLine(); return contrib.ToString(); } private string FormatProjectType(string projectType) { return projectType switch { "library" => ".NET Library", "application" => ".NET Application", "tool" => "Command-Line Tool", "maui" => ".NET MAUI Application", _ => ".NET Project" }; } // Helper methods for parameter extraction private object GetParameterValue(IReadOnlyDictionary parameters, params string[] keys) { foreach (var key in keys) { if (parameters.TryGetValue(key, out var value)) return value; } return null; } private bool GetBoolParameter(IReadOnlyDictionary parameters, string key1, string key2, bool defaultValue = false) { var value = GetParameterValue(parameters, key1, key2); return value != null ? Convert.ToBoolean(value) : defaultValue; } private int GetIntParameter(IReadOnlyDictionary parameters, string key1, string key2, int defaultValue = 0) { var value = GetParameterValue(parameters, key1, key2); return value != null ? Convert.ToInt32(value) : defaultValue; } } // Supporting classes for README generation public class ProjectAnalysisResult { public bool Success { get; set; } public string Error { get; set; } public string ProjectName { get; set; } public string ProjectPath { get; set; } public string DetectedProjectType { get; set; } public string TargetFramework { get; set; } public bool IsSolution { get; set; } public bool HasTests { get; set; } public bool HasDocumentation { get; set; } public int FilesAnalyzed { get; set; } public List Dependencies { get; set; } = new List(); public List KeyFiles { get; set; } = new List(); public List PublicApis { get; set; } = new List(); public List SubProjects { get; set; } = new List(); public List IncludedSections { get; set; } = new List(); } public class CodeFileAnalysis { public string FilePath { get; set; } public string FileName { get; set; } public string Namespace { get; set; } public int LineCount { get; set; } public List Classes { get; set; } = new List(); public List Interfaces { get; set; } = new List(); public bool HasAttributes { get; set; } public bool HasAsyncMethods { get; set; } } public class ApiMethod { public string Name { get; set; } public string ClassName { get; set; } public string ReturnType { get; set; } public List Parameters { get; set; } = new List(); public bool IsAsync { get; set; } public string Summary { get; set; } public bool IsPluginMethod { get; set; } } }