Files
G4F/ReactDev/core/project_map.py
2025-06-02 14:22:46 +03:00

82 lines
3.2 KiB
Python

import os
from pathlib import Path
from pathspec import PathSpec
from pathspec.patterns import GitWildMatchPattern
from ..utils.logger import log
class ProjectMap:
def __init__(self, project_path: str):
self.project_path = project_path
self.gitignore_rules = self._load_gitignore()
def generate_map(self) -> str:
"""
Создает карту структуры проекта, игнорируя файлы из .gitignore и директорию .git/.
"""
log("Generating project structure map...")
structure = self._traverse_directory(self.project_path)
return structure
def _traverse_directory(self, path: str, level: int = 0) -> str:
"""
Рекурсивно обходит директории и формирует строку структуры,
игнорируя файлы и директории из .gitignore и .git/.
"""
indent = " " * level
result = ""
for entry in sorted(os.listdir(path)):
full_path = os.path.join(path, entry)
# Игнорируем директорию .git/
if entry == ".git":
continue
# Проверяем, игнорируется ли файл или директория по правилам .gitignore
relative_path = os.path.relpath(full_path, self.project_path)
if self._is_ignored(relative_path):
continue
if os.path.isdir(full_path):
result += f"{indent}- {entry}/\n"
result += self._traverse_directory(full_path, level + 1)
else:
result += f"{indent}- {entry}\n"
return result
def save_map(self, output_file: str = "react_app_map.txt"):
"""
Сохраняет карту структуры в файл.
"""
map_content = self.generate_map()
with open(output_file, "w", encoding="utf-8") as f:
f.write(map_content)
log(f"Project map saved to {output_file}")
def _load_gitignore(self) -> list:
"""
Загружает правила из .gitignore, если файл существует.
"""
gitignore_path = os.path.join(self.project_path, ".gitignore")
rules = []
if os.path.exists(gitignore_path):
with open(gitignore_path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"): # Игнорируем комментарии и пустые строки
rules.append(line)
return rules
def _is_ignored(self, path: str) -> bool:
"""
Проверяет, игнорируется ли файл или директория по правилам .gitignore,
включая поддержку сложных правил (например, **/logs/*.log).
"""
# Преобразуем правила .gitignore в PathSpec
spec = PathSpec.from_lines(GitWildMatchPattern, self.gitignore_rules)
# Проверяем, соответствует ли путь правилам
return spec.match_file(path)