Skip to content

Commit 73c24d6

Browse files
committed
test(bundler): cover absolute inline ref rewrite
1 parent 3d440aa commit 73c24d6

2 files changed

Lines changed: 111 additions & 40 deletions

File tree

bundler/bundler.go

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -577,26 +577,7 @@ func composeWithOrigins(model *v3.Document, compositionConfig *BundleComposition
577577
rewriteAllRefs(idx, processedNodes, rolodex)
578578
}
579579

580-
// Fix any remaining absolute path references that match inlined content
581-
// Also check the root index
582-
allIndexes := append(allLoadedIndexes, rolodex.GetRootIndex())
583-
for _, idx := range allIndexes {
584-
for _, seqRef := range idx.GetRawReferencesSequenced() {
585-
if isRef, _, refVal := utils.IsNodeRefValue(seqRef.Node); isRef {
586-
// Check if this is an absolute path that should have been inlined
587-
if filepath.IsAbs(refVal) {
588-
// Try to find matching inlined content
589-
for inlinedPath, inlinedNode := range inlinedPaths {
590-
// Match if paths are the same or if they refer to the same file
591-
if refVal == inlinedPath {
592-
seqRef.Node.Content = inlinedNode.Content
593-
break
594-
}
595-
}
596-
}
597-
}
598-
}
599-
}
580+
rewriteInlinedAbsoluteRefs(rolodex, allLoadedIndexes, inlinedPaths)
600581

601582
b, err := renderBundledModel(model, rootIndex)
602583
errs = append(errs, err)
@@ -707,33 +688,48 @@ func compose(model *v3.Document, compositionConfig *BundleCompositionConfig) ([]
707688
rewriteAllRefs(idx, processedNodes, rolodex)
708689
}
709690

710-
// Fix any remaining absolute path references that match inlined content
711-
// Also check the root index
712-
allIndexes := append(allLoadedIndexes, rolodex.GetRootIndex())
713-
for _, idx := range allIndexes {
714-
for _, seqRef := range idx.GetRawReferencesSequenced() {
715-
if isRef, _, refVal := utils.IsNodeRefValue(seqRef.Node); isRef {
716-
// Check if this is an absolute path that should have been inlined
717-
if filepath.IsAbs(refVal) {
718-
// Try to find matching inlined content
719-
for inlinedPath, inlinedNode := range inlinedPaths {
720-
// Match if paths are the same or if they refer to the same file
721-
if refVal == inlinedPath {
722-
seqRef.Node.Content = inlinedNode.Content
723-
break
724-
}
725-
}
726-
}
727-
}
728-
}
729-
}
691+
rewriteInlinedAbsoluteRefs(rolodex, allLoadedIndexes, inlinedPaths)
730692

731693
b, err := renderBundledModel(model, rootIndex)
732694
errs = append(errs, err)
733695

734696
return b, errors.Join(errs...)
735697
}
736698

699+
// rewriteInlinedAbsoluteRefs updates absolute $ref values that were resolved by
700+
// the inline fallback after the index's normal rewrite pass has already run.
701+
func rewriteInlinedAbsoluteRefs(rolodex *index.Rolodex, indexes []*index.SpecIndex, inlinedPaths map[string]*yaml.Node) {
702+
if rolodex == nil || len(inlinedPaths) == 0 {
703+
return
704+
}
705+
706+
allIndexes := append([]*index.SpecIndex{}, indexes...)
707+
allIndexes = append(allIndexes, rolodex.GetRootIndex())
708+
seen := make(map[*index.SpecIndex]struct{}, len(allIndexes))
709+
710+
for _, idx := range allIndexes {
711+
if idx == nil {
712+
continue
713+
}
714+
if _, ok := seen[idx]; ok {
715+
continue
716+
}
717+
seen[idx] = struct{}{}
718+
719+
for _, seqRef := range idx.GetRawReferencesSequenced() {
720+
isRef, _, refVal := utils.IsNodeRefValue(seqRef.Node)
721+
if !isRef || !filepath.IsAbs(refVal) {
722+
continue
723+
}
724+
inlinedNode := inlinedPaths[refVal]
725+
if inlinedNode == nil {
726+
continue
727+
}
728+
seqRef.Node.Content = inlinedNode.Content
729+
}
730+
}
731+
}
732+
737733
// inlineRequiredRefs inlines refs that cannot be represented as root components.
738734
func inlineRequiredRefs(required []*processRef, rolodex *index.Rolodex) map[string]*yaml.Node {
739735
inlinedPaths := make(map[string]*yaml.Node)

bundler/composer_functions_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
v3low "github.com/pb33f/libopenapi/datamodel/low/v3"
1414
"github.com/pb33f/libopenapi/index"
1515
"github.com/pb33f/libopenapi/orderedmap"
16+
"github.com/pb33f/libopenapi/utils"
1617
"github.com/stretchr/testify/assert"
1718
"github.com/stretchr/testify/require"
1819
"go.yaml.in/yaml/v4"
@@ -416,6 +417,65 @@ x-extension:
416417
assert.NotEqual(t, replacement.Content, schemaRef.Node.Content)
417418
}
418419

