"""Adapter: dotnet build text output normalized to Finding[].""" from __future__ import annotations import os import re from scripts.manifest import Finding _LINE_RE = re.compile( r"^(?P[^(]+)\((?P\d+),\d+\):\s*" r"(?Perror|warning)\s+" r"(?P[A-Z]+\d+):\s*" r"(?P.+?)\s*" r"(?:\[[^\]]+\])?\s*$" ) def _severity(code: str, severity_word: str) -> str: if code.startswith("SCS"): return "high" if severity_word == "error": return "medium" return "low" def parse_dotnet_build_output(stdout: str, repo_root: str) -> list[Finding]: out: list[Finding] = [] seen: set[tuple[str, int, str]] = set() for raw in stdout.splitlines(): m = _LINE_RE.match(raw) if not m: continue file_abs = m.group("file") rel = os.path.relpath(file_abs, repo_root) if file_abs.startswith(repo_root) else file_abs code = m.group("code") line = int(m.group("line")) key = (rel, line, code) if key in seen: continue seen.add(key) out.append(Finding( tool="dotnet", rule_id=code, severity=_severity(code, m.group("severity")), file=rel, line=line, end_line=line, message=m.group("message"), )) return out