Skip to content

Commit 0af9c35

Browse files
vkddaveshanley
authored andcommitted
fix "IsReference/GetReference" for all types in components
1 parent fd14ceb commit 0af9c35

File tree

13 files changed

+155
-25
lines changed

13 files changed

+155
-25
lines changed

datamodel/low/base/example.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,13 @@ func (ex *Example) Hash() [32]byte {
7272
// Build extracts extensions and example value
7373
func (ex *Example) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
7474
ex.KeyNode = keyNode
75+
ex.Reference = new(low.Reference)
76+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
77+
ex.SetReference(ref, root)
78+
}
7579
root = utils.NodeAlias(root)
7680
ex.RootNode = root
7781
utils.CheckForMergeNodes(root)
78-
ex.Reference = new(low.Reference)
7982
ex.Nodes = low.ExtractNodes(ctx, root)
8083
ex.Extensions = low.ExtractExtensions(root)
8184
ex.context = ctx

datamodel/low/base/example_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,22 @@ x-burger: nice`
195195
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
196196
assert.Equal(t, 1, orderedmap.Len(lDoc.GetExtensions()))
197197
}
198+
199+
func TestExample_Build_Success_Ref(t *testing.T) {
200+
yml := `$ref: "#/responses/abc"`
201+
202+
var idxNode yaml.Node
203+
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
204+
assert.NoError(t, mErr)
205+
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
206+
207+
var n Example
208+
err := low.BuildModel(idxNode.Content[0], &n)
209+
assert.NoError(t, err)
210+
211+
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
212+
assert.NoError(t, err)
213+
214+
assert.True(t, n.IsReference())
215+
assert.Equal(t, "#/responses/abc", n.GetReference())
216+
}

datamodel/low/v3/callback.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,13 @@ func (cb *Callback) FindExpression(exp string) *low.ValueReference[*PathItem] {
6767
// Build will extract extensions, expressions and PathItem objects for Callback
6868
func (cb *Callback) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
6969
cb.KeyNode = keyNode
70+
cb.Reference = new(low.Reference)
71+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
72+
cb.SetReference(ref, root)
73+
}
7074
root = utils.NodeAlias(root)
7175
cb.RootNode = root
7276
utils.CheckForMergeNodes(root)
73-
cb.Reference = new(low.Reference)
7477
cb.Nodes = low.ExtractNodes(ctx, root)
7578
cb.Extensions = low.ExtractExtensions(root)
7679
cb.context = ctx

datamodel/low/v3/components.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -310,23 +310,9 @@ func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, labe
310310
currentLabel := value.currentLabel
311311
node := value.node
312312

313-
// if this is a reference, extract it (although components with references is an antipattern)
314-
// If you're building components as references... pls... stop, this code should not need to be here.
315-
// TODO: check circular crazy on this. It may explode
316-
var err error
317-
nCtx := ctx
318-
fIdx := idx
319-
if h, rv, _ := utils.IsNodeRefValue(node); h && label != SchemasLabel {
320-
node, fIdx, err, nCtx = low.LocateRefNodeWithContext(ctx, node, idx)
321-
nCtx = context.WithValue(nCtx, "reference", rv)
322-
}
323-
if err != nil {
324-
return componentBuildResult[T]{}, err
325-
}
326-
327313
// build.
328314
_ = low.BuildModel(node, n)
329-
err = n.Build(nCtx, currentLabel, node, fIdx)
315+
err := n.Build(ctx, currentLabel, node, idx)
330316
if err != nil {
331317
return componentBuildResult[T]{}, err
332318
}

datamodel/low/v3/components_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,101 @@ func TestComponents_Build_HashEmpty(t *testing.T) {
262262
assert.Equal(t, "e45605d7361dbc9d4b9723257701bef1d283f8fe9566b9edda127fc66a6b8fdd",
263263
low.GenerateHashString(&n))
264264
}
265+
266+
func TestComponents_IsReference(t *testing.T) {
267+
var yml = `
268+
schemas:
269+
one:
270+
description: one of many
271+
two:
272+
$ref: "#/schemas/one"
273+
responses:
274+
three:
275+
description: three of many
276+
four:
277+
$ref: "#/responses/three"
278+
parameters:
279+
five:
280+
description: five of many
281+
six:
282+
$ref: "#/parameters/five"
283+
examples:
284+
seven:
285+
description: seven of many
286+
eight:
287+
$ref: "#/examples/seven"
288+
requestBodies:
289+
nine:
290+
description: nine of many
291+
ten:
292+
$ref: "#/requestBodies/nine"
293+
headers:
294+
eleven:
295+
description: eleven of many
296+
twelve:
297+
$ref: "#/headers/eleven"
298+
securitySchemes:
299+
thirteen:
300+
description: thirteen of many
301+
fourteen:
302+
$ref: "#/securitySchemes/thirteen"
303+
links:
304+
fifteen:
305+
description: fifteen of many
306+
sixteen:
307+
$ref: "#/links/fifteen"
308+
callbacks:
309+
seventeen:
310+
'{reference}':
311+
post:
312+
description: seventeen of many
313+
eighteen:
314+
$ref: "#/callbacks/seventeen"
315+
`
316+
317+
var idxNode yaml.Node
318+
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
319+
assert.NoError(t, mErr)
320+
idx := index.NewSpecIndex(&idxNode)
321+
322+
var n Components
323+
err := low.BuildModel(idxNode.Content[0], &n)
324+
assert.NoError(t, err)
325+
326+
err = n.Build(context.Background(), idxNode.Content[0], idx)
327+
assert.NoError(t, err)
328+
329+
assert.Equal(t, "#/schemas/one", n.FindSchema("two").Value.GetReference())
330+
assert.Equal(t, "#/responses/three", n.FindResponse("four").Value.GetReference())
331+
assert.Equal(t, "#/parameters/five", n.FindParameter("six").Value.GetReference())
332+
assert.Equal(t, "#/examples/seven", n.FindExample("eight").Value.GetReference())
333+
assert.Equal(t, "#/requestBodies/nine", n.FindRequestBody("ten").Value.GetReference())
334+
assert.Equal(t, "#/headers/eleven", n.FindHeader("twelve").Value.GetReference())
335+
assert.Equal(t, "#/securitySchemes/thirteen", n.FindSecurityScheme("fourteen").Value.GetReference())
336+
assert.Equal(t, "#/links/fifteen", n.FindLink("sixteen").Value.GetReference())
337+
assert.Equal(t, "#/callbacks/seventeen", n.FindCallback("eighteen").Value.GetReference())
338+
}
339+
340+
func TestComponents_IsReference_OutOfSpecification_PathItem(t *testing.T) {
341+
var yml = `
342+
pathItems:
343+
one:
344+
description: one of many
345+
two:
346+
$ref: "#/pathItems/one"
347+
`
348+
349+
var idxNode yaml.Node
350+
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
351+
assert.NoError(t, mErr)
352+
idx := index.NewSpecIndex(&idxNode)
353+
354+
var n Components
355+
err := low.BuildModel(idxNode.Content[0], &n)
356+
assert.NoError(t, err)
357+
358+
err = n.Build(context.Background(), idxNode.Content[0], idx)
359+
assert.NoError(t, err)
360+
361+
assert.Equal(t, "#/pathItems/one", n.FindPathItem("two").Value.GetReference())
362+
}

datamodel/low/v3/create_document_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ components:
753753
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
754754
var err error
755755
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{})
756-
assert.Equal(t, "reference at line 5, column 7 is empty, it cannot be resolved", err.Error())
756+
assert.Equal(t, "schema build failed: reference '[empty]' cannot be found at line 5, col 12", err.Error())
757757
}
758758

759759
func TestCreateDocument_Paths_Errors(t *testing.T) {

datamodel/low/v3/header.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,13 @@ func (h *Header) Hash() [32]byte {
113113
// Build will extract extensions, examples, schema and content/media types from node.
114114
func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
115115
h.KeyNode = keyNode
116+
h.Reference = new(low.Reference)
117+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
118+
h.SetReference(ref, root)
119+
}
116120
root = utils.NodeAlias(root)
117121
h.RootNode = root
118122
utils.CheckForMergeNodes(root)
119-
h.Reference = new(low.Reference)
120123
h.Nodes = low.ExtractNodes(ctx, root)
121124
h.Extensions = low.ExtractExtensions(root)
122125
h.context = ctx

datamodel/low/v3/link.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,13 @@ func (l *Link) GetKeyNode() *yaml.Node {
8181
// Build will extract extensions and servers from the node.
8282
func (l *Link) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
8383
l.KeyNode = keyNode
84+
l.Reference = new(low.Reference)
85+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
86+
l.SetReference(ref, root)
87+
}
8488
root = utils.NodeAlias(root)
8589
l.RootNode = root
8690
utils.CheckForMergeNodes(root)
87-
l.Reference = new(low.Reference)
8891
l.Nodes = low.ExtractNodes(ctx, root)
8992
l.Extensions = low.ExtractExtensions(root)
9093
l.index = idx

datamodel/low/v3/parameter.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,14 @@ func (p *Parameter) GetExtensions() *orderedmap.Map[low.KeyReference[string], lo
8787

8888
// Build will extract examples, extensions and content/media types.
8989
func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
90+
p.Reference = new(low.Reference)
91+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
92+
p.SetReference(ref, root)
93+
}
9094
root = utils.NodeAlias(root)
9195
p.KeyNode = keyNode
9296
p.RootNode = root
9397
utils.CheckForMergeNodes(root)
94-
p.Reference = new(low.Reference)
9598
p.Nodes = low.ExtractNodes(ctx, root)
9699
p.Extensions = low.ExtractExtensions(root)
97100
p.index = idx

datamodel/low/v3/path_item.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,14 @@ func (p *PathItem) GetExtensions() *orderedmap.Map[low.KeyReference[string], low
129129
// Build extracts extensions, parameters, servers and each http method defined.
130130
// everything is extracted asynchronously for speed.
131131
func (p *PathItem) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
132+
p.Reference = new(low.Reference)
133+
if ok, _, ref := utils.IsNodeRefValue(root); ok {
134+
p.SetReference(ref, root)
135+
}
132136
root = utils.NodeAlias(root)
133137
p.KeyNode = keyNode
134138
p.RootNode = root
135139
utils.CheckForMergeNodes(root)
136-
p.Reference = new(low.Reference)
137140
p.Nodes = low.ExtractNodes(ctx, root)
138141
p.Extensions = low.ExtractExtensions(root)
139142
p.index = idx

0 commit comments

Comments
 (0)