44using System . Text ;
55using System . Text . RegularExpressions ;
66using Humanizer ;
7- using Humanizer . Inflections ;
7+ using Json . Schema ;
8+ using Json . Schema . OpenApi ;
89using Microsoft . OpenApi . Hidi . Extensions ;
910using Microsoft . OpenApi . Models ;
1011using Microsoft . OpenApi . Services ;
12+ using Microsoft . OpenApi . Extensions ;
1113
1214namespace Microsoft . OpenApi . Hidi . Formatters
1315{
1416 internal class PowerShellFormatter : OpenApiVisitorBase
1517 {
1618 private const string DefaultPutPrefix = ".Update" ;
1719 private const string PowerShellPutPrefix = ".Set" ;
18- private readonly Stack < OpenApiSchema > _schemaLoop = new ( ) ;
20+ private readonly Stack < JsonSchema > _schemaLoop = new ( ) ;
1921 private static readonly Regex s_oDataCastRegex = new ( "(.*(?<=[a-z]))\\ .(As(?=[A-Z]).*)" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
2022 private static readonly Regex s_hashSuffixRegex = new ( @"^[^-]+" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
2123 private static readonly Regex s_oDataRefRegex = new ( "(?<=[a-z])Ref(?=[A-Z])" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 5 ) ) ;
@@ -24,11 +26,11 @@ static PowerShellFormatter()
2426 {
2527 // Add singularization exclusions.
2628 // 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" ) ;
3234 }
3335
3436 //FHL task for PS
@@ -41,13 +43,13 @@ static PowerShellFormatter()
4143 // 5. Fix anyOf and oneOf schema.
4244 // 6. Add AdditionalProperties to object schemas.
4345
44- public override void Visit ( OpenApiSchema schema )
46+ public override void Visit ( ref JsonSchema schema )
4547 {
4648 AddAdditionalPropertiesToSchema ( schema ) ;
47- ResolveAnyOfSchema ( schema ) ;
48- ResolveOneOfSchema ( schema ) ;
49+ schema = ResolveAnyOfSchema ( ref schema ) ;
50+ schema = ResolveOneOfSchema ( ref schema ) ;
4951
50- base . Visit ( schema ) ;
52+ base . Visit ( ref schema ) ;
5153 }
5254
5355 public override void Visit ( OpenApiPathItem pathItem )
@@ -163,97 +165,228 @@ private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiPa
163165 // Replace content with a schema object of type array
164166 // for structured or collection-valued function parameters
165167 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+ ;
174173 }
175174 return parameters ;
176175 }
177176
178- private void AddAdditionalPropertiesToSchema ( OpenApiSchema schema )
177+ private void AddAdditionalPropertiesToSchema ( JsonSchema schema )
179178 {
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 ) )
181180 {
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 ) ) ;
183191
184192 /* Because 'additionalProperties' are now being walked,
185193 * we need a way to keep track of visited schemas to avoid
186194 * endlessly creating and walking them in an infinite recursion.
187195 */
188- _schemaLoop . Push ( schema . AdditionalProperties ) ;
196+ var additionalProps = schema . GetAdditionalProperties ( ) ;
197+
198+ if ( additionalProps != null )
199+ {
200+ _schemaLoop . Push ( additionalProps ) ;
201+ }
189202 }
190203 }
191204
192- private static void ResolveOneOfSchema ( OpenApiSchema schema )
205+ private static JsonSchema ResolveOneOfSchema ( ref JsonSchema schema )
193206 {
194- if ( schema . OneOf ? . FirstOrDefault ( ) is { } newSchema )
207+ if ( schema . GetOneOf ( ) ? . FirstOrDefault ( ) is { } newSchema )
195208 {
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 ) ;
198214 }
215+
216+ return schema ;
199217 }
200218
201- private static void ResolveAnyOfSchema ( OpenApiSchema schema )
219+ private static JsonSchema ResolveAnyOfSchema ( ref JsonSchema schema )
202220 {
203- if ( schema . AnyOf ? . FirstOrDefault ( ) is { } newSchema )
221+ if ( schema . GetAnyOf ( ) ? . FirstOrDefault ( ) is { } newSchema )
204222 {
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 ) ;
207228 }
229+
230+ return schema ;
208231 }
209232
210- private static void FlattenSchema ( OpenApiSchema schema , OpenApiSchema newSchema )
233+ private static JsonSchema FlattenSchema ( JsonSchema schema , JsonSchema newSchema )
211234 {
212235 if ( newSchema != null )
213236 {
214- if ( newSchema . Reference != null )
237+ var newSchemaRef = newSchema . GetRef ( ) ;
238+
239+ if ( newSchemaRef != null )
215240 {
216- schema . Reference = newSchema . Reference ;
217- schema . UnresolvedReference = true ;
241+ var schemaBuilder = BuildSchema ( schema ) ;
242+ schema = schemaBuilder . Ref ( newSchemaRef ) ;
218243 }
219244 else
220245 {
221246 // Copies schema properties based on https://github.com/microsoft/OpenAPI.NET.OData/pull/264.
222- CopySchema ( schema , newSchema ) ;
247+ schema = CopySchema ( schema , newSchema ) ;
223248 }
224249 }
250+
251+ return schema ;
225252 }
226253
227- private static void CopySchema ( OpenApiSchema schema , OpenApiSchema newSchema )
254+ private static JsonSchema CopySchema ( JsonSchema schema , JsonSchema newSchema )
228255 {
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 ;
257390 }
258391 }
259392}
0 commit comments