6
6
using System . Linq ;
7
7
using System . Text ;
8
8
using Microsoft . OpenApi . Any ;
9
- using Microsoft . OpenApi . Exceptions ;
10
9
using Microsoft . OpenApi . Models ;
11
10
12
11
namespace Microsoft . OpenApi . Readers . ParseNodes
13
12
{
14
13
internal static class OpenApiAnyConverter
15
14
{
16
- /// <summary>
17
- /// Converts the <see cref="OpenApiString"/>s in the given <see cref="IOpenApiAny"/>
18
- /// into the most specific <see cref="IOpenApiPrimitive"/> type based on the value.
19
- /// </summary>
20
- public static IOpenApiAny GetSpecificOpenApiAny ( IOpenApiAny openApiAny )
21
- {
22
- if ( openApiAny is OpenApiArray openApiArray )
23
- {
24
- var newArray = new OpenApiArray ( ) ;
25
- foreach ( var element in openApiArray )
26
- {
27
- newArray . Add ( GetSpecificOpenApiAny ( element ) ) ;
28
- }
29
-
30
- return newArray ;
31
- }
32
-
33
- if ( openApiAny is OpenApiObject openApiObject )
34
- {
35
- var newObject = new OpenApiObject ( ) ;
36
-
37
- foreach ( var key in openApiObject . Keys . ToList ( ) )
38
- {
39
- newObject [ key ] = GetSpecificOpenApiAny ( openApiObject [ key ] ) ;
40
- }
41
-
42
- return newObject ;
43
- }
44
-
45
- if ( ! ( openApiAny is OpenApiString ) )
46
- {
47
- return openApiAny ;
48
- }
49
-
50
- var value = ( ( OpenApiString ) openApiAny ) . Value ;
51
-
52
- if ( value == null || value == "null" )
53
- {
54
- return new OpenApiNull ( ) ;
55
- }
56
-
57
- if ( value == "true" )
58
- {
59
- return new OpenApiBoolean ( true ) ;
60
- }
61
-
62
- if ( value == "false" )
63
- {
64
- return new OpenApiBoolean ( false ) ;
65
- }
66
-
67
- if ( int . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var intValue ) )
68
- {
69
- return new OpenApiInteger ( intValue ) ;
70
- }
71
-
72
- if ( long . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var longValue ) )
73
- {
74
- return new OpenApiLong ( longValue ) ;
75
- }
76
-
77
- if ( double . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var doubleValue ) )
78
- {
79
- return new OpenApiDouble ( doubleValue ) ;
80
- }
81
-
82
- if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateTimeValue ) )
83
- {
84
- return new OpenApiDateTime ( dateTimeValue ) ;
85
- }
86
-
87
- // if we can't identify the type of value, return it as string.
88
- return new OpenApiString ( value ) ;
89
- }
90
-
91
15
/// <summary>
92
16
/// Converts the <see cref="OpenApiString"/>s in the given <see cref="IOpenApiAny"/>
93
17
/// into the appropriate <see cref="IOpenApiPrimitive"/> type based on the given <see cref="OpenApiSchema"/>.
94
18
/// For those strings that the schema does not specify the type for, convert them into
95
19
/// the most specific type based on the value.
96
20
/// </summary>
97
- public static IOpenApiAny GetSpecificOpenApiAny ( IOpenApiAny openApiAny , OpenApiSchema schema )
21
+ public static IOpenApiAny GetSpecificOpenApiAny ( IOpenApiAny openApiAny , OpenApiSchema schema = null )
98
22
{
99
23
if ( openApiAny is OpenApiArray openApiArray )
100
24
{
@@ -113,9 +37,9 @@ public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiS
113
37
114
38
foreach ( var key in openApiObject . Keys . ToList ( ) )
115
39
{
116
- if ( schema != null && schema . Properties != null && schema . Properties . ContainsKey ( key ) )
40
+ if ( schema ? . Properties != null && schema . Properties . TryGetValue ( key , out var property ) )
117
41
{
118
- newObject [ key ] = GetSpecificOpenApiAny ( openApiObject [ key ] , schema . Properties [ key ] ) ;
42
+ newObject [ key ] = GetSpecificOpenApiAny ( openApiObject [ key ] , property ) ;
119
43
}
120
44
else
121
45
{
@@ -126,133 +50,162 @@ public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiS
126
50
return newObject ;
127
51
}
128
52
129
- if ( ! ( openApiAny is OpenApiString ) )
53
+ if ( ! ( openApiAny is OpenApiString ) || ( ( OpenApiString ) openApiAny ) . IsExplicit ( ) )
130
54
{
131
55
return openApiAny ;
132
56
}
133
57
134
- if ( schema ? . Type == null )
135
- {
136
- return GetSpecificOpenApiAny ( openApiAny ) ;
137
- }
138
-
139
- var type = schema . Type ;
140
- var format = schema . Format ;
141
-
142
58
var value = ( ( OpenApiString ) openApiAny ) . Value ;
143
-
144
59
if ( value == null || value == "null" )
145
60
{
146
61
return new OpenApiNull ( ) ;
147
62
}
148
63
149
- if ( type == "integer" && format == "int32" )
64
+ if ( schema ? . Type == null )
150
65
{
151
- if ( int . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var intValue ) )
66
+ if ( value == "true" )
152
67
{
153
- return new OpenApiInteger ( intValue ) ;
68
+ return new OpenApiBoolean ( true ) ;
154
69
}
155
- }
156
70
157
- if ( type == "integer" && format == "int64" )
158
- {
159
- if ( long . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var longValue ) )
71
+ if ( value == "false" )
160
72
{
161
- return new OpenApiLong ( longValue ) ;
73
+ return new OpenApiBoolean ( false ) ;
162
74
}
163
- }
164
75
165
- if ( type == "integer" )
166
- {
167
76
if ( int . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var intValue ) )
168
77
{
169
78
return new OpenApiInteger ( intValue ) ;
170
79
}
171
- }
172
80
173
- if ( type == "number" && format == "float" )
174
- {
175
- if ( float . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var floatValue ) )
81
+ if ( long . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var longValue ) )
176
82
{
177
- return new OpenApiFloat ( floatValue ) ;
83
+ return new OpenApiLong ( longValue ) ;
178
84
}
179
- }
180
85
181
- if ( type == "number" && format == "double" )
182
- {
183
86
if ( double . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var doubleValue ) )
184
87
{
185
88
return new OpenApiDouble ( doubleValue ) ;
186
89
}
187
- }
188
90
189
- if ( type == "number" )
190
- {
191
- if ( double . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var doubleValue ) )
91
+ if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateTimeValue ) )
192
92
{
193
- return new OpenApiDouble ( doubleValue ) ;
93
+ return new OpenApiDateTime ( dateTimeValue ) ;
194
94
}
195
95
}
196
-
197
- if ( type == "string" && format == "byte" )
96
+ else
198
97
{
199
- try
98
+ var type = schema . Type ;
99
+ var format = schema . Format ;
100
+
101
+ if ( type == "integer" && format == "int32" )
200
102
{
201
- return new OpenApiByte ( Convert . FromBase64String ( value ) ) ;
103
+ if ( int . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var intValue ) )
104
+ {
105
+ return new OpenApiInteger ( intValue ) ;
106
+ }
202
107
}
203
- catch ( FormatException )
204
- { }
205
- }
206
108
207
- // binary
208
- if ( type == "string" && format == "binary" )
209
- {
210
- try
109
+ if ( type == "integer" && format == "int64" )
211
110
{
212
- return new OpenApiBinary ( Encoding . UTF8 . GetBytes ( value ) ) ;
111
+ if ( long . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var longValue ) )
112
+ {
113
+ return new OpenApiLong ( longValue ) ;
114
+ }
213
115
}
214
- catch ( EncoderFallbackException )
215
- { }
216
- }
217
116
218
- if ( type == "string" && format == "date" )
219
- {
220
- if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateValue ) )
117
+ if ( type == "integer" )
221
118
{
222
- return new OpenApiDate ( dateValue . Date ) ;
119
+ if ( int . TryParse ( value , NumberStyles . Integer , CultureInfo . InvariantCulture , out var intValue ) )
120
+ {
121
+ return new OpenApiInteger ( intValue ) ;
122
+ }
223
123
}
224
- }
225
124
226
- if ( type == "string" && format == "date-time" )
227
- {
228
- if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateTimeValue ) )
125
+ if ( type == "number" && format == "float" )
229
126
{
230
- return new OpenApiDateTime ( dateTimeValue ) ;
127
+ if ( float . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var floatValue ) )
128
+ {
129
+ return new OpenApiFloat ( floatValue ) ;
130
+ }
231
131
}
232
- }
233
132
234
- if ( type == "string" && format == "password" )
235
- {
236
- return new OpenApiPassword ( value ) ;
237
- }
133
+ if ( type == "number" && format == "double" )
134
+ {
135
+ if ( double . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var doubleValue ) )
136
+ {
137
+ return new OpenApiDouble ( doubleValue ) ;
138
+ }
139
+ }
238
140
239
- if ( type == "string" )
240
- {
241
- return new OpenApiString ( value ) ;
242
- }
141
+ if ( type == "number" )
142
+ {
143
+ if ( double . TryParse ( value , NumberStyles . Float | NumberStyles . AllowThousands , CultureInfo . InvariantCulture , out var doubleValue ) )
144
+ {
145
+ return new OpenApiDouble ( doubleValue ) ;
146
+ }
147
+ }
243
148
244
- if ( type == "boolean" )
245
- {
246
- if ( bool . TryParse ( value , out var booleanValue ) )
149
+ if ( type == "string" && format == "byte" )
150
+ {
151
+ try
152
+ {
153
+ return new OpenApiByte ( Convert . FromBase64String ( value ) ) ;
154
+ }
155
+ catch ( FormatException )
156
+ { }
157
+ }
158
+
159
+ // binary
160
+ if ( type == "string" && format == "binary" )
247
161
{
248
- return new OpenApiBoolean ( booleanValue ) ;
162
+ try
163
+ {
164
+ return new OpenApiBinary ( Encoding . UTF8 . GetBytes ( value ) ) ;
165
+ }
166
+ catch ( EncoderFallbackException )
167
+ { }
168
+ }
169
+
170
+ if ( type == "string" && format == "date" )
171
+ {
172
+ if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateValue ) )
173
+ {
174
+ return new OpenApiDate ( dateValue . Date ) ;
175
+ }
176
+ }
177
+
178
+ if ( type == "string" && format == "date-time" )
179
+ {
180
+ if ( DateTimeOffset . TryParse ( value , CultureInfo . InvariantCulture , DateTimeStyles . None , out var dateTimeValue ) )
181
+ {
182
+ return new OpenApiDateTime ( dateTimeValue ) ;
183
+ }
184
+ }
185
+
186
+ if ( type == "string" && format == "password" )
187
+ {
188
+ return new OpenApiPassword ( value ) ;
189
+ }
190
+
191
+ if ( type == "string" )
192
+ {
193
+ return new OpenApiString ( value ) ;
194
+ }
195
+
196
+ if ( type == "boolean" )
197
+ {
198
+ if ( bool . TryParse ( value , out var booleanValue ) )
199
+ {
200
+ return new OpenApiBoolean ( booleanValue ) ;
201
+ }
249
202
}
250
203
}
251
204
252
205
// If data conflicts with the given type, return a string.
253
206
// This converter is used in the parser, so it does not perform any validations,
254
207
// but the validator can be used to validate whether the data and given type conflicts.
255
- return new OpenApiString ( value ) ;
208
+ return openApiAny ;
256
209
}
257
210
}
258
211
}
0 commit comments