| """Source-independent API projection for citation-graph judgment nodes.""" |
|
|
| from __future__ import annotations |
|
|
| import re |
| from typing import Any, Mapping |
|
|
|
|
| THEMIS_DECIMAL_ID = re.compile(r"^[1-9][0-9]{12}$") |
|
|
|
|
| def graph_node_card( |
| node_id: object, |
| metadata: Mapping[str, Any] | None = None, |
| *, |
| treatment: str | None = None, |
| cited_by: int = 0, |
| good_law_status: str = "unknown", |
| ) -> dict[str, Any]: |
| """Return the graph/UI contract for one judgment node. |
| |
| The permanent Moonley ID remains the routing key. All presentation fields |
| use the human legal identity so internal IDs never need to be rendered. |
| """ |
|
|
| judgment_id = str(node_id) |
| meta = dict(metadata or {}) |
| case_name = " ".join(str(meta.get("case_name") or "").split()) |
| citation = " ".join(str(meta.get("neutral_citation") or "").split()) |
| date = meta.get("date") or meta.get("decision_date") |
| display_name = case_name or citation or "Case name unavailable" |
| tooltip_parts = [display_name] |
| if citation and citation != display_name: |
| tooltip_parts.append(citation) |
| if date: |
| tooltip_parts.append(str(date)) |
| tooltip_parts.append(str(good_law_status or "unknown").replace("_", " ")) |
|
|
| return { |
| |
| "node_id": judgment_id, |
| "judgment_id": judgment_id, |
| "label": display_name, |
| "display_name": display_name, |
| "tooltip": " · ".join(tooltip_parts), |
| "hover": { |
| "case_name": case_name or None, |
| "neutral_citation": citation or None, |
| "decision_date": date, |
| "good_law_status": good_law_status or "unknown", |
| }, |
| "open": { |
| "judgment_id": judgment_id, |
| "pdf_id": judgment_id, |
| }, |
| "is_themis_decimal_id": bool(THEMIS_DECIMAL_ID.fullmatch(judgment_id)), |
| |
| "id": judgment_id, |
| "name": display_name, |
| "citation": citation or None, |
| "treatment": treatment, |
| "cited_by": int(cited_by or 0), |
| "good_law": good_law_status or "unknown", |
| } |
|
|