Add source code files (detectors, generators, CLI)

This commit is contained in:
2026-02-01 20:15:29 +00:00
parent 1807df8833
commit 56d2adcd14

114
src/detectors/base.py Normal file
View 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