4
4
using System . Text ;
5
5
using System . Text . RegularExpressions ;
6
6
using Humanizer ;
7
- using Humanizer . Inflections ;
7
+ using Json . Schema ;
8
+ using Json . Schema . OpenApi ;
8
9
using Microsoft . OpenApi . Hidi . Extensions ;
9
10
using Microsoft . OpenApi . Models ;
10
11
using Microsoft . OpenApi . Services ;
12
+ using Microsoft . OpenApi . Extensions ;
11
13
12
14
namespace Microsoft . OpenApi . Hidi . Formatters
13
15
{
14
16
internal class PowerShellFormatter : OpenApiVisitorBase
15
17
{
16
18
private const string DefaultPutPrefix = ".Update" ;
17
19
private const string PowerShellPutPrefix = ".Set" ;
18
- private readonly Stack < OpenApiSchema > _schemaLoop = new ( ) ;
20
+ private readonly Stack < JsonSchema > _schemaLoop = new ( ) ;
19
21
private static readonly Regex s_oDataCastRegex = new ( "(.*(?<=[a-z]))\\ .(As(?=[A-Z]).*)" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
20
22
private static readonly Regex s_hashSuffixRegex = new ( @"^[^-]+" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
21
23
private static readonly Regex s_oDataRefRegex = new ( "(?<=[a-z])Ref(?=[A-Z])" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
@@ -24,11 +26,11 @@ static PowerShellFormatter()
24
26
{
25
27
// Add singularization exclusions.
26
28
// Enhancement: Read exclusions from a user provided file.
27
- Vocabularies . Default . AddSingular ( "(drive)s$" , "$1" ) ; // drives does not properly singularize to drive.
28
- Vocabularies . Default . AddSingular ( "(data)$" , "$1" ) ; // exclude the following from singularization.
29
- Vocabularies . Default . AddSingular ( "(delta)$" , "$1" ) ;
30
- Vocabularies . Default . AddSingular ( "(quota)$" , "$1" ) ;
31
- Vocabularies . Default . AddSingular ( "(statistics)$" , "$1" ) ;
29
+ Humanizer . Inflections . Vocabularies . Default . AddSingular ( "(drive)s$" , "$1" ) ; // drives does not properly singularize to drive.
30
+ Humanizer . Inflections . Vocabularies . Default . AddSingular ( "(data)$" , "$1" ) ; // exclude the following from singularization.
31
+ Humanizer . Inflections . Vocabularies . Default . AddSingular ( "(delta)$" , "$1" ) ;
32
+ Humanizer . Inflections . Vocabularies . Default . AddSingular ( "(quota)$" , "$1" ) ;
33
+ Humanizer . Inflections . Vocabularies . Default . AddSingular ( "(statistics)$" , "$1" ) ;
32
34
}
33
35
34
36
//FHL task for PS
@@ -41,13 +43,13 @@ static PowerShellFormatter()
41
43
// 5. Fix anyOf and oneOf schema.
42
44
// 6. Add AdditionalProperties to object schemas.
43
45
44
- public override void Visit ( OpenApiSchema schema )
46
+ public override void Visit ( ref JsonSchema schema )
45
47
{
46
48
AddAdditionalPropertiesToSchema ( schema ) ;
47
- ResolveAnyOfSchema ( schema ) ;
48
- ResolveOneOfSchema ( schema ) ;
49
+ schema = ResolveAnyOfSchema ( ref schema ) ;
50
+ schema = ResolveOneOfSchema ( ref schema ) ;
49
51
50
- base . Visit ( schema ) ;
52
+ base . Visit ( ref schema ) ;
51
53
}
52
54
53
55
public override void Visit ( OpenApiPathItem pathItem )
@@ -163,97 +165,228 @@ private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiPa
163
165
// Replace content with a schema object of type array
164
166
// for structured or collection-valued function parameters
165
167
parameter . Content = null ;
166
- parameter . Schema = new ( )
167
- {
168
- Type = "array" ,
169
- Items = new ( )
170
- {
171
- Type = "string"
172
- }
173
- } ;
168
+ parameter . Schema = new JsonSchemaBuilder ( )
169
+ . Type ( SchemaValueType . Array )
170
+ . Items ( new JsonSchemaBuilder ( )
171
+ . Type ( SchemaValueType . String ) )
172
+ ;
174
173
}
175
174
return parameters ;
176
175
}
177
176
178
- private void AddAdditionalPropertiesToSchema ( OpenApiSchema schema )
177
+ private void AddAdditionalPropertiesToSchema ( JsonSchema schema )
179
178
{
180
- if ( schema != null && ! _schemaLoop . Contains ( schema ) && "object" . Equals ( schema . Type , StringComparison . OrdinalIgnoreCase ) )
179
+ if ( schema != null && ! _schemaLoop . Contains ( schema ) && schema . GetJsonType ( ) . Equals ( SchemaValueType . Object ) )
181
180
{
182
- schema . AdditionalProperties = new ( ) { Type = "object" } ;
181
+ var schemaBuilder = new JsonSchemaBuilder ( ) ;
182
+ if ( schema . Keywords != null )
183
+ {
184
+ foreach ( var keyword in schema . Keywords )
185
+ {
186
+ schemaBuilder . Add ( keyword ) ;
187
+ }
188
+ }
189
+
190
+ schema = schemaBuilder . AdditionalProperties ( new JsonSchemaBuilder ( ) . Type ( SchemaValueType . Object ) ) ;
183
191
184
192
/* Because 'additionalProperties' are now being walked,
185
193
* we need a way to keep track of visited schemas to avoid
186
194
* endlessly creating and walking them in an infinite recursion.
187
195
*/
188
- _schemaLoop . Push ( schema . AdditionalProperties ) ;
196
+ var additionalProps = schema . GetAdditionalProperties ( ) ;
197
+
198
+ if ( additionalProps != null )
199
+ {
200
+ _schemaLoop . Push ( additionalProps ) ;
201
+ }
189
202
}
190
203
}
191
204
192
- private static void ResolveOneOfSchema ( OpenApiSchema schema )
205
+ private static JsonSchema ResolveOneOfSchema ( ref JsonSchema schema )
193
206
{
194
- if ( schema . OneOf ? . FirstOrDefault ( ) is { } newSchema )
207
+ if ( schema . GetOneOf ( ) ? . FirstOrDefault ( ) is { } newSchema )
195
208
{
196
- schema . OneOf = null ;
197
- FlattenSchema ( schema , newSchema ) ;
209
+ var schemaBuilder = BuildSchema ( schema ) ;
210
+ schemaBuilder = schemaBuilder . Remove ( "oneOf" ) ;
211
+ schema = schemaBuilder . Build ( ) ;
212
+
213
+ schema = FlattenSchema ( schema , newSchema ) ;
198
214
}
215
+
216
+ return schema ;
199
217
}
200
218
201
- private static void ResolveAnyOfSchema ( OpenApiSchema schema )
219
+ private static JsonSchema ResolveAnyOfSchema ( ref JsonSchema schema )
202
220
{
203
- if ( schema . AnyOf ? . FirstOrDefault ( ) is { } newSchema )
221
+ if ( schema . GetAnyOf ( ) ? . FirstOrDefault ( ) is { } newSchema )
204
222
{
205
- schema . AnyOf = null ;
206
- FlattenSchema ( schema , newSchema ) ;
223
+ var schemaBuilder = BuildSchema ( schema ) ;
224
+ schemaBuilder = schemaBuilder . Remove ( "anyOf" ) ;
225
+ schema = schemaBuilder . Build ( ) ;
226
+
227
+ schema = FlattenSchema ( schema , newSchema ) ;
207
228
}
229
+
230
+ return schema ;
208
231
}
209
232
210
- private static void FlattenSchema ( OpenApiSchema schema , OpenApiSchema newSchema )
233
+ private static JsonSchema FlattenSchema ( JsonSchema schema , JsonSchema newSchema )
211
234
{
212
235
if ( newSchema != null )
213
236
{
214
- if ( newSchema . Reference != null )
237
+ var newSchemaRef = newSchema . GetRef ( ) ;
238
+
239
+ if ( newSchemaRef != null )
215
240
{
216
- schema . Reference = newSchema . Reference ;
217
- schema . UnresolvedReference = true ;
241
+ var schemaBuilder = BuildSchema ( schema ) ;
242
+ schema = schemaBuilder . Ref ( newSchemaRef ) ;
218
243
}
219
244
else
220
245
{
221
246
// Copies schema properties based on https://github.com/microsoft/OpenAPI.NET.OData/pull/264.
222
- CopySchema ( schema , newSchema ) ;
247
+ schema = CopySchema ( schema , newSchema ) ;
223
248
}
224
249
}
250
+
251
+ return schema ;
225
252
}
226
253
227
- private static void CopySchema ( OpenApiSchema schema , OpenApiSchema newSchema )
254
+ private static JsonSchema CopySchema ( JsonSchema schema , JsonSchema newSchema )
228
255
{
229
- schema . Title ??= newSchema . Title ;
230
- schema . Type ??= newSchema . Type ;
231
- schema . Format ??= newSchema . Format ;
232
- schema . Description ??= newSchema . Description ;
233
- schema . Maximum ??= newSchema . Maximum ;
234
- schema . ExclusiveMaximum ??= newSchema . ExclusiveMaximum ;
235
- schema . Minimum ??= newSchema . Minimum ;
236
- schema . ExclusiveMinimum ??= newSchema . ExclusiveMinimum ;
237
- schema . MaxLength ??= newSchema . MaxLength ;
238
- schema . MinLength ??= newSchema . MinLength ;
239
- schema . Pattern ??= newSchema . Pattern ;
240
- schema . MultipleOf ??= newSchema . MultipleOf ;
241
- schema . Not ??= newSchema . Not ;
242
- schema . Required ??= newSchema . Required ;
243
- schema . Items ??= newSchema . Items ;
244
- schema . MaxItems ??= newSchema . MaxItems ;
245
- schema . MinItems ??= newSchema . MinItems ;
246
- schema . UniqueItems ??= newSchema . UniqueItems ;
247
- schema . Properties ??= newSchema . Properties ;
248
- schema . MaxProperties ??= newSchema . MaxProperties ;
249
- schema . MinProperties ??= newSchema . MinProperties ;
250
- schema . Discriminator ??= newSchema . Discriminator ;
251
- schema . ExternalDocs ??= newSchema . ExternalDocs ;
252
- schema . Enum ??= newSchema . Enum ;
253
- schema . ReadOnly = ! schema . ReadOnly ? newSchema . ReadOnly : schema . ReadOnly ;
254
- schema . WriteOnly = ! schema . WriteOnly ? newSchema . WriteOnly : schema . WriteOnly ;
255
- schema . Nullable = ! schema . Nullable ? newSchema . Nullable : schema . Nullable ;
256
- schema . Deprecated = ! schema . Deprecated ? newSchema . Deprecated : schema . Deprecated ;
256
+ var schemaBuilder = new JsonSchemaBuilder ( ) ;
257
+
258
+ if ( schema . GetTitle ( ) == null && newSchema . GetTitle ( ) is { } title )
259
+ {
260
+ schemaBuilder . Title ( title ) ;
261
+ }
262
+ if ( schema . GetJsonType ( ) == null && newSchema . GetJsonType ( ) is { } type )
263
+ {
264
+ schemaBuilder . Type ( type ) ;
265
+ }
266
+ if ( schema . GetFormat ( ) == null && newSchema . GetFormat ( ) is { } format )
267
+ {
268
+ schemaBuilder . Format ( format ) ;
269
+ }
270
+ if ( schema . GetDescription ( ) == null && newSchema . GetDescription ( ) is { } description )
271
+ {
272
+ schemaBuilder . Description ( description ) ;
273
+ }
274
+ if ( schema . GetMaximum ( ) == null && newSchema . GetMaximum ( ) is { } max )
275
+ {
276
+ schemaBuilder . Maximum ( max ) ;
277
+ }
278
+ if ( schema . GetExclusiveMaximum ( ) == null && newSchema . GetExclusiveMaximum ( ) is { } exclusiveMaximum )
279
+ {
280
+ schemaBuilder . ExclusiveMaximum ( exclusiveMaximum ) ;
281
+ }
282
+ if ( schema . GetMinimum ( ) == null && newSchema . GetMinimum ( ) is { } min )
283
+ {
284
+ schemaBuilder . Minimum ( min ) ;
285
+ }
286
+ if ( schema . GetExclusiveMinimum ( ) == null && newSchema . GetExclusiveMinimum ( ) is { } exclusiveMinimum )
287
+ {
288
+ schemaBuilder . ExclusiveMinimum ( exclusiveMinimum ) ;
289
+ }
290
+ if ( schema . GetMaxLength ( ) == null && newSchema . GetMaxLength ( ) is { } maxLength )
291
+ {
292
+ schemaBuilder . MaxLength ( maxLength ) ;
293
+ }
294
+ if ( schema . GetMinLength ( ) == null && newSchema . GetMinLength ( ) is { } minLength )
295
+ {
296
+ schemaBuilder . MinLength ( minLength ) ;
297
+ }
298
+ if ( schema . GetPattern ( ) == null && newSchema . GetPattern ( ) is { } pattern )
299
+ {
300
+ schemaBuilder . Pattern ( pattern ) ;
301
+ }
302
+ if ( schema . GetMultipleOf ( ) == null && newSchema . GetMultipleOf ( ) is { } multipleOf )
303
+ {
304
+ schemaBuilder . MultipleOf ( multipleOf ) ;
305
+ }
306
+ if ( schema . GetNot ( ) == null && newSchema . GetNot ( ) is { } not )
307
+ {
308
+ schemaBuilder . Not ( not ) ;
309
+ }
310
+ if ( schema . GetRequired ( ) == null && newSchema . GetRequired ( ) is { } required )
311
+ {
312
+ schemaBuilder . Required ( required ) ;
313
+ }
314
+ if ( schema . GetItems ( ) == null && newSchema . GetItems ( ) is { } items )
315
+ {
316
+ schemaBuilder . Items ( items ) ;
317
+ }
318
+ if ( schema . GetMaxItems ( ) == null && newSchema . GetMaxItems ( ) is { } maxItems )
319
+ {
320
+ schemaBuilder . MaxItems ( maxItems ) ;
321
+ }
322
+ if ( schema . GetMinItems ( ) == null && newSchema . GetMinItems ( ) is { } minItems )
323
+ {
324
+ schemaBuilder . MinItems ( minItems ) ;
325
+ }
326
+ if ( schema . GetUniqueItems ( ) == null && newSchema . GetUniqueItems ( ) is { } uniqueItems )
327
+ {
328
+ schemaBuilder . UniqueItems ( uniqueItems ) ;
329
+ }
330
+ if ( schema . GetProperties ( ) == null && newSchema . GetProperties ( ) is { } properties )
331
+ {
332
+ schemaBuilder . Properties ( properties ) ;
333
+ }
334
+ if ( schema . GetMaxProperties ( ) == null && newSchema . GetMaxProperties ( ) is { } maxProperties )
335
+ {
336
+ schemaBuilder . MaxProperties ( maxProperties ) ;
337
+ }
338
+ if ( schema . GetMinProperties ( ) == null && newSchema . GetMinProperties ( ) is { } minProperties )
339
+ {
340
+ schemaBuilder . MinProperties ( minProperties ) ;
341
+ }
342
+ if ( schema . GetDiscriminator ( ) == null && newSchema . GetOpenApiDiscriminator ( ) is { } discriminator )
343
+ {
344
+ schemaBuilder . Discriminator ( discriminator ) ;
345
+ }
346
+ if ( schema . GetOpenApiExternalDocs ( ) == null && newSchema . GetOpenApiExternalDocs ( ) is { } externalDocs )
347
+ {
348
+ schemaBuilder . OpenApiExternalDocs ( externalDocs ) ;
349
+ }
350
+ if ( schema . GetEnum ( ) == null && newSchema . GetEnum ( ) is { } enumCollection )
351
+ {
352
+ schemaBuilder . Enum ( enumCollection ) ;
353
+ }
354
+
355
+ if ( ! schema . GetReadOnly ( ) is { } && newSchema . GetReadOnly ( ) is { } newValue )
356
+ {
357
+ schemaBuilder . ReadOnly ( newValue ) ;
358
+ }
359
+
360
+ if ( ! schema . GetWriteOnly ( ) is { } && newSchema . GetWriteOnly ( ) is { } newWriteOnlyValue )
361
+ {
362
+ schemaBuilder . WriteOnly ( newWriteOnlyValue ) ;
363
+ }
364
+
365
+ if ( ! schema . GetNullable ( ) is { } && newSchema . GetNullable ( ) is { } newNullableValue )
366
+ {
367
+ schemaBuilder . Nullable ( newNullableValue ) ;
368
+ }
369
+
370
+ if ( ! schema . GetDeprecated ( ) is { } && newSchema . GetDeprecated ( ) is { } newDepracatedValue )
371
+ {
372
+ schemaBuilder . Deprecated ( newDepracatedValue ) ;
373
+ }
374
+
375
+ return schemaBuilder ;
376
+ }
377
+
378
+ private static JsonSchemaBuilder BuildSchema ( JsonSchema schema )
379
+ {
380
+ var schemaBuilder = new JsonSchemaBuilder ( ) ;
381
+ if ( schema . Keywords != null )
382
+ {
383
+ foreach ( var keyword in schema . Keywords )
384
+ {
385
+ schemaBuilder . Add ( keyword ) ;
386
+ }
387
+ }
388
+
389
+ return schemaBuilder ;
257
390
}
258
391
}
259
392
}
0 commit comments