"""Base parser interface and data structures.""" from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import Optional from enum import Enum class ElementType(Enum): """Types of documentation elements.""" FUNCTION = "function" CLASS = "class" METHOD = "method" INTERFACE = "interface" STRUCT = "struct" MODULE = "module" CONSTANT = "constant" VARIABLE = "variable" @dataclass class Parameter: """Represents a function/method parameter.""" name: str type_hint: Optional[str] = None description: Optional[str] = None default_value: Optional[str] = None is_optional: bool = False def __str__(self) -> str: parts = [self.name] if self.type_hint: parts.append(f": {self.type_hint}") if self.default_value: parts.append(f" = {self.default_value}") return "".join(parts) @dataclass class DocElement: """Represents a documentation element extracted from source code.""" name: str element_type: ElementType description: str = "" full_docstring: str = "" parameters: list[Parameter] = field(default_factory=list) return_type: Optional[str] = None return_description: Optional[str] = None raises: list[tuple[str, str]] = field(default_factory=list) examples: list[str] = field(default_factory=list) source_file: str = "" line_number: int = 0 visibility: str = "public" decorators: list[str] = field(default_factory=list) attributes: list[tuple[str, Optional[str], Optional[str]]] = field( default_factory=list ) imports: list[str] = field(default_factory=list) class Parser(ABC): """Abstract base class for code parsers.""" def __init__(self, file_path: str): self.file_path = file_path self.content: str = "" self.elements: list[DocElement] = [] @abstractmethod def parse(self) -> list[DocElement]: """Parse the file and extract documentation elements.""" pass @abstractmethod def get_language_name(self) -> str: """Return the name of the language this parser handles.""" pass @classmethod @abstractmethod def supports_file(cls, file_path: str) -> bool: """Check if this parser supports the given file.""" pass def _read_content(self) -> str: """Read file content safely.""" with open(self.file_path, "r", encoding="utf-8") as f: return f.read() def _strip_docstring_quotes(self, docstring: str) -> str: """Remove leading/trailing quotes from docstring.""" if not docstring: return "" lines = docstring.split("\n") if len(lines) == 1: return docstring.strip('"""').strip("'''").strip() first_line = lines[0].strip('"""').strip("'''").strip() last_line = lines[-1].strip('"""').strip("'''").strip() if len(lines) > 1: middle_lines = lines[1:-1] cleaned = [] for line in middle_lines: stripped = line.strip() if stripped: cleaned.append(stripped) return "\n".join([first_line] + cleaned + [last_line]) if cleaned else first_line return first_line