Skip to content

Commit a008173

Browse files
authored
Merge pull request microsoft#596 from microsoft/dm/toolcleanup
Added transform and validate commands to the OpenAPI.Tool
2 parents a28f5dd + 7d236f8 commit a008173

File tree

5 files changed

+230
-33
lines changed

5 files changed

+230
-33
lines changed

install-tool.ps1

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
$latest = Get-ChildItem .\artifacts\ Microsoft.OpenApi.Tool* | select-object -Last 1
2+
$version = $latest.Name.Split(".")[3..5] | join-string -Separator "."
3+
4+
if (Test-Path -Path ./artifacts/openapi-parser.exe) {
5+
dotnet tool uninstall --tool-path artifacts Microsoft.OpenApi.Tool
6+
}
7+
dotnet tool install --tool-path artifacts --add-source .\artifacts\ --version $version Microsoft.OpenApi.Tool

src/Microsoft.OpenApi.Tool/Microsoft.OpenApi.Tool.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
<OutputType>Exe</OutputType>
55
<TargetFramework>netcoreapp3.1</TargetFramework>
66
<PackAsTool>true</PackAsTool>
7-
<ToolCommandName>openapi</ToolCommandName>
7+
<ToolCommandName>openapi-parser</ToolCommandName>
88
<PackageOutputPath>./../../artifacts</PackageOutputPath>
99
<Version>1.3.0-preview</Version>
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
13+
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21216.1" />
1414
</ItemGroup>
1515

1616
<ItemGroup>
@@ -19,7 +19,7 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22-
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
22+
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" />
2323
</ItemGroup>
2424

2525
</Project>

src/Microsoft.OpenApi.Tool/OpenApiService.cs

+90-22
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using System.Net;
6+
using System.Net.Http;
57
using System.Text;
68
using Microsoft.OpenApi.Extensions;
79
using Microsoft.OpenApi.Models;
810
using Microsoft.OpenApi.Readers;
11+
using Microsoft.OpenApi.Services;
912
using Microsoft.OpenApi.Validations;
1013
using Microsoft.OpenApi.Writers;
1114

@@ -14,48 +17,57 @@ namespace Microsoft.OpenApi.Tool
1417
static class OpenApiService
1518
{
1619
public static void ProcessOpenApiDocument(
17-
FileInfo input,
20+
string input,
1821
FileInfo output,
1922
OpenApiSpecVersion version,
2023
OpenApiFormat format,
2124
bool inline,
2225
bool resolveExternal)
2326
{
27+
if (input == null)
28+
{
29+
throw new ArgumentNullException("input");
30+
}
31+
32+
var stream = GetStream(input);
33+
2434
OpenApiDocument document;
25-
using (Stream stream = input.OpenRead())
35+
36+
var result = new OpenApiStreamReader(new OpenApiReaderSettings
37+
{
38+
ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
39+
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
40+
}
41+
).ReadAsync(stream).GetAwaiter().GetResult();
42+
43+
document = result.OpenApiDocument;
44+
var context = result.OpenApiDiagnostic;
45+
46+
if (context.Errors.Count != 0)
2647
{
48+
var errorReport = new StringBuilder();
2749

28-
document = new OpenApiStreamReader(new OpenApiReaderSettings
50+
foreach (var error in context.Errors)
2951
{
30-
ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
31-
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
52+
errorReport.AppendLine(error.ToString());
3253
}
33-
).Read(stream, out var context);
34-
if (context.Errors.Count != 0)
35-
{
36-
var errorReport = new StringBuilder();
37-
38-
foreach (var error in context.Errors)
39-
{
40-
errorReport.AppendLine(error.ToString());
41-
}
4254

43-
throw new ArgumentException(String.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray()));
44-
}
55+
throw new ArgumentException(String.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray()));
4556
}
4657

