-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathparam_locations.go
More file actions
122 lines (101 loc) · 3.8 KB
/
Copy pathparam_locations.go
File metadata and controls
122 lines (101 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package validate
import (
"strconv"
"github.com/go-openapi/spec"
)
// paramLocations tells where an operation declares a parameter.
//
// Parameters are held in an array, so a name is not how a document addresses
// one: only its index is. The index is not something a validator can work out
// from an expanded parameter either, because expansion merges the parameters
// an operation declares with those its path item declares, and resolves the
// ones written as a $ref. So the unexpanded document is indexed once, and
// looked up by what a validator does know: the operation, and the name and
// location of the parameter it is reporting on.
type paramLocations map[paramKey]pathSegments
// paramKey identifies a parameter the way the swagger specification does:
// a name is unique only within an "in".
type paramKey struct {
path string
method string
in string
name string
}
// newParamLocations indexes the parameters declared by an unexpanded document.
func newParamLocations(sp *spec.Swagger) paramLocations {
locations := make(paramLocations)
if sp == nil || sp.Paths == nil {
return locations
}
for path, pathItem := range sp.Paths.Paths {
at := newPathSegments(swaggerPaths, path)
// parameters declared by the path item are shared by all its
// operations: recorded once, without a method
locations.collect(sp, paramKey{path: path}, at, pathItem.Parameters)
for method, op := range operationsOf(&pathItem) { //#nosec
if op == nil {
continue
}
locations.collect(sp, paramKey{path: path, method: method}, at.child(method), op.Parameters)
}
}
return locations
}
// at returns where an operation declares a parameter.
//
// A parameter the operation does not declare itself may come from its path
// item. When neither knows it, which happens for a parameter too broken to be
// identified, the pointer stops on the array holding it and the name is kept
// for the message alone: an index no one could work out would be a guess.
func (l paramLocations) at(path, method, in, name string) pathSegments {
if found, isDeclared := l[paramKey{path: path, method: methodToken(method), in: in, name: name}]; isDeclared {
return found
}
if found, isDeclared := l[paramKey{path: path, in: in, name: name}]; isDeclared {
return found
}
return operationPath(path, method).child(swaggerParameters).cosmeticChild(name)
}
func (l paramLocations) collect(sp *spec.Swagger, key paramKey, at pathSegments, params []spec.Parameter) {
for i := range params {
name, in, ok := parameterIdentity(sp, ¶ms[i])
if !ok {
continue
}
key.name = name
key.in = in
l[key] = at.child(swaggerParameters).childAs(strconv.Itoa(i), name)
}
}
// parameterIdentity names a parameter as declared, resolving the one indirection
// a document may put in the way: an entry written as a local $ref.
func parameterIdentity(sp *spec.Swagger, param *spec.Parameter) (name, in string, ok bool) {
if param.Ref.String() == "" {
return param.Name, param.In, param.Name != ""
}
shared := localRefPath(param.Ref.String())
const sharedParameterDepth = 2
if len(shared) != sharedParameterDepth || shared.beforeLast() != swaggerParameters {
return "", "", false
}
declared, isDeclared := sp.Parameters[shared.last()]
if !isDeclared {
return "", "", false
}
return declared.Name, declared.In, declared.Name != ""
}
// operationsOf yields the operations of a path item, keyed as the document
// spells them.
func operationsOf(pathItem *spec.PathItem) map[string]*spec.Operation {
return map[string]*spec.Operation{
"get": pathItem.Get,
"put": pathItem.Put,
"post": pathItem.Post,
"delete": pathItem.Delete,
"options": pathItem.Options,
"head": pathItem.Head,
"patch": pathItem.Patch,
}
}