# Parser Registry (patron extensible)

Fuente conceptual: OpenViking `openviking/parse/registry.py` (AGPL-3.0)
Reimplementar desde cero. No copiar codigo.

## Clase a implementar

### ParserRegistry

- **Dominio:** core
- **Lang:** Python
- **Purity:** impure (mantiene estado mutable, singleton)
- **Descripcion:** Registry extensible que despacha parsing de archivos al parser correcto basado en extension. Patron plugin: registrar parsers por nombre y extensiones, resolver automaticamente.
- **Signature:**
  ```python
  class ParserRegistry:
      def __init__(self): ...
      def register(self, name: str, parser: BaseParser) -> None: ...
      def unregister(self, name: str) -> None: ...
      def get_parser(self, name: str) -> BaseParser | None: ...
      def get_parser_for_file(self, path: str) -> BaseParser | None: ...
      async def parse(self, source: str, **kwargs) -> ParseResult: ...
      def list_parsers(self) -> list[str]: ...
      def list_supported_extensions(self) -> list[str]: ...
  ```
- **Protocolo BaseParser:**
  ```python
  class BaseParser(ABC):
      @property
      @abstractmethod
      def supported_extensions(self) -> list[str]: ...

      @abstractmethod
      async def parse(self, source: str | Path, **kwargs) -> ParseResult: ...

      @abstractmethod
      async def parse_content(self, content: str, source_path: str | None = None, **kwargs) -> ParseResult: ...

      def can_parse(self, path: str) -> bool:
          return Path(path).suffix.lower() in self.supported_extensions
  ```
- **Algoritmo de despacho (`parse()`):**
  1. Si source es URL de repo de codigo → delegar a code parser
  2. Si source parece path de archivo (corto, sin newlines) y existe:
     - Si es directorio → delegar a directory parser
     - Resolver parser por extension → delegar
     - Si no hay parser → fallback a text parser
  3. Si no es path → parsear como string de contenido con text parser
- **Extension map:** `{".md": "markdown", ".pdf": "pdf", ".html": "html", ...}` construido automaticamente al registrar parsers
- **Singleton:** `get_registry()` retorna instancia global lazy-initialized
- **Deps:** `pathlib`
- **Tests:** registrar parser custom, resolver por extension, parse file, parse string, unregister, extension desconocida (fallback a text)
- **Notas:** Este patron es util mas alla de parsing — cualquier sistema de plugins extensible por tipo de archivo puede usar este patron.
