Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions install-tool.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
$latest = Get-ChildItem .\artifacts\ Microsoft.OpenApi.Tool* | select-object -Last 1
$version = $latest.Name.Split(".")[3..5] | join-string -Separator "."

if (Test-Path -Path ./artifacts/openapi-parser.exe) {
dotnet tool uninstall --tool-path artifacts Microsoft.OpenApi.Tool
}
dotnet tool install --tool-path artifacts --add-source .\artifacts\ --version $version Microsoft.OpenApi.Tool
6 changes: 3 additions & 3 deletions src/Microsoft.OpenApi.Tool/Microsoft.OpenApi.Tool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>openapi</ToolCommandName>
<ToolCommandName>openapi-parser</ToolCommandName>
<PackageOutputPath>./../../artifacts</PackageOutputPath>
<Version>1.3.0-preview</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21216.1" />
</ItemGroup>

<ItemGroup>
Expand All @@ -19,7 +19,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" />
</ItemGroup>

</Project>
112 changes: 90 additions & 22 deletions src/Microsoft.OpenApi.Tool/OpenApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Validations;
using Microsoft.OpenApi.Writers;

Expand All @@ -14,48 +17,57 @@ namespace Microsoft.OpenApi.Tool
static class OpenApiService
{
public static void ProcessOpenApiDocument(
FileInfo input,
string input,
FileInfo output,
OpenApiSpecVersion version,
OpenApiFormat format,
bool inline,
bool resolveExternal)
{
if (input == null)
{
throw new ArgumentNullException("input");
}

var stream = GetStream(input);

OpenApiDocument document;
using (Stream stream = input.OpenRead())

var result = new OpenApiStreamReader(new OpenApiReaderSettings
{
ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
}
).ReadAsync(stream).GetAwaiter().GetResult();

document = result.OpenApiDocument;
var context = result.OpenApiDiagnostic;

if (context.Errors.Count != 0)
{
var errorReport = new StringBuilder();

document = new OpenApiStreamReader(new OpenApiReaderSettings
foreach (var error in context.Errors)
{
ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
errorReport.AppendLine(error.ToString());
}
).Read(stream, out var context);
if (context.Errors.Count != 0)
{
var errorReport = new StringBuilder();

foreach (var error in context.Errors)
{
errorReport.AppendLine(error.ToString());
}

throw new ArgumentException(String.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray()));
}
throw new ArgumentException(String.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray()));
}

using (var outputStream = output?.Create())
{
TextWriter textWriter;

if (outputStream!=null)
if (outputStream != null)
{
textWriter = new StreamWriter(outputStream);
} else
}
else
{
textWriter = Console.Out;
}

var settings = new OpenApiWriterSettings()
{
ReferenceInline = inline == true ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
Expand All @@ -72,11 +84,67 @@ public static void ProcessOpenApiDocument(
default:
throw new ArgumentException("Unknown format");
}
document.Serialize(writer,version );

document.Serialize(writer, version);

textWriter.Flush();
}
}
}

private static Stream GetStream(string input)
{
Stream stream;
if (input.StartsWith("http"))
{
var httpClient = new HttpClient(new HttpClientHandler()
{
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
})
{
DefaultRequestVersion = HttpVersion.Version20
};
stream = httpClient.GetStreamAsync(input).Result;
}
else
{
var fileInput = new FileInfo(input);
stream = fileInput.OpenRead();
}

return stream;
}

