Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
2b3abef
Adds nullability check to HasOperations method and updates/refactors …
irvinesunday Jun 7, 2021
6bb23b6
Adds setting to configure leaving stream open (#605)
irvinesunday Jun 14, 2021
0dc267c
Add a mock OpenApiDocument
MaggieKimani1 Oct 12, 2021
0ecca08
Add tests for filtering validation
MaggieKimani1 Oct 12, 2021
2f4a1c8
Add an OpenApi filtering service for filtering an OpenApiDocument bas…
MaggieKimani1 Oct 12, 2021
8e45f8b
Add necessary packages
MaggieKimani1 Oct 12, 2021
f270b90
Simplify using statement and switch condition
MaggieKimani1 Oct 12, 2021
9cda4fb
Use static class reference
MaggieKimani1 Oct 18, 2021
af61c14
Add --filterbyOperationId command option
MaggieKimani1 Oct 18, 2021
d24442d
Add filterByOperationId param and logic
MaggieKimani1 Oct 18, 2021
501e88c
Add static modifier
MaggieKimani1 Oct 18, 2021
d5b1b5e
Clean up and add xml comments
MaggieKimani1 Oct 18, 2021
4016ba1
Add a class that visits the OpenApi operations and returns the search…
MaggieKimani1 Oct 18, 2021
73bef22
Add a search result object model
MaggieKimani1 Oct 18, 2021
a1d46e5
Copies OpenApiOperation references to the new subset document
MaggieKimani1 Oct 18, 2021
68fc2de
Merge branch 'mk/add-filter-commandOption' into mk/add-filter-by-tags
MaggieKimani1 Oct 19, 2021
b3c79eb
Copy OpenApiInfo and components from the source document to the new s…
MaggieKimani1 Oct 20, 2021
cd5f3fa
Add an info object to the mock document
MaggieKimani1 Oct 20, 2021
3c43ea1
Clean up: Remove unnecessary params
MaggieKimani1 Oct 20, 2021
74a336b
Merge branch 'mk/add-filter-commandOption' into mk/add-filter-by-tags
MaggieKimani1 Oct 21, 2021
43f48ec
Remove package reference
MaggieKimani1 Oct 21, 2021
77063ae
Add test cases for filtering OpenApiDocument by tags provided
MaggieKimani1 Oct 25, 2021
8a60acf
Add --filterByTag command option
MaggieKimani1 Oct 25, 2021
c4aed08
Add a tags parameter to the filtering service to allow for slicing of…
MaggieKimani1 Oct 25, 2021
849d841
Add a filterByTag param and logic
MaggieKimani1 Oct 25, 2021
1553a0c
Code refactoring
MaggieKimani1 Oct 26, 2021
9931ddb
Merge branch 'mk/add-filter-commandOption' into mk/add-filter-by-tags
MaggieKimani1 Oct 26, 2021
8ba33cd
Revert "Remove package reference"
MaggieKimani1 Oct 21, 2021
2397e9d
Update the Public API interface text file
MaggieKimani1 Oct 26, 2021
d13dcf4
Remove unnecessary package dependency
MaggieKimani1 Oct 26, 2021
ad0bda0
Fixed spelling of "Path" (from "Past")
peteraritchie Oct 29, 2021
00dd9c4
Allow filtering for multiple operationIds
MaggieKimani1 Nov 1, 2021
3f3dae0
Add check for writing to an already existing file
MaggieKimani1 Nov 1, 2021
b6910f7
Merge branch 'mk/add-filter-commandOption' into mk/add-filter-by-tags
MaggieKimani1 Nov 1, 2021
5a3da1a
Code cleanup
MaggieKimani1 Nov 1, 2021
9af85db
Update the public API text file
MaggieKimani1 Nov 1, 2021
f33d1f6
Add license header
MaggieKimani1 Nov 2, 2021
27ab7f7
Copy over all Info properties
MaggieKimani1 Nov 2, 2021
c3c0abc
Add license header
MaggieKimani1 Nov 2, 2021
dbd8d92
Clean up and add XML documentations for public methods
MaggieKimani1 Nov 2, 2021
a689c36
Copy over extensions object to new document
MaggieKimani1 Nov 2, 2021
8fbb809
Update ci-build.yml for Azure Pipelines
MaggieKimani1 Nov 2, 2021
deaa2fe
Move declaration closer to first reference point
MaggieKimani1 Nov 3, 2021
015b3cd
Code cleanup
MaggieKimani1 Nov 4, 2021
58b380f
Merge pull request #642 from peteraritchie/patch-1
darrelmiller Nov 5, 2021
ac94489
Merge branch 'vnext' into mk/add-filter-commandOption
darrelmiller Nov 5, 2021
d259cc1
Remove [Fact] attribute
MaggieKimani1 Nov 5, 2021
f2102cc
Merge remote-tracking branch 'origin/mk/add-filter-commandOption' int…
MaggieKimani1 Nov 5, 2021
9f46c00
Merge pull request #636 from microsoft/mk/add-filter-commandOption
MaggieKimani1 Nov 5, 2021
d4451e9
Merge remote-tracking branch 'origin/vnext' into mk/add-filter-by-tags
MaggieKimani1 Nov 5, 2021
526162e
Remove unused variable
MaggieKimani1 Nov 5, 2021
1321c1e
Rename project and update namespaces
MaggieKimani1 Nov 8, 2021
fb5512c
Update build script and solution file
MaggieKimani1 Nov 8, 2021
e01b885
Rename the OpenApi.Tool to Hidi
MaggieKimani1 Nov 9, 2021
c900208
Address PR feedback
MaggieKimani1 Nov 9, 2021
d1a13a5
Update package name
MaggieKimani1 Nov 9, 2021
02eeec1
Merge branch 'vnext' into mk/add-cmdtool-build-task
MaggieKimani1 Nov 9, 2021
6acf634
Add validation check and add test
MaggieKimani1 Nov 9, 2021
403a40f
Rename tool to OpenApi.Hidi
MaggieKimani1 Nov 9, 2021
6922d61
Merge pull request #639 from microsoft/mk/add-filter-by-tags
darrelmiller Nov 9, 2021
0e63879
Merge branch 'vnext' into mk/add-cmdtool-build-task
darrelmiller Nov 9, 2021
e9f5257
Merge pull request #644 from microsoft/mk/add-cmdtool-build-task
MaggieKimani1 Nov 9, 2021
ba84828
Merge remote-tracking branch 'origin/vnext' into mk/rename-commandlin…
MaggieKimani1 Nov 10, 2021
97f4ac3
Remove whitespace
MaggieKimani1 Nov 10, 2021
ede11f1
Update solution file with the correct directory path
MaggieKimani1 Nov 10, 2021
431a4e9
Add blank line
MaggieKimani1 Nov 12, 2021
561b07a
Update .sln
MaggieKimani1 Nov 12, 2021
7b678a8
Revert
MaggieKimani1 Nov 12, 2021
733ca6b
Update dll path in launch.json
MaggieKimani1 Nov 12, 2021
520a55e
Update ci-cd.yml and codeql.yml files
MaggieKimani1 Nov 12, 2021
39f5bea
Update the tool's version
MaggieKimani1 Nov 16, 2021
0834f1f
Merge pull request #647 from microsoft/mk/rename-commandline-tool
MaggieKimani1 Nov 16, 2021
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
83 changes: 41 additions & 42 deletions src/Microsoft.OpenApi.Tool/OpenApiService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.IO;
using System.Linq;
using System.Net;
Expand All @@ -21,29 +23,44 @@ public static void ProcessOpenApiDocument(
FileInfo output,
OpenApiSpecVersion version,
OpenApiFormat format,
string filterByOperationIds,
bool inline,
bool resolveExternal)
{
if (input == null)
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException("input");
throw new ArgumentNullException(nameof(input));
}
if(output == null)
{
throw new ArgumentException(nameof(output));
}
if (output.Exists)
{
throw new IOException("The file you're writing to already exists. Please input a new output path.");
}

var stream = GetStream(input);

OpenApiDocument document;

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

OpenApiDocument document;
document = result.OpenApiDocument;

// Check if filter options are provided, then execute
if (!string.IsNullOrEmpty(filterByOperationIds))
{
var predicate = OpenApiFilterService.CreatePredicate(filterByOperationIds);
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
}

var context = result.OpenApiDiagnostic;

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

Expand All @@ -52,43 +69,26 @@ public static void ProcessOpenApiDocument(
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)
{
textWriter = new StreamWriter(outputStream);
}
else
{
textWriter = Console.Out;
}
using var outputStream = output?.Create();

var settings = new OpenApiWriterSettings()
{
ReferenceInline = inline == true ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
};
IOpenApiWriter writer;
switch (format)
{
case OpenApiFormat.Json:
writer = new OpenApiJsonWriter(textWriter, settings);
break;
case OpenApiFormat.Yaml:
writer = new OpenApiYamlWriter(textWriter, settings);
break;
default:
throw new ArgumentException("Unknown format");
}
var textWriter = outputStream != null ? new StreamWriter(outputStream) : Console.Out;

document.Serialize(writer, version);
var settings = new OpenApiWriterSettings()
{
ReferenceInline = inline ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
};
IOpenApiWriter writer = format switch
{
OpenApiFormat.Json => new OpenApiJsonWriter(textWriter, settings),
OpenApiFormat.Yaml => new OpenApiYamlWriter(textWriter, settings),
_ => throw new ArgumentException("Unknown format"),
};
document.Serialize(writer, version);

textWriter.Flush();
}
textWriter.Flush();
}

