ShowOpenApiDocumentAsync(HidiOptions options, ILogger logger, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(options.OpenApi) && string.IsNullOrEmpty(options.Csdl))
+ {
+ throw new ArgumentException("Please input a file path or URL");
+ }
+
+ var format = OpenApiModelFactory.GetFormat(options.OpenApi);
+ var document = await GetOpenApiAsync(options, format, logger, null, cancellationToken).ConfigureAwait(false);
+
+ using (logger.BeginScope("Creating diagram"))
+ {
+ // If output is null, create a HTML file in the user's temporary directory
+ var sourceUrl = (string.IsNullOrEmpty(options.OpenApi), string.IsNullOrEmpty(options.Csdl)) switch {
+ (false, _) => options.OpenApi!,
+ (_, false) => options.Csdl!,
+ _ => throw new InvalidOperationException("No input file path or URL provided")
+ };
+ if (options.Output == null)
+ {
+ var tempPath = Path.GetTempPath() + "/hidi/";
+ if (!File.Exists(tempPath))
+ {
+ Directory.CreateDirectory(tempPath);
+ }
+
+ var fileName = Path.GetRandomFileName();
+
+ var output = new FileInfo(Path.Combine(tempPath, fileName + ".html"));
+ using (var file = new FileStream(output.FullName, FileMode.Create))
+ {
+ using var writer = new StreamWriter(file);
+ WriteTreeDocumentAsHtml(sourceUrl, document, writer);
+ }
+ logger.LogTrace("Created Html document with diagram ");
+
+ // Launch a browser to display the output html file
+ using var process = new Process();
+ process.StartInfo.FileName = output.FullName;
+ process.StartInfo.UseShellExecute = true;
+ process.Start();
+
+ return output.FullName;
+ }
+ else // Write diagram as Markdown document to output file
+ {
+ using (var file = new FileStream(options.Output.FullName, FileMode.Create))
+ {
+ using var writer = new StreamWriter(file);
+ WriteTreeDocumentAsMarkdown(sourceUrl, document, writer);
+ }
+ logger.LogTrace("Created markdown document with diagram ");
+ return options.Output.FullName;
+ }
+ }
+ }
+ catch (TaskCanceledException)
+ {
+ await Console.Error.WriteLineAsync("CTRL+C pressed, aborting the operation.").ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"Could not generate the document, reason: {ex.Message}", ex);
+ }
+ return null;
+ }
+
+ private static void LogErrors(ILogger logger, ReadResult result)
+ {
+ var context = result.OpenApiDiagnostic;
+ if (context.Errors.Count != 0)
+ {
+ using (logger.BeginScope("Detected errors"))
+ {
+ foreach (var error in context.Errors)
+ {
+ logger.LogError("Detected error during parsing: {Error}", error.ToString());
+ }
+ }
+ }
+ }
+
+ internal static void WriteTreeDocumentAsMarkdown(string openapiUrl, OpenApiDocument document, StreamWriter writer)
+ {
+ var rootNode = OpenApiUrlTreeNode.Create(document, "main");
+
+ writer.WriteLine("# " + document.Info.Title);
+ writer.WriteLine();
+ writer.WriteLine("API Description: " + openapiUrl);
+
+ writer.WriteLine(@"");
+ // write a span for each mermaidcolorscheme
+ foreach (var style in OpenApiUrlTreeNode.MermaidNodeStyles)
+ {
+ writer.WriteLine($"{style.Key.Replace("_", " ", StringComparison.OrdinalIgnoreCase)}");
+ }
+ writer.WriteLine("
");
+ writer.WriteLine();
+ writer.WriteLine("```mermaid");
+ rootNode.WriteMermaid(writer);
+ writer.WriteLine("```");
+ }
+
+ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument document, StreamWriter writer, bool asHtmlFile = false)
+ {
+ var rootNode = OpenApiUrlTreeNode.Create(document, "main");
+
+ writer.WriteLine(
+ """
+
+
+
+
+
+
+
+
+ """);
+ writer.WriteLine("" + document.Info.Title + "
");
+ writer.WriteLine();
+ writer.WriteLine($"");
+
+ writer.WriteLine(@"");
+ // write a span for each mermaidcolorscheme
+ foreach (var style in OpenApiUrlTreeNode.MermaidNodeStyles)
+ {
+ writer.WriteLine($"{style.Key.Replace("_", " ", StringComparison.OrdinalIgnoreCase)}");
+ }
+
+ writer.WriteLine("
");
+ writer.WriteLine("
");
+ writer.WriteLine("");
+ rootNode.WriteMermaid(writer);
+ writer.WriteLine("");
+
+ // Write script tag to include JS library for rendering markdown
+ writer.WriteLine(
+ """
+
+ """);
+ // Write script tag to include JS library for rendering mermaid
+ writer.WriteLine(" OpenApiDescriptionOption = new("--openapi", "Input OpenAPI description file path or URL");
+ public readonly Option CsdlOption = new("--csdl", "Input CSDL file path or URL");
+ public readonly Option CsdlFilterOption = new("--csdl-filter", "Comma delimited list of EntitySets or Singletons to filter CSDL on. e.g. tasks,accounts");
+ public readonly Option OutputOption = new("--output", "The output file path for the generated file.") { Arity = ArgumentArity.ZeroOrOne };
+ public readonly Option OutputFolderOption = new("--output-folder", "The output directory path for the generated files.") { Arity = ArgumentArity.ZeroOrOne };
+ public readonly Option CleanOutputOption = new("--clean-output", "Overwrite an existing file");
+ public readonly Option VersionOption = new("--version", "OpenAPI specification version");
+ public readonly Option MetadataVersionOption = new("--metadata-version", "Graph metadata version to use.");
+ public readonly Option FormatOption = new("--format", "File format");
+ public readonly Option TerseOutputOption = new("--terse-output", "Produce terse json output");
+ public readonly Option SettingsFileOption = new("--settings-path", "The configuration file with CSDL conversion settings.");
+ public readonly Option LogLevelOption = new("--log-level", () => LogLevel.Information, "The log level to use when logging messages to the main output.");
+ public readonly Option FilterByOperationIdsOption = new("--filter-by-operationids", "Filters OpenApiDocument by comma delimited list of OperationId(s) provided");
+ public readonly Option FilterByTagsOption = new("--filter-by-tags", "Filters OpenApiDocument by comma delimited list of Tag(s) provided. Also accepts a single regex.");
+ public readonly Option FilterByCollectionOption = new("--filter-by-collection", "Filters OpenApiDocument by Postman collection provided. Provide path to collection file.");
+ public readonly Option ManifestOption = new("--manifest", "Path to API manifest file to locate and filter an OpenApiDocument");
+ public readonly Option InlineLocalOption = new("--inline-local", "Inline local $ref instances");
+ public readonly Option InlineExternalOption = new("--inline-external", "Inline external $ref instances");
+
+ public CommandOptions()
+ {
+ OpenApiDescriptionOption.AddAlias("-d");
+ CsdlOption.AddAlias("--cs");
+ CsdlFilterOption.AddAlias("--csf");
+ OutputOption.AddAlias("-o");
+ OutputFolderOption.AddAlias("--of");
+ CleanOutputOption.AddAlias("--co");
+ VersionOption.AddAlias("-v");
+ MetadataVersionOption.AddAlias("--mv");
+ FormatOption.AddAlias("-f");
+ TerseOutputOption.AddAlias("--to");
+ SettingsFileOption.AddAlias("--sp");
+ LogLevelOption.AddAlias("--ll");
+ FilterByOperationIdsOption.AddAlias("--op");
+ FilterByTagsOption.AddAlias("--t");
+ FilterByCollectionOption.AddAlias("-c");
+ ManifestOption.AddAlias("-m");
+ InlineLocalOption.AddAlias("--il");
+ InlineExternalOption.AddAlias("--ie");
+ }
+
+ public IReadOnlyList