File size: 2,831 Bytes
ed6bec6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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}")

        # id index
        if entry_id in self.entries_by_id:
            raise ValueError(f"Duplicate id detected: {entry_id}")
        self.entries_by_id[entry_id] = entry

        # glyph index
        self.entries_by_glyph.setdefault(glyph, []).append(entry)

        # category index
        self.entries_by_category.setdefault(category, []).append(entry)

        # roles index
        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, [])


# Singleton-style loader for convenience
_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