Keep the last in-template copy on main so history can restore it; product continues in jiangchang-ui-recorder. Co-authored-by: Cursor <cursoragent@cursor.com>
51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
"""Locator uniqueness validation against snapshot / live tree rows."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Optional
|
|
|
|
from models.locator import LocatorCandidate
|
|
|
|
from .base import count_matches
|
|
|
|
|
|
def validate_locator_against_rows(
|
|
candidate: LocatorCandidate,
|
|
rows: list[dict[str, Any]],
|
|
*,
|
|
level: str = "snapshot_only",
|
|
expected_count: int = 1,
|
|
) -> LocatorCandidate:
|
|
"""
|
|
Validate structured locator properties against a row list.
|
|
|
|
Levels supported in this phase: snapshot_only | live_tree
|
|
"""
|
|
actual = count_matches(
|
|
rows,
|
|
properties=candidate.properties,
|
|
scope=candidate.scope,
|
|
)
|
|
candidate.mark_counts(actual, expected=expected_count)
|
|
candidate.validation = level
|
|
if not candidate.unique:
|
|
candidate.reasons = list(candidate.reasons or [])
|
|
if "ambiguous_match_count" not in candidate.reasons:
|
|
candidate.reasons.append("ambiguous_match_count")
|
|
candidate.production_eligible = False
|
|
if candidate.uses_coordinates:
|
|
candidate.production_eligible = False
|
|
if "coordinates_never_primary" not in (candidate.reasons or []):
|
|
candidate.reasons = list(candidate.reasons or []) + ["coordinates_never_primary"]
|
|
return candidate
|
|
|
|
|
|
def choose_production_primary(
|
|
candidates: list[LocatorCandidate],
|
|
) -> Optional[LocatorCandidate]:
|
|
"""Return first production-eligible unique non-coordinate locator, else None."""
|
|
for c in candidates:
|
|
if c.production_eligible and c.unique and not c.uses_coordinates:
|
|
return c
|
|
return None
|