""" Доменные модели инструментария. Все типы данных, которыми обмениваются модули системы. """ from __future__ import annotations from dataclasses import dataclass, field from enum import Enum, auto from pathlib import Path from typing import Dict, List, Optional, Set # --------------------------------------------------------------------------- # Метрики # --------------------------------------------------------------------------- @dataclass class FunctionMetrics: """Метрики одной функции / метода.""" name: str file: str line: int ccn: int # Цикломатическая сложность (McCabe) nloc: int # Строк кода без комментариев params: int # Число параметров language: str # "cpp" | "js" @property def is_complex(self) -> bool: return self.ccn > 10 @property def is_large(self) -> bool: return self.nloc > 50 @dataclass class ModuleMetrics: """Агрегированные метрики модуля (директории или файла).""" name: str # Имя модуля (путь относительно корня) files: List[str] = field(default_factory=list) functions: List[FunctionMetrics] = field(default_factory=list) language: str = "mixed" # "cpp" | "js" | "mixed" # Агрегированные показатели (заполняются MetricsEngine) total_nloc: int = 0 avg_ccn: float = 0.0 max_ccn: int = 0 total_functions: int = 0 heavy_functions_count: int = 0 # Функций с CCN > порога heavy_functions_ratio: float = 0.0 # Граф зависимостей (заполняется DependencyAnalyzer) coupling_out: int = 0 # Исходящая связность (fan-out) coupling_in: int = 0 # Входящая связность (fan-in) instability: float = 0.0 # C_out / (C_in + C_out), метрика Р. Мартина has_cycles: bool = False # Участвует в циклической зависимости # Зависимости dependencies: Set[str] = field(default_factory=set) # Модули, от которых зависит этот dependents: Set[str] = field(default_factory=set) # Модули, зависящие от этого # --------------------------------------------------------------------------- # Классификация риска и стратегия # --------------------------------------------------------------------------- class RiskLevel(Enum): """Уровень архитектурного риска модуля.""" LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" class ModernizationStrategy(Enum): """Рекомендуемая стратегия модернизации (Lehman & Belady, 1985).""" KEEP = auto() # Оставить без изменений REFACTOR = auto() # Локальный рефакторинг (Fowler, 2018) REENGINEER = auto() # Реинжиниринг архитектуры REPLACE = auto() # Полная замена @dataclass class ModuleDecision: """Решение DecisionEngine по конкретному модулю.""" module_name: str risk_level: RiskLevel strategy: ModernizationStrategy reasons: List[str] = field(default_factory=list) # Причины в человекочитаемом виде priority: int = 0 # Приоритет в плане рефакторинга (1 = высший) # --------------------------------------------------------------------------- # Итоговый отчёт # --------------------------------------------------------------------------- @dataclass class AnalysisReport: """Итоговый отчёт по всей системе.""" project_root: str modules: Dict[str, ModuleMetrics] = field(default_factory=dict) decisions: List[ModuleDecision] = field(default_factory=list) dependency_cycles: List[List[str]] = field(default_factory=list) # Системные агрегаты total_files: int = 0 total_nloc: int = 0 total_functions: int = 0 avg_system_ccn: float = 0.0 system_risk_level: RiskLevel = RiskLevel.LOW recommended_system_strategy: ModernizationStrategy = ModernizationStrategy.KEEP @property def critical_modules(self) -> List[ModuleDecision]: return [d for d in self.decisions if d.risk_level == RiskLevel.CRITICAL] @property def high_risk_modules(self) -> List[ModuleDecision]: return [d for d in self.decisions if d.risk_level in (RiskLevel.HIGH, RiskLevel.CRITICAL)]