5
5
"encoding/json"
6
6
"errors"
7
7
"fmt"
8
+ "net/url"
9
+ "path"
10
+ "strings"
8
11
9
12
"github.com/go-openapi/jsonpointer"
10
13
)
@@ -24,6 +27,96 @@ type T struct {
24
27
ExternalDocs * ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
25
28
26
29
visited visitedComponent
30
+ url * url.URL
31
+ }
32
+
33
+ // MatchesSchemaInRootDocument returns if the given schema is identical
34
+ // to a schema defined in the root document's '#/components/schemas'.
35
+ // It returns a reference to the schema in the form
36
+ // '#/components/schemas/NameXXX'
37
+ //
38
+ // Of course given it a schema from the root document will always match.
39
+ //
40
+ // https://swagger.io/docs/specification/using-ref/#syntax
41
+ //
42
+ // Case 1: Directly via
43
+ //
44
+ // ../openapi.yaml#/components/schemas/Record
45
+ //
46
+ // Case 2: Or indirectly by using a $ref which matches a schema
47
+ // in the root document's '#/components/schemas' using the same
48
+ // $ref.
49
+ //
50
+ // In schemas/record.yaml
51
+ //
52
+ // $ref: ./record.yaml
53
+ //
54
+ // In openapi.yaml
55
+ //
56
+ // components:
57
+ // schemas:
58
+ // Record:
59
+ // $ref: schemas/record.yaml
60
+ func (doc * T ) MatchesSchemaInRootDocument (sch * SchemaRef ) (string , bool ) {
61
+ // Case 1:
62
+ // Something like: ../another-folder/document.json#/myElement
63
+ if isRemoteReference (sch .Ref ) && isSchemaReference (sch .Ref ) {
64
+ // Determine if it is *this* root doc.
65
+ if sch .referencesRootDocument (doc ) {
66
+ _ , name , _ := strings .Cut (sch .Ref , "#/components/schemas" )
67
+
68
+ return path .Join ("#/components/schemas" , name ), true
69
+ }
70
+ }
71
+
72
+ // If there are no schemas defined in the root document return early.
73
+ if doc .Components == nil || doc .Components .Schemas == nil {
74
+ return "" , false
75
+ }
76
+
77
+ // Case 2:
78
+ // Something like: ../openapi.yaml#/components/schemas/myElement
79
+ for name , s := range doc .Components .Schemas {
80
+ // Must be a reference to a YAML file.
81
+ if ! isWholeDocumentReference (s .Ref ) {
82
+ continue
83
+ }
84
+
85
+ // Is the schema a ref to the same resource.
86
+ if ! sch .refersToSameDocument (s ) {
87
+ continue
88
+ }
89
+
90
+ // Transform the remote ref to the equivalent schema in the root document.
91
+ return path .Join ("#/components/schemas" , name ), true
92
+ }
93
+
94
+ return "" , false
95
+ }
96
+
97
+ // isElementReference takes a $ref value and checks if it references a specific element.
98
+ func isElementReference (ref string ) bool {
99
+ return ref != "" && ! isWholeDocumentReference (ref )
100
+ }
101
+
102
+ // isSchemaReference takes a $ref value and checks if it references a schema element.
103
+ func isSchemaReference (ref string ) bool {
104
+ return isElementReference (ref ) && strings .Contains (ref , "#/components/schemas" )
105
+ }
106
+
107
+ // isWholeDocumentReference takes a $ref value and checks if it is whole document reference.
108
+ func isWholeDocumentReference (ref string ) bool {
109
+ return ref != "" && ! strings .ContainsAny (ref , "#" )
110
+ }
111
+
112
+ // isRemoteReference takes a $ref value and checks if it is remote reference.
113
+ func isRemoteReference (ref string ) bool {
114
+ return ref != "" && ! strings .HasPrefix (ref , "#" ) && ! isURLReference (ref )
115
+ }
116
+
117
+ // isURLReference takes a $ref value and checks if it is URL reference.
118
+ func isURLReference (ref string ) bool {
119
+ return strings .HasPrefix (ref , "http://" ) || strings .HasPrefix (ref , "https://" ) || strings .HasPrefix (ref , "//" )
27
120
}
28
121
29
122
var _ jsonpointer.JSONPointable = (* T )(nil )
0 commit comments