jsonschema: make schema state independent of resolve arguments (#85)

Move schema state that depends on resolution into the Resolved struct.
The remaining unexported schema fields are dependent only on the schema
itself and its sub-schemas.

Now a schema can be resolved multiple times, as itself or as part of
other schemas.

Fixes #84.
This commit is contained in:
Jonathan Amsterdam 2025-07-21 10:41:00 -04:00 • committed by GitHub
commit 3bbe74f8a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -17,7 +17,8 @@ import (
func TestSchemaStructure(t *testing.T) {
check := func(s *Schema, want string) {
t.Helper()
err := s.checkStructure()
infos := map[*Schema]*resolvedInfo{}
err := s.checkStructure(infos)
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("checkStructure returned error %q, want %q", err, want)
}
@ -89,13 +90,14 @@ func TestPaths(t *testing.T) {
{root.PrefixItems[1], "/prefixItems/1"},
{root.PrefixItems[1].Items, "/prefixItems/1/items"},
}
if err := root.checkStructure(); err != nil {
rs := newResolved(root)
if err := root.checkStructure(rs.resolvedInfos); err != nil {
t.Fatal(err)
}
var got []item
for s := range root.all() {
got = append(got, item{s, s.path})
got = append(got, item{s, rs.resolvedInfos[s].path})
}
if !slices.Equal(got, want) {
t.Errorf("\ngot %v\nwant %v", got, want)
@ -129,8 +131,12 @@ func TestResolveURIs(t *testing.T) {
if err != nil {
t.Fatal(err)
}
got, err := resolveURIs(root, base)
if err != nil {
rs := newResolved(root)
if err := root.check(rs.resolvedInfos); err != nil {
t.Fatal(err)
}
if err := resolveURIs(rs, base); err != nil {
t.Fatal(err)
}
@ -154,6 +160,7 @@ func TestResolveURIs(t *testing.T) {
},
}
got := rs.resolvedURIs
gotKeys := slices.Sorted(maps.Keys(got))
wantKeys := slices.Sorted(maps.Keys(wantIDs))
if !slices.Equal(gotKeys, wantKeys) {
@ -163,11 +170,12 @@ func TestResolveURIs(t *testing.T) {
t.Errorf("IDs:\ngot %+v\n\nwant %+v", got, wantIDs)
}
for s := range root.all() {
info := rs.resolvedInfos[s]
if want := wantAnchors[s]; want != nil {
if got := s.anchors; !maps.Equal(got, want) {
if got := info.anchors; !maps.Equal(got, want) {
t.Errorf("anchors:\ngot %+v\n\nwant %+v", got, want)
}
} else if s.anchors != nil {
} else if info.anchors != nil {
t.Errorf("non-nil anchors for %s", s)
}
}
@ -199,7 +207,7 @@ func TestRefCycle(t *testing.T) {
check := func(s *Schema, key string) {
t.Helper()
if s.resolvedRef != schemas[key] {
if rs.resolvedInfos[s].resolvedRef != schemas[key] {
t.Errorf("%s resolvedRef != schemas[%q]", s.json(), key)
}
}