|
|
import json |
|
|
import os |
|
|
from typing import Dict, List, Any, Optional |
|
|
|
|
|
DICTIONARY_DIR = os.path.join( |
|
|
os.path.dirname(os.path.dirname(__file__)), |
|
|
"dictionary" |
|
|
) |
|
|
|
|
|
|
|
|
class GlyphDictionary: |
|
|
def __init__(self) -> None: |
|
|
self.entries_by_glyph: Dict[str, List[Dict[str, Any]]] = {} |
|
|
self.entries_by_id: Dict[str, Dict[str, Any]] = {} |
|
|
self.entries_by_category: Dict[str, List[Dict[str, Any]]] = {} |
|
|
self.entries_by_role: Dict[str, List[Dict[str, Any]]] = {} |
|
|
|
|
|
def load(self, directory: str = DICTIONARY_DIR) -> None: |
|
|
for filename in os.listdir(directory): |
|
|
if not filename.endswith(".json"): |
|
|
continue |
|
|
path = os.path.join(directory, filename) |
|
|
with open(path, "r", encoding="utf-8") as f: |
|
|
try: |
|
|
data = json.load(f) |
|
|
except json.JSONDecodeError as e: |
|
|
raise ValueError(f"Invalid JSON in {filename}: {e}") |
|
|
|
|
|
if not isinstance(data, list): |
|
|
raise ValueError(f"Dictionary file {filename} must contain a list of entries.") |
|
|
|
|
|
for entry in data: |
|
|
self._index_entry(entry) |
|
|
|
|
|
def _index_entry(self, entry: Dict[str, Any]) -> None: |
|
|
glyph = entry.get("glyph") |
|
|
entry_id = entry.get("id") |
|
|
category = entry.get("category") |
|
|
roles = entry.get("roles", []) |
|
|
|
|
|
if not glyph or not entry_id or not category: |
|
|
raise ValueError(f"Entry missing required fields: {entry}") |
|
|
|
|
|
|
|
|
if entry_id in self.entries_by_id: |
|
|
raise ValueError(f"Duplicate id detected: {entry_id}") |
|
|
self.entries_by_id[entry_id] = entry |
|
|
|
|
|
|
|
|
self.entries_by_glyph.setdefault(glyph, []).append(entry) |
|
|
|
|
|
|
|
|
self.entries_by_category.setdefault(category, []).append(entry) |
|
|
|
|
|
|
|
|
for role in roles: |
|
|
self.entries_by_role.setdefault(role, []).append(entry) |
|
|
|
|
|
def get_entry_by_glyph(self, glyph: str) -> Optional[List[Dict[str, Any]]]: |
|
|
return self.entries_by_glyph.get(glyph) |
|
|
|
|
|
def get_entry_by_id(self, entry_id: str) -> Optional[Dict[str, Any]]: |
|
|
return self.entries_by_id.get(entry_id) |
|
|
|
|
|
def get_entries_by_category(self, category: str) -> List[Dict[str, Any]]: |
|
|
return self.entries_by_category.get(category, []) |
|
|
|
|
|
def get_entries_by_role(self, role: str) -> List[Dict[str, Any]]: |
|
|
return self.entries_by_role.get(role, []) |
|
|
|
|
|
|
|
|
|
|
|
_dictionary_instance: Optional[GlyphDictionary] = None |
|
|
|
|
|
|
|
|
def get_dictionary() -> GlyphDictionary: |
|
|
global _dictionary_instance |
|
|
if _dictionary_instance is None: |
|
|
_dictionary_instance = GlyphDictionary() |
|
|
_dictionary_instance.load() |
|
|
return _dictionary_instance |
|
|
|
|
|
|