This commit is contained in:
119
src/docgen/detectors/go.py
Normal file
119
src/docgen/detectors/go.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Go endpoint detector for Gin and chi."""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from docgen.models import Endpoint, HTTPMethod
|
||||
from docgen.detectors.base import BaseDetector
|
||||
|
||||
|
||||
class GoDetector(BaseDetector):
|
||||
"""Detector for Go web frameworks."""
|
||||
|
||||
extensions = [".go"]
|
||||
framework_name = "go"
|
||||
|
||||
GIN_PATTERN = re.compile(
|
||||
r'(?:r\.router|r\.Group|routers?)\s*\.\s*(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s*\(\s*"([^"]+)"',
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
GIN_HANDLE_PATTERN = re.compile(
|
||||
r'(?:routers?|router)\s*\.\s*Handle\s*\("(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)"\s*,\s*"([^"]+)"',
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
GIN_SIMPLE_PATTERN = re.compile(
|
||||
r'r\s*\.\s*(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s*\(\s*"([^"]+)"',
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
CHI_PATTERN = re.compile(
|
||||
r'(?:routers?|router|Mux|r)\s*\.\s*(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s*\(\s*"([^"]+)"',
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
CHI_MOUNT_PATTERN = re.compile(
|
||||
r'Mount\s*\(\s*"([^"]+)"\s*,\s*[a-zA-Z]+\)',
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
HTTP_METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"}
|
||||
|
||||
def detect_endpoints(self, file_path: Path) -> list[Endpoint]:
|
||||
"""Detect endpoints in a Go file."""
|
||||
content = file_path.read_text()
|
||||
endpoints = []
|
||||
|
||||
framework = self._detect_framework(content)
|
||||
|
||||
if framework == "chi":
|
||||
endpoints.extend(self._detect_chi(content, file_path))
|
||||
else:
|
||||
endpoints.extend(self._detect_gin(content, file_path))
|
||||
|
||||
return endpoints
|
||||
|
||||
def _detect_framework(self, content: str) -> Optional[str]:
|
||||
"""Auto-detect the Go framework."""
|
||||
if 'github.com/go-chi/chi' in content or '"github.com/go-chi/chi' in content:
|
||||
return "chi"
|
||||
if 'github.com/gin-gonic/gin' in content or '"github.com/gin-gonic/gin' in content:
|
||||
return "gin"
|
||||
return None
|
||||
|
||||
def _detect_gin(self, content: str, file_path: Path) -> list[Endpoint]:
|
||||
"""Detect Gin endpoints."""
|
||||
endpoints = []
|
||||
|
||||
for match in self.GIN_SIMPLE_PATTERN.finditer(content):
|
||||
method, path = match.groups()
|
||||
endpoint = Endpoint(
|
||||
path=path,
|
||||
method=HTTPMethod(method),
|
||||
summary=f"{method} {path}",
|
||||
file_path=str(file_path),
|
||||
line_number=content[:match.start()].count("\n") + 1,
|
||||
)
|
||||
endpoints.append(endpoint)
|
||||
|
||||
for match in self.GIN_PATTERN.finditer(content):
|
||||
method, path = match.groups()
|
||||
endpoint = Endpoint(
|
||||
path=path,
|
||||
method=HTTPMethod(method),
|
||||
summary=f"{method} {path}",
|
||||
file_path=str(file_path),
|
||||
line_number=content[:match.start()].count("\n") + 1,
|
||||
)
|
||||
endpoints.append(endpoint)
|
||||
|
||||
for match in self.GIN_HANDLE_PATTERN.finditer(content):
|
||||
method, path = match.groups()
|
||||
endpoint = Endpoint(
|
||||
path=path,
|
||||
method=HTTPMethod(method),
|
||||
summary=f"{method} {path}",
|
||||
file_path=str(file_path),
|
||||
line_number=content[:match.start()].count("\n") + 1,
|
||||
)
|
||||
endpoints.append(endpoint)
|
||||
|
||||
return endpoints
|
||||
|
||||
def _detect_chi(self, content: str, file_path: Path) -> list[Endpoint]:
|
||||
"""Detect chi endpoints."""
|
||||
endpoints = []
|
||||
|
||||
for match in self.CHI_PATTERN.finditer(content):
|
||||
method, path = match.groups()
|
||||
endpoint = Endpoint(
|
||||
path=path,
|
||||
method=HTTPMethod(method),
|
||||
summary=f"{method} {path}",
|
||||
file_path=str(file_path),
|
||||
line_number=content[:match.start()].count("\n") + 1,
|
||||
)
|
||||
endpoints.append(endpoint)
|
||||
|
||||
return endpoints
|
||||
Reference in New Issue
Block a user