internal static void ValidateOpenApiDocument(string input)
{
if (input == null)
{
throw new ArgumentNullException("input");
}

var stream = GetStream(input);

OpenApiDocument document;

document = new OpenApiStreamReader(new OpenApiReaderSettings
{
//ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
}
).Read(stream, out var context);

if (context.Errors.Count != 0)
{
foreach (var error in context.Errors)
{
Console.WriteLine(error.ToString());
}
}

var statsVisitor = new StatsVisitor();
var walker = new OpenApiWalker(statsVisitor);
walker.Walk(document);

Console.WriteLine(statsVisitor.GetStatisticsReport());
}
}
}
47 changes: 39 additions & 8 deletions src/Microsoft.OpenApi.Tool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,54 @@ namespace Microsoft.OpenApi.Tool
{
class Program
{
static async Task<int> Main(string[] args)
static async Task<int> OldMain(string[] args)
{

var command = new RootCommand
{
new Option("--input") { Argument = new Argument<FileInfo>() },
new Option("--output") { Argument = new Argument<FileInfo>() },
new Option("--version") { Argument = new Argument<OpenApiSpecVersion>() },
new Option("--format") { Argument = new Argument<OpenApiFormat>() },
new Option("--inline") { Argument = new Argument<bool>() },
new Option("--resolveExternal") { Argument = new Argument<bool>() }
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) ),
new Option("--output","Output OpenAPI description file", typeof(FileInfo), arity: ArgumentArity.ZeroOrOne),
new Option("--version", "OpenAPI specification version", typeof(OpenApiSpecVersion)),
new Option("--format", "File format",typeof(OpenApiFormat) ),
new Option("--inline", "Inline $ref instances", typeof(bool) ),
new Option("--resolveExternal","Resolve external $refs", typeof(bool))
};

command.Handler = CommandHandler.Create<FileInfo,FileInfo,OpenApiSpecVersion,OpenApiFormat,bool, bool>(
command.Handler = CommandHandler.Create<string,FileInfo,OpenApiSpecVersion,OpenApiFormat,bool, bool>(
OpenApiService.ProcessOpenApiDocument);

// Parse the incoming args and invoke the handler
return await command.InvokeAsync(args);
}

static async Task<int> Main(string[] args)
{
var rootCommand = new RootCommand() {
};

var validateCommand = new Command("validate")
{
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) )
};
validateCommand.Handler = CommandHandler.Create<string>(OpenApiService.ValidateOpenApiDocument);

var transformCommand = new Command("transform")
{
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) ),
new Option("--output","Output OpenAPI description file", typeof(FileInfo), arity: ArgumentArity.ZeroOrOne),
new Option("--version", "OpenAPI specification version", typeof(OpenApiSpecVersion)),
new Option("--format", "File format",typeof(OpenApiFormat) ),
new Option("--inline", "Inline $ref instances", typeof(bool) ),
new Option("--resolveExternal","Resolve external $refs", typeof(bool))
};
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, bool, bool>(
OpenApiService.ProcessOpenApiDocument);

rootCommand.Add(transformCommand);
rootCommand.Add(validateCommand);

// Parse the incoming args and invoke the handler
return await rootCommand.InvokeAsync(args);
}
}
}
91 changes: 91 additions & 0 deletions src/Microsoft.OpenApi.Tool/StatsVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Services;

namespace Microsoft.OpenApi.Tool
{
internal class StatsVisitor : OpenApiVisitorBase
{
public int ParameterCount { get; set; } = 0;

public override void Visit(OpenApiParameter parameter)
{
ParameterCount++;
}

public int SchemaCount { get; set; } = 0;

public override void Visit(OpenApiSchema schema)
{
SchemaCount++;
}

public int HeaderCount { get; set; } = 0;

public override void Visit(IDictionary<string, OpenApiHeader> headers)
{
HeaderCount++;
}

public int PathItemCount { get; set; } = 0;

public override void Visit(OpenApiPathItem pathItem)
{
PathItemCount++;
}

public int RequestBodyCount { get; set; } = 0;

public override void Visit(OpenApiRequestBody requestBody)
{
RequestBodyCount++;
}

public int ResponseCount { get; set; } = 0;

public override void Visit(OpenApiResponses response)
{
ResponseCount++;
}

public int OperationCount { get; set; } = 0;

public override void Visit(OpenApiOperation operation)
{
OperationCount++;
}

public int LinkCount { get; set; } = 0;

public override void Visit(OpenApiLink operation)
{
LinkCount++;
}

public int CallbackCount { get; set; } = 0;

public override void Visit(OpenApiCallback callback)
{
CallbackCount++;
}

public string GetStatisticsReport()
{
return $"Path Items: {PathItemCount}" + Environment.NewLine
+ $"Operations: {OperationCount}" + Environment.NewLine
+ $"Parameters: {ParameterCount}" + Environment.NewLine
+ $"Request Bodies: {RequestBodyCount}" + Environment.NewLine
+ $"Responses: {ResponseCount}" + Environment.NewLine
+ $"Links: {LinkCount}" + Environment.NewLine
+ $"Callbacks: {CallbackCount}" + Environment.NewLine
+ $"Schemas: {SchemaCount}" + Environment.NewLine;
}
}
}