2929using Microsoft . OpenApi . Hidi . Utilities ;
3030using Microsoft . OpenApi . Models ;
3131using Microsoft . OpenApi . OData ;
32+ using Microsoft . OpenApi . Reader ;
3233using Microsoft . OpenApi . Readers ;
3334using Microsoft . OpenApi . Services ;
3435using Microsoft . OpenApi . Writers ;
@@ -38,6 +39,12 @@ namespace Microsoft.OpenApi.Hidi
3839{
3940 internal static class OpenApiService
4041 {
42+ static OpenApiService ( )
43+ {
44+ OpenApiReaderRegistry . RegisterReader ( OpenApiConstants . Yaml , new OpenApiYamlReader ( ) ) ;
45+ OpenApiReaderRegistry . RegisterReader ( OpenApiConstants . Yml , new OpenApiYamlReader ( ) ) ;
46+ }
47+
4148 /// <summary>
4249 /// Implementation of the transform command
4350 /// </summary>
@@ -52,7 +59,12 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
5259 {
5360 if ( options . Output == null )
5461 {
55- var inputExtension = GetInputPathExtension ( options . OpenApi , options . Csdl ) ;
62+ #pragma warning disable CA1308 // Normalize strings to uppercase
63+ var extension = options . OpenApiFormat ? . GetDisplayName ( ) . ToLowerInvariant ( ) ;
64+ var inputExtension = ! string . IsNullOrEmpty ( extension ) ? string . Concat ( "." , extension )
65+ : GetInputPathExtension ( options . OpenApi , options . Csdl ) ;
66+
67+ #pragma warning restore CA1308 // Normalize strings to uppercase
5668 options . Output = new ( $ "./output{ inputExtension } ") ;
5769 } ;
5870
@@ -67,7 +79,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
6779
6880 // Default to yaml and OpenApiVersion 3 during csdl to OpenApi conversion
6981 var openApiFormat = options . OpenApiFormat ?? ( ! string . IsNullOrEmpty ( options . OpenApi ) ? GetOpenApiFormat ( options . OpenApi , logger ) : OpenApiFormat . Yaml ) ;
70- var openApiVersion = options . Version != null ? TryParseOpenApiSpecVersion ( options . Version ) : OpenApiSpecVersion . OpenApi3_0 ;
82+ var openApiVersion = options . Version != null ? TryParseOpenApiSpecVersion ( options . Version ) : OpenApiSpecVersion . OpenApi3_1 ;
7183
7284 // If ApiManifest is provided, set the referenced OpenAPI document
7385 var apiDependency = await FindApiDependencyAsync ( options . FilterOptions . FilterByApiManifest , logger , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -85,7 +97,8 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
8597 }
8698
8799 // Load OpenAPI document
88- var document = await GetOpenApiAsync ( options , logger , options . MetadataVersion , cancellationToken ) . ConfigureAwait ( false ) ;
100+ var format = OpenApiModelFactory . GetFormat ( options . OpenApi ) ;
101+ var document = await GetOpenApiAsync ( options , format , logger , options . MetadataVersion , cancellationToken ) . ConfigureAwait ( false ) ;
89102
90103 if ( options . FilterOptions != null )
91104 {
@@ -212,7 +225,7 @@ private static void WriteOpenApi(HidiOptions options, OpenApiFormat openApiForma
212225 }
213226
214227 // Get OpenAPI document either from OpenAPI or CSDL
215- private static async Task < OpenApiDocument > GetOpenApiAsync ( HidiOptions options , ILogger logger , string ? metadataVersion = null , CancellationToken cancellationToken = default )
228+ private static async Task < OpenApiDocument > GetOpenApiAsync ( HidiOptions options , string format , ILogger logger , string ? metadataVersion = null , CancellationToken cancellationToken = default )
216229 {
217230 OpenApiDocument document ;
218231 Stream stream ;
@@ -233,7 +246,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,
233246 await stream . DisposeAsync ( ) . ConfigureAwait ( false ) ;
234247 }
235248
236- document = await ConvertCsdlToOpenApiAsync ( filteredStream ?? stream , metadataVersion , options . SettingsConfig , cancellationToken ) . ConfigureAwait ( false ) ;
249+ document = await ConvertCsdlToOpenApiAsync ( filteredStream ?? stream , format , metadataVersion , options . SettingsConfig , cancellationToken ) . ConfigureAwait ( false ) ;
237250 stopwatch . Stop ( ) ;
238251 logger . LogTrace ( "{Timestamp}ms: Generated OpenAPI with {Paths} paths." , stopwatch . ElapsedMilliseconds , document . Paths . Count ) ;
239252 }
@@ -375,14 +388,16 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
375388 {
376389 stopwatch . Start ( ) ;
377390
378- result = await new OpenApiStreamReader ( new ( )
379- {
391+ var settings = new OpenApiReaderSettings
392+ {
380393 LoadExternalRefs = inlineExternal ,
381394 BaseUrl = openApiFile . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase ) ?
382395 new ( openApiFile ) :
383396 new Uri ( "file://" + new FileInfo ( openApiFile ) . DirectoryName + Path . DirectorySeparatorChar )
384- }
385- ) . ReadAsync ( stream , cancellationToken ) . ConfigureAwait ( false ) ;
397+ } ;
398+
399+ var format = OpenApiModelFactory . GetFormat ( openApiFile ) ;
400+ result = await OpenApiDocument . LoadAsync ( stream , format , settings , cancellationToken ) . ConfigureAwait ( false ) ;
386401
387402 logger . LogTrace ( "{Timestamp}ms: Completed parsing." , stopwatch . ElapsedMilliseconds ) ;
388403
@@ -398,15 +413,15 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
398413 /// </summary>
399414 /// <param name="csdl">The CSDL stream.</param>
400415 /// <returns>An OpenAPI document.</returns>
401- public static async Task < OpenApiDocument > ConvertCsdlToOpenApiAsync ( Stream csdl , string ? metadataVersion = null , IConfiguration ? settings = null , CancellationToken token = default )
416+ public static async Task < OpenApiDocument > ConvertCsdlToOpenApiAsync ( Stream csdl , string format , string ? metadataVersion = null , IConfiguration ? settings = null , CancellationToken token = default )
402417 {
403418 using var reader = new StreamReader ( csdl ) ;
404419 var csdlText = await reader . ReadToEndAsync ( token ) . ConfigureAwait ( false ) ;
405420 var edmModel = CsdlReader . Parse ( XElement . Parse ( csdlText ) . CreateReader ( ) ) ;
406421 settings ??= SettingsUtilities . GetConfiguration ( ) ;
407422
408423 var document = edmModel . ConvertToOpenApi ( SettingsUtilities . GetOpenApiConvertSettings ( settings , metadataVersion ) ) ;
409- document = FixReferences ( document ) ;
424+ document = FixReferences ( document , format ) ;
410425
411426 return document ;
412427 }
@@ -416,14 +431,15 @@ public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl,
416431 /// </summary>
417432 /// <param name="document"> The converted OpenApiDocument.</param>
418433 /// <returns> A valid OpenApiDocument instance.</returns>
419- public static OpenApiDocument FixReferences ( OpenApiDocument document )
434+ public static OpenApiDocument FixReferences ( OpenApiDocument document , string format )
420435 {
421436 // This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
422437 // So we write it out, and read it back in again to fix it up.
423438
424439 var sb = new StringBuilder ( ) ;
425440 document . SerializeAsV3 ( new OpenApiYamlWriter ( new StringWriter ( sb ) ) ) ;
426- var doc = new OpenApiStringReader ( ) . Read ( sb . ToString ( ) , out _ ) ;
441+
442+ var doc = OpenApiDocument . Parse ( sb . ToString ( ) , format ) . OpenApiDocument ;
427443
428444 return doc ;
429445 }
@@ -571,7 +587,8 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
571587 throw new ArgumentException ( "Please input a file path or URL" ) ;
572588 }
573589
574- var document = await GetOpenApiAsync ( options , logger , null , cancellationToken ) . ConfigureAwait ( false ) ;
590+ var format = OpenApiModelFactory . GetFormat ( options . OpenApi ) ;
591+ var document = await GetOpenApiAsync ( options , format , logger , null , cancellationToken ) . ConfigureAwait ( false ) ;
575592
576593 using ( logger . BeginScope ( "Creating diagram" ) )
577594 {
@@ -732,7 +749,8 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
732749 }
733750
734751 // Load OpenAPI document
735- var document = await GetOpenApiAsync ( options , logger , options . MetadataVersion , cancellationToken ) . ConfigureAwait ( false ) ;
752+ var format = OpenApiModelFactory . GetFormat ( options . OpenApi ) ;
753+ var document = await GetOpenApiAsync ( options , format , logger , options . MetadataVersion , cancellationToken ) . ConfigureAwait ( false ) ;
736754
737755 cancellationToken . ThrowIfCancellationRequested ( ) ;
738756
@@ -750,7 +768,7 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
750768 // Write OpenAPI to Output folder
751769 options . Output = new ( Path . Combine ( options . OutputFolder , "openapi.json" ) ) ;
752770 options . TerseOutput = true ;
753- WriteOpenApi ( options , OpenApiFormat . Json , OpenApiSpecVersion . OpenApi3_0 , document , logger ) ;
771+ WriteOpenApi ( options , OpenApiFormat . Json , OpenApiSpecVersion . OpenApi3_1 , document , logger ) ;
754772
755773 // Create OpenAIPluginManifest from ApiDependency and OpenAPI document
756774 var manifest = new OpenAIPluginManifest
0 commit comments