mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-07 12:37:48 +00:00
fix: Issue #82
The index can now accept multiple parameters with the same name, as long as they have different `in` types.
This commit is contained in:
@@ -105,10 +105,10 @@ type SpecIndex struct {
|
|||||||
allMappedRefsSequenced []*ReferenceMapped // sequenced mapped refs
|
allMappedRefsSequenced []*ReferenceMapped // sequenced mapped refs
|
||||||
refsByLine map[string]map[int]bool // every reference and the lines it's referenced from
|
refsByLine map[string]map[int]bool // every reference and the lines it's referenced from
|
||||||
pathRefs map[string]map[string]*Reference // all path references
|
pathRefs map[string]map[string]*Reference // all path references
|
||||||
paramOpRefs map[string]map[string]map[string]*Reference // params in operations.
|
paramOpRefs map[string]map[string]map[string][]*Reference // params in operations.
|
||||||
paramCompRefs map[string]*Reference // params in components
|
paramCompRefs map[string]*Reference // params in components
|
||||||
paramAllRefs map[string]*Reference // combined components and ops
|
paramAllRefs map[string]*Reference // combined components and ops
|
||||||
paramInlineDuplicates map[string][]*Reference // inline params all with the same name
|
paramInlineDuplicateNames map[string][]*Reference // inline params all with the same name
|
||||||
globalTagRefs map[string]*Reference // top level global tags
|
globalTagRefs map[string]*Reference // top level global tags
|
||||||
securitySchemeRefs map[string]*Reference // top level security schemes
|
securitySchemeRefs map[string]*Reference // top level security schemes
|
||||||
requestBodiesRefs map[string]*Reference // top level request bodies
|
requestBodiesRefs map[string]*Reference // top level request bodies
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ func boostrapIndexCollections(rootNode *yaml.Node, index *SpecIndex) {
|
|||||||
index.refsByLine = make(map[string]map[int]bool)
|
index.refsByLine = make(map[string]map[int]bool)
|
||||||
index.linesWithRefs = make(map[int]bool)
|
index.linesWithRefs = make(map[int]bool)
|
||||||
index.pathRefs = make(map[string]map[string]*Reference)
|
index.pathRefs = make(map[string]map[string]*Reference)
|
||||||
index.paramOpRefs = make(map[string]map[string]map[string]*Reference)
|
index.paramOpRefs = make(map[string]map[string]map[string][]*Reference)
|
||||||
index.operationTagsRefs = make(map[string]map[string][]*Reference)
|
index.operationTagsRefs = make(map[string]map[string][]*Reference)
|
||||||
index.operationDescriptionRefs = make(map[string]map[string]*Reference)
|
index.operationDescriptionRefs = make(map[string]map[string]*Reference)
|
||||||
index.operationSummaryRefs = make(map[string]map[string]*Reference)
|
index.operationSummaryRefs = make(map[string]map[string]*Reference)
|
||||||
index.paramCompRefs = make(map[string]*Reference)
|
index.paramCompRefs = make(map[string]*Reference)
|
||||||
index.paramAllRefs = make(map[string]*Reference)
|
index.paramAllRefs = make(map[string]*Reference)
|
||||||
index.paramInlineDuplicates = make(map[string][]*Reference)
|
index.paramInlineDuplicateNames = make(map[string][]*Reference)
|
||||||
index.globalTagRefs = make(map[string]*Reference)
|
index.globalTagRefs = make(map[string]*Reference)
|
||||||
index.securitySchemeRefs = make(map[string]*Reference)
|
index.securitySchemeRefs = make(map[string]*Reference)
|
||||||
index.requestBodiesRefs = make(map[string]*Reference)
|
index.requestBodiesRefs = make(map[string]*Reference)
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ func (index *SpecIndex) GetMappedReferencesSequenced() []*ReferenceMapped {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetOperationParameterReferences will return all references to operation parameters
|
// GetOperationParameterReferences will return all references to operation parameters
|
||||||
func (index *SpecIndex) GetOperationParameterReferences() map[string]map[string]map[string]*Reference {
|
func (index *SpecIndex) GetOperationParameterReferences() map[string]map[string]map[string][]*Reference {
|
||||||
return index.paramOpRefs
|
return index.paramOpRefs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ func (index *SpecIndex) GetAllCallbacks() map[string]*Reference {
|
|||||||
|
|
||||||
// GetInlineOperationDuplicateParameters will return a map of duplicates located in operation parameters.
|
// GetInlineOperationDuplicateParameters will return a map of duplicates located in operation parameters.
|
||||||
func (index *SpecIndex) GetInlineOperationDuplicateParameters() map[string][]*Reference {
|
func (index *SpecIndex) GetInlineOperationDuplicateParameters() map[string][]*Reference {
|
||||||
return index.paramInlineDuplicates
|
return index.paramInlineDuplicateNames
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReferencesWithSiblings will return a map of all the references with sibling nodes (illegal)
|
// GetReferencesWithSiblings will return a map of all the references with sibling nodes (illegal)
|
||||||
@@ -359,7 +359,7 @@ func (index *SpecIndex) GetOperationTags() map[string]map[string][]*Reference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAllParametersFromOperations will return all paths indexed in the document
|
// GetAllParametersFromOperations will return all paths indexed in the document
|
||||||
func (index *SpecIndex) GetAllParametersFromOperations() map[string]map[string]map[string]*Reference {
|
func (index *SpecIndex) GetAllParametersFromOperations() map[string]map[string]map[string][]*Reference {
|
||||||
return index.paramOpRefs
|
return index.paramOpRefs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1104,14 +1104,23 @@ func (index *SpecIndex) GetOperationsParameterCount() int {
|
|||||||
for mName, mValue := range params {
|
for mName, mValue := range params {
|
||||||
for pName, pValue := range mValue {
|
for pName, pValue := range mValue {
|
||||||
if !strings.HasPrefix(pName, "#") {
|
if !strings.HasPrefix(pName, "#") {
|
||||||
index.paramInlineDuplicates[pName] = append(index.paramInlineDuplicates[pName], pValue)
|
index.paramInlineDuplicateNames[pName] = append(index.paramInlineDuplicateNames[pName], pValue...)
|
||||||
index.paramAllRefs[fmt.Sprintf("%s:::%s", path, mName)] = pValue
|
for i := range pValue {
|
||||||
|
if pValue[i] != nil {
|
||||||
|
_, in := utils.FindKeyNodeTop("in", pValue[i].Node.Content)
|
||||||
|
if in != nil {
|
||||||
|
index.paramAllRefs[fmt.Sprintf("%s:::%s:::%s", path, mName, in.Value)] = pValue[i]
|
||||||
|
} else {
|
||||||
|
index.paramAllRefs[fmt.Sprintf("%s:::%s", path, mName)] = pValue[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index.operationParamCount = len(index.paramCompRefs) + len(index.paramInlineDuplicates)
|
index.operationParamCount = len(index.paramCompRefs) + len(index.paramInlineDuplicateNames)
|
||||||
return index.operationParamCount
|
return index.operationParamCount
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1120,7 +1129,7 @@ func (index *SpecIndex) GetInlineDuplicateParamCount() int {
|
|||||||
if index.componentsInlineParamDuplicateCount > 0 {
|
if index.componentsInlineParamDuplicateCount > 0 {
|
||||||
return index.componentsInlineParamDuplicateCount
|
return index.componentsInlineParamDuplicateCount
|
||||||
}
|
}
|
||||||
dCount := len(index.paramInlineDuplicates) - index.countUniqueInlineDuplicates()
|
dCount := len(index.paramInlineDuplicateNames) - index.countUniqueInlineDuplicates()
|
||||||
index.componentsInlineParamDuplicateCount = dCount
|
index.componentsInlineParamDuplicateCount = dCount
|
||||||
return dCount
|
return dCount
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -661,7 +661,7 @@ paths:
|
|||||||
|
|
||||||
index := NewSpecIndex(&rootNode)
|
index := NewSpecIndex(&rootNode)
|
||||||
|
|
||||||
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"].Node)
|
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
||||||
@@ -775,18 +775,18 @@ components:
|
|||||||
if assert.Contains(t, params, "/") {
|
if assert.Contains(t, params, "/") {
|
||||||
if assert.Contains(t, params["/"], "top") {
|
if assert.Contains(t, params["/"], "top") {
|
||||||
if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") {
|
if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") {
|
||||||
assert.Equal(t, "$.components.parameters.param1", params["/"]["top"]["#/components/parameters/param1"].Path)
|
assert.Equal(t, "$.components.parameters.param1", params["/"]["top"]["#/components/parameters/param1"][0].Path)
|
||||||
}
|
}
|
||||||
if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") {
|
if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") {
|
||||||
assert.Equal(t, "$.components.parameters.param3", params["/"]["top"]["paramour.yaml#/components/parameters/param3"].Path)
|
assert.Equal(t, "$.components.parameters.param3", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if assert.Contains(t, params["/"], "get") {
|
if assert.Contains(t, params["/"], "get") {
|
||||||
if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") {
|
if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") {
|
||||||
assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"].Path)
|
assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
||||||
}
|
}
|
||||||
if assert.Contains(t, params["/"]["get"], "test") {
|
if assert.Contains(t, params["/"]["get"], "test") {
|
||||||
assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"].Path)
|
assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"][0].Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -854,6 +854,103 @@ func TestSpecIndex_schemaComponentsHaveParentsAndPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSpecIndex_ParamsWithDuplicateNamesButUniqueInTypes(t *testing.T) {
|
||||||
|
yml := `openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Test
|
||||||
|
version: 0.0.1
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:35123
|
||||||
|
paths:
|
||||||
|
/example/{action}:
|
||||||
|
parameters:
|
||||||
|
- name: fastAction
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: fastAction
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
get:
|
||||||
|
operationId: example
|
||||||
|
parameters:
|
||||||
|
- name: action
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: action
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK`
|
||||||
|
|
||||||
|
var rootNode yaml.Node
|
||||||
|
yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
|
idx := NewSpecIndex(&rootNode)
|
||||||
|
|
||||||
|
assert.Len(t, idx.paramAllRefs, 4)
|
||||||
|
assert.Len(t, idx.paramInlineDuplicateNames, 2)
|
||||||
|
assert.Len(t, idx.operationParamErrors, 0)
|
||||||
|
assert.Len(t, idx.refErrors, 0)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSpecIndex_ParamsWithDuplicateNamesAndSameInTypes(t *testing.T) {
|
||||||
|
yml := `openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Test
|
||||||
|
version: 0.0.1
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:35123
|
||||||
|
paths:
|
||||||
|
/example/{action}:
|
||||||
|
parameters:
|
||||||
|
- name: fastAction
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: fastAction
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
get:
|
||||||
|
operationId: example
|
||||||
|
parameters:
|
||||||
|
- name: action
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: action
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK`
|
||||||
|
|
||||||
|
var rootNode yaml.Node
|
||||||
|
yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
|
idx := NewSpecIndex(&rootNode)
|
||||||
|
|
||||||
|
assert.Len(t, idx.paramAllRefs, 3)
|
||||||
|
assert.Len(t, idx.paramInlineDuplicateNames, 2)
|
||||||
|
assert.Len(t, idx.operationParamErrors, 1)
|
||||||
|
assert.Len(t, idx.refErrors, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSpecIndex_foundObjectsWithProperties(t *testing.T) {
|
func TestSpecIndex_foundObjectsWithProperties(t *testing.T) {
|
||||||
yml := `paths:
|
yml := `paths:
|
||||||
/test:
|
/test:
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ func (index *SpecIndex) countUniqueInlineDuplicates() int {
|
|||||||
return index.componentsInlineParamUniqueCount
|
return index.componentsInlineParamUniqueCount
|
||||||
}
|
}
|
||||||
unique := 0
|
unique := 0
|
||||||
for _, p := range index.paramInlineDuplicates {
|
for _, p := range index.paramInlineDuplicateNames {
|
||||||
if len(p) == 1 {
|
if len(p) == 1 {
|
||||||
unique++
|
unique++
|
||||||
}
|
}
|
||||||
@@ -279,13 +279,13 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
paramRef := index.allMappedRefs[paramRefName]
|
paramRef := index.allMappedRefs[paramRefName]
|
||||||
|
|
||||||
if index.paramOpRefs[pathItemNode.Value] == nil {
|
if index.paramOpRefs[pathItemNode.Value] == nil {
|
||||||
index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string][]*Reference)
|
||||||
index.paramOpRefs[pathItemNode.Value][method] = make(map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference)
|
||||||
|
|
||||||
}
|
}
|
||||||
// if we know the path, but it's a new method
|
// if we know the path, but it's a new method
|
||||||
if index.paramOpRefs[pathItemNode.Value][method] == nil {
|
if index.paramOpRefs[pathItemNode.Value][method] == nil {
|
||||||
index.paramOpRefs[pathItemNode.Value][method] = make(map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a duplicate, add an error and ignore it
|
// if this is a duplicate, add an error and ignore it
|
||||||
@@ -302,7 +302,8 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
Path: path,
|
Path: path,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
index.paramOpRefs[pathItemNode.Value][method][paramRefName] = paramRef
|
index.paramOpRefs[pathItemNode.Value][method][paramRefName] =
|
||||||
|
append(index.paramOpRefs[pathItemNode.Value][method][paramRefName], paramRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@@ -334,17 +335,28 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
Path: path,
|
Path: path,
|
||||||
}
|
}
|
||||||
if index.paramOpRefs[pathItemNode.Value] == nil {
|
if index.paramOpRefs[pathItemNode.Value] == nil {
|
||||||
index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string][]*Reference)
|
||||||
index.paramOpRefs[pathItemNode.Value][method] = make(map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we know the path but this is a new method.
|
// if we know the path but this is a new method.
|
||||||
if index.paramOpRefs[pathItemNode.Value][method] == nil {
|
if index.paramOpRefs[pathItemNode.Value][method] == nil {
|
||||||
index.paramOpRefs[pathItemNode.Value][method] = make(map[string]*Reference)
|
index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a duplicate, add an error and ignore it
|
// if this is a duplicate name, check if the `in` type is also the same, if so, it's a duplicate.
|
||||||
if index.paramOpRefs[pathItemNode.Value][method][ref.Name] != nil {
|
if len(index.paramOpRefs[pathItemNode.Value][method][ref.Name]) > 0 {
|
||||||
|
|
||||||
|
currentNode := ref.Node
|
||||||
|
checkNodes := index.paramOpRefs[pathItemNode.Value][method][ref.Name]
|
||||||
|
_, currentIn := utils.FindKeyNodeTop("in", currentNode.Content)
|
||||||
|
|
||||||
|
for _, checkNode := range checkNodes {
|
||||||
|
|
||||||
|
_, checkIn := utils.FindKeyNodeTop("in", checkNode.Node.Content)
|
||||||
|
|
||||||
|
if currentIn != nil && checkIn != nil && currentIn.Value == checkIn.Value {
|
||||||
|
|
||||||
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
|
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
|
||||||
if method == "top" {
|
if method == "top" {
|
||||||
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
|
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
|
||||||
@@ -352,12 +364,18 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
|
|
||||||
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
||||||
Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+
|
Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+
|
||||||
"index %d has a duplicate name `%s`", method, pathItemNode.Value, i, vn.Value),
|
"index %d has a duplicate name `%s` and `in` type", method, pathItemNode.Value, i, vn.Value),
|
||||||
Node: param,
|
Node: param,
|
||||||
Path: path,
|
Path: path,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
index.paramOpRefs[pathItemNode.Value][method][ref.Name] = ref
|
index.paramOpRefs[pathItemNode.Value][method][ref.Name] =
|
||||||
|
append(index.paramOpRefs[pathItemNode.Value][method][ref.Name], ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index.paramOpRefs[pathItemNode.Value][method][ref.Name] =
|
||||||
|
append(index.paramOpRefs[pathItemNode.Value][method][ref.Name], ref)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user