From a88ab0dadcf587856ddf311a98396d871088b8e2 Mon Sep 17 00:00:00 2001 From: Jonathan Amsterdam Date: Wed, 7 May 2025 09:27:59 -0400 Subject: [PATCH] internal/mcp/jsonschema: make Schema.every fully recursive s.every now visits the entire subtree of schemas at s, not only the immediate children of s. This re-introduces a tower: now of closures instead of iterators. We could remove it having everyChild call every recursively instead of returning, just passing f down all the way unwrapped. But this is going to complicate the recursive function inside resolveURIs, which needs to pass parent context down. It would have the same problem that ast.Inspect has, and we'd have to adopt the same solution, maintaining a stack explicitly. I feel it's cleaner to keep the recursion simple at the cost of building several closures. To do otherwise would be premature optimization. Change-Id: Ic453cdaac482da8147dafc34b0117d25458d1c9d Reviewed-on: https://go-review.googlesource.com/c/tools/+/670675 LUCI-TryBot-Result: Go LUCI Reviewed-by: Alan Donovan --- jsonschema/schema.go | 2 +- jsonschema/schema_test.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/jsonschema/schema.go b/jsonschema/schema.go index 19b1728..4e78eb2 100644 --- a/jsonschema/schema.go +++ b/jsonschema/schema.go @@ -293,7 +293,7 @@ func Ptr[T any](x T) *T { return &x } // It stops when f returns false. func (s *Schema) every(f func(*Schema) bool) bool { return s == nil || - f(s) && s.everyChild(f) + f(s) && s.everyChild(func(s *Schema) bool { return s.every(f) }) } // everyChild reports whether f is true for every immediate child schema of s. diff --git a/jsonschema/schema_test.go b/jsonschema/schema_test.go index 614cca1..117db7b 100644 --- a/jsonschema/schema_test.go +++ b/jsonschema/schema_test.go @@ -111,3 +111,18 @@ func TestUnmarshalErrors(t *testing.T) { } } + +func TestEvery(t *testing.T) { + // Schema.every should visit all descendants of a schema, not just the immediate ones. + s := &Schema{ + Items: &Schema{ + Items: &Schema{}, + }, + } + want := 3 + got := 0 + s.every(func(*Schema) bool { got++; return true }) + if got != want { + t.Errorf("got %d, want %d", got, want) + } +}