Add source code files (detectors, generators, CLI)

This commit is contained in:
2026-02-01 20:15:31 +00:00
parent d48ac70796
commit b4a043e759

176
src/generators/pattern.py Normal file
View File

@@ -0,0 +1,176 @@
"""Pattern generator for creating .gitignore content."""
from typing import List, Optional, Set
from src.data.patterns import (
FRAMEWORK_PATTERNS,
IDE_PATTERNS,
LANGUAGE_PATTERNS,
OS_PATTERNS,
)
class PatternGenerator:
"""Generates .gitignore patterns based on detected stack."""
def __init__(self) -> None:
self.language_patterns = LANGUAGE_PATTERNS
self.framework_patterns = FRAMEWORK_PATTERNS
self.ide_patterns = IDE_PATTERNS
self.os_patterns = OS_PATTERNS
def generate(
self,
languages: Optional[List[str]] = None,
frameworks: Optional[List[str]] = None,
ides: Optional[List[str]] = None,
os_list: Optional[List[str]] = None,
custom_patterns: Optional[List[str]] = None,
) -> str:
"""Generate .gitignore content.
Args:
languages: List of detected languages.
frameworks: List of detected frameworks.
ides: List of detected IDEs.
os_list: List of operating systems.
custom_patterns: User-provided custom patterns.
Returns:
Complete .gitignore content as string.
"""
lines: List[str] = []
seen_patterns: Set[str] = set()
os_order = ["macos", "windows", "linux"]
ide_order = ["jetbrains", "vscode", "pycharm", "webstorm", "intellij", "eclipse", "netbeans", "sublime", "vim", "emacs", "atom", "spacemacs"]
language_order = ["python", "nodejs", "go", "java", "rust", "csharp", "cpp", "ruby", "php", "dart", "swift", "kotlin", "scala", "perl", "r", "elixir", "clojure", "lua", "haskell"]
framework_order = ["django", "flask", "fastapi", "react", "vue", "angular", "express", "nextjs", "nuxt", "svelte", "gatsby", "astro", "gin", "spring", "rails", "laravel", "dotnet", "quasar", "sveltekit", "remix", "vite", "nestjs"]
os_list = os_list or []
ides = ides or []
languages = languages or []
frameworks = frameworks or []
if not os_list and not ides and not languages and not frameworks:
os_list = ["macos", "windows", "linux"]
for os_name in os_order:
if os_name in os_list:
self._add_patterns(lines, seen_patterns, self.os_patterns.get(os_name, []), f"=== {os_name.upper()} ===")
for ide_name in ide_order:
if ide_name in ides:
self._add_patterns(lines, seen_patterns, self.ide_patterns.get(ide_name, []), f"=== {ide_name.upper()} ===")
for lang_name in language_order:
if lang_name in languages:
self._add_patterns(lines, seen_patterns, self.language_patterns.get(lang_name, []), f"=== {lang_name.upper()} ===")
for fw_name in framework_order:
if fw_name in frameworks:
self._add_patterns(lines, seen_patterns, self.framework_patterns.get(fw_name, []), f"=== {fw_name.upper()} ===")
if custom_patterns:
self._add_patterns(lines, seen_patterns, custom_patterns, "=== CUSTOM ===")
return "\n".join(lines)
def _add_patterns(
self,
lines: List[str],
seen_patterns: Set[str],
patterns: List[str],
header: Optional[str] = None,
) -> None:
"""Add patterns to lines list, avoiding duplicates.
Args:
lines: List to append patterns to.
seen_patterns: Set of already added patterns.
patterns: Patterns to add.
header: Optional section header.
"""
if not patterns:
return
section_patterns: List[str] = []
for pattern in patterns:
if pattern and pattern not in seen_patterns:
normalized = pattern.strip()
if normalized and normalized not in seen_patterns:
seen_patterns.add(normalized)
section_patterns.append(normalized)
if section_patterns:
if header:
lines.append(f"# {header}")
lines.extend(section_patterns)
lines.append("")
def get_supported_languages(self) -> List[str]:
"""Get list of supported languages.
Returns:
List of language names.
"""
return list(self.language_patterns.keys())
def get_supported_frameworks(self) -> List[str]:
"""Get list of supported frameworks.
Returns:
List of framework names.
"""
return list(self.framework_patterns.keys())
def get_supported_ides(self) -> List[str]:
"""Get list of supported IDEs.
Returns:
List of IDE names.
"""
return list(self.ide_patterns.keys())
def get_supported_os(self) -> List[str]:
"""Get list of supported operating systems.
Returns:
List of OS names.
"""
return list(self.os_patterns.keys())
def validate_pattern(self, pattern: str) -> tuple[bool, str]:
"""Validate a single gitignore pattern.
Args:
pattern: Pattern to validate.
Returns:
Tuple of (is_valid, error_message).
"""
if not pattern or not pattern.strip():
return False, "Pattern cannot be empty"
pattern = pattern.strip()
if pattern.startswith("#"):
return True, ""
if pattern.startswith("!"):
if len(pattern) < 2:
return False, "Negation pattern must have content after '!'"
return True, ""
if pattern.startswith("/"):
if len(pattern) < 2:
return False, "Root pattern must have content after '/'"
return True, ""
invalid_chars = ["\n", "\r", "\t"]
for char in invalid_chars:
if char in pattern:
return False, f"Pattern contains invalid character: {repr(char)}"
return True, ""