"""Editor HTTP router — file read/write and impact analysis endpoints.""" from __future__ import annotations from dataclasses import asdict from fastapi import APIRouter from fastapi.responses import JSONResponse from pydantic import BaseModel from app.modules.project.application.services import ProjectService from app.modules.scanner.application.services import ScanService from app.modules.editor.application.services import EditorService router = APIRouter(prefix="/projects/{project_id}/files", tags=["editor"]) _project_service: ProjectService | None = None _scan_service: ScanService | None = None _editor_service: EditorService | None = None def init_router( project_service: ProjectService, scan_service: ScanService, editor_service: EditorService, ) -> None: global _project_service, _scan_service, _editor_service _project_service = project_service _scan_service = scan_service _editor_service = editor_service class SaveFileRequest(BaseModel): content: str def _get_or_trigger_scan(project_id: str): """Get cached scan or trigger a new one.""" result = _scan_service.get_latest_scan(project_id) if result is None: project = _project_service.get_project(project_id) result = _scan_service.scan(project) return result @router.get("/{path:path}/impact") def get_impact(project_id: str, path: str): """Return impact analysis for a given file.""" project = _project_service.get_project(project_id) scan_result = _get_or_trigger_scan(project_id) impact = _editor_service.get_impact(project, path, scan_result) return asdict(impact) @router.get("/{path:path}") def get_file(project_id: str, path: str): """Read a design file and return its content.""" project = _project_service.get_project(project_id) editable = _editor_service.get_file(project, path) return { "path": editable.path, "format": editable.format, "content": editable.content, "last_modified": editable.last_modified.isoformat(), } @router.put("/{path:path}") def save_file(project_id: str, path: str, body: SaveFileRequest): """Write content to a design file and re-scan.""" project = _project_service.get_project(project_id) scan_result = _editor_service.save_file(project, path, body.content) return { "project_id": scan_result.project_id, "scanned_at": scan_result.scanned_at.isoformat(), "summary": { "total_files": scan_result.summary.total_files, "ok": scan_result.summary.ok, "sparse": scan_result.summary.sparse, "missing": scan_result.summary.missing, "placeholder_heavy": scan_result.summary.placeholder_heavy, "template_residue": scan_result.summary.template_residue, }, }