diff --git a/datamodel/document_config.go b/datamodel/document_config.go index 8051dad..7b7d113 100644 --- a/datamodel/document_config.go +++ b/datamodel/document_config.go @@ -40,6 +40,18 @@ type DocumentConfiguration struct { // BypassDocumentCheck will bypass the document check. This is disabled by default. This will allow any document to // passed in and used. Only enable this when parsing non openapi documents. BypassDocumentCheck bool + + // IgnorePolymorphicCircularReferences will skip over checking for circular references in polymorphic schemas. + // A polymorphic schema is any schema that is composed other schemas using references via `oneOf`, `anyOf` of `allOf`. + // This is disabled by default, which means polymorphic circular references will be checked. + IgnorePolymorphicCircularReferences bool + + // IgnoreArrayCircularReferences will skip over checking for circular references in arrays. Sometimes a circular + // reference is required to describe a data-shape correctly. Often those shapes are valid circles if the + // type of the schema implementing the loop is an array. An empty array would technically break the loop. + // So if libopenapi is returning circular references for this use case, then this option should be enabled. + // this is disabled by default, which means array circular references will be checked. + IgnoreArrayCircularReferences bool } func NewOpenDocumentConfiguration() *DocumentConfiguration { diff --git a/datamodel/low/v3/create_document.go b/datamodel/low/v3/create_document.go index fce4e7e..85cc843 100644 --- a/datamodel/low/v3/create_document.go +++ b/datamodel/low/v3/create_document.go @@ -63,6 +63,16 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur // create resolver and check for circular references. resolve := resolver.NewResolver(idx) + + // if configured, ignore circular references in arrays and polymorphic schemas + if config.IgnoreArrayCircularReferences { + resolve.IgnoreArrayCircularReferences() + } + if config.IgnorePolymorphicCircularReferences { + resolve.IgnorePolymorphicCircularReferences() + } + + // check for circular references. resolvingErrors := resolve.CheckForCircularReferences() if len(resolvingErrors) > 0 { diff --git a/document_test.go b/document_test.go index 9c7d3c5..2c9be68 100644 --- a/document_test.go +++ b/document_test.go @@ -790,3 +790,71 @@ paths: assert.Equal(t, spec, strings.TrimSpace(string(rend))) } + +func TestDocument_IgnorePolymorphicCircularReferences(t *testing.T) { + + var d = `openapi: 3.1.0 +components: + schemas: + ProductCategory: + type: "object" + properties: + name: + type: "string" + children: + type: "object" + anyOf: + - $ref: "#/components/schemas/ProductCategory" + description: "Array of sub-categories in the same format." + required: + - "name" + - "children"` + + config := datamodel.NewClosedDocumentConfiguration() + config.IgnorePolymorphicCircularReferences = true + + doc, err := NewDocumentWithConfiguration([]byte(d), config) + if err != nil { + panic(err) + } + + m, errs := doc.BuildV3Model() + + assert.Len(t, errs, 0) + assert.Len(t, m.Index.GetCircularReferences(), 0) + +} + +func TestDocument_IgnoreArrayCircularReferences(t *testing.T) { + + var d = `openapi: 3.1.0 +components: + schemas: + ProductCategory: + type: "object" + properties: + name: + type: "string" + children: + type: "array" + items: + $ref: "#/components/schemas/ProductCategory" + description: "Array of sub-categories in the same format." + required: + - "name" + - "children"` + + config := datamodel.NewClosedDocumentConfiguration() + config.IgnoreArrayCircularReferences = true + + doc, err := NewDocumentWithConfiguration([]byte(d), config) + if err != nil { + panic(err) + } + + m, errs := doc.BuildV3Model() + + assert.Len(t, errs, 0) + assert.Len(t, m.Index.GetCircularReferences(), 0) + +} diff --git a/index/index_model.go b/index/index_model.go index 5058c8e..08f629b 100644 --- a/index/index_model.go +++ b/index/index_model.go @@ -105,12 +105,6 @@ type SpecIndexConfig struct { // Use the `BuildIndex()` method on the index to build it out once resolved/ready. AvoidBuildIndex bool - // If set to true, the index will ignore circular references in polymorphic schemas. - IgnorePolymorphicCircularReferences bool // ignore circular references in polymorphic schemas. - - // If set to true, the index will ignore circular references in arrays. - IgnoreArrayCircularReferences bool // ignore circular references in arrays. - // private fields seenRemoteSources *syncmap.Map remoteLock *sync.Mutex