1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package loads
16
17 import (
18 "bytes"
19 "encoding/gob"
20 "encoding/json"
21 "fmt"
22
23 "github.com/go-openapi/analysis"
24 "github.com/go-openapi/spec"
25 "github.com/go-openapi/swag"
26 )
27
28 func init() {
29 gob.Register(map[string]interface{}{})
30 gob.Register([]interface{}{})
31 }
32
33
34 type Document struct {
35
36 Analyzer *analysis.Spec
37 spec *spec.Swagger
38 specFilePath string
39 origSpec *spec.Swagger
40 schema *spec.Schema
41 pathLoader *loader
42 raw json.RawMessage
43 }
44
45
46 func JSONSpec(path string, options ...LoaderOption) (*Document, error) {
47 data, err := JSONDoc(path)
48 if err != nil {
49 return nil, err
50 }
51
52 doc, err := Analyzed(data, "", options...)
53 if err != nil {
54 return nil, err
55 }
56
57 doc.specFilePath = path
58
59 return doc, nil
60 }
61
62
63 func Embedded(orig, flat json.RawMessage, options ...LoaderOption) (*Document, error) {
64 var origSpec, flatSpec spec.Swagger
65 if err := json.Unmarshal(orig, &origSpec); err != nil {
66 return nil, err
67 }
68 if err := json.Unmarshal(flat, &flatSpec); err != nil {
69 return nil, err
70 }
71 return &Document{
72 raw: orig,
73 origSpec: &origSpec,
74 spec: &flatSpec,
75 pathLoader: loaderFromOptions(options),
76 }, nil
77 }
78
79
80 func Spec(path string, options ...LoaderOption) (*Document, error) {
81 ldr := loaderFromOptions(options)
82
83 b, err := ldr.Load(path)
84 if err != nil {
85 return nil, err
86 }
87
88 document, err := Analyzed(b, "", options...)
89 if err != nil {
90 return nil, err
91 }
92
93 document.specFilePath = path
94 document.pathLoader = ldr
95
96 return document, nil
97 }
98
99
100 func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*Document, error) {
101 if version == "" {
102 version = "2.0"
103 }
104 if version != "2.0" {
105 return nil, fmt.Errorf("spec version %q is not supported", version)
106 }
107
108 raw, err := trimData(data)
109 if err != nil {
110 return nil, err
111 }
112
113 swspec := new(spec.Swagger)
114 if err = json.Unmarshal(raw, swspec); err != nil {
115 return nil, err
116 }
117
118 origsqspec, err := cloneSpec(swspec)
119 if err != nil {
120 return nil, err
121 }
122
123 d := &Document{
124 Analyzer: analysis.New(swspec),
125 schema: spec.MustLoadSwagger20Schema(),
126 spec: swspec,
127 raw: raw,
128 origSpec: origsqspec,
129 pathLoader: loaderFromOptions(options),
130 }
131
132 return d, nil
133 }
134
135 func trimData(in json.RawMessage) (json.RawMessage, error) {
136 trimmed := bytes.TrimSpace(in)
137 if len(trimmed) == 0 {
138 return in, nil
139 }
140
141 if trimmed[0] == '{' || trimmed[0] == '[' {
142 return trimmed, nil
143 }
144
145
146 yml, err := swag.BytesToYAMLDoc(trimmed)
147 if err != nil {
148 return nil, fmt.Errorf("analyzed: %v", err)
149 }
150
151 d, err := swag.YAMLToJSON(yml)
152 if err != nil {
153 return nil, fmt.Errorf("analyzed: %v", err)
154 }
155
156 return d, nil
157 }
158
159
160 func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
161 swspec := new(spec.Swagger)
162 if err := json.Unmarshal(d.raw, swspec); err != nil {
163 return nil, err
164 }
165
166 var expandOptions *spec.ExpandOptions
167 if len(options) > 0 {
168 expandOptions = options[0]
169 if expandOptions.RelativeBase == "" {
170 expandOptions.RelativeBase = d.specFilePath
171 }
172 } else {
173 expandOptions = &spec.ExpandOptions{
174 RelativeBase: d.specFilePath,
175 }
176 }
177
178 if expandOptions.PathLoader == nil {
179 if d.pathLoader != nil {
180
181 expandOptions.PathLoader = d.pathLoader.Load
182 } else {
183
184 expandOptions.PathLoader = loaders.Load
185 }
186 }
187
188 if err := spec.ExpandSpec(swspec, expandOptions); err != nil {
189 return nil, err
190 }
191
192 dd := &Document{
193 Analyzer: analysis.New(swspec),
194 spec: swspec,
195 specFilePath: d.specFilePath,
196 schema: spec.MustLoadSwagger20Schema(),
197 raw: d.raw,
198 origSpec: d.origSpec,
199 }
200 return dd, nil
201 }
202
203
204 func (d *Document) BasePath() string {
205 return d.spec.BasePath
206 }
207
208
209 func (d *Document) Version() string {
210 return d.spec.Swagger
211 }
212
213
214 func (d *Document) Schema() *spec.Schema {
215 return d.schema
216 }
217
218
219 func (d *Document) Spec() *spec.Swagger {
220 return d.spec
221 }
222
223
224 func (d *Document) Host() string {
225 return d.spec.Host
226 }
227
228
229 func (d *Document) Raw() json.RawMessage {
230 return d.raw
231 }
232
233
234 func (d *Document) OrigSpec() *spec.Swagger {
235 return d.origSpec
236 }
237
238
239 func (d *Document) ResetDefinitions() *Document {
240 defs := make(map[string]spec.Schema, len(d.origSpec.Definitions))
241 for k, v := range d.origSpec.Definitions {
242 defs[k] = v
243 }
244
245 d.spec.Definitions = defs
246 return d
247 }
248
249
250 func (d *Document) Pristine() *Document {
251 raw, _ := json.Marshal(d.Spec())
252 dd, _ := Analyzed(raw, d.Version())
253 dd.pathLoader = d.pathLoader
254 dd.specFilePath = d.specFilePath
255
256 return dd
257 }
258
259
260 func (d *Document) SpecFilePath() string {
261 return d.specFilePath
262 }
263
264 func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) {
265 var b bytes.Buffer
266 if err := gob.NewEncoder(&b).Encode(src); err != nil {
267 return nil, err
268 }
269
270 var dst spec.Swagger
271 if err := gob.NewDecoder(&b).Decode(&dst); err != nil {
272 return nil, err
273 }
274 return &dst, nil
275 }
276
View as plain text