Add source code files (detectors, generators, CLI)
This commit is contained in:
114
src/detectors/base.py
Normal file
114
src/detectors/base.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""Base detector class for project detection."""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
class BaseDetector(ABC):
|
||||
"""Abstract base class for all detectors."""
|
||||
|
||||
@abstractmethod
|
||||
def detect(self, project_path: Path) -> List[str]:
|
||||
"""Detect items from the project path.
|
||||
|
||||
Args:
|
||||
project_path: Path to the project directory.
|
||||
|
||||
Returns:
|
||||
List of detected item names (e.g., language names, framework names).
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_priority(self) -> int:
|
||||
"""Get the priority of this detector.
|
||||
|
||||
Higher priority detectors are run first.
|
||||
|
||||
Returns:
|
||||
Integer priority value.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _find_files(self, project_path: Path, patterns: List[str]) -> List[Path]:
|
||||
"""Find files matching given patterns.
|
||||
|
||||
Args:
|
||||
project_path: Root directory to search.
|
||||
patterns: List of filename patterns to match.
|
||||
|
||||
Returns:
|
||||
List of matching file paths.
|
||||
"""
|
||||
if not project_path.exists() or not project_path.is_dir():
|
||||
return []
|
||||
|
||||
found_files = []
|
||||
try:
|
||||
for pattern in patterns:
|
||||
matches = list(project_path.rglob(pattern))
|
||||
found_files.extend(matches)
|
||||
except PermissionError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return found_files
|
||||
|
||||
def _read_file_content(self, file_path: Path, max_size: int = 10240) -> Optional[str]:
|
||||
"""Read file content safely.
|
||||
|
||||
Args:
|
||||
file_path: Path to the file.
|
||||
max_size: Maximum file size to read in bytes.
|
||||
|
||||
Returns:
|
||||
File content as string, or None if reading fails.
|
||||
"""
|
||||
try:
|
||||
if file_path.stat().st_size > max_size:
|
||||
return None
|
||||
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
return f.read()
|
||||
except (PermissionError, OSError, UnicodeDecodeError):
|
||||
return None
|
||||
|
||||
def _check_file_exists(self, project_path: Path, filenames: List[str]) -> List[str]:
|
||||
"""Check if any of the given filenames exist.
|
||||
|
||||
Args:
|
||||
project_path: Project root directory.
|
||||
filenames: List of filenames to check.
|
||||
|
||||
Returns:
|
||||
List of existing filenames.
|
||||
"""
|
||||
existing = []
|
||||
for filename in filenames:
|
||||
if (project_path / filename).exists():
|
||||
existing.append(filename)
|
||||
return existing
|
||||
|
||||
def _check_content_markers(self, project_path: Path, markers: Dict[str, str]) -> List[str]:
|
||||
"""Check for content markers in source files.
|
||||
|
||||
Args:
|
||||
project_path: Project root directory.
|
||||
markers: Dict mapping marker names to search patterns.
|
||||
|
||||
Returns:
|
||||
List of found marker names.
|
||||
"""
|
||||
found = []
|
||||
try:
|
||||
for file_path in project_path.rglob("*"):
|
||||
if file_path.is_file() and file_path.suffix in ['.py', '.js', '.ts', '.go', '.java', '.rb', '.php', '.rs']:
|
||||
content = self._read_file_content(file_path)
|
||||
if content:
|
||||
for name, pattern in markers.items():
|
||||
if name not in found and pattern.lower() in content.lower():
|
||||
found.append(name)
|
||||
except (PermissionError, OSError):
|
||||
pass
|
||||
return found
|
||||
Reference in New Issue
Block a user