project_detector
¶
Full name: tenets.core.analysis.project_detector
project_detector¶
Project type detection and entry point discovery.
This module provides intelligent detection of project types, main entry points, and project structure based on language analyzers and file patterns.
Classes¶
ProjectDetector¶
Detects project type and structure using language analyzers.
This class leverages the language-specific analyzers to detect project types and entry points, avoiding duplication of language-specific knowledge.
Initialize project detector with language analyzers.
Source code in tenets/core/analysis/project_detector.py
def __init__(self):
"""Initialize project detector with language analyzers."""
self.logger = get_logger(__name__)
# Initialize all language analyzers
self.analyzers = [
PythonAnalyzer(),
JavaScriptAnalyzer(),
JavaAnalyzer(),
GoAnalyzer(),
RustAnalyzer(),
CppAnalyzer(),
CSharpAnalyzer(),
RubyAnalyzer(),
PhpAnalyzer(),
SwiftAnalyzer(),
KotlinAnalyzer(),
ScalaAnalyzer(),
DartAnalyzer(),
GDScriptAnalyzer(),
HTMLAnalyzer(),
CSSAnalyzer(),
]
# Build dynamic mappings from analyzers
self._build_mappings()
# Additional framework patterns not tied to specific languages
self.FRAMEWORK_PATTERNS = {
"docker": ["Dockerfile", "docker-compose.yml", "docker-compose.yaml"],
"kubernetes": ["k8s/", "kubernetes/", "deployment.yaml", "service.yaml"],
"terraform": ["*.tf", "terraform.tfvars"],
"ansible": ["ansible.cfg", "playbook.yml", "inventory"],
"ci_cd": [".github/workflows/", ".gitlab-ci.yml", "Jenkinsfile", ".travis.yml"],
}
Functions¶
detect_project_type¶
Detect project type and main entry points.
PARAMETER | DESCRIPTION |
---|---|
path | Root directory to analyze TYPE: |
RETURNS | DESCRIPTION |
---|---|
Dict[str, any] | Dictionary containing: - type: Primary project type - languages: List of detected languages - frameworks: List of detected frameworks - entry_points: List of likely entry point files - confidence: Confidence score (0-1) |
Source code in tenets/core/analysis/project_detector.py
def detect_project_type(self, path: Path) -> Dict[str, any]:
"""Detect project type and main entry points.
Args:
path: Root directory to analyze
Returns:
Dictionary containing:
- type: Primary project type
- languages: List of detected languages
- frameworks: List of detected frameworks
- entry_points: List of likely entry point files
- confidence: Confidence score (0-1)
"""
path = Path(path)
if not path.exists():
return {
"type": "unknown",
"languages": [],
"frameworks": [],
"entry_points": [],
"confidence": 0.0,
}
# Collect all files
all_files = []
for ext in ["*.*", "Dockerfile", "Makefile", "Jenkinsfile"]:
all_files.extend(path.rglob(ext))
# Analyze file extensions to detect languages
extensions = Counter()
for file in all_files:
if file.is_file():
ext = file.suffix.lower()
if ext:
extensions[ext] += 1
# Determine primary languages based on extensions
languages = []
for ext, count in extensions.most_common(10):
if ext in self.EXTENSION_TO_LANGUAGE:
lang = self.EXTENSION_TO_LANGUAGE[ext]
if lang not in languages:
languages.append(lang)
# Detect frameworks based on indicators
frameworks = []
file_names = {f.name for f in all_files if f.is_file()}
dir_names = {f.name for f in all_files if f.is_dir()}
# Check language-specific project indicators
for project_type, indicators in self.PROJECT_INDICATORS.items():
for indicator in indicators:
if indicator in file_names or indicator in dir_names:
frameworks.append(project_type)
break
# Check general framework patterns
for framework, patterns in self.FRAMEWORK_PATTERNS.items():
for pattern in patterns:
if pattern.endswith("/"):
# Directory pattern
if pattern[:-1] in dir_names:
frameworks.append(framework)
break
elif "*" in pattern:
# Glob pattern
if any(f.match(pattern) for f in all_files if f.is_file()):
frameworks.append(framework)
break
else:
# File pattern
if pattern in file_names:
frameworks.append(framework)
break
# Find entry points
entry_points = self._find_entry_points(path, languages, file_names)
# Determine primary project type
project_type = self._determine_project_type(languages, frameworks)
# Calculate confidence
confidence = self._calculate_confidence(languages, frameworks, entry_points)
return {
"type": project_type,
"languages": languages[:3], # Top 3 languages
"frameworks": list(set(frameworks))[:3], # Top 3 unique frameworks
"entry_points": entry_points[:5], # Top 5 entry points
"confidence": confidence,
}
find_main_file¶
Find the most likely main/entry file in a project.
PARAMETER | DESCRIPTION |
---|---|
path | Directory to search in TYPE: |
RETURNS | DESCRIPTION |
---|---|
Optional[Path] | Path to the main file, or None if not found |
Source code in tenets/core/analysis/project_detector.py
def find_main_file(self, path: Path) -> Optional[Path]:
"""Find the most likely main/entry file in a project.
Args:
path: Directory to search in
Returns:
Path to the main file, or None if not found
"""
path = Path(path)
if not path.is_dir():
return None
# Detect project info
project_info = self.detect_project_type(path)
# Use detected entry points
if project_info["entry_points"]:
main_file = path / project_info["entry_points"][0]
if main_file.exists():
return main_file
# Fall back to language-specific patterns
for lang in project_info["languages"]:
if lang in self.ENTRY_POINTS:
for entry_point in self.ENTRY_POINTS[lang]:
for file_path in path.rglob(entry_point):
if file_path.is_file():
return file_path
return None