420+
func TestRewriteInlinedAbsoluteRefs(t *testing.T) {
421+
tmpDir := t.TempDir()
422+
rootPath := filepath.Join(tmpDir, "root.yaml")
423+
matchedPath := filepath.Join(tmpDir, "matched.yaml")
424+
425+
rootSource := strings.ReplaceAll(`openapi: 3.1.0
426+
info:
427+
title: Test
428+
version: 1.0.0
429+
paths:
430+
/matched:
431+
get:
432+
responses:
433+
'200':
434+
description: ok
435+
content:
436+
application/json:
437+
schema:
438+
$ref: 'MATCHED_PATH'
439+
/relative:
440+
get:
441+
responses:
442+
'200':
443+
description: ok
444+
content:
445+
application/json:
446+
schema:
447+
$ref: './relative.yaml'
448+
`, "MATCHED_PATH", matchedPath)
449+
require.NoError(t, os.WriteFile(rootPath, []byte(rootSource), 0644))
450+
451+
var root yaml.Node
452+
require.NoError(t, yaml.Unmarshal([]byte(rootSource), &root))
453+
454+
cfg := index.CreateOpenAPIIndexConfig()
455+
cfg.BasePath = tmpDir
456+
cfg.SpecAbsolutePath = rootPath
457+
idx := index.NewSpecIndexWithConfig(&root, cfg)
458+
459+
matchedRef := findRawRefByValue(t, idx, matchedPath)
460+
relativeRef := findRawRefByValue(t, idx, "./relative.yaml")
461+
replacement := testYAMLContentNode(t, "type: object\nproperties:\n id:\n type: string\n")
462+
463+
rolodex := index.NewRolodex(cfg)
464+
rolodex.SetRootIndex(idx)
465+
rolodex.AddIndex(idx)
466+
467+
rewriteInlinedAbsoluteRefs(nil, []*index.SpecIndex{idx}, map[string]*yaml.Node{matchedPath: replacement})
468+
assert.NotEqual(t, replacement.Content, matchedRef.Node.Content)
469+
470+
rewriteInlinedAbsoluteRefs(rolodex, []*index.SpecIndex{nil, idx}, nil)
471+
rewriteInlinedAbsoluteRefs(rolodex, []*index.SpecIndex{nil, idx}, map[string]*yaml.Node{matchedPath: nil})
472+
assert.NotEqual(t, replacement.Content, matchedRef.Node.Content)
473+
474+
rewriteInlinedAbsoluteRefs(rolodex, []*index.SpecIndex{nil, idx}, map[string]*yaml.Node{matchedPath: replacement})
475+
assert.Equal(t, replacement.Content, matchedRef.Node.Content)
476+
assert.NotEqual(t, replacement.Content, relativeRef.Node.Content)
477+
}
478+
419479
func newVersionedIndex(version float32) *index.SpecIndex {
420480
var root yaml.Node
421481
_ = yaml.Unmarshal([]byte(`openapi: 3.1.0
@@ -454,6 +514,21 @@ func findRawRefByComponentType(t *testing.T, idx *index.SpecIndex, componentType
454514
return nil
455515
}
456516

517+
func findRawRefByValue(t *testing.T, idx *index.SpecIndex, refValue string) *index.Reference {
518+
t.Helper()
519+
520+
for _, ref := range idx.GetRawReferencesSequenced() {
521+
if ref == nil || ref.Node == nil {
522+
continue
523+
}
524+
if isRef, _, value := utils.IsNodeRefValue(ref.Node); isRef && value == refValue {
525+
return ref
526+
}
527+
}
528+
t.Fatalf("expected raw ref value %q", refValue)
529+
return nil
530+
}
531+
457532
func newProcessRefForTest(t *testing.T, name, source string) *processRef {
458533
t.Helper()
459534

0 commit comments

Comments
 (0)