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 ;
7
+ using Json . Schema ;
5
8
using Json . Schema . OpenApi ;
9
+ using Microsoft . OpenApi . Extensions ;
10
+ using Microsoft . OpenApi . Interfaces ;
6
11
using Microsoft . OpenApi . Models ;
7
12
using Microsoft . OpenApi . Reader . ParseNodes ;
8
13
using JsonSchema = Json . Schema . JsonSchema ;
@@ -15,10 +20,293 @@ namespace Microsoft.OpenApi.Reader.V31
15
20
/// </summary>
16
21
internal static partial class OpenApiV31Deserializer
17
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 , p ) => 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 , p ) => SchemaTypeConverter . ConvertToSchemaValueType ( s . GetScalarValue ( ) ) ) ) ;
127
+ }
128
+ else
129
+ {
130
+ o . Type ( SchemaTypeConverter . ConvertToSchemaValueType ( n . GetScalarValue ( ) ) ) ;
131
+ }
132
+ }
133
+ } ,
134
+ {
135
+ "allOf" , ( o , n , t ) =>
136
+ {
137
+ o . AllOf ( n . CreateList ( LoadSchema , t ) ) ;
138
+ }
139
+ } ,
140
+ {
141
+ "oneOf" , ( o , n , t ) =>
142
+ {
143
+ o . OneOf ( n . CreateList ( LoadSchema , t ) ) ;
144
+ }
145
+ } ,
146
+ {
147
+ "anyOf" , ( o , n , t ) =>
148
+ {
149
+ o . AnyOf ( n . CreateList ( LoadSchema , t ) ) ;
150
+ }
151
+ } ,
152
+ {
153
+ "not" , ( o , n , t ) =>
154
+ {
155
+ o . Not ( LoadSchema ( n , t ) ) ;
156
+ }
157
+ } ,
158
+ {
159
+ "items" , ( o , n , t ) =>
160
+ {
161
+ o . Items ( LoadSchema ( n , t ) ) ;
162
+ }
163
+ } ,
164
+ {
165
+ "properties" , ( o , n , t ) =>
166
+ {
167
+ o . Properties ( n . CreateMap ( LoadSchema , t ) ) ;
168
+ }
169
+ } ,
170
+ {
171
+ "patternProperties" , ( o , n , t ) =>
172
+ {
173
+ o . PatternProperties ( n . CreateMap ( LoadSchema , t ) ) ;
174
+ }
175
+ } ,
176
+ {
177
+ "additionalProperties" , ( o , n , t ) =>
178
+ {
179
+ if ( n is ValueNode )
180
+ {
181
+ o . AdditionalPropertiesAllowed ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
182
+ }
183
+ else
184
+ {
185
+ o . AdditionalProperties ( LoadSchema ( n , t ) ) ;
186
+ }
187
+ }
188
+ } ,
189
+ {
190
+ "description" , ( o , n , _ ) =>
191
+ {
192
+ o . Description ( n . GetScalarValue ( ) ) ;
193
+ }
194
+ } ,
195
+ {
196
+ "format" , ( o , n , _ ) =>
197
+ {
198
+ o . Format ( n . GetScalarValue ( ) ) ;
199
+ }
200
+ } ,
201
+ {
202
+ "default" , ( o , n , _ ) =>
203
+ {
204
+ o . Default ( n . CreateAny ( ) . Node ) ;
205
+ }
206
+ } ,
207
+ {
208
+ "discriminator" , ( o , n , t ) =>
209
+ {
210
+ var discriminator = LoadDiscriminator ( n , t ) ;
211
+ o . Discriminator ( discriminator ) ;
212
+ }
213
+ } ,
214
+ {
215
+ "readOnly" , ( o , n , _ ) =>
216
+ {
217
+ o . ReadOnly ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
218
+ }
219
+ } ,
220
+ {
221
+ "writeOnly" , ( o , n , _ ) =>
222
+ {
223
+ o . WriteOnly ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
224
+ }
225
+ } ,
226
+ {
227
+ "xml" , ( o , n , t ) =>
228
+ {
229
+ var xml = LoadXml ( n ) ;
230
+ o . Xml ( xml . Namespace , xml . Name , xml . Prefix , xml . Attribute , xml . Wrapped ,
231
+ ( IReadOnlyDictionary < string , JsonNode > ) xml . Extensions ) ;
232
+ }
233
+ } ,
234
+ {
235
+ "externalDocs" , ( o , n , t ) =>
236
+ {
237
+ var externalDocs = LoadExternalDocs ( n , t ) ;
238
+ o . ExternalDocs ( externalDocs . Url , externalDocs . Description ,
239
+ ( IReadOnlyDictionary < string , JsonNode > ) externalDocs . Extensions ) ;
240
+ }
241
+ } ,
242
+ {
243
+ "example" , ( o , n , _ ) =>
244
+ {
245
+ o . Example ( n . CreateAny ( ) . Node ) ;
246
+ }
247
+ } ,
248
+ {
249
+ "examples" , ( o , n , _ ) =>
250
+ {
251
+ o . Examples ( n . CreateSimpleList ( ( s , p ) => ( JsonNode ) s . GetScalarValue ( ) ) ) ;
252
+ }
253
+ } ,
254
+ {
255
+ "deprecated" , ( o , n , _ ) =>
256
+ {
257
+ o . Deprecated ( bool . Parse ( n . GetScalarValue ( ) ) ) ;
258
+ }
259
+ } ,
260
+ } ;
261
+
262
+ private static readonly PatternFieldMap < JsonSchemaBuilder > _schemaPatternFields = new PatternFieldMap < JsonSchemaBuilder >
263
+ {
264
+ { s => s . StartsWith ( "x-" ) , ( o , p , n , _ ) => o . Extensions ( LoadExtensions ( p , LoadExtension ( p , n ) ) ) }
265
+ } ;
266
+
18
267
public static JsonSchema LoadSchema ( ParseNode node , OpenApiDocument hostDocument = null )
19
268
{
20
- Vocabularies . Register ( ) ;
21
- return JsonSerializer . Deserialize < JsonSchema > ( node . JsonNode ) ;
269
+ var mapNode = node . CheckMapNode ( OpenApiConstants . Schema ) ;
270
+ var builder = new JsonSchemaBuilder ( ) ;
271
+
272
+ // check for a $ref and if present, add it to the builder as a Ref keyword
273
+ var pointer = mapNode . GetReferencePointer ( ) ;
274
+ if ( pointer != null )
275
+ {
276
+ builder = builder . Ref ( pointer ) ;
277
+
278
+ // Check for summary and description and append to builder
279
+ var summary = mapNode . GetSummaryValue ( ) ;
280
+ var description = mapNode . GetDescriptionValue ( ) ;
281
+ if ( ! string . IsNullOrEmpty ( summary ) )
282
+ {
283
+ builder . Summary ( summary ) ;
284
+ }
285
+ if ( ! string . IsNullOrEmpty ( description ) )
286
+ {
287
+ builder . Description ( description ) ;
288
+ }
289
+
290
+ return builder . Build ( ) ;
291
+ }
292
+
293
+ foreach ( var propertyNode in mapNode )
294
+ {
295
+ propertyNode . ParseField ( builder , _schemaFixedFields , _schemaPatternFields ) ;
296
+ }
297
+
298
+ var schema = builder . Build ( ) ;
299
+ return schema ;
300
+ }
301
+
302
+ private static Dictionary < string , IOpenApiExtension > LoadExtensions ( string value , IOpenApiExtension extension )
303
+ {
304
+ var extensions = new Dictionary < string , IOpenApiExtension >
305
+ {
306
+ { value , extension }
307
+ } ;
308
+ return extensions ;
22
309
}
23
310
}
311
+
24
312
}
0 commit comments