11"""Schema projections — extract typed information from a parsed AST.
22
3- The TS `schema.ts` exposes a full `convertNodeToJson(node, schemaDef)` system. For
4- Milestone 1, we only need :
3+ The TS `schema.ts` exposes a full `convertNodeToJson(node, schemaDef)` system. This
4+ module covers the subset the MCP server needs :
55
66 * `to_json(node)` — convert any Node to a JSON-serialisable dict (used by `parse_file`
77 and `parse_string` MCP tools)
88 * `extract_focus_ids(root)` — port of `extractFocusIds` from `previewdef/focustree/schema.ts`
9-
10- Additional extractors (events, decisions, ideas, sprites) land in Milestone 2 .
9+ * Extractors for events, decisions, ideas, and sprites, plus the `EVENT_KINDS` /
10+ `SPRITE_KINDS` container-kind lists that `indexes/` reuses to stay in sync .
1111"""
1212
1313from __future__ import annotations
@@ -214,15 +214,21 @@ def _get_id(node: Node) -> str | None:
214214# ---------------------------------------------------------------------------
215215
216216
217- _EVENT_KINDS = frozenset (
218- {"country_event" , "news_event" , "state_event" , "unit_leader_event" , "operative_leader_event" }
217+ # Canonical list of event container kinds — indexes/event.py reuses this for its
218+ # text prefilter so a new kind only needs to be added here.
219+ EVENT_KINDS = (
220+ "country_event" ,
221+ "news_event" ,
222+ "state_event" ,
223+ "unit_leader_event" ,
224+ "operative_leader_event" ,
219225)
220226
221227
222228def _iter_event_definitions (root : Node ) -> Iterator [tuple [Node , str ]]:
223229 """Yield `(node, id_str)` for every node satisfying the event hierarchy."""
224230 for top in root .children ():
225- if top .name in _EVENT_KINDS :
231+ if top .name in EVENT_KINDS :
226232 id_str = _get_id (top )
227233 if id_str :
228234 yield top , id_str
@@ -477,18 +483,18 @@ def _looks_like_slot_wrapper(node: Node) -> bool:
477483# ---------------------------------------------------------------------------
478484
479485
480- _SPRITE_KINDS = frozenset (
481- {
482- "spriteType" ,
483- "corneredTileSpriteType " ,
484- "frameAnimatedSpriteType " ,
485- "maskedShieldType " ,
486- "progressbartype " ,
487- "barChartType " ,
488- "PieChartType " ,
489- "LineChartType " ,
490- "scrollingSprite " ,
491- }
486+ # Canonical list of sprite container kinds — indexes/gfx.py reuses this to build
487+ # its regex scanner, so order must stay deterministic (a plain tuple, not a set).
488+ SPRITE_KINDS = (
489+ "spriteType " ,
490+ "corneredTileSpriteType " ,
491+ "frameAnimatedSpriteType " ,
492+ "maskedShieldType " ,
493+ "progressbartype " ,
494+ "barChartType " ,
495+ "PieChartType " ,
496+ "LineChartType " ,
497+ "scrollingSprite" ,
492498)
493499
494500
@@ -503,7 +509,7 @@ def _iter_sprite_definitions(root: Node) -> Iterator[tuple[Node, str, str]]:
503509 if not (top .name and top .name .lower ().startswith ("spritetypes" )):
504510 continue
505511 for sprite in top .children ():
506- if sprite .name not in _SPRITE_KINDS :
512+ if sprite .name not in SPRITE_KINDS :
507513 continue
508514 name_node = sprite .get ("name" )
509515 if name_node is None :
0 commit comments