check-key-references.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import json
  2. import os
  3. import logging
  4. from collections import OrderedDict
  5. import time
  6. import ahocorasick
  7. logging.basicConfig(level=logging.INFO)
  8. logger = logging.getLogger()
  9. # PATHS
  10. REFERENCE_LANGUAGE = "src/PixiEditor/Data/Localization/Languages/en.json"
  11. SEARCH_DIRECTORIES = ["src/PixiEditor/Views", "src/PixiEditor/ViewModels", "src/PixiEditor", "src/"]
  12. IGNORE_DIRECTORIES = ["src/PixiEditor/Data/Localization"]
  13. def load_json(file_path):
  14. """Load language JSON"""
  15. try:
  16. with open(file_path, "r", encoding="utf-8-sig") as f:
  17. return json.load(f, object_pairs_hook=OrderedDict)
  18. except FileNotFoundError:
  19. print(f"::error::File not found: {file_path}")
  20. return OrderedDict()
  21. except json.JSONDecodeError as e:
  22. print(f"::error::Failed to parse JSON in {file_path}: {e}")
  23. return OrderedDict()
  24. def build_automaton(keys: list[str]) -> ahocorasick.Automaton:
  25. A = ahocorasick.Automaton()
  26. for i, k in enumerate(keys):
  27. A.add_word(k, (i, k))
  28. A.make_automaton()
  29. return A
  30. def find_missing_keys(keys):
  31. automaton = build_automaton(keys)
  32. present = set()
  33. ignore_prefixes = tuple(os.path.abspath(p) for p in IGNORE_DIRECTORIES)
  34. for base_dir in SEARCH_DIRECTORIES:
  35. for root, dirs, files in os.walk(base_dir, topdown=True):
  36. dirs[:] = [d for d in dirs if not os.path.abspath(os.path.join(root, d)).startswith(ignore_prefixes)]
  37. for file in files:
  38. with open(os.path.join(root, file), "r", encoding="utf‑8", errors="ignore") as f:
  39. for _, (_, k) in automaton.iter(f.read()):
  40. present.add(k)
  41. if len(present) == len(keys):
  42. return []
  43. return sorted(set(keys) - present)
  44. def main():
  45. keys = load_json(REFERENCE_LANGUAGE)
  46. print("Searching trough keys...")
  47. start = time.time()
  48. missing_keys = find_missing_keys(keys)
  49. end = time.time()
  50. print(f"Done, searching took {end - start}s")
  51. if len(missing_keys) > 0:
  52. print("Unreferenced keys have been found")
  53. for key in missing_keys:
  54. print(f"::error file={REFERENCE_LANGUAGE},title=Unreferenced key::No reference to '{key}' found")
  55. return 1
  56. else:
  57. print("All keys have been referenced")
  58. return 0
  59. if __name__ == "__main__":
  60. exit(main())