podman

Форк
0
256 строк · 6.5 Кб
1
package analysis
2

3
import (
4
	"fmt"
5

6
	"github.com/go-openapi/spec"
7
	"github.com/go-openapi/strfmt"
8
)
9

10
// SchemaOpts configures the schema analyzer
11
type SchemaOpts struct {
12
	Schema   *spec.Schema
13
	Root     interface{}
14
	BasePath string
15
	_        struct{}
16
}
17

18
// Schema analysis, will classify the schema according to known
19
// patterns.
20
func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
21
	if opts.Schema == nil {
22
		return nil, fmt.Errorf("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
// AnalyzedSchema indicates what the schema represents
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
// Inherits copies value fields from other onto this schema
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
			// NOTE(fredbi): currently the only cause for errors is
120
			// unresolved ref. Since spec.ExpandSchema() expands the
121
			// schema recursively, there is no chance to get there,
122
			// until we add more causes for error in this schema analysis.
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
	// maps
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
	// an array has Items defined as an object schema, otherwise we qualify this JSON array as a tuple
179
	// (yes, even if the Items array contains only one element).
180
	// arrays in JSON schema may be unrestricted (i.e no Items specified).
181
	// Note that arrays in Swagger MUST have Items. Nonetheless, we analyze unrestricted arrays.
182
	//
183
	// NOTE: the spec package misses the distinction between:
184
	// items: [] and items: {}, so we consider both arrays here.
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
// isAnalyzedAsComplex determines if an analyzed schema is eligible to flattening (i.e. it is "complex").
248
//
249
// Complex means the schema is any of:
250
//  - a simple type (primitive)
251
//  - an array of something (items are possibly complex ; if this is the case, items will generate a definition)
252
//  - a map of something (additionalProperties are possibly complex ; if this is the case, additionalProperties will
253
//    generate a definition)
254
func (a *AnalyzedSchema) isAnalyzedAsComplex() bool {
255
	return !a.IsSimpleSchema && !a.IsArray && !a.IsMap
256
}
257

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.