4758
using (var outputStream = output?.Create())
4859
{
4960
TextWriter textWriter;
5061

51-
if (outputStream!=null)
62+
if (outputStream != null)
5263
{
5364
textWriter = new StreamWriter(outputStream);
54-
} else
65+
}
66+
else
5567
{
5668
textWriter = Console.Out;
5769
}
58-
70+
5971
var settings = new OpenApiWriterSettings()
6072
{
6173
ReferenceInline = inline == true ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
@@ -72,11 +84,67 @@ public static void ProcessOpenApiDocument(
7284
default:
7385
throw new ArgumentException("Unknown format");
7486
}
75-
76-
document.Serialize(writer,version );
87+
88+
document.Serialize(writer, version);
7789

7890
textWriter.Flush();
7991
}
8092
}
81-
}
93+
94+
private static Stream GetStream(string input)
95+
{
96+
Stream stream;
97+
if (input.StartsWith("http"))
98+
{
99+
var httpClient = new HttpClient(new HttpClientHandler()
100+
{
101+
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
102+
})
103+
{
104+
DefaultRequestVersion = HttpVersion.Version20
105+
};
106+
stream = httpClient.GetStreamAsync(input).Result;
107+
}
108+
else
109+
{
110+
var fileInput = new FileInfo(input);
111+
stream = fileInput.OpenRead();
112+
}
113+
114+
return stream;
115+
}
116+
117+
internal static void ValidateOpenApiDocument(string input)
118+
{
119+
if (input == null)
120+
{
121+
throw new ArgumentNullException("input");
122+
}
123+
124+
var stream = GetStream(input);
125+
126+
OpenApiDocument document;
127+
128+
document = new OpenApiStreamReader(new OpenApiReaderSettings
129+
{
130+
//ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
131+
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
132+
}
133+
).Read(stream, out var context);
134+
135+
if (context.Errors.Count != 0)
136+
{
137+
foreach (var error in context.Errors)
138+
{
139+
Console.WriteLine(error.ToString());
140+
}
141+
}
142+
143+
var statsVisitor = new StatsVisitor();
144+
var walker = new OpenApiWalker(statsVisitor);
145+
walker.Walk(document);
146+
147+
Console.WriteLine(statsVisitor.GetStatisticsReport());
148+
}
149+
}
82150
}

src/Microsoft.OpenApi.Tool/Program.cs

