@@ -94,7 +94,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
9494 // Load OpenAPI document
9595 var document = await GetOpenApiAsync ( options , openApiFormat . GetDisplayName ( ) , logger , options . MetadataVersion , cancellationToken ) . ConfigureAwait ( false ) ;
9696
97- if ( options . FilterOptions != null )
97+ if ( options . FilterOptions != null && document is not null )
9898 {
9999 document = ApplyFilters ( options , logger , apiDependency , postmanCollection , document ) ;
100100 }
@@ -107,7 +107,11 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
107107 var walker = new OpenApiWalker ( powerShellFormatter ) ;
108108 walker . Walk ( document ) ;
109109 }
110- await WriteOpenApiAsync ( options , openApiFormat , openApiVersion , document , logger , cancellationToken ) . ConfigureAwait ( false ) ;
110+ if ( document is not null )
111+ {
112+ // Write the OpenAPI document to the output file
113+ await WriteOpenApiAsync ( options , openApiFormat , openApiVersion , document , logger , cancellationToken ) . ConfigureAwait ( false ) ;
114+ }
111115 }
112116 catch ( TaskCanceledException )
113117 {
@@ -172,7 +176,7 @@ private static OpenApiDocument ApplyFilters(HidiOptions options, ILogger logger,
172176 options . FilterOptions . FilterByTags ,
173177 requestUrls ,
174178 document ,
175- logger ) ;
179+ logger ) ;
176180 if ( predicate != null )
177181 {
178182 var stopwatch = new Stopwatch ( ) ;
@@ -210,6 +214,7 @@ private static async Task WriteOpenApiAsync(HidiOptions options, OpenApiFormat o
210214
211215 var stopwatch = new Stopwatch ( ) ;
212216 stopwatch . Start ( ) ;
217+
213218 await document . SerializeAsync ( writer , openApiVersion , cancellationToken ) . ConfigureAwait ( false ) ;
214219 stopwatch . Stop ( ) ;
215220
@@ -219,9 +224,9 @@ private static async Task WriteOpenApiAsync(HidiOptions options, OpenApiFormat o
219224 }
220225
221226 // Get OpenAPI document either from OpenAPI or CSDL
222- private static async Task < OpenApiDocument > GetOpenApiAsync ( HidiOptions options , string format , ILogger logger , string ? metadataVersion = null , CancellationToken cancellationToken = default )
227+ private static async Task < OpenApiDocument ? > GetOpenApiAsync ( HidiOptions options , string format , ILogger logger , string ? metadataVersion = null , CancellationToken cancellationToken = default )
223228 {
224- OpenApiDocument document ;
229+ OpenApiDocument ? document ;
225230 Stream stream ;
226231
227232 if ( ! string . IsNullOrEmpty ( options . Csdl ) )
@@ -242,7 +247,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,
242247
243248 document = await ConvertCsdlToOpenApiAsync ( filteredStream ?? stream , format , metadataVersion , options . SettingsConfig , cancellationToken ) . ConfigureAwait ( false ) ;
244249 stopwatch . Stop ( ) ;
245- logger . LogTrace ( "{Timestamp}ms: Generated OpenAPI with {Paths} paths." , stopwatch . ElapsedMilliseconds , document . Paths . Count ) ;
250+ logger . LogTrace ( "{Timestamp}ms: Generated OpenAPI with {Paths} paths." , stopwatch . ElapsedMilliseconds , document ? . Paths . Count ) ;
246251 }
247252 }
248253 else if ( ! string . IsNullOrEmpty ( options . OpenApi ) )
@@ -370,7 +375,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe
370375
371376 if ( result is null ) return null ;
372377
373- return result . Diagnostic . Errors . Count == 0 ;
378+ return result . Diagnostic ? . Errors . Count == 0 ;
374379 }
375380
376381 private static async Task < ReadResult > ParseOpenApiAsync ( string openApiFile , bool inlineExternal , ILogger logger , Stream stream , CancellationToken cancellationToken = default )
@@ -407,7 +412,7 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
407412 /// </summary>
408413 /// <param name="csdl">The CSDL stream.</param>
409414 /// <returns>An OpenAPI document.</returns>
410- public static async Task < OpenApiDocument > ConvertCsdlToOpenApiAsync ( Stream csdl , string format , string ? metadataVersion = null , IConfiguration ? settings = null , CancellationToken token = default )
415+ public static async Task < OpenApiDocument ? > ConvertCsdlToOpenApiAsync ( Stream csdl , string format , string ? metadataVersion = null , IConfiguration ? settings = null , CancellationToken token = default )
411416 {
412417 using var reader = new StreamReader ( csdl ) ;
413418 var csdlText = await reader . ReadToEndAsync ( token ) . ConfigureAwait ( false ) ;
@@ -425,7 +430,7 @@ public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl,
425430 /// </summary>
426431 /// <param name="document"> The converted OpenApiDocument.</param>
427432 /// <returns> A valid OpenApiDocument instance.</returns>
428- public static OpenApiDocument FixReferences ( OpenApiDocument document , string format )
433+ public static OpenApiDocument ? FixReferences ( OpenApiDocument document , string format )
429434 {
430435 // This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
431436 // So we write it out, and read it back in again to fix it up.
@@ -584,52 +589,54 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
584589
585590 var openApiFormat = options . OpenApiFormat ?? ( ! string . IsNullOrEmpty ( options . OpenApi ) ? GetOpenApiFormat ( options . OpenApi , logger ) : OpenApiFormat . Yaml ) ;
586591 var document = await GetOpenApiAsync ( options , openApiFormat . GetDisplayName ( ) , logger , null , cancellationToken ) . ConfigureAwait ( false ) ;
587-
588- using ( logger . BeginScope ( "Creating diagram" ) )
592+ if ( document is not null )
589593 {
590- // If output is null, create a HTML file in the user's temporary directory
591- var sourceUrl = ( string . IsNullOrEmpty ( options . OpenApi ) , string . IsNullOrEmpty ( options . Csdl ) ) switch {
592- ( false , _ ) => options . OpenApi ! ,
593- ( _, false ) => options . Csdl ! ,
594- _ => throw new InvalidOperationException ( "No input file path or URL provided" )
595- } ;
596- if ( options . Output == null )
594+ using ( logger . BeginScope ( "Creating diagram" ) )
597595 {
598- var tempPath = Path . GetTempPath ( ) + "/hidi/" ;
599- if ( ! File . Exists ( tempPath ) )
596+ // If output is null, create a HTML file in the user's temporary directory
597+ var sourceUrl = ( string . IsNullOrEmpty ( options . OpenApi ) , string . IsNullOrEmpty ( options . Csdl ) ) switch
600598 {
601- Directory . CreateDirectory ( tempPath ) ;
602- }
603-
604- var fileName = Path . GetRandomFileName ( ) ;
605-
606- var output = new FileInfo ( Path . Combine ( tempPath , fileName + ".html" ) ) ;
607- using ( var file = new FileStream ( output . FullName , FileMode . Create ) )
599+ ( false , _ ) => options . OpenApi ! ,
600+ ( _, false ) => options . Csdl ! ,
601+ _ => throw new InvalidOperationException ( "No input file path or URL provided" )
602+ } ;
603+ if ( options . Output == null )
608604 {
609- using var writer = new StreamWriter ( file ) ;
610- WriteTreeDocumentAsHtml ( sourceUrl , document , writer ) ;
605+ var tempPath = Path . GetTempPath ( ) + "/hidi/" ;
606+ if ( ! File . Exists ( tempPath ) )
607+ {
608+ Directory . CreateDirectory ( tempPath ) ;
609+ }
610+
611+ var fileName = Path . GetRandomFileName ( ) ;
612+
613+ var output = new FileInfo ( Path . Combine ( tempPath , fileName + ".html" ) ) ;
614+ using ( var file = new FileStream ( output . FullName , FileMode . Create ) )
615+ {
616+ using var writer = new StreamWriter ( file ) ;
617+ WriteTreeDocumentAsHtml ( sourceUrl , document , writer ) ;
618+ }
619+ logger . LogTrace ( "Created Html document with diagram " ) ;
620+
621+ // Launch a browser to display the output html file
622+ using var process = new Process ( ) ;
623+ process . StartInfo . FileName = output . FullName ;
624+ process . StartInfo . UseShellExecute = true ;
625+ process . Start ( ) ;
626+
627+ return output . FullName ;
611628 }
612- logger . LogTrace ( "Created Html document with diagram " ) ;
613-
614- // Launch a browser to display the output html file
615- using var process = new Process ( ) ;
616- process . StartInfo . FileName = output . FullName ;
617- process . StartInfo . UseShellExecute = true ;
618- process . Start ( ) ;
619-
620- return output . FullName ;
621- }
622- else // Write diagram as Markdown document to output file
623- {
624- using ( var file = new FileStream ( options . Output . FullName , FileMode . Create ) )
629+ else // Write diagram as Markdown document to output file
625630 {
631+ using var file = new FileStream ( options . Output . FullName , FileMode . Create ) ;
626632 using var writer = new StreamWriter ( file ) ;
627633 WriteTreeDocumentAsMarkdown ( sourceUrl , document , writer ) ;
634+
635+ logger . LogTrace ( "Created markdown document with diagram " ) ;
636+ return options . Output . FullName ;
628637 }
629- logger . LogTrace ( "Created markdown document with diagram " ) ;
630- return options . Output . FullName ;
631638 }
632- }
639+ }
633640 }
634641 catch ( TaskCanceledException )
635642 {
@@ -645,7 +652,7 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
645652 private static void LogErrors ( ILogger logger , ReadResult result )
646653 {
647654 var context = result . Diagnostic ;
648- if ( context . Errors . Count != 0 )
655+ if ( context is not null && context . Errors . Count != 0 )
649656 {
650657 using ( logger . BeginScope ( "Detected errors" ) )
651658 {
@@ -697,7 +704,7 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d
697704 </style>
698705 <body>
699706 """ ) ;
700- writer . WriteLine ( "<h1>" + document . Info . Title + "</h1>" ) ;
707+ writer . WriteLine ( "<h1>" + document ? . Info . Title + "</h1>" ) ;
701708 writer . WriteLine ( ) ;
702709 writer . WriteLine ( $ "<h3> API Description: <a href='{ sourceUrl } '>{ sourceUrl } </a></h3>") ;
703710
@@ -751,7 +758,7 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
751758
752759 cancellationToken . ThrowIfCancellationRequested ( ) ;
753760
754- if ( options . FilterOptions != null )
761+ if ( options . FilterOptions != null && document is not null )
755762 {
756763 document = ApplyFilters ( options , logger , apiDependency , null , document ) ;
757764 }
@@ -765,24 +772,31 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
765772 // Write OpenAPI to Output folder
766773 options . Output = new ( Path . Combine ( options . OutputFolder , "openapi.json" ) ) ;
767774 options . TerseOutput = true ;
768- await WriteOpenApiAsync ( options , OpenApiFormat . Json , OpenApiSpecVersion . OpenApi3_1 , document , logger , cancellationToken ) . ConfigureAwait ( false ) ;
769-
770- // Create OpenAIPluginManifest from ApiDependency and OpenAPI document
771- var manifest = new OpenAIPluginManifest ( document . Info ? . Title ?? "Title" , document . Info ? . Title ?? "Title" , "https://go.microsoft.com/fwlink/?LinkID=288890" , document . Info ? . Contact ? . Email ?? "placeholder@contoso.com" , document . Info ? . License ? . Url . ToString ( ) ?? "https://placeholderlicenseurl.com" )
772- {
773- DescriptionForHuman = document . Info ? . Description ?? "Description placeholder" ,
774- Api = new ( "openapi" , "./openapi.json" ) ,
775- Auth = new ManifestNoAuth ( ) ,
776- } ;
777- manifest . NameForModel = manifest . NameForHuman ;
778- manifest . DescriptionForModel = manifest . DescriptionForHuman ;
779-
780- // Write OpenAIPluginManifest to Output folder
781- var manifestFile = new FileInfo ( Path . Combine ( options . OutputFolder , "ai-plugin.json" ) ) ;
782- using var file = new FileStream ( manifestFile . FullName , FileMode . Create ) ;
783- using var jsonWriter = new Utf8JsonWriter ( file , new ( ) { Indented = true } ) ;
784- manifest . Write ( jsonWriter ) ;
785- await jsonWriter . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
775+ if ( document is not null )
776+ {
777+ await WriteOpenApiAsync ( options , OpenApiFormat . Json , OpenApiSpecVersion . OpenApi3_1 , document , logger , cancellationToken ) . ConfigureAwait ( false ) ;
778+
779+ // Create OpenAIPluginManifest from ApiDependency and OpenAPI document
780+ var manifest = new OpenAIPluginManifest ( document . Info . Title ?? "Title" ,
781+ document . Info . Title ?? "Title" ,
782+ "https://go.microsoft.com/fwlink/?LinkID=288890" ,
783+ document . Info ? . Contact ? . Email ?? "placeholder@contoso.com" ,
784+ document . Info ? . License ? . Url ? . ToString ( ) ?? "https://placeholderlicenseurl.com" )
785+ {
786+ DescriptionForHuman = document . Info ? . Description ?? "Description placeholder" ,
787+ Api = new ( "openapi" , "./openapi.json" ) ,
788+ Auth = new ManifestNoAuth ( ) ,
789+ } ;
790+ manifest . NameForModel = manifest . NameForHuman ;
791+ manifest . DescriptionForModel = manifest . DescriptionForHuman ;
792+
793+ // Write OpenAIPluginManifest to Output folder
794+ var manifestFile = new FileInfo ( Path . Combine ( options . OutputFolder , "ai-plugin.json" ) ) ;
795+ using var file = new FileStream ( manifestFile . FullName , FileMode . Create ) ;
796+ using var jsonWriter = new Utf8JsonWriter ( file , new ( ) { Indented = true } ) ;
797+ manifest . Write ( jsonWriter ) ;
798+ await jsonWriter . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
799+ }
786800 }
787801 }
788802}
0 commit comments