from __future__ import annotations from dataclasses import asdict, dataclass, field from typing import Any from .featurescript_parser import symbolic_string from .ir import Call @dataclass class QueryInfo: kind: str | None = None owner_feature: str | None = None topology_type: str | None = None source_sketch: str | None = None source_entity: str | None = None is_start: bool | None = None calls: list[str] = field(default_factory=list) def as_dict(self) -> dict[str, Any]: return asdict(self) def walk_calls(value: Any): if isinstance(value, Call): yield value for arg in value.args: yield from walk_calls(arg) elif isinstance(value, list): for item in value: yield from walk_calls(item) elif isinstance(value, dict): for item in value.values(): yield from walk_calls(item) def parse_query(value: Any) -> QueryInfo: info = QueryInfo() for call in walk_calls(value): info.calls.append(call.name) if call.name in {"makeQuery", "qCreatedBy"} and call.args: owner = symbolic_string(call.args[0]) if "F" in owner: tail = owner[owner.find("F"):].split(".", 1)[0] info.owner_feature = tail if call.name == "makeQuery" and len(call.args) > 2: info.topology_type = str(call.args[1]); info.kind = str(call.args[2]).lower() definition = next((arg for arg in call.args if isinstance(arg, dict)), {}) if isinstance(definition.get("isStart"), str): info.is_start = definition["isStart"].lower() == "true" elif "isStart" in definition: info.is_start = bool(definition["isStart"]) if call.name in {"sQuery", "sketchEntityQuery"} and len(call.args) >= 3: sketch = symbolic_string(call.args[0]); info.source_sketch = sketch.split(".", 1)[0] if info.topology_type is None: info.kind = str(call.args[1]).lower() info.source_entity = str(call.args[2]) if call.name == "qSketchRegion" and call.args: info.source_sketch = symbolic_string(call.args[0]); info.kind = "face" return info