from __future__ import annotations from pathlib import Path from depaudit.parsers import Parser, ParsedManifest class GoParser(Parser): language = "go" def can_parse(self, file_path: Path) -> bool: return file_path.name == "go.mod" def parse(self, file_path: Path) -> ParsedManifest: content = file_path.read_text(encoding="utf-8") lines = content.split("\n") manifest = ParsedManifest( language=self.language, file_path=file_path, ) i = 0 in_require_block = False current_line_indent = 0 while i < len(lines): line = lines[i].strip() if not line or line.startswith("//"): i += 1 continue if line.startswith("module"): manifest.project_name = line.split()[1].strip() elif line.startswith("go"): pass elif line.startswith("require"): in_require_block = True current_line_indent = len(lines[i]) - len(lines[i].lstrip()) self._parse_require(line, file_path, manifest) elif in_require_block: current_indent = len(lines[i]) - len(lines[i].lstrip()) if current_indent > current_line_indent and not line.startswith("//"): self._parse_require(lines[i], file_path, manifest) else: in_require_block = False i += 1 return manifest def _parse_require( self, line: str, file_path: Path, manifest: ParsedManifest ) -> None: content = line.strip() if content.startswith("//"): return if content.startswith("require"): content = content[len("require"):].strip() if content.startswith("("): content = content[1:] if content.endswith(")"): content = content[:-1] if not content: return parts = content.split() i = 0 while i < len(parts): if parts[i].startswith("//"): break name = parts[i] version = "" if i + 1 < len(parts) and not parts[i + 1].startswith("/"): version = parts[i + 1] i += 2 else: i += 1 if name: indirect = "// indirect" in line or "(// indirect)" in line or "(indirect)" in line manifest.dependencies.append( self._create_dependency(file_path, name, version, indirect=indirect) )