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:
Dave Shanley
2023-02-22 09:11:35 -05:00
parent 5481353994
commit bc1d8c5454
5 changed files with 249 additions and 125 deletions

View File

@@ -98,96 +98,96 @@ func CreateClosedAPIIndexConfig() *SpecIndexConfig {
// quick direct access to paths, operations, tags are all available. No need to walk the entire node tree in rules, // quick direct access to paths, operations, tags are all available. No need to walk the entire node tree in rules,
// everything is pre-walked if you need it. // everything is pre-walked if you need it.
type SpecIndex struct { type SpecIndex struct {
allRefs map[string]*Reference // all (deduplicated) refs allRefs map[string]*Reference // all (deduplicated) refs
rawSequencedRefs []*Reference // all raw references in sequence as they are scanned, not deduped. rawSequencedRefs []*Reference // all raw references in sequence as they are scanned, not deduped.
linesWithRefs map[int]bool // lines that link to references. linesWithRefs map[int]bool // lines that link to references.
allMappedRefs map[string]*Reference // these are the located mapped refs allMappedRefs map[string]*Reference // these are the located mapped refs
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
responsesRefs map[string]*Reference // top level responses responsesRefs map[string]*Reference // top level responses
headersRefs map[string]*Reference // top level responses headersRefs map[string]*Reference // top level responses
examplesRefs map[string]*Reference // top level examples examplesRefs map[string]*Reference // top level examples
securityRequirementRefs map[string]map[string][]*Reference // (NOT $ref) but a name based lookup for requirements securityRequirementRefs map[string]map[string][]*Reference // (NOT $ref) but a name based lookup for requirements
callbacksRefs map[string]map[string][]*Reference // all links callbacksRefs map[string]map[string][]*Reference // all links
linksRefs map[string]map[string][]*Reference // all callbacks linksRefs map[string]map[string][]*Reference // all callbacks
operationTagsRefs map[string]map[string][]*Reference // tags found in operations operationTagsRefs map[string]map[string][]*Reference // tags found in operations
operationDescriptionRefs map[string]map[string]*Reference // descriptions in operations. operationDescriptionRefs map[string]map[string]*Reference // descriptions in operations.
operationSummaryRefs map[string]map[string]*Reference // summaries in operations operationSummaryRefs map[string]map[string]*Reference // summaries in operations
callbackRefs map[string]*Reference // top level callback refs callbackRefs map[string]*Reference // top level callback refs
serversRefs []*Reference // all top level server refs serversRefs []*Reference // all top level server refs
rootServersNode *yaml.Node // servers root node rootServersNode *yaml.Node // servers root node
opServersRefs map[string]map[string][]*Reference // all operation level server overrides. opServersRefs map[string]map[string][]*Reference // all operation level server overrides.
polymorphicRefs map[string]*Reference // every reference to a polymorphic ref polymorphicRefs map[string]*Reference // every reference to a polymorphic ref
polymorphicAllOfRefs []*Reference // every reference to 'allOf' references polymorphicAllOfRefs []*Reference // every reference to 'allOf' references
polymorphicOneOfRefs []*Reference // every reference to 'oneOf' references polymorphicOneOfRefs []*Reference // every reference to 'oneOf' references
polymorphicAnyOfRefs []*Reference // every reference to 'anyOf' references polymorphicAnyOfRefs []*Reference // every reference to 'anyOf' references
externalDocumentsRef []*Reference // all external documents in spec externalDocumentsRef []*Reference // all external documents in spec
rootSecurity []*Reference // root security definitions. rootSecurity []*Reference // root security definitions.
rootSecurityNode *yaml.Node // root security node. rootSecurityNode *yaml.Node // root security node.
refsWithSiblings map[string]Reference // references with sibling elements next to them refsWithSiblings map[string]Reference // references with sibling elements next to them
pathRefsLock sync.Mutex // create lock for all refs maps, we want to build data as fast as we can pathRefsLock sync.Mutex // create lock for all refs maps, we want to build data as fast as we can
externalDocumentsCount int // number of externalDocument nodes found externalDocumentsCount int // number of externalDocument nodes found
operationTagsCount int // number of unique tags in operations operationTagsCount int // number of unique tags in operations
globalTagsCount int // number of global tags defined globalTagsCount int // number of global tags defined
totalTagsCount int // number unique tags in spec totalTagsCount int // number unique tags in spec
securitySchemesCount int // security schemes securitySchemesCount int // security schemes
globalRequestBodiesCount int // component request bodies globalRequestBodiesCount int // component request bodies
globalResponsesCount int // component responses globalResponsesCount int // component responses
globalHeadersCount int // component headers globalHeadersCount int // component headers
globalExamplesCount int // component examples globalExamplesCount int // component examples
globalLinksCount int // component links globalLinksCount int // component links
globalCallbacksCount int // component callbacks globalCallbacksCount int // component callbacks
globalCallbacks int // component callbacks. globalCallbacks int // component callbacks.
pathCount int // number of paths pathCount int // number of paths
operationCount int // number of operations operationCount int // number of operations
operationParamCount int // number of params defined in operations operationParamCount int // number of params defined in operations
componentParamCount int // number of params defined in components componentParamCount int // number of params defined in components
componentsInlineParamUniqueCount int // number of inline params with unique names componentsInlineParamUniqueCount int // number of inline params with unique names
componentsInlineParamDuplicateCount int // number of inline params with duplicate names componentsInlineParamDuplicateCount int // number of inline params with duplicate names
schemaCount int // number of schemas schemaCount int // number of schemas
refCount int // total ref count refCount int // total ref count
root *yaml.Node // the root document root *yaml.Node // the root document
pathsNode *yaml.Node // paths node pathsNode *yaml.Node // paths node
tagsNode *yaml.Node // tags node tagsNode *yaml.Node // tags node
componentsNode *yaml.Node // components node componentsNode *yaml.Node // components node
parametersNode *yaml.Node // components/parameters node parametersNode *yaml.Node // components/parameters node
allParametersNode map[string]*Reference // all parameters node allParametersNode map[string]*Reference // all parameters node
allParameters map[string]*Reference // all parameters (components/defs) allParameters map[string]*Reference // all parameters (components/defs)
schemasNode *yaml.Node // components/schemas node schemasNode *yaml.Node // components/schemas node
allInlineSchemaDefinitions []*Reference // all schemas found in document outside of components (openapi) or definitions (swagger). 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). 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). allComponentSchemaDefinitions map[string]*Reference // all schemas found in components (openapi) or definitions (swagger).
securitySchemesNode *yaml.Node // components/securitySchemes node securitySchemesNode *yaml.Node // components/securitySchemes node
allSecuritySchemes map[string]*Reference // all security schemes / definitions. allSecuritySchemes map[string]*Reference // all security schemes / definitions.
requestBodiesNode *yaml.Node // components/requestBodies node requestBodiesNode *yaml.Node // components/requestBodies node
allRequestBodies map[string]*Reference // all request bodies allRequestBodies map[string]*Reference // all request bodies
responsesNode *yaml.Node // components/responses node responsesNode *yaml.Node // components/responses node
allResponses map[string]*Reference // all responses allResponses map[string]*Reference // all responses
headersNode *yaml.Node // components/headers node headersNode *yaml.Node // components/headers node
allHeaders map[string]*Reference // all headers allHeaders map[string]*Reference // all headers
examplesNode *yaml.Node // components/examples node examplesNode *yaml.Node // components/examples node
allExamples map[string]*Reference // all components examples allExamples map[string]*Reference // all components examples
linksNode *yaml.Node // components/links node linksNode *yaml.Node // components/links node
allLinks map[string]*Reference // all links allLinks map[string]*Reference // all links
callbacksNode *yaml.Node // components/callbacks node callbacksNode *yaml.Node // components/callbacks node
allCallbacks map[string]*Reference // all components examples allCallbacks map[string]*Reference // all components examples
externalDocumentsNode *yaml.Node // external documents node externalDocumentsNode *yaml.Node // external documents node
allExternalDocuments map[string]*Reference // all external documents allExternalDocuments map[string]*Reference // all external documents
externalSpecIndex map[string]*SpecIndex // create a primary index of all external specs and componentIds externalSpecIndex map[string]*SpecIndex // create a primary index of all external specs and componentIds
refErrors []error // errors when indexing references refErrors []error // errors when indexing references
operationParamErrors []error // errors when indexing parameters operationParamErrors []error // errors when indexing parameters
allDescriptions []*DescriptionReference // every single description found in the spec. allDescriptions []*DescriptionReference // every single description found in the spec.
allSummaries []*DescriptionReference // every single summary found in the spec. allSummaries []*DescriptionReference // every single summary found in the spec.
allEnums []*EnumReference // every single enum found in the spec. allEnums []*EnumReference // every single enum found in the spec.
allObjectsWithProperties []*ObjectReference // every single object with properties found in the spec. allObjectsWithProperties []*ObjectReference // every single object with properties found in the spec.
enumCount int enumCount int
descriptionCount int descriptionCount int
summaryCount int summaryCount int

View File

@@ -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)

View File

@@ -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
} }

View File

@@ -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:

View File

@@ -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,30 +335,47 @@ 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 {
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
if method == "top" {
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
}
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{ currentNode := ref.Node
Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+ checkNodes := index.paramOpRefs[pathItemNode.Value][method][ref.Name]
"index %d has a duplicate name `%s`", method, pathItemNode.Value, i, vn.Value), _, currentIn := utils.FindKeyNodeTop("in", currentNode.Content)
Node: param,
Path: path, 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)
if method == "top" {
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
}
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+
"index %d has a duplicate name `%s` and `in` type", method, pathItemNode.Value, i, vn.Value),
Node: param,
Path: path,
})
} else {
index.paramOpRefs[pathItemNode.Value][method][ref.Name] =
append(index.paramOpRefs[pathItemNode.Value][method][ref.Name], ref)
}
}
} 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)
} }
continue continue
} }