@@ -768,6 +768,7 @@ components:
768768 assert .NoError (t , err )
769769
770770 config := CreateClosedAPIIndexConfig ()
771+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
771772 index := NewSpecIndexWithConfig (& rootNode , config )
772773 assert .NotNil (t , index )
773774
@@ -831,13 +832,16 @@ components:
831832 assert .NoError (t , err )
832833
833834 config := CreateClosedAPIIndexConfig ()
835+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
834836 index := NewSpecIndexWithConfig (& rootNode , config )
835837 assert .NotNil (t , index )
836838
837839 // Test resolution by $id
838840 resolved := index .ResolveRefViaSchemaId ("https://example.com/schemas/pet.json" )
839841 assert .NotNil (t , resolved )
840- assert .Equal (t , "https://example.com/schemas/pet.json" , resolved .FullDefinition )
842+ assert .Equal (t , "#/components/schemas/Pet" , resolved .Definition )
843+ assert .Equal (t , "https://example.com/openapi.yaml#/components/schemas/Pet" , resolved .FullDefinition )
844+ assert .Equal (t , "https://example.com/schemas/pet.json" , resolved .RawRef )
841845}
842846
843847func TestResolveRefViaSchemaId_NotFound (t * testing.T ) {
@@ -852,6 +856,7 @@ info:
852856 assert .NoError (t , err )
853857
854858 config := CreateClosedAPIIndexConfig ()
859+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
855860 index := NewSpecIndexWithConfig (& rootNode , config )
856861 assert .NotNil (t , index )
857862
@@ -893,12 +898,15 @@ components:
893898 assert .NoError (t , err )
894899
895900 config := CreateClosedAPIIndexConfig ()
901+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
896902 index := NewSpecIndexWithConfig (& rootNode , config )
897903 assert .NotNil (t , index )
898904
899905 // Test resolution with fragment
900906 resolved := index .ResolveRefViaSchemaId ("https://example.com/schemas/pet.json#/properties/name" )
901907 assert .NotNil (t , resolved )
908+ assert .Equal (t , "#/components/schemas/Pet/properties/name" , resolved .Definition )
909+ assert .Equal (t , "https://example.com/openapi.yaml#/components/schemas/Pet/properties/name" , resolved .FullDefinition )
902910 // The resolved node should be the "name" property schema
903911 if resolved .Node != nil {
904912 // Check it's the right node (type: string)
@@ -1235,7 +1243,8 @@ info:
12351243 // ResolveRefViaSchemaId should find the schema via rolodex global registry
12361244 resolved := index2 .ResolveRefViaSchemaId ("https://example.com/schemas/pet.json" )
12371245 assert .NotNil (t , resolved )
1238- assert .Equal (t , "https://example.com/schemas/pet.json" , resolved .FullDefinition )
1246+ assert .Equal (t , "https://example.com/openapi.yaml#/components/schemas/Pet" , resolved .FullDefinition )
1247+ assert .Equal (t , "#/components/schemas/Pet" , resolved .Definition )
12391248}
12401249
12411250// Test that FindSchemaIdInNode returns empty for non-mapping nodes
@@ -1283,6 +1292,7 @@ components:
12831292 assert .NoError (t , err )
12841293
12851294 config := CreateClosedAPIIndexConfig ()
1295+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
12861296 index := NewSpecIndexWithConfig (& rootNode , config )
12871297 assert .NotNil (t , index )
12881298
@@ -1367,6 +1377,7 @@ components:
13671377 assert .NoError (t , err )
13681378
13691379 config := CreateClosedAPIIndexConfig ()
1380+ config .SpecAbsolutePath = "https://example.com/openapi.yaml"
13701381 index := NewSpecIndexWithConfig (& rootNode , config )
13711382 assert .NotNil (t , index )
13721383
@@ -1382,6 +1393,106 @@ components:
13821393 assert .Equal (t , resolved1 .FullDefinition , resolved2 .FullDefinition )
13831394}
13841395
1396+ func TestJoinSchemaIdDefinitionPath (t * testing.T ) {
1397+ tests := []struct {
1398+ name string
1399+ definitionPath string
1400+ fragment string
1401+ expected string
1402+ }{
1403+ {
1404+ name : "empty definition path" ,
1405+ definitionPath : "" ,
1406+ fragment : "#/properties/name" ,
1407+ expected : "" ,
1408+ },
1409+ {
1410+ name : "no fragment" ,
1411+ definitionPath : "#/components/schemas/Pet" ,
1412+ fragment : "" ,
1413+ expected : "#/components/schemas/Pet" ,
1414+ },
1415+ {
1416+ name : "root definition with fragment" ,
1417+ definitionPath : "#" ,
1418+ fragment : "#/properties/name" ,
1419+ expected : "#/properties/name" ,
1420+ },
1421+ {
1422+ name : "nested definition with fragment" ,
1423+ definitionPath : "#/components/schemas/Pet" ,
1424+ fragment : "#/properties/name" ,
1425+ expected : "#/components/schemas/Pet/properties/name" ,
1426+ },
1427+ }
1428+
1429+ for _ , tc := range tests {
1430+ t .Run (tc .name , func (t * testing.T ) {
1431+ assert .Equal (t , tc .expected , joinSchemaIdDefinitionPath (tc .definitionPath , tc .fragment ))
1432+ })
1433+ }
1434+ }
1435+
1436+ func TestBuildSchemaIdResolvedReference (t * testing.T ) {
1437+ spec := `type: object
1438+ properties:
1439+ name:
1440+ type: string
1441+ `
1442+
1443+ var rootNode yaml.Node
1444+ err := yaml .Unmarshal ([]byte (spec ), & rootNode )
1445+ assert .NoError (t , err )
1446+
1447+ rootIndex := & SpecIndex {specAbsolutePath : "https://example.com/openapi.yaml" }
1448+ entryIndex := & SpecIndex {specAbsolutePath : "https://example.com/models.yaml" }
1449+
1450+ entry := & SchemaIdEntry {
1451+ Id : "https://example.com/schema.json" ,
1452+ ResolvedUri : "https://example.com/schema.json" ,
1453+ SchemaNode : rootNode .Content [0 ],
1454+ Index : entryIndex ,
1455+ DefinitionPath : "#/components/schemas/Pet" ,
1456+ }
1457+
1458+ resolved := buildSchemaIdResolvedReference (rootIndex , entry ,
1459+ "https://example.com/schema.json#/properties/name" ,
1460+ "https://example.com/schema.json" ,
1461+ "#/properties/name" ,
1462+ )
1463+ if assert .NotNil (t , resolved ) {
1464+ assert .Equal (t , "#/components/schemas/Pet/properties/name" , resolved .Definition )
1465+ assert .Equal (t , "https://example.com/models.yaml#/components/schemas/Pet/properties/name" , resolved .FullDefinition )
1466+ assert .Equal (t , "https://example.com/models.yaml" , resolved .RemoteLocation )
1467+ assert .True (t , resolved .IsRemote )
1468+ _ , _ , typeNode := utils .FindKeyNodeFullTop ("type" , resolved .Node .Content )
1469+ assert .NotNil (t , typeNode )
1470+ assert .Equal (t , "string" , typeNode .Value )
1471+ }
1472+
1473+ fallback := buildSchemaIdResolvedReference (rootIndex , & SchemaIdEntry {
1474+ Id : "https://example.com/schema.json" ,
1475+ ResolvedUri : "https://example.com/schema.json" ,
1476+ SchemaNode : rootNode .Content [0 ],
1477+ }, "https://example.com/schema.json" , "https://example.com/schema.json" , "" )
1478+ if assert .NotNil (t , fallback ) {
1479+ assert .Equal (t , "https://example.com/schema.json" , fallback .Definition )
1480+ assert .Equal (t , "https://example.com/schema.json" , fallback .FullDefinition )
1481+ assert .True (t , fallback .IsRemote )
1482+ }
1483+
1484+ missingFragment := buildSchemaIdResolvedReference (rootIndex , entry ,
1485+ "https://example.com/schema.json#/properties/unknown" ,
1486+ "https://example.com/schema.json" ,
1487+ "#/properties/unknown" ,
1488+ )
1489+ if assert .NotNil (t , missingFragment ) {
1490+ assert .Equal (t , rootNode .Content [0 ], missingFragment .Node )
1491+ }
1492+
1493+ assert .Nil (t , buildSchemaIdResolvedReference (rootIndex , nil , "https://example.com/schema.json" , "" , "" ))
1494+ }
1495+
13851496// Test $id extraction uses document base when no scope exists
13861497func TestSchemaId_ExtractionWithDocumentBase (t * testing.T ) {
13871498 spec := `openapi: "3.1.0"
@@ -1449,7 +1560,8 @@ components:
14491560 assert .NotNil (t , ref , "Should find reference via $id" )
14501561 assert .NotNil (t , foundIdx )
14511562 assert .NotNil (t , ctx )
1452- assert .Equal (t , "https://example.com/schemas/pet.json" , ref .FullDefinition )
1563+ assert .Equal (t , "#/components/schemas/Pet" , ref .Definition )
1564+ assert .Equal (t , "#/components/schemas/Pet" , ref .FullDefinition )
14531565}
14541566
14551567func TestFindComponent_AbsolutePathViaSchemaId (t * testing.T ) {
@@ -1580,15 +1692,16 @@ func TestResolveRefViaSchemaIdPath_SkipsInvalidEntries(t *testing.T) {
15801692 "relative" : {Id : "schemas/relative.json" },
15811693 "no-path" : {ResolvedUri : "https://example.com" },
15821694 "match" : {
1583- ResolvedUri : "https://example.com/schemas/target" ,
1584- SchemaNode : & yaml.Node {Kind : yaml .MappingNode },
1585- Index : index ,
1695+ ResolvedUri : "https://example.com/schemas/target" ,
1696+ SchemaNode : & yaml.Node {Kind : yaml .MappingNode },
1697+ Index : index ,
1698+ DefinitionPath : "#/components/schemas/Target" ,
15861699 },
15871700 }
15881701
15891702 ref := index .resolveRefViaSchemaIdPath ("/schemas/target" )
15901703 assert .NotNil (t , ref )
1591- assert .Equal (t , "https://example.com/ schemas/target " , ref .FullDefinition )
1704+ assert .Equal (t , "#/components/ schemas/Target " , ref .FullDefinition )
15921705}
15931706
15941707func TestResolveRefViaSchemaIdPath_UsesGlobalEntries (t * testing.T ) {
@@ -1617,7 +1730,7 @@ components:
16171730
16181731 ref := localIdx .resolveRefViaSchemaIdPath ("/schemas/mixins/integer" )
16191732 assert .NotNil (t , ref )
1620- assert .Equal (t , "https://example.com/ schemas/mixins/integer " , ref .FullDefinition )
1733+ assert .Equal (t , "#/components/ schemas/Integer " , ref .FullDefinition )
16211734 assert .Equal (t , globalIdx , ref .Index )
16221735}
16231736
@@ -1712,7 +1825,8 @@ components:
17121825
17131826 found , foundIdx , _ := index .SearchIndexForReferenceByReferenceWithContext (context .Background (), searchRef )
17141827 if assert .NotNil (t , found ) && assert .NotNil (t , foundIdx ) {
1715- assert .Equal (t , "https://example.com/schemas/non-negative-integer#/$defs/nonNegativeInteger" , found .FullDefinition )
1828+ assert .Equal (t , "#/components/schemas/NonNegativeInteger/$defs/nonNegativeInteger" , found .Definition )
1829+ assert .Equal (t , "#/components/schemas/NonNegativeInteger/$defs/nonNegativeInteger" , found .FullDefinition )
17161830 }
17171831}
17181832
0 commit comments