+39-8
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,54 @@ namespace Microsoft.OpenApi.Tool
99
{
1010
class Program
1111
{
12-
static async Task<int> Main(string[] args)
12+
static async Task<int> OldMain(string[] args)
1313
{
14+
1415
var command = new RootCommand
1516
{
16-
new Option("--input") { Argument = new Argument<FileInfo>() },
17-
new Option("--output") { Argument = new Argument<FileInfo>() },
18-
new Option("--version") { Argument = new Argument<OpenApiSpecVersion>() },
19-
new Option("--format") { Argument = new Argument<OpenApiFormat>() },
20-
new Option("--inline") { Argument = new Argument<bool>() },
21-
new Option("--resolveExternal") { Argument = new Argument<bool>() }
17+
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) ),
18+
new Option("--output","Output OpenAPI description file", typeof(FileInfo), arity: ArgumentArity.ZeroOrOne),
19+
new Option("--version", "OpenAPI specification version", typeof(OpenApiSpecVersion)),
20+
new Option("--format", "File format",typeof(OpenApiFormat) ),
21+
new Option("--inline", "Inline $ref instances", typeof(bool) ),
22+
new Option("--resolveExternal","Resolve external $refs", typeof(bool))
2223
};
2324

24-
command.Handler = CommandHandler.Create<FileInfo,FileInfo,OpenApiSpecVersion,OpenApiFormat,bool, bool>(
25+
command.Handler = CommandHandler.Create<string,FileInfo,OpenApiSpecVersion,OpenApiFormat,bool, bool>(
2526
OpenApiService.ProcessOpenApiDocument);
2627

2728
// Parse the incoming args and invoke the handler
2829
return await command.InvokeAsync(args);
2930
}
31+
32+
static async Task<int> Main(string[] args)
33+
{
34+
var rootCommand = new RootCommand() {
35+
};
36+
37+
var validateCommand = new Command("validate")
38+
{
39+
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) )
40+
};
41+
validateCommand.Handler = CommandHandler.Create<string>(OpenApiService.ValidateOpenApiDocument);
42+
43+
var transformCommand = new Command("transform")
44+
{
45+
new Option("--input", "Input OpenAPI description file path or URL", typeof(string) ),
46+
new Option("--output","Output OpenAPI description file", typeof(FileInfo), arity: ArgumentArity.ZeroOrOne),
47+
new Option("--version", "OpenAPI specification version", typeof(OpenApiSpecVersion)),
48+
new Option("--format", "File format",typeof(OpenApiFormat) ),
49+
new Option("--inline", "Inline $ref instances", typeof(bool) ),
50+
new Option("--resolveExternal","Resolve external $refs", typeof(bool))
51+
};
52+
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, bool, bool>(
53+
OpenApiService.ProcessOpenApiDocument);
54+
55+
rootCommand.Add(transformCommand);
56+
rootCommand.Add(validateCommand);
57+
58+
// Parse the incoming args and invoke the handler
59+
return await rootCommand.InvokeAsync(args);
60+
}
3061
}
3162
}
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.OpenApi.Models;
10+
using Microsoft.OpenApi.Services;
11+
12+
namespace Microsoft.OpenApi.Tool
13+
{
14+
internal class StatsVisitor : OpenApiVisitorBase
15+
{
16+
public int ParameterCount { get; set; } = 0;
17+
18+
public override void Visit(OpenApiParameter parameter)
19+
{
20+
ParameterCount++;
21+
}
22+
23+
public int SchemaCount { get; set; } = 0;
24+
25+
public override void Visit(OpenApiSchema schema)
26+
{
27+
SchemaCount++;
28+
}
29+
30+
public int HeaderCount { get; set; } = 0;
31+
32+
public override void Visit(IDictionary<string, OpenApiHeader> headers)
33+
{
34+
HeaderCount++;
35+
}
36+
37+
public int PathItemCount { get; set; } = 0;
38+
39+
public override void Visit(OpenApiPathItem pathItem)
40+
{
41+
PathItemCount++;
42+
}
43+
44+
public int RequestBodyCount { get; set; } = 0;
45+
46+
public override void Visit(OpenApiRequestBody requestBody)
47+
{
48+
RequestBodyCount++;
49+
}
50+
51+
public int ResponseCount { get; set; } = 0;
52+
53+
public override void Visit(OpenApiResponses response)
54+
{
55+
ResponseCount++;
56+
}
57+
58+
public int OperationCount { get; set; } = 0;
59+
60+
public override void Visit(OpenApiOperation operation)
61+
{
62+
OperationCount++;
63+
}
64+
65+
public int LinkCount { get; set; } = 0;
66+
67+
public override void Visit(OpenApiLink operation)
68+
{
69+
LinkCount++;
70+
}
71+
72+
public int CallbackCount { get; set; } = 0;
73+
74+
public override void Visit(OpenApiCallback callback)
75+
{
76+
CallbackCount++;
77+
}
78+
79+
public string GetStatisticsReport()
80+
{
81+
return $"Path Items: {PathItemCount}" + Environment.NewLine
82+
+ $"Operations: {OperationCount}" + Environment.NewLine
83+
+ $"Parameters: {ParameterCount}" + Environment.NewLine
84+
+ $"Request Bodies: {RequestBodyCount}" + Environment.NewLine
85+
+ $"Responses: {ResponseCount}" + Environment.NewLine
86+
+ $"Links: {LinkCount}" + Environment.NewLine
87+
+ $"Callbacks: {CallbackCount}" + Environment.NewLine
88+
+ $"Schemas: {SchemaCount}" + Environment.NewLine;
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)