using System; using System.IO; using System.Linq; namespace MarketAlly.ProjectDetector { /// /// Locates the best project or solution file to index/analyze in a given directory /// public static class ProjectFileLocator { /// /// Finds the best file to index based on the project type /// public static string FindBestFileToIndex(string projectPath, ProjectType projectType, bool ignoreSolution) { if (!ignoreSolution) { // Look for solution files first (they're usually the best to index) var solutionFiles = Directory.GetFiles(projectPath, "*.sln", SearchOption.TopDirectoryOnly); if (solutionFiles.Any()) { return Path.GetFullPath(solutionFiles.First()); } } // Based on project type, look for appropriate project files switch (projectType) { // .NET project types case ProjectType.API: case ProjectType.WebApp: case ProjectType.Library: case ProjectType.Service: case ProjectType.Tests: case ProjectType.WpfApp: case ProjectType.WinFormsApp: case ProjectType.MobileApp: case ProjectType.Function: case ProjectType.Standalone: case ProjectType.Tool: case ProjectType.Plugin: case ProjectType.ChatBot: return FindDotNetProjectFile(projectPath) ?? projectPath; // Node.js project types case ProjectType.ReactApp: case ProjectType.VueApp: case ProjectType.AngularApp: case ProjectType.NextJsApp: case ProjectType.NodeJsApi: case ProjectType.NodeJsApp: case ProjectType.ElectronApp: // For Node projects, the directory itself is usually the best option // as package.json defines the project return projectPath; // Python project types case ProjectType.DjangoApp: case ProjectType.FlaskApp: case ProjectType.PythonApp: return FindPythonProjectFile(projectPath) ?? projectPath; // Java project types case ProjectType.JavaMavenProject: return FindMavenProjectFile(projectPath) ?? projectPath; case ProjectType.JavaGradleProject: return FindGradleProjectFile(projectPath) ?? projectPath; // Go projects case ProjectType.GoApp: var goMod = Path.Combine(projectPath, "go.mod"); return File.Exists(goMod) ? goMod : projectPath; // Rust projects case ProjectType.RustApp: var cargoToml = Path.Combine(projectPath, "Cargo.toml"); return File.Exists(cargoToml) ? cargoToml : projectPath; // Game development case ProjectType.UnityProject: // Unity projects are defined by the directory containing Assets folder var assetsFolder = Path.Combine(projectPath, "Assets"); return Directory.Exists(assetsFolder) ? projectPath : projectPath; case ProjectType.UnrealProject: // Look for .uproject files var uprojectFiles = Directory.GetFiles(projectPath, "*.uproject", SearchOption.TopDirectoryOnly); return uprojectFiles.FirstOrDefault() ?? projectPath; case ProjectType.GodotProject: // Look for project.godot file var godotProject = Path.Combine(projectPath, "project.godot"); return File.Exists(godotProject) ? projectPath : projectPath; default: // For unknown types, try to find any common project file return FindAnyIndexableFile(projectPath, ignoreSolution); } } /// /// Finds any indexable file when project type is unknown or manually overridden /// public static string FindAnyIndexableFile(string projectPath, bool ignoreSolution) { // 1. Look for solution files first (highest priority) if (!ignoreSolution) { var solutionFiles = Directory.GetFiles(projectPath, "*.sln", SearchOption.TopDirectoryOnly); if (solutionFiles.Any()) { return Path.GetFullPath(solutionFiles.First()); } } // 2. Look for .NET project files var dotnetProject = FindDotNetProjectFile(projectPath); if (dotnetProject != null) { return dotnetProject; } // 3. Check for package.json (Node.js projects) var packageJson = Path.Combine(projectPath, "package.json"); if (File.Exists(packageJson)) { return projectPath; // For Node projects, index the directory } // 4. Check for Python project files var pythonProject = FindPythonProjectFile(projectPath); if (pythonProject != null) { return pythonProject; } // 5. Check for Java project files var mavenProject = FindMavenProjectFile(projectPath); if (mavenProject != null) { return mavenProject; } var gradleProject = FindGradleProjectFile(projectPath); if (gradleProject != null) { return gradleProject; } // 6. Check for Go modules var goMod = Path.Combine(projectPath, "go.mod"); if (File.Exists(goMod)) { return goMod; } // 7. Check for Rust projects var cargoToml = Path.Combine(projectPath, "Cargo.toml"); if (File.Exists(cargoToml)) { return cargoToml; } // 8. Check for requirements.txt (generic Python projects) var requirementsTxt = Path.Combine(projectPath, "requirements.txt"); if (File.Exists(requirementsTxt)) { return projectPath; } // Default: Just return the directory for analysis return projectPath; } private static string? FindDotNetProjectFile(string projectPath) { var projectFiles = Directory.GetFiles(projectPath, "*.csproj", SearchOption.AllDirectories) .Concat(Directory.GetFiles(projectPath, "*.vbproj", SearchOption.AllDirectories)) .Concat(Directory.GetFiles(projectPath, "*.fsproj", SearchOption.AllDirectories)) .OrderBy(f => f.Count(c => c == Path.DirectorySeparatorChar)) // Prefer files closer to root .FirstOrDefault(); // Normalize the path if found return projectFiles != null ? Path.GetFullPath(projectFiles) : null; } private static string? FindPythonProjectFile(string projectPath) { // Check for setup.py var setupPy = Path.Combine(projectPath, "setup.py"); if (File.Exists(setupPy)) return setupPy; // Check for pyproject.toml var pyprojectToml = Path.Combine(projectPath, "pyproject.toml"); if (File.Exists(pyprojectToml)) return pyprojectToml; // Check for setup.cfg var setupCfg = Path.Combine(projectPath, "setup.cfg"); if (File.Exists(setupCfg)) return projectPath; return null; } private static string? FindMavenProjectFile(string projectPath) { var pomFile = Directory.GetFiles(projectPath, "pom.xml", SearchOption.AllDirectories) .OrderBy(f => f.Count(c => c == Path.DirectorySeparatorChar)) .FirstOrDefault(); return pomFile != null ? Path.GetFullPath(pomFile) : null; } private static string? FindGradleProjectFile(string projectPath) { var buildGradle = Directory.GetFiles(projectPath, "build.gradle", SearchOption.AllDirectories) .OrderBy(f => f.Count(c => c == Path.DirectorySeparatorChar)) .FirstOrDefault(); if (buildGradle != null) return Path.GetFullPath(buildGradle); // Also check for build.gradle.kts (Kotlin DSL) var buildGradleKts = Directory.GetFiles(projectPath, "build.gradle.kts", SearchOption.AllDirectories) .OrderBy(f => f.Count(c => c == Path.DirectorySeparatorChar)) .FirstOrDefault(); return buildGradleKts != null ? Path.GetFullPath(buildGradleKts) : null; } } }