...
1 package analysis
2
3 import (
4 "errors"
5
6 "github.com/go-openapi/spec"
7 "github.com/go-openapi/strfmt"
8 )
9
10
11 type SchemaOpts struct {
12 Schema *spec.Schema
13 Root interface{}
14 BasePath string
15 _ struct{}
16 }
17
18
19
20 func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
21 if opts.Schema == nil {
22 return nil, errors.New("no schema to analyze")
23 }
24
25 a := &AnalyzedSchema{
26 schema: opts.Schema,
27 root: opts.Root,
28 basePath: opts.BasePath,
29 }
30
31 a.initializeFlags()
32 a.inferKnownType()
33 a.inferEnum()
34 a.inferBaseType()
35
36 if err := a.inferMap(); err != nil {
37 return nil, err
38 }
39 if err := a.inferArray(); err != nil {
40 return nil, err
41 }
42
43 a.inferTuple()
44
45 if err := a.inferFromRef(); err != nil {
46 return nil, err
47 }
48
49 a.inferSimpleSchema()
50
51 return a, nil
52 }
53
54
55 type AnalyzedSchema struct {
56 schema *spec.Schema
57 root interface{}
58 basePath string
59
60 hasProps bool
61 hasAllOf bool
62 hasItems bool
63 hasAdditionalProps bool
64 hasAdditionalItems bool
65 hasRef bool
66
67 IsKnownType bool
68 IsSimpleSchema bool
69 IsArray bool
70 IsSimpleArray bool
71 IsMap bool
72 IsSimpleMap bool
73 IsExtendedObject bool
74 IsTuple bool
75 IsTupleWithExtra bool
76 IsBaseType bool
77 IsEnum bool
78 }
79
80
81 func (a *AnalyzedSchema) inherits(other *AnalyzedSchema) {
82 if other == nil {
83 return
84 }
85 a.hasProps = other.hasProps
86 a.hasAllOf = other.hasAllOf
87 a.hasItems = other.hasItems
88 a.hasAdditionalItems = other.hasAdditionalItems
89 a.hasAdditionalProps = other.hasAdditionalProps
90 a.hasRef = other.hasRef
91
92 a.IsKnownType = other.IsKnownType
93 a.IsSimpleSchema = other.IsSimpleSchema
94 a.IsArray = other.IsArray
95 a.IsSimpleArray = other.IsSimpleArray
96 a.IsMap = other.IsMap
97 a.IsSimpleMap = other.IsSimpleMap
98 a.IsExtendedObject = other.IsExtendedObject
99 a.IsTuple = other.IsTuple
100 a.IsTupleWithExtra = other.IsTupleWithExtra
101 a.IsBaseType = other.IsBaseType
102 a.IsEnum = other.IsEnum
103 }
104
105 func (a *AnalyzedSchema) inferFromRef() error {
106 if a.hasRef {
107 sch := new(spec.Schema)
108 sch.Ref = a.schema.Ref
109 err := spec.ExpandSchema(sch, a.root, nil)
110 if err != nil {
111 return err
112 }
113 rsch, err := Schema(SchemaOpts{
114 Schema: sch,
115 Root: a.root,
116 BasePath: a.basePath,
117 })
118 if err != nil {
119
120
121
122
123 return err
124 }
125 a.inherits(rsch)
126 }
127
128 return nil
129 }
130
131 func (a *AnalyzedSchema) inferSimpleSchema() {
132 a.IsSimpleSchema = a.IsKnownType || a.IsSimpleArray || a.IsSimpleMap
133 }
134
135 func (a *AnalyzedSchema) inferKnownType() {
136 tpe := a.schema.Type
137 format := a.schema.Format
138 a.IsKnownType = tpe.Contains("boolean") ||
139 tpe.Contains("integer") ||
140 tpe.Contains("number") ||
141 tpe.Contains("string") ||
142 (format != "" && strfmt.Default.ContainsName(format)) ||
143 (a.isObjectType() && !a.hasProps && !a.hasAllOf && !a.hasAdditionalProps && !a.hasAdditionalItems)
144 }
145
146 func (a *AnalyzedSchema) inferMap() error {
147 if !a.isObjectType() {
148 return nil
149 }
150
151 hasExtra := a.hasProps || a.hasAllOf
152 a.IsMap = a.hasAdditionalProps && !hasExtra
153 a.IsExtendedObject = a.hasAdditionalProps && hasExtra
154
155 if !a.IsMap {
156 return nil
157 }
158
159
160 if a.schema.AdditionalProperties.Schema != nil {
161 msch, err := Schema(SchemaOpts{
162 Schema: a.schema.AdditionalProperties.Schema,
163 Root: a.root,
164 BasePath: a.basePath,
165 })
166 if err != nil {
167 return err
168 }
169 a.IsSimpleMap = msch.IsSimpleSchema
170 } else if a.schema.AdditionalProperties.Allows {
171 a.IsSimpleMap = true
172 }
173
174 return nil
175 }
176
177 func (a *AnalyzedSchema) inferArray() error {
178
179
180
181
182
183
184
185 a.IsArray = a.isArrayType() && (a.schema.Items == nil || a.schema.Items.Schemas == nil)
186 if a.IsArray && a.hasItems {
187 if a.schema.Items.Schema != nil {
188 itsch, err := Schema(SchemaOpts{
189 Schema: a.schema.Items.Schema,
190 Root: a.root,
191 BasePath: a.basePath,
192 })
193 if err != nil {
194 return err
195 }
196
197 a.IsSimpleArray = itsch.IsSimpleSchema
198 }
199 }
200
201 if a.IsArray && !a.hasItems {
202 a.IsSimpleArray = true
203 }
204
205 return nil
206 }
207
208 func (a *AnalyzedSchema) inferTuple() {
209 tuple := a.hasItems && a.schema.Items.Schemas != nil
210 a.IsTuple = tuple && !a.hasAdditionalItems
211 a.IsTupleWithExtra = tuple && a.hasAdditionalItems
212 }
213
214 func (a *AnalyzedSchema) inferBaseType() {
215 if a.isObjectType() {
216 a.IsBaseType = a.schema.Discriminator != ""
217 }
218 }
219
220 func (a *AnalyzedSchema) inferEnum() {
221 a.IsEnum = len(a.schema.Enum) > 0
222 }
223
224 func (a *AnalyzedSchema) initializeFlags() {
225 a.hasProps = len(a.schema.Properties) > 0
226 a.hasAllOf = len(a.schema.AllOf) > 0
227 a.hasRef = a.schema.Ref.String() != ""
228
229 a.hasItems = a.schema.Items != nil &&
230 (a.schema.Items.Schema != nil || len(a.schema.Items.Schemas) > 0)
231
232 a.hasAdditionalProps = a.schema.AdditionalProperties != nil &&
233 (a.schema.AdditionalProperties.Schema != nil || a.schema.AdditionalProperties.Allows)
234
235 a.hasAdditionalItems = a.schema.AdditionalItems != nil &&
236 (a.schema.AdditionalItems.Schema != nil || a.schema.AdditionalItems.Allows)
237 }
238
239 func (a *AnalyzedSchema) isObjectType() bool {
240 return !a.hasRef && (a.schema.Type == nil || a.schema.Type.Contains("") || a.schema.Type.Contains("object"))
241 }
242
243 func (a *AnalyzedSchema) isArrayType() bool {
244 return !a.hasRef && (a.schema.Type != nil && a.schema.Type.Contains("array"))
245 }
246
247
248
249
250
251
252
253
254 func (a *AnalyzedSchema) isAnalyzedAsComplex() bool {
255 return !a.IsSimpleSchema && !a.IsArray && !a.IsMap
256 }
257
View as plain text