refactor(hierarchy): one Tree.Transitional, drop the duplicated cross-fade check

This commit is contained in:
pj committed 2026-07-30 22:33:46 +05:30
1 parent 1a893c570d
commit b82a27df4e
5 files changed
+52 -71

No files matched your search

+19
View File
@@ -272,6 +272,25 @@ func elementFromNode(node *treeNodeJSON) *Element {
return element
}
// Transitional reports more than one resource id ending in "Screen": the marker
// of a Compose NavHost mid cross-fade, where the source and destination route
// composables are both alive in a collapsed, mid-animation layout.
func (t *Tree) Transitional() bool {
if t == nil {
return false
}
screens := 0
for _, element := range t.Elements {
if strings.HasSuffix(element.ResourceID, "Screen") {
screens++
if screens > 1 {
return true
}
}
}
return false
}
// Find returns the first element matching the selector, or nil.
func (t *Tree) Find(selector string) *Element {
node := t.FindNode(selector)
+29
View File
@@ -1006,3 +1006,32 @@ func TestParseBoundsRejectsBadInput(t *testing.T) {
}
}
}
// Bug class: a NavHost cross-fade carries two route-level *Screen ids at once;
// both the runner's re-fetch guard and the LLM's candidate enumeration depend on
// spotting it, and neither must flag a settled single-screen tree.
func TestTreeTransitional(t *testing.T) {
multi, err := Parse(`{"attributes":{"resource-id":"root"},"children":[
{"attributes":{"resource-id":"AddAccountScreen"},"children":[]},
{"attributes":{"resource-id":"HomeScreen"},"children":[]}
]}`)
if err != nil {
t.Fatal(err)
}
if !multi.Transitional() {
t.Error("expected multi-screen tree to be flagged as transitional")
}
single, err := Parse(`{"attributes":{"resource-id":"HomeScreen"},"children":[]}`)
if err != nil {
t.Fatal(err)
}
if single.Transitional() {
t.Error("single-screen tree must not be flagged as transitional")
}
var nilTree *Tree
if nilTree.Transitional() {
t.Error("nil tree must not be flagged as transitional")
}
}