Skip to content

Commit 195bf09

Browse files
fix
1 parent 36386df commit 195bf09

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

openapi/index.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,11 +1023,13 @@ func (i *Index) isFromMainDocument() bool {
10231023

10241024
// buildPathSegmentsFromStack builds path segments from a point in the reference stack to current location.
10251025
func (i *Index) buildPathSegmentsFromStack(startStackIdx int, currentLoc Locations) []CircularPathSegment {
1026-
// Collect all locations from the stack starting point plus current
1026+
// Collect only the segments WITHIN the circular loop.
1027+
// Skip referenceStack[startStackIdx].location because it contains the path
1028+
// leading TO the circular loop start (outside the loop), not the path within it.
1029+
// Only include entries after startStackIdx (intermediate refs in the loop) plus currentLoc.
10271030
var segments []CircularPathSegment
10281031

1029-
// Add segments from each stack entry after the circular start point
1030-
for stackIdx := startStackIdx; stackIdx < len(i.referenceStack); stackIdx++ {
1032+
for stackIdx := startStackIdx + 1; stackIdx < len(i.referenceStack); stackIdx++ {
10311033
entry := i.referenceStack[stackIdx]
10321034
for _, locCtx := range entry.location {
10331035
segments = append(segments, buildPathSegment(locCtx))

openapi/index_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,3 +2145,63 @@ func TestIndex_GetAllReferences_NilIndex_Success(t *testing.T) {
21452145
allRefs := idx.GetAllReferences()
21462146
assert.Nil(t, allRefs, "should return nil for nil index")
21472147
}
2148+
2149+
func TestBuildIndex_CircularRef_OneOfSelfRefWithBaseCases_Valid(t *testing.T) {
2150+
t.Parallel()
2151+
ctx := t.Context()
2152+
2153+
// A recursive JSON-value-like type: oneOf with self-referencing branches (object/array)
2154+
// AND non-recursive base-case branches (string/number/boolean).
2155+
// Referenced from within an inline oneOf in a path response.
2156+
// This should be VALID because the oneOf has non-recursive branches.
2157+
yaml := `
2158+
openapi: "3.0.3"
2159+
info:
2160+
title: Test API
2161+
version: 1.0.0
2162+
paths:
2163+
/test:
2164+
get:
2165+
operationId: getTest
2166+
responses:
2167+
"200":
2168+
description: OK
2169+
content:
2170+
application/json:
2171+
schema:
2172+
oneOf:
2173+
- type: object
2174+
properties:
2175+
data:
2176+
$ref: '#/components/schemas/JsonValue'
2177+
- type: object
2178+
properties:
2179+
items:
2180+
$ref: '#/components/schemas/JsonValue'
2181+
components:
2182+
schemas:
2183+
JsonValue:
2184+
nullable: true
2185+
oneOf:
2186+
- type: string
2187+
- type: number
2188+
- type: object
2189+
additionalProperties:
2190+
$ref: '#/components/schemas/JsonValue'
2191+
- type: array
2192+
items:
2193+
$ref: '#/components/schemas/JsonValue'
2194+
- type: boolean
2195+
`
2196+
doc := unmarshalOpenAPI(t, ctx, yaml)
2197+
idx := openapi.BuildIndex(ctx, doc, references.ResolveOptions{
2198+
RootDocument: doc,
2199+
TargetDocument: doc,
2200+
TargetLocation: "test.yaml",
2201+
})
2202+
2203+
require.NotNil(t, idx, "index should not be nil")
2204+
2205+
circularErrs := idx.GetCircularReferenceErrors()
2206+
assert.Empty(t, circularErrs, "oneOf with non-recursive base-case branches should be valid")
2207+
}

0 commit comments

Comments
 (0)