diff --git a/src/skill_seekers/cli/architectural_pattern_detector.py b/src/skill_seekers/cli/architectural_pattern_detector.py index 57e6279..66b0a25 100644 --- a/src/skill_seekers/cli/architectural_pattern_detector.py +++ b/src/skill_seekers/cli/architectural_pattern_detector.py @@ -101,14 +101,14 @@ class ArchitecturalPatternDetector: # Web Frameworks "Django": ["django", "manage.py", "settings.py", "urls.py"], "Flask": ["flask", "app.py", "wsgi.py"], - "Spring": ["springframework", "@Controller", "@Service", "@Repository"], - "ASP.NET": ["Controllers", "Models", "Views", ".cshtml", "Startup.cs"], - "Rails": ["app/models", "app/views", "app/controllers", "config/routes.rb"], - "Angular": ["app.module.ts", "@Component", "@Injectable", "angular.json"], - "React": ["package.json", "react", "components"], + "Spring": ["springframework", "org.springframework", "@Controller", "@Service", "@Repository"], + "ASP.NET": ["Microsoft.AspNetCore", "System.Web", "Controllers", "Models", "Views", ".cshtml", "Startup.cs"], + "Rails": ["rails", "action", "app/models", "app/views", "app/controllers", "config/routes.rb"], + "Angular": ["@angular", "angular", "app.module.ts", "@Component", "@Injectable", "angular.json"], + "React": ["react", "package.json", "components"], "Vue.js": ["vue", ".vue", "components"], "Express": ["express", "app.js", "routes"], - "Laravel": ["artisan", "app/Http/Controllers", "app/Models"], + "Laravel": ["laravel", "illuminate", "artisan", "app/Http/Controllers", "app/Models"], } def __init__(self, enhance_with_ai: bool = True): @@ -200,15 +200,15 @@ class ArchitecturalPatternDetector: all_paths = [str(f.get("file", "")) for f in files] all_content = " ".join(all_paths) - # Extract all imports from Python files (fixes #239) + # Extract all imports from ALL languages (fixes #239 - extended to multi-language) all_imports = [] for file_data in files: - if file_data.get("language") == "Python" and file_data.get("imports"): + if file_data.get("imports"): all_imports.extend(file_data["imports"]) # Create searchable import string import_content = " ".join(all_imports) - logger.debug(f"Collected {len(all_imports)} imports for framework detection") + logger.debug(f"Collected {len(all_imports)} imports from {len([f for f in files if f.get('imports')])} files for framework detection") # Also check actual directory structure for game engine markers # (project.godot, .unity, .uproject are config files, not in analyzed files) diff --git a/src/skill_seekers/cli/code_analyzer.py b/src/skill_seekers/cli/code_analyzer.py index a8d939b..273161d 100644 --- a/src/skill_seekers/cli/code_analyzer.py +++ b/src/skill_seekers/cli/code_analyzer.py @@ -361,7 +361,31 @@ class CodeAnalyzer: # Extract comments comments = self._extract_js_comments(content) - return {"classes": classes, "functions": functions, "comments": comments} + # Extract imports for framework detection + imports = [] + # Match: import foo from 'bar' + # Match: import { foo } from 'bar' + # Match: import * as foo from 'bar' + # Match: const foo = require('bar') + import_patterns = [ + r"import\s+.*?\s+from\s+['\"]([^'\"]+)['\"]", # ES6 imports + r"import\s+['\"]([^'\"]+)['\"]", # Side-effect imports + r"require\(['\"]([^'\"]+)['\"]\)", # CommonJS require + ] + for pattern in import_patterns: + for match in re.finditer(pattern, content): + module = match.group(1) + # Extract package name (before first /) + package = module.split('/')[0] + if package and not package.startswith('.'): # Skip relative imports + imports.append(package) + + return { + "classes": classes, + "functions": functions, + "comments": comments, + "imports": list(set(imports)), # Deduplicate + } def _extract_js_methods(self, class_body: str) -> list[dict]: """Extract method signatures from class body.""" @@ -662,7 +686,29 @@ class CodeAnalyzer: # Extract comments comments = self._extract_csharp_comments(content) - return {"classes": classes, "functions": functions, "comments": comments} + # Extract imports for framework detection + imports = [] + # Match: using System.Collections.Generic; + # Match: using static System.Math; + using_pattern = r"using\s+(?:static\s+)?([^;=]+);" + for match in re.finditer(using_pattern, content): + namespace = match.group(1).strip() + # Skip using aliases (using Foo = Bar.Baz) + if '=' not in namespace: + # Extract base namespace (first 1-2 segments) + parts = namespace.split('.') + if len(parts) >= 2: + base_ns = '.'.join(parts[:2]) + imports.append(base_ns) + elif len(parts) == 1: + imports.append(parts[0]) + + return { + "classes": classes, + "functions": functions, + "comments": comments, + "imports": list(set(imports)), # Deduplicate + } def _extract_csharp_methods(self, class_body: str) -> list[dict]: """Extract C# method signatures from class body.""" @@ -1076,7 +1122,26 @@ class CodeAnalyzer: # Extract comments comments = self._extract_java_comments(content) - return {"classes": classes, "functions": functions, "comments": comments} + # Extract imports for framework detection + imports = [] + # Match: import com.example.Foo; + # Match: import static com.example.Foo.bar; + import_pattern = r"import\s+(?:static\s+)?([^;]+);" + for match in re.finditer(import_pattern, content): + import_path = match.group(1).strip() + # Extract package name (first 2-3 segments for framework detection) + parts = import_path.split('.') + if len(parts) >= 2: + # Get base package (e.g., "org.springframework" from "org.springframework.boot.SpringApplication") + package = '.'.join(parts[:2]) + imports.append(package) + + return { + "classes": classes, + "functions": functions, + "comments": comments, + "imports": list(set(imports)), # Deduplicate + } def _extract_java_methods(self, class_body: str) -> list[dict]: """Extract Java method signatures from class body.""" @@ -1229,7 +1294,24 @@ class CodeAnalyzer: # Extract comments comments = self._extract_ruby_comments(content) - return {"classes": classes, "functions": functions, "comments": comments} + # Extract imports for framework detection + imports = [] + # Match: require 'foo' + # Match: require "foo" + # Match: require_relative 'foo' + require_pattern = r"require(?:_relative)?\s+['\"]([^'\"]+)['\"]" + for match in re.finditer(require_pattern, content): + module = match.group(1) + # Extract gem name (before first /) + gem = module.split('/')[0] + imports.append(gem) + + return { + "classes": classes, + "functions": functions, + "comments": comments, + "imports": list(set(imports)), # Deduplicate + } def _parse_ruby_parameters(self, params_str: str) -> list[dict]: """Parse Ruby parameter string.""" @@ -1353,7 +1435,25 @@ class CodeAnalyzer: # Extract comments comments = self._extract_php_comments(content) - return {"classes": classes, "functions": functions, "comments": comments} + # Extract imports for framework detection + imports = [] + # Match: use Foo\Bar\Baz; + # Match: use Foo\Bar\Baz as Alias; + use_pattern = r"use\s+([^;]+?)(?:\s+as\s+\w+)?;" + for match in re.finditer(use_pattern, content): + namespace = match.group(1).strip() + # Extract vendor name (first segment) + parts = namespace.split('\\') + if parts: + vendor = parts[0] + imports.append(vendor.lower()) + + return { + "classes": classes, + "functions": functions, + "comments": comments, + "imports": list(set(imports)), # Deduplicate + } def _extract_php_methods(self, class_body: str) -> list[dict]: """Extract PHP method signatures from class body."""