1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT license.
3
3
4
- using System . Text . Json ;
4
+ using System . Collections . Generic ;
5
+ using System . Globalization ;
6
+ using System . Text . Json . Nodes ;
5
7
using Json . Schema ;
8
+ using Json . Schema . OpenApi ;
6
9
using Microsoft . OpenApi . Extensions ;
10
+ using Microsoft . OpenApi . Interfaces ;
7
11
using Microsoft . OpenApi . Models ;
8
12
using Microsoft . OpenApi . Readers . ParseNodes ;
9
13
using JsonSchema = Json . Schema . JsonSchema ;
@@ -15,20 +19,260 @@ namespace Microsoft.OpenApi.Readers.V31
15
19
/// runtime Open API object model.
16
20
/// </summary>
17
21
internal static partial class OpenApiV31Deserializer
18
- {
22
+ {
23
+ private static readonly FixedFieldMap < JsonSchemaBuilder > _schemaFixedFields = new ( )
24
+ {
25
+ {
26
+ "title" , ( o , n ) =>
27
+ {
28
+ o . Title ( n . GetScalarValue ( ) ) ;
29
+ }
30
+ } ,
31
+ {
32
+ "multipleOf" , ( o , n ) =>
33
+ {
34
+ o . MultipleOf ( decimal . Parse ( n . GetScalarValue ( ) , NumberStyles . Float , CultureInfo . InvariantCulture ) ) ;
35
+ }
36
+ } ,
37
+ {
38
+ "maximum" , ( o , n ) =>
39
+ {
40
+ o . Maximum ( decimal . Parse ( n . GetScalarValue ( ) , NumberStyles . Float , CultureInfo . InvariantCulture ) ) ;
41
+ }
42
+ } ,
43
+ {
44
+ "exclusiveMaximum" , ( o , n ) =>
45
+ {
46
+ o . ExclusiveMaximum ( decimal . Parse ( n . GetScalarValue ( ) , NumberStyles . Float , CultureInfo . InvariantCulture ) ) ;
47
+ }
48
+ } ,
49
+ {
50
+ "minimum" , ( o , n ) =>
51
+ {
52
+ o . Minimum ( decimal . Parse ( n . GetScalarValue ( ) , NumberStyles . Float , CultureInfo . InvariantCulture ) ) ;
53
+ }
54
+ } ,
55
+ {
56
+ "exclusiveMinimum" , ( o , n ) =>
57
+ {
58
+ o . ExclusiveMinimum ( decimal . Parse ( n . GetScalarValue ( ) , NumberStyles . Float , CultureInfo . InvariantCulture ) ) ;
59
+ }
60
+ } ,
61
+ {
62
+ "maxLength" , ( o , n ) =>
63
+ {
64
+ o . MaxLength ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
65
+ }
66
+ } ,
67
+ {
68
+ "minLength" , ( o , n ) =>
69
+ {
70
+ o . MinLength ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
71
+ }
72
+ } ,
73
+ {
74
+ "pattern" , ( o , n ) =>
75
+ {
76
+ o . Pattern ( n . GetScalarValue ( ) ) ;
77
+ }
78
+ } ,
79
+ {
80
+ "maxItems" , ( o , n ) =>
81
+ {
82
+ o . MaxItems ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
83
+ }
84
+ } ,
85
+ {
86
+ "minItems" , ( o , n ) =>
87
+ {
88
+ o . MinItems ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
89
+ }
90
+ } ,
91
+ {
92
+ "uniqueItems" , ( o , n ) =>
93
+ {
94
+ o . UniqueItems ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
95
+ }
96
+ } ,
97
+ {
98
+ "maxProperties" , ( o , n ) =>
99
+ {
100
+ o . MaxProperties ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
101
+ }
102
+ } ,
103
+ {
104
+ "minProperties" , ( o , n ) =>
105
+ {
106
+ o . MinProperties ( uint . Parse ( n . GetScalarValue ( ) , CultureInfo . InvariantCulture ) ) ;
107
+ }
108
+ } ,
109
+ {
110
+ "required" , ( o , n ) =>
111
+ {
112
+ o . Required ( new HashSet < string > ( n . CreateSimpleList ( n2 => n2 . GetScalarValue ( ) ) ) ) ;
113
+ }
114
+ } ,
115
+ {
116
+ "enum" , ( o , n ) =>
117
+ {
118
+ o . Enum ( n . CreateListOfAny ( ) ) ;
119
+ }
120
+ } ,
121
+ {
122
+ "type" , ( o , n ) =>
123
+ {
124
+ if ( n is ListNode )
125
+ {
126
+ o . Type ( n . CreateSimpleList ( s => SchemaTypeConverter . ConvertToSchemaValueType ( s . GetScalarValue ( ) ) ) ) ;
127
+ }
128
+ else
129
+ {
130
+ o . Type ( SchemaTypeConverter . ConvertToSchemaValueType ( n . GetScalarValue ( ) ) ) ;
131
+ }
132
+ }
133
+ } ,
134
+ {
135
+ "allOf" , ( o , n ) =>
136
+ {
137
+ o . AllOf ( n . CreateList ( LoadSchema ) ) ;
138
+ }
139
+ } ,
140
+ {
141
+ "oneOf" , ( o , n ) =>
142
+ {
143
+ o . OneOf ( n . CreateList ( LoadSchema ) ) ;
144
+ }
145
+ } ,
146
+ {
147
+ "anyOf" , ( o , n ) =>
148
+ {
149
+ o . AnyOf ( n . CreateList ( LoadSchema ) ) ;
150
+ }
151
+ } ,
152
+ {
153
+ "not" , ( o , n ) =>
154
+ {
155
+ o . Not ( LoadSchema ( n ) ) ;
156
+ }
157
+ } ,
158
+ {
159
+ "items" , ( o , n ) =>
160
+ {
161
+ o . Items ( LoadSchema ( n ) ) ;
162
+ }
163
+ } ,
164
+ {
165
+ "properties" , ( o , n ) =>
166
+ {
167
+ o . Properties ( n . CreateMap ( LoadSchema ) ) ;
168
+ }
169
+ } ,
170
+ {
171
+ "additionalProperties" , ( o , n ) =>
172
+ {
173
+ if ( n is ValueNode )
174
+ {
175
+ o . AdditionalPropertiesAllowed ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
176
+ }
177
+ else
178
+ {
179
+ o . AdditionalProperties ( LoadSchema ( n ) ) ;
180
+ }
181
+ }
182
+ } ,
183
+ {
184
+ "description" , ( o , n ) =>
185
+ {
186
+ o . Description ( n . GetScalarValue ( ) ) ;
187
+ }
188
+ } ,
189
+ {
190
+ "format" , ( o , n ) =>
191
+ {
192
+ o . Format ( n . GetScalarValue ( ) ) ;
193
+ }
194
+ } ,
195
+ {
196
+ "default" , ( o , n ) =>
197
+ {
198
+ o . Default ( n . CreateAny ( ) . Node ) ;
199
+ }
200
+ } ,
201
+ {
202
+ "discriminator" , ( o , n ) =>
203
+ {
204
+ var discriminator = LoadDiscriminator ( n ) ;
205
+ o . Discriminator ( discriminator ) ;
206
+ }
207
+ } ,
208
+ {
209
+ "readOnly" , ( o , n ) =>
210
+ {
211
+ o . ReadOnly ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
212
+ }
213
+ } ,
214
+ {
215
+ "writeOnly" , ( o , n ) =>
216
+ {
217
+ o . WriteOnly ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
218
+ }
219
+ } ,
220
+ {
221
+ "xml" , ( o , n ) =>
222
+ {
223
+ var xml = LoadXml ( n ) ;
224
+ o . Xml ( xml . Namespace , xml . Name , xml . Prefix , xml . Attribute , xml . Wrapped ,
225
+ ( IReadOnlyDictionary < string , JsonNode > ) xml . Extensions ) ;
226
+ }
227
+ } ,
228
+ {
229
+ "externalDocs" , ( o , n ) =>
230
+ {
231
+ var externalDocs = LoadExternalDocs ( n ) ;
232
+ o . ExternalDocs ( externalDocs . Url , externalDocs . Description ,
233
+ ( IReadOnlyDictionary < string , JsonNode > ) externalDocs . Extensions ) ;
234
+ }
235
+ } ,
236
+ {
237
+ "example" , ( o , n ) =>
238
+ {
239
+ if ( n is ListNode )
240
+ {
241
+ o . Examples ( n . CreateSimpleList ( s => ( JsonNode ) s . GetScalarValue ( ) ) ) ;
242
+ }
243
+ else
244
+ {
245
+ o . Example ( n . CreateAny ( ) . Node ) ;
246
+ }
247
+ }
248
+ } ,
249
+ {
250
+ "deprecated" , ( o , n ) =>
251
+ {
252
+ o . Deprecated ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
253
+ }
254
+ } ,
255
+ } ;
256
+
257
+ private static readonly PatternFieldMap < JsonSchemaBuilder > _schemaPatternFields = new PatternFieldMap < JsonSchemaBuilder >
258
+ {
259
+ { s => s . StartsWith ( "x-" ) , ( o , p , n ) => o . Extensions ( LoadExtensions ( p , LoadExtension ( p , n ) ) ) }
260
+ } ;
261
+
19
262
public static JsonSchema LoadSchema ( ParseNode node )
20
263
{
21
264
var mapNode = node . CheckMapNode ( OpenApiConstants . Schema ) ;
22
265
var builder = new JsonSchemaBuilder ( ) ;
23
266
24
267
// check for a $ref and if present, add it to the builder as a Ref keyword
25
- if ( mapNode . GetReferencePointer ( ) is { } pointer )
268
+ var pointer = mapNode . GetReferencePointer ( ) ;
269
+ if ( pointer != null )
26
270
{
27
271
builder = builder . Ref ( pointer ) ;
28
272
29
273
// Check for summary and description and append to builder
30
274
var summary = mapNode . GetSummaryValue ( ) ;
31
- var description = mapNode . GetDescriptionValue ( ) ;
275
+ var description = mapNode . GetDescriptionValue ( ) ;
32
276
if ( ! string . IsNullOrEmpty ( summary ) )
33
277
{
34
278
builder . Summary ( summary ) ;
@@ -40,10 +284,23 @@ public static JsonSchema LoadSchema(ParseNode node)
40
284
41
285
return builder . Build ( ) ;
42
286
}
43
- else
287
+
288
+ foreach ( var propertyNode in mapNode )
44
289
{
45
- return node . JsonNode . Deserialize < JsonSchema > ( ) ;
290
+ propertyNode . ParseField ( builder , _schemaFixedFields , _schemaPatternFields ) ;
46
291
}
292
+
293
+ var schema = builder . Build ( ) ;
294
+ return schema ;
295
+ }
296
+
297
+ private static Dictionary < string , IOpenApiExtension > LoadExtensions ( string value , IOpenApiExtension extension )
298
+ {
299
+ var extensions = new Dictionary < string , IOpenApiExtension >
300
+ {
301
+ { value , extension }
302
+ } ;
303
+ return extensions ;
47
304
}
48
305
}
49
306
0 commit comments