private static Stream GetStream(string input)
Expand Down Expand Up @@ -127,7 +127,6 @@ internal static void ValidateOpenApiDocument(string input)

document = new OpenApiStreamReader(new OpenApiReaderSettings
{
//ReferenceResolution = resolveExternal == true ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
}
).Read(stream, out var context);
Expand Down
32 changes: 7 additions & 25 deletions src/Microsoft.OpenApi.Tool/Program.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
using System;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Threading.Tasks;
using Microsoft.OpenApi;

namespace Microsoft.OpenApi.Tool
{
class Program
static class Program
{
static async Task<int> OldMain(string[] args)
{

var command = new RootCommand
{
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<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() {
Expand All @@ -47,9 +28,10 @@ static async Task<int> Main(string[] args)
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))
new Option("--resolveExternal","Resolve external $refs", typeof(bool)),
new Option("--filterByOperationIds", "Filters by OperationId provided", typeof(string))
};
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, bool, bool>(
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, string, bool, bool>(
OpenApiService.ProcessOpenApiDocument);

rootCommand.Add(transformCommand);
Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageIconUrl>http://go.microsoft.com/fwlink/?LinkID=288890</PackageIconUrl>
<PackageProjectUrl>https://github.com/Microsoft/OpenAPI.NET</PackageProjectUrl>
Expand Down Expand Up @@ -36,7 +37,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
112 changes: 112 additions & 0 deletions src/Microsoft.OpenApi/Services/CopyReferences.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System.Collections.Generic;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;

namespace Microsoft.OpenApi.Services
{
internal class CopyReferences : OpenApiVisitorBase
{
private readonly OpenApiDocument _target;
public OpenApiComponents Components = new();

public CopyReferences(OpenApiDocument target)
{
_target = target;
}

/// <summary>
/// Visits IOpenApiReferenceable instances that are references and not in components.
/// </summary>
/// <param name="referenceable"> An IOpenApiReferenceable object.</param>
public override void Visit(IOpenApiReferenceable referenceable)
{
switch (referenceable)
{
case OpenApiSchema schema:
EnsureComponentsExists();
EnsureSchemasExists();
if (!Components.Schemas.ContainsKey(schema.Reference.Id))
{
Components.Schemas.Add(schema.Reference.Id, schema);
}
break;

case OpenApiParameter parameter:
EnsureComponentsExists();
EnsureParametersExists();
if (!Components.Parameters.ContainsKey(parameter.Reference.Id))
{
Components.Parameters.Add(parameter.Reference.Id, parameter);
}
break;

case OpenApiResponse response:
EnsureComponentsExists();
EnsureResponsesExists();
if (!Components.Responses.ContainsKey(response.Reference.Id))
{
Components.Responses.Add(response.Reference.Id, response);
}
break;

default:
break;
}
base.Visit(referenceable);
}

/// <summary>
/// Visits <see cref="OpenApiSchema"/>
/// </summary>
/// <param name="schema">The OpenApiSchema to be visited.</param>
public override void Visit(OpenApiSchema schema)
{
// This is needed to handle schemas used in Responses in components
if (schema.Reference != null)
{
EnsureComponentsExists();
EnsureSchemasExists();
if (!Components.Schemas.ContainsKey(schema.Reference.Id))
{
Components.Schemas.Add(schema.Reference.Id, schema);
}
}
base.Visit(schema);
}

private void EnsureComponentsExists()
{
if (_target.Components == null)
{
_target.Components = new OpenApiComponents();
}
}

private void EnsureSchemasExists()
{
if (_target.Components.Schemas == null)
{
_target.Components.Schemas = new Dictionary<string, OpenApiSchema>();
}
}

private void EnsureParametersExists()
{
if (_target.Components.Parameters == null)
{
_target.Components.Parameters = new Dictionary<string, OpenApiParameter>();
}
}

private void EnsureResponsesExists()
{
if (_target.Components.Responses == null)
{
_target.Components.Responses = new Dictionary<string, OpenApiResponse>();
}
}
}
}
Loading