@@ -640,19 +640,8 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
640640 root = utils .NodeAlias (root )
641641 utils .CheckForMergeNodes (root )
642642
643- // transform sibling refs to allOf structure if enabled and applicable
644- if idx != nil && idx .GetConfig () != nil && idx .GetConfig ().TransformSiblingRefs {
645- transformer := NewSiblingRefTransformer (idx )
646- if transformer .ShouldTransform (root ) {
647- transformed , err := transformer .TransformSiblingRef (root )
648- if err != nil {
649- return fmt .Errorf ("sibling ref transformation failed: %w" , err )
650- }
651- if transformed != nil {
652- root = transformed
653- }
654- }
655- }
643+ // Note: sibling ref transformation now happens in SchemaProxy.Build()
644+ // so the root node should already be pre-transformed if needed
656645
657646 s .Reference = new (low.Reference )
658647 no := low .ExtractNodes (ctx , root )
@@ -662,21 +651,30 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
662651 s .context = ctx
663652 s .index = idx
664653
665- if h , _ , _ := utils .IsNodeRefValue (root ); h {
666- ref , _ , err , fctx := low .LocateRefNodeWithContext (ctx , root , idx )
667- if ref != nil {
668- root = ref
669- if fctx != nil {
670- ctx = fctx
671- }
672- if err != nil {
673- if ! idx .AllowCircularReferenceResolving () {
674- return fmt .Errorf ("build schema failed: %s" , err .Error ())
654+ // check if this schema was transformed from a sibling ref
655+ // if so, skip reference dereferencing to preserve the allOf structure
656+ isTransformed := false
657+ if s .ParentProxy != nil && s .ParentProxy .TransformedRef != nil {
658+ isTransformed = true
659+ }
660+
661+ if ! isTransformed {
662+ if h , _ , _ := utils .IsNodeRefValue (root ); h {
663+ ref , _ , err , fctx := low .LocateRefNodeWithContext (ctx , root , idx )
664+ if ref != nil {
665+ root = ref
666+ if fctx != nil {
667+ ctx = fctx
675668 }
669+ if err != nil {
670+ if ! idx .AllowCircularReferenceResolving () {
671+ return fmt .Errorf ("build schema failed: %s" , err .Error ())
672+ }
673+ }
674+ } else {
675+ return fmt .Errorf ("build schema failed: reference cannot be found: '%s', line %d, col %d" ,
676+ root .Content [1 ].Value , root .Content [1 ].Line , root .Content [1 ].Column )
676677 }
677- } else {
678- return fmt .Errorf ("build schema failed: reference cannot be found: '%s', line %d, col %d" ,
679- root .Content [1 ].Value , root .Content [1 ].Line , root .Content [1 ].Column )
680678 }
681679 }
682680
@@ -1299,12 +1297,17 @@ func buildPropertyMap(ctx context.Context, parent *Schema, root *yaml.Node, idx
12991297 sp := & SchemaProxy {ctx : foundCtx , kn : currentProp , vn : prop , idx : foundIdx }
13001298 sp .SetReference (refString , refNode )
13011299
1300+ err := sp .Build (foundCtx , currentProp , prop , foundIdx )
1301+ if err != nil {
1302+ return nil , fmt .Errorf ("schema proxy build failed: %w" , err )
1303+ }
1304+
13021305 propertyMap .Set (low.KeyReference [string ]{
13031306 KeyNode : currentProp ,
13041307 Value : currentProp .Value ,
13051308 }, low.ValueReference [* SchemaProxy ]{
13061309 Value : sp ,
1307- ValueNode : prop ,
1310+ ValueNode : sp . vn , // use transformed node
13081311 })
13091312 }
13101313
@@ -1384,12 +1387,56 @@ func (s *Schema) extractExtensions(root *yaml.Node) {
13841387 s .Extensions = low .ExtractExtensions (root )
13851388}
13861389
1390+ // buildAllOfFromTransformedNode manually builds the AllOf field from a transformed allOf node structure
1391+ // This is used when transformation creates an allOf structure but BuildModel doesn't pick it up
1392+ func (s * Schema ) buildAllOfFromTransformedNode (root * yaml.Node ) error {
1393+ if len (root .Content ) < 2 || root .Content [0 ].Value != "allOf" {
1394+ return fmt .Errorf ("invalid allOf structure" )
1395+ }
1396+
1397+ allOfArray := root .Content [1 ] // the array node containing allOf items
1398+ if allOfArray .Kind != yaml .SequenceNode {
1399+ return fmt .Errorf ("allOf value is not an array" )
1400+ }
1401+
1402+ var allOfSchemas []low.ValueReference [* SchemaProxy ]
1403+ for _ , item := range allOfArray .Content {
1404+ // create a schema proxy for each allOf item and build it
1405+ schemaProxy := & SchemaProxy {
1406+ vn : item ,
1407+ idx : s .index ,
1408+ ctx : s .context ,
1409+ }
1410+
1411+ // build the schema proxy so it has proper content
1412+ err := schemaProxy .Build (s .context , nil , item , s .index )
1413+ if err != nil {
1414+ return fmt .Errorf ("failed to build schema proxy for allOf item: %w" , err )
1415+ }
1416+
1417+ allOfSchemas = append (allOfSchemas , low.ValueReference [* SchemaProxy ]{
1418+ Value : schemaProxy ,
1419+ ValueNode : item ,
1420+ })
1421+ }
1422+
1423+ // set the AllOf field
1424+ s .AllOf = low.NodeReference [[]low.ValueReference [* SchemaProxy ]]{
1425+ Value : allOfSchemas ,
1426+ KeyNode : root .Content [0 ], // "allOf" key
1427+ ValueNode : root .Content [1 ], // array value
1428+ }
1429+
1430+ return nil
1431+ }
1432+
13871433// build out a child schema for parent schema.
13881434func buildSchema (ctx context.Context , schemas chan schemaProxyBuildResult , labelNode , valueNode * yaml.Node , errors chan error , idx * index.SpecIndex ) {
13891435 if valueNode != nil {
13901436 type buildResult struct {
13911437 res * low.ValueReference [* SchemaProxy ]
13921438 idx int
1439+ err error
13931440 }
13941441
13951442 syncChan := make (chan buildResult )
@@ -1405,16 +1452,19 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
14051452 // In order to combat this, we need a schema proxy that will only resolve the schema when asked, and then
14061453 // it will only do it one level at a time.
14071454 sp := new (SchemaProxy )
1408- sp .kn = kn
1409- sp .vn = vn
1410- sp .idx = fIdx
1411- sp .ctx = pctx
1455+
1456+ // call Build to ensure transformation happens
1457+ err := sp .Build (pctx , kn , vn , fIdx )
1458+ if err != nil {
1459+ return buildResult {err : err }
1460+ }
1461+
14121462 if isRef {
14131463 sp .SetReference (refLocation , rf )
14141464 }
14151465 res := & low.ValueReference [* SchemaProxy ]{
14161466 Value : sp ,
1417- ValueNode : vn ,
1467+ ValueNode : sp . vn , // use transformed node
14181468 }
14191469 return buildResult {
14201470 res : res ,
@@ -1446,6 +1496,10 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
14461496 // this only runs once, however to keep things consistent, it makes sense to use the same async method
14471497 // that arrays will use.
14481498 r := build (foundCtx , foundIdx , labelNode , valueNode , refNode , - 1 , syncChan , isRef , refLocation )
1499+ if r .err != nil {
1500+ errors <- r .err
1501+ return
1502+ }
14491503 schemas <- schemaProxyBuildResult {
14501504 k : low.KeyReference [string ]{
14511505 KeyNode : labelNode ,
@@ -1479,6 +1533,10 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
14791533 }
14801534 refBuilds ++
14811535 r := build (foundCtx , foundIdx , vn , vn , refNode , i , syncChan , isRef , refLocation )
1536+ if r .err != nil {
1537+ errors <- r .err
1538+ return
1539+ }
14821540 results [r .idx ] = r .res
14831541 }
14841542
@@ -1554,12 +1612,19 @@ func ExtractSchema(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (
15541612 if schNode != nil {
15551613 // check if schema has already been built.
15561614 schema := & SchemaProxy {kn : schLabel , vn : schNode , idx : foundIndex , ctx : foundCtx }
1615+
1616+ // call Build to ensure transformation happens
1617+ err := schema .Build (foundCtx , schLabel , schNode , foundIndex )
1618+ if err != nil {
1619+ return nil , fmt .Errorf ("schema proxy build failed in ExtractSchema: %w" , err )
1620+ }
1621+
15571622 schema .SetReference (refLocation , refNode )
15581623
15591624 n := & low.NodeReference [* SchemaProxy ]{
15601625 Value : schema ,
15611626 KeyNode : schLabel ,
1562- ValueNode : schNode ,
1627+ ValueNode : schema . vn , // use transformed node
15631628 }
15641629 n .SetReference (refLocation , refNode )
15651630 return n , nil
0 commit comments