Source code for skill_creator_mcp.utils.refactorors

"""重构建议工具函数."""

from pathlib import Path
from typing import TYPE_CHECKING

from ..constants import (
    CODE_SIZE_LARGE_THRESHOLD,
    REFERENCE_FILE_LONG_THRESHOLD,
    REFERENCE_FILE_MAX_LINES,
    REFERENCE_FILE_MIN_LINES,
    SKILL_MD_RECOMMENDED_MAX_LINES,
)

if TYPE_CHECKING:
    from ..models.skill_config import (
        ComplexityMetrics,
        QualityScore,
        StructureAnalysis,
    )


[docs] def generate_refactor_suggestions( skill_dir: Path, structure: "StructureAnalysis", complexity: "ComplexityMetrics", quality: "QualityScore", focus_areas: list[str] | None = None, ) -> list[dict]: """生成重构建议. Args: skill_dir: 技能目录路径 structure: 结构分析结果 complexity: 复杂度指标 quality: 质量评分 focus_areas: 重点关注领域(可选) Returns: 重构建议列表(字典格式) """ suggestions: list[dict] = [] # 如果指定了关注领域,只生成相关建议 if focus_areas: focus_set = set(area.lower() for area in focus_areas) if "structure" not in focus_set and "结构" not in focus_set: return _filter_suggestions_by_focus(suggestions, focus_set) # 1. 基于结构评分生成建议 if quality.structure_score < 20: suggestions.append( { "priority": "P0", "category": "structure", "issue": "项目结构不完整", "suggestion": ( "完善项目结构,添加必需的目录和文件(references、examples、scripts、.claude)" ), "impact": "high", "effort": "medium", } ) # 2. 基于文档评分生成建议 if quality.documentation_score < 15: suggestions.append( { "priority": "P1", "category": "documentation", "issue": "文档不足", "suggestion": "增加文档和示例,提高代码可读性", "impact": "medium", "effort": "low", } ) # 3. 基于测试评分生成建议 if quality.test_coverage_score < 15: suggestions.append( { "priority": "P0", "category": "testing", "issue": "测试覆盖率低", "suggestion": "增加测试用例,提高测试覆盖率至 95% 以上", "impact": "high", "effort": "high", } ) # 4. 基于复杂度生成建议 if complexity.cyclomatic_complexity and complexity.cyclomatic_complexity > 10: suggestions.append( { "priority": "P1", "category": "complexity", "issue": f"代码圈复杂度过高 ({complexity.cyclomatic_complexity})", "suggestion": "重构简化复杂逻辑,拆分大函数,减少嵌套层级", "impact": "high", "effort": "medium", } ) # 5. 基于可维护性指数生成建议 if complexity.maintainability_index and complexity.maintainability_index < 50: suggestions.append( { "priority": "P1", "category": "maintainability", "issue": f"可维护性指数低 ({complexity.maintainability_index:.1f})", "suggestion": "优化代码结构,增加注释,提高代码可读性", "impact": "medium", "effort": "medium", } ) # 6. 基于文件数量生成建议 if structure.total_files > 20: suggestions.append( { "priority": "P2", "category": "modularity", "issue": f"文件数量较多 ({structure.total_files})", "suggestion": "考虑模块化拆分,将相关功能组织到独立模块", "impact": "low", "effort": "high", } ) # 7. 基于代码行数生成建议 if structure.total_lines > CODE_SIZE_LARGE_THRESHOLD: suggestions.append( { "priority": "P2", "category": "size", "issue": f"代码行数较多 ({structure.total_lines})", "suggestion": "考虑拆分模块或提取独立包", "impact": "low", "effort": "high", } ) # 8. SKILL.md 特定建议 skill_md = skill_dir / "SKILL.md" if skill_md.exists(): content = skill_md.read_text(encoding="utf-8") if len(content) > 3000: suggestions.append( { "priority": "P2", "category": "token-efficiency", "issue": "SKILL.md 过长", "suggestion": ( f"将详细内容移至 references/ 目录," f"保持 SKILL.md 在 {SKILL_MD_RECOMMENDED_MAX_LINES} 行以内" ), "impact": "medium", "effort": "low", } ) # 9. 检查 references 目录结构 refs_dir = skill_dir / "references" if refs_dir.exists(): for ref_file in refs_dir.glob("*.md"): content = ref_file.read_text(encoding="utf-8") if len(content.split("\n")) > REFERENCE_FILE_LONG_THRESHOLD: suggestions.append( { "priority": "P2", "category": "documentation", "issue": f"参考文档过长: {ref_file.name}", "suggestion": ( f"拆分 {ref_file.name} 为多个小文件" f"(每个 {REFERENCE_FILE_MIN_LINES}-" f"{REFERENCE_FILE_MAX_LINES} 行)" ), "impact": "low", "effort": "low", } ) # 10. 检查是否有重复的模式或代码 _check_duplication_patterns(skill_dir, suggestions) focus_areas_set = set(area.lower() for area in (focus_areas or [])) return _filter_suggestions_by_focus(suggestions, focus_areas_set)
def _filter_suggestions_by_focus( suggestions: list[dict], focus_set: set[str], ) -> list[dict]: """根据关注领域过滤建议. Args: suggestions: 所有建议 focus_set: 关注领域集合 Returns: 过滤后的建议列表 """ if not focus_set: return suggestions # 创建映射关系 focus_map: dict[str, set[str]] = { "structure": {"structure", "结构", "modularity", "模块化", "size", "大小"}, "documentation": {"documentation", "文档", "token-efficiency", "token效率"}, "testing": {"testing", "测试"}, "complexity": {"complexity", "复杂度", "maintainability", "可维护性"}, "code": {"duplication", "重复", "quality", "质量"}, } # 收合所有匹配的关注领域 matched_categories = set() for focus in focus_set: for category, keywords in focus_map.items(): if focus in keywords: matched_categories.update(keywords) # 过滤建议 filtered = [] for suggestion in suggestions: category_lower = suggestion["category"].lower() issue_lower = suggestion["issue"].lower() # 检查是否有匹配的关注领域 has_match = any( keyword in category_lower or keyword in issue_lower for keyword in matched_categories ) if has_match: filtered.append(suggestion) return filtered def _check_duplication_patterns(skill_dir: Path, suggestions: list[dict]) -> None: """检查重复的模式或代码. Args: skill_dir: 技能目录路径 suggestions: 建议列表(会直接修改) """ # 检查是否有重复的文档内容 refs_dir = skill_dir / "references" if refs_dir.exists(): ref_files = list(refs_dir.glob("*.md")) if len(ref_files) > 5: suggestions.append( { "priority": "P2", "category": "organization", "issue": f"参考文档文件过多 ({len(ref_files)})", "suggestion": "考虑合并相似主题的文档,或使用子目录组织", "impact": "low", "effort": "low", } )
[docs] def generate_refactor_report( skill_path: str, structure: "StructureAnalysis", complexity: "ComplexityMetrics", quality: "QualityScore", suggestions: list[dict], ) -> str: """生成重构报告. Args: skill_path: 技能路径 structure: 结构分析结果 complexity: 复杂度指标 quality: 质量评分 suggestions: 重构建议 Returns: 重构报告(Markdown 格式) """ skill_dir = Path(skill_path) skill_name = skill_dir.name lines = [] lines.append("# 重构分析报告\n") lines.append("## 当前状态评估\n") lines.append("### 基本信息") lines.append(f"- 技能名称:`{skill_name}`") lines.append(f"- 路径:`{skill_path}`") lines.append(f"- 文件数量:{structure.total_files}") lines.append(f"- 代码行数:{structure.total_lines}\n") lines.append("### 质量评分") lines.append(f"- 结构质量:{quality.structure_score:.0f}/100") lines.append(f"- 文档质量:{quality.documentation_score:.0f}/100") lines.append(f"- 测试质量:{quality.test_coverage_score:.0f}/100") lines.append(f"- **总体评分:{quality.overall_score:.0f}/100**\n") if complexity.cyclomatic_complexity: lines.append("### 复杂度指标") lines.append(f"- 圈复杂度:{complexity.cyclomatic_complexity}") if complexity.maintainability_index: lines.append(f"- 可维持性指数:{complexity.maintainability_index:.1f}") lines.append("") # 按优先级分组建议 p0_suggestions = [s for s in suggestions if s["priority"] == "P0"] p1_suggestions = [s for s in suggestions if s["priority"] == "P1"] p2_suggestions = [s for s in suggestions if s["priority"] == "P2"] lines.append("## 发现的问题\n") if p0_suggestions: lines.append("### 严重问题 (P0) - 必须修复") for i, s in enumerate(p0_suggestions, 1): lines.append(f"{i}. **{s['issue']}**") lines.append(f" - 类别:{s['category']}") lines.append(f" - 建议:{s['suggestion']}") lines.append(f" - 影响:{s['impact']} | 工作量:{s['effort']}\n") if p1_suggestions: lines.append("### 重要问题 (P1) - 建议修复") for i, s in enumerate(p1_suggestions, 1): lines.append(f"{i}. **{s['issue']}**") lines.append(f" - 类别:{s['category']}") lines.append(f" - 建议:{s['suggestion']}") lines.append(f" - 影响:{s['impact']} | 工作量:{s['effort']}\n") if p2_suggestions: lines.append("### 优化建议 (P2) - 可选优化") for i, s in enumerate(p2_suggestions, 1): lines.append(f"{i}. **{s['issue']}**") lines.append(f" - 类别:{s['category']}") lines.append(f" - 建议:{s['suggestion']}") lines.append(f" - 影响:{s['impact']} | 工作量:{s['effort']}\n") if not suggestions: lines.append("*未发现需要重构的问题,技能质量良好!*\n") lines.append("## 实施计划\n") if p0_suggestions: lines.append("### 第一阶段(必须)") for s in p0_suggestions: lines.append(f"- [ ] 修复:{s['issue']}") lines.append("") if p1_suggestions: lines.append("### 第二阶段(建议)") for s in p1_suggestions: lines.append(f"- [ ] 修复:{s['issue']}") lines.append("") if p2_suggestions: lines.append("### 第三阶段(可选)") for s in p2_suggestions: lines.append(f"- [ ] 优化:{s['issue']}") lines.append("") return "\n".join(lines)
[docs] def estimate_refactor_effort(suggestions: list[dict]) -> dict[str, int]: """估算重构工作量. Args: suggestions: 重构建议列表 Returns: 工作量估算(按优先级分组的小时数) """ effort_map = {"low": 1, "medium": 4, "high": 8} p0_effort = sum( effort_map.get(s.get("effort", "medium"), 4) for s in suggestions if s["priority"] == "P0" ) p1_effort = sum( effort_map.get(s.get("effort", "medium"), 4) for s in suggestions if s["priority"] == "P1" ) p2_effort = sum( effort_map.get(s.get("effort", "medium"), 4) for s in suggestions if s["priority"] == "P2" ) return { "p0_hours": p0_effort, "p1_hours": p1_effort, "p2_hours": p2_effort, "total_hours": p0_effort + p1_effort + p2_effort, }