mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 04:20:17 +00:00
feat: add index for getting all "schema" objects #50
There is new code that looks for inline `schema` definitions and collects them, as well as a futher subset of references that are specifically `object` or `array` types. This is a breaking change because the `index.GetAllSchemas()` method now returns a slice of *Reference pointers, rather than a map of them. The original behavior of `GetAllSchemas()` has been replaced with `GetAllComponentSchemas()` which retains the signature. Two new additional methods `GetAllInlineSchemas()` and `GetAllInlineSchemaObjects()`. The former will return everything in the spec marked with `schema` that is not a reference. The latter will return everything the former does, except filtered down by `object` or `array` types. Also the index is now bubbled up through the document model. There isn't a simple way to get access to it, small non breaking change that attaches a reference to the index, returned by `DocumentModel`
This commit is contained in:
@@ -15,6 +15,7 @@ package libopenapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
|
||||
"github.com/pb33f/libopenapi/datamodel"
|
||||
v2high "github.com/pb33f/libopenapi/datamodel/high/v2"
|
||||
@@ -68,6 +69,7 @@ type document struct {
|
||||
// built from a parent Document.
|
||||
type DocumentModel[T v2high.Swagger | v3high.Document] struct {
|
||||
Model T
|
||||
Index *index.SpecIndex // index created from the document.
|
||||
}
|
||||
|
||||
// NewDocument will create a new OpenAPI instance from an OpenAPI specification []byte array. If anything goes
|
||||
@@ -133,6 +135,7 @@ func (d *document) BuildV2Model() (*DocumentModel[v2high.Swagger], []error) {
|
||||
highDoc := v2high.NewSwaggerDocument(lowDoc)
|
||||
return &DocumentModel[v2high.Swagger]{
|
||||
Model: *highDoc,
|
||||
Index: lowDoc.Index,
|
||||
}, errs
|
||||
}
|
||||
|
||||
@@ -162,6 +165,7 @@ func (d *document) BuildV3Model() (*DocumentModel[v3high.Document], []error) {
|
||||
highDoc := v3high.NewDocument(lowDoc)
|
||||
return &DocumentModel[v3high.Document]{
|
||||
Model: *highDoc,
|
||||
Index: lowDoc.Index,
|
||||
}, errs
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,9 @@ type SpecIndex struct {
|
||||
allParametersNode map[string]*Reference // all parameters node
|
||||
allParameters map[string]*Reference // all parameters (components/defs)
|
||||
schemasNode *yaml.Node // components/schemas node
|
||||
allSchemas map[string]*Reference // all schemas
|
||||
allInlineSchemaDefinitions []*Reference // all schemas found in document outside of components (openapi) or definitions (swagger).
|
||||
allInlineSchemaObjectDefinitions []*Reference // all schemas that are objects found in document outside of components (openapi) or definitions (swagger).
|
||||
allComponentSchemaDefinitions map[string]*Reference // all schemas found in components (openapi) or definitions (swagger).
|
||||
securitySchemesNode *yaml.Node // components/securitySchemes node
|
||||
allSecuritySchemes map[string]*Reference // all security schemes / definitions.
|
||||
requestBodiesNode *yaml.Node // components/requestBodies node
|
||||
@@ -227,7 +229,7 @@ func NewSpecIndex(rootNode *yaml.Node) *SpecIndex {
|
||||
index.linksRefs = make(map[string]map[string][]*Reference)
|
||||
index.callbackRefs = make(map[string]*Reference)
|
||||
index.externalSpecIndex = make(map[string]*SpecIndex)
|
||||
index.allSchemas = make(map[string]*Reference)
|
||||
index.allComponentSchemaDefinitions = make(map[string]*Reference)
|
||||
index.allParameters = make(map[string]*Reference)
|
||||
index.allSecuritySchemes = make(map[string]*Reference)
|
||||
index.allRequestBodies = make(map[string]*Reference)
|
||||
@@ -304,7 +306,7 @@ func (index *SpecIndex) GetRootNode() *yaml.Node {
|
||||
return index.root
|
||||
}
|
||||
|
||||
// GetGlobalTagsNode returns document root node.
|
||||
// GetGlobalTagsNode returns document root tags node.
|
||||
func (index *SpecIndex) GetGlobalTagsNode() *yaml.Node {
|
||||
return index.tagsNode
|
||||
}
|
||||
@@ -391,9 +393,41 @@ func (index *SpecIndex) GetOperationParameterReferences() map[string]map[string]
|
||||
return index.paramOpRefs
|
||||
}
|
||||
|
||||
// GetAllSchemas will return all schemas found in the document
|
||||
func (index *SpecIndex) GetAllSchemas() map[string]*Reference {
|
||||
return index.allSchemas
|
||||
// GetAllSchemas will return references to all schemas found in the document both inline and those under components
|
||||
// The first elements of at the top of the slice, are all the inline references (using GetAllInlineSchemas),
|
||||
// and then following on are all the references extracted from the components section (using GetAllComponentSchemas).
|
||||
func (index *SpecIndex) GetAllSchemas() []*Reference {
|
||||
|
||||
componentSchemas := index.GetAllComponentSchemas()
|
||||
inlineSchemas := index.GetAllInlineSchemas()
|
||||
|
||||
combined := make([]*Reference, len(inlineSchemas)+len(componentSchemas))
|
||||
i := 0
|
||||
for x := range inlineSchemas {
|
||||
combined[i] = inlineSchemas[x]
|
||||
i++
|
||||
}
|
||||
for x := range componentSchemas {
|
||||
combined[i] = componentSchemas[x]
|
||||
i++
|
||||
}
|
||||
return combined
|
||||
}
|
||||
|
||||
// GetAllInlineSchemaObjects will return all schemas that are inline (not inside components) and that are also typed
|
||||
// as 'object' or 'array' (not primitives).
|
||||
func (index *SpecIndex) GetAllInlineSchemaObjects() []*Reference {
|
||||
return index.allInlineSchemaObjectDefinitions
|
||||
}
|
||||
|
||||
// GetAllInlineSchemas will return all schemas defined in the components section of the document.
|
||||
func (index *SpecIndex) GetAllInlineSchemas() []*Reference {
|
||||
return index.allInlineSchemaDefinitions
|
||||
}
|
||||
|
||||
// GetAllComponentSchemas will return all schemas defined in the components section of the document.
|
||||
func (index *SpecIndex) GetAllComponentSchemas() map[string]*Reference {
|
||||
return index.allComponentSchemaDefinitions
|
||||
}
|
||||
|
||||
// GetAllSecuritySchemes will return all security schemes / definitions found in the document.
|
||||
@@ -600,6 +634,27 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
||||
found = append(found, index.ExtractRefs(n, node, seenPath, level, poly, polyName)...)
|
||||
}
|
||||
|
||||
if i%2 == 0 && n.Value == "schema" {
|
||||
isRef, _, _ := utils.IsNodeRefValue(node.Content[i+1])
|
||||
if isRef {
|
||||
continue
|
||||
}
|
||||
ref := &Reference{
|
||||
Node: node.Content[i+1],
|
||||
Path: fmt.Sprintf("$.%s", strings.Join(seenPath, ".")),
|
||||
}
|
||||
index.allInlineSchemaDefinitions = append(index.allInlineSchemaDefinitions, ref)
|
||||
|
||||
// check if the schema is an object or an array,
|
||||
// and if so, add it to the list of inline schema object definitions.
|
||||
k, v := utils.FindKeyNodeTop("type", node.Content[i+1].Content)
|
||||
if k != nil && v != nil {
|
||||
if v.Value == "object" || v.Value == "array" {
|
||||
index.allInlineSchemaObjectDefinitions = append(index.allInlineSchemaObjectDefinitions, ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if i%2 == 0 && n.Value == "$ref" {
|
||||
|
||||
// only look at scalar values, not maps (looking at you k8s)
|
||||
@@ -1711,7 +1766,7 @@ func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pat
|
||||
ParentNode: schemasNode,
|
||||
RequiredRefProperties: index.extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}),
|
||||
}
|
||||
index.allSchemas[def] = ref
|
||||
index.allComponentSchemaDefinitions[def] = ref
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,8 @@ func TestSpecIndex_BurgerShop(t *testing.T) {
|
||||
assert.Equal(t, 6, index.pathCount)
|
||||
assert.Equal(t, 6, index.GetPathCount())
|
||||
|
||||
assert.Equal(t, 6, len(index.GetAllSchemas()))
|
||||
assert.Equal(t, 6, len(index.GetAllComponentSchemas()))
|
||||
assert.Equal(t, 15, len(index.GetAllSchemas()))
|
||||
|
||||
assert.Equal(t, 34, len(index.GetAllSequencedReferences()))
|
||||
assert.NotNil(t, index.GetSchemasNode())
|
||||
@@ -833,19 +834,28 @@ func ExampleNewSpecIndex() {
|
||||
fmt.Printf("There are %d references\n"+
|
||||
"%d paths\n"+
|
||||
"%d operations\n"+
|
||||
"%d schemas\n"+
|
||||
"%d component schemas\n"+
|
||||
"%d inline schemas\n"+
|
||||
"%d inline schemas that are objects or arrays\n"+
|
||||
"%d total schemas\n"+
|
||||
"%d enums\n"+
|
||||
"%d polymorphic references",
|
||||
len(index.GetAllCombinedReferences()),
|
||||
len(index.GetAllPaths()),
|
||||
index.GetOperationCount(),
|
||||
len(index.GetAllComponentSchemas()),
|
||||
len(index.GetAllInlineSchemas()),
|
||||
len(index.GetAllInlineSchemaObjects()),
|
||||
len(index.GetAllSchemas()),
|
||||
len(index.GetAllEnums()),
|
||||
len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences()))
|
||||
// Output: There are 537 references
|
||||
// 246 paths
|
||||
// 402 operations
|
||||
// 537 schemas
|
||||
// 537 component schemas
|
||||
// 1530 inline schemas
|
||||
// 711 inline schemas that are objects or arrays
|
||||
// 2067 total schemas
|
||||
// 1516 enums
|
||||
// 828 polymorphic references
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user