Skip to content

Commit 18482f3

Browse files
Merge pull request #1906 from microsoft/vnext
V2-preview1 release
2 parents 3e0a83f + 7f4f935 commit 18482f3

File tree

498 files changed

+19638
-11333
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

498 files changed

+19638
-11333
lines changed

src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ internal static class OpenApiExtensibleExtensions
1414
/// <returns>A <see cref="string"/> value matching the provided extensionKey. Return null when extensionKey is not found. </returns>
1515
internal static string GetExtension(this IDictionary<string, IOpenApiExtension> extensions, string extensionKey)
1616
{
17-
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiString castValue)
17+
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny castValue)
1818
{
19-
return castValue.Value;
19+
return castValue.Node.GetValue<string>();
2020
}
2121
return string.Empty;
2222
}

src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs

+11-10
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public override void Visit(OpenApiSchema schema)
5252

5353
public override void Visit(OpenApiPathItem pathItem)
5454
{
55-
if (pathItem.Operations.TryGetValue(OperationType.Put, out var value))
55+
if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) &&
56+
value.OperationId != null)
5657
{
5758
var operationId = value.OperationId;
5859
pathItem.Operations[OperationType.Put].OperationId = ResolvePutOperationId(operationId);
@@ -67,14 +68,14 @@ public override void Visit(OpenApiOperation operation)
6768
throw new ArgumentException($"OperationId is required {PathString}", nameof(operation));
6869

6970
var operationId = operation.OperationId;
70-
var operationTypeExtension = operation.Extensions.GetExtension("x-ms-docs-operation-type");
71+
var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type");
7172
if (operationTypeExtension.IsEquals("function"))
72-
operation.Parameters = ResolveFunctionParameters(operation.Parameters);
73+
operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List<OpenApiParameter>());
7374

7475
// Order matters. Resolve operationId.
7576
operationId = RemoveHashSuffix(operationId);
7677
if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function"))
77-
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters);
78+
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List<OpenApiParameter>());
7879
operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.'));
7980
operationId = ResolveODataCastOperationId(operationId);
8081
operationId = ResolveByRefOperationId(operationId);
@@ -165,10 +166,10 @@ private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiPa
165166
parameter.Content = null;
166167
parameter.Schema = new()
167168
{
168-
Type = "array",
169+
Type = JsonSchemaType.Array,
169170
Items = new()
170171
{
171-
Type = "string"
172+
Type = JsonSchemaType.String
172173
}
173174
};
174175
}
@@ -177,9 +178,9 @@ private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiPa
177178

178179
private void AddAdditionalPropertiesToSchema(OpenApiSchema schema)
179180
{
180-
if (schema != null && !_schemaLoop.Contains(schema) && "object".Equals(schema.Type, StringComparison.OrdinalIgnoreCase))
181+
if (schema != null && !_schemaLoop.Contains(schema) && schema.Type.Equals(JsonSchemaType.Object))
181182
{
182-
schema.AdditionalProperties = new() { Type = "object" };
183+
schema.AdditionalProperties = new() { Type = JsonSchemaType.Object };
183184

184185
/* Because 'additionalProperties' are now being walked,
185186
* we need a way to keep track of visited schemas to avoid
@@ -191,7 +192,7 @@ private void AddAdditionalPropertiesToSchema(OpenApiSchema schema)
191192

192193
private static void ResolveOneOfSchema(OpenApiSchema schema)
193194
{
194-
if (schema.OneOf?.FirstOrDefault() is {} newSchema)
195+
if (schema.OneOf?.FirstOrDefault() is { } newSchema)
195196
{
196197
schema.OneOf = null;
197198
FlattenSchema(schema, newSchema);
@@ -200,7 +201,7 @@ private static void ResolveOneOfSchema(OpenApiSchema schema)
200201

201202
private static void ResolveAnyOfSchema(OpenApiSchema schema)
202203
{
203-
if (schema.AnyOf?.FirstOrDefault() is {} newSchema)
204+
if (schema.AnyOf?.FirstOrDefault() is { } newSchema)
204205
{
205206
schema.AnyOf = null;
206207
FlattenSchema(schema, newSchema);

src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>

src/Microsoft.OpenApi.Hidi/OpenApiService.cs

+34-16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
using Microsoft.OpenApi.Hidi.Utilities;
3030
using Microsoft.OpenApi.Models;
3131
using Microsoft.OpenApi.OData;
32+
using Microsoft.OpenApi.Reader;
3233
using Microsoft.OpenApi.Readers;
3334
using Microsoft.OpenApi.Services;
3435
using Microsoft.OpenApi.Writers;
@@ -38,6 +39,12 @@ namespace Microsoft.OpenApi.Hidi
3839
{
3940
internal static class OpenApiService
4041
{
42+
static OpenApiService()
43+
{
44+
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
45+
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader());
46+
}
47+
4148
/// <summary>
4249
/// Implementation of the transform command
4350
/// </summary>
@@ -52,7 +59,12 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
5259
{
5360
if (options.Output == null)
5461
{
55-
var inputExtension = GetInputPathExtension(options.OpenApi, options.Csdl);
62+
#pragma warning disable CA1308 // Normalize strings to uppercase
63+
var extension = options.OpenApiFormat?.GetDisplayName().ToLowerInvariant();
64+
var inputExtension = !string.IsNullOrEmpty(extension) ? string.Concat(".", extension)
65+
: GetInputPathExtension(options.OpenApi, options.Csdl);
66+
67+
#pragma warning restore CA1308 // Normalize strings to uppercase
5668
options.Output = new($"./output{inputExtension}");
5769
};
5870

@@ -67,7 +79,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
6779

6880
// Default to yaml and OpenApiVersion 3 during csdl to OpenApi conversion
6981
var openApiFormat = options.OpenApiFormat ?? (!string.IsNullOrEmpty(options.OpenApi) ? GetOpenApiFormat(options.OpenApi, logger) : OpenApiFormat.Yaml);
70-
var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_0;
82+
var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_1;
7183

7284
// If ApiManifest is provided, set the referenced OpenAPI document
7385
var apiDependency = await FindApiDependencyAsync(options.FilterOptions.FilterByApiManifest, logger, cancellationToken).ConfigureAwait(false);
@@ -85,7 +97,8 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
8597
}
8698

8799
// Load OpenAPI document
88-
var document = await GetOpenApiAsync(options, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
100+
var format = OpenApiModelFactory.GetFormat(options.OpenApi);
101+
var document = await GetOpenApiAsync(options, format, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
89102

90103
if (options.FilterOptions != null)
91104
{
@@ -212,7 +225,7 @@ private static void WriteOpenApi(HidiOptions options, OpenApiFormat openApiForma
212225
}
213226

214227
// Get OpenAPI document either from OpenAPI or CSDL
215-
private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
228+
private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options, string format, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
216229
{
217230
OpenApiDocument document;
218231
Stream stream;
@@ -233,7 +246,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,
233246
await stream.DisposeAsync().ConfigureAwait(false);
234247
}
235248

236-
document = await ConvertCsdlToOpenApiAsync(filteredStream ?? stream, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false);
249+
document = await ConvertCsdlToOpenApiAsync(filteredStream ?? stream, format, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false);
237250
stopwatch.Stop();
238251
logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
239252
}
@@ -375,14 +388,16 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
375388
{
376389
stopwatch.Start();
377390

378-
result = await new OpenApiStreamReader(new()
379-
{
391+
var settings = new OpenApiReaderSettings
392+
{
380393
LoadExternalRefs = inlineExternal,
381394
BaseUrl = openApiFile.StartsWith("http", StringComparison.OrdinalIgnoreCase) ?
382395
new(openApiFile) :
383396
new Uri("file://" + new FileInfo(openApiFile).DirectoryName + Path.DirectorySeparatorChar)
384-
}
385-
).ReadAsync(stream, cancellationToken).ConfigureAwait(false);
397+
};
398+
399+
var format = OpenApiModelFactory.GetFormat(openApiFile);
400+
result = await OpenApiDocument.LoadAsync(stream, format, settings, cancellationToken).ConfigureAwait(false);
386401

387402
logger.LogTrace("{Timestamp}ms: Completed parsing.", stopwatch.ElapsedMilliseconds);
388403

@@ -398,15 +413,15 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
398413
/// </summary>
399414
/// <param name="csdl">The CSDL stream.</param>
400415
/// <returns>An OpenAPI document.</returns>
401-
public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
416+
public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl, string format, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
402417
{
403418
using var reader = new StreamReader(csdl);
404419
var csdlText = await reader.ReadToEndAsync(token).ConfigureAwait(false);
405420
var edmModel = CsdlReader.Parse(XElement.Parse(csdlText).CreateReader());
406421
settings ??= SettingsUtilities.GetConfiguration();
407422

408423
var document = edmModel.ConvertToOpenApi(SettingsUtilities.GetOpenApiConvertSettings(settings, metadataVersion));
409-
document = FixReferences(document);
424+
document = FixReferences(document, format);
410425

411426
return document;
412427
}
@@ -416,14 +431,15 @@ public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl,
416431
/// </summary>
417432
/// <param name="document"> The converted OpenApiDocument.</param>
418433
/// <returns> A valid OpenApiDocument instance.</returns>
419-
public static OpenApiDocument FixReferences(OpenApiDocument document)
434+
public static OpenApiDocument FixReferences(OpenApiDocument document, string format)
420435
{
421436
// This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
422437
// So we write it out, and read it back in again to fix it up.
423438

424439
var sb = new StringBuilder();
425440
document.SerializeAsV3(new OpenApiYamlWriter(new StringWriter(sb)));
426-
var doc = new OpenApiStringReader().Read(sb.ToString(), out _);
441+
442+
var doc = OpenApiDocument.Parse(sb.ToString(), format).OpenApiDocument;
427443

428444
return doc;
429445
}
@@ -571,7 +587,8 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
571587
throw new ArgumentException("Please input a file path or URL");
572588
}
573589

574-
var document = await GetOpenApiAsync(options, logger, null, cancellationToken).ConfigureAwait(false);
590+
var format = OpenApiModelFactory.GetFormat(options.OpenApi);
591+
var document = await GetOpenApiAsync(options, format, logger, null, cancellationToken).ConfigureAwait(false);
575592

576593
using (logger.BeginScope("Creating diagram"))
577594
{
@@ -732,7 +749,8 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
732749
}
733750

734751
// Load OpenAPI document
735-
var document = await GetOpenApiAsync(options, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
752+
var format = OpenApiModelFactory.GetFormat(options.OpenApi);
753+
var document = await GetOpenApiAsync(options, format, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
736754

737755
cancellationToken.ThrowIfCancellationRequested();
738756

@@ -750,7 +768,7 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
750768
// Write OpenAPI to Output folder
751769
options.Output = new(Path.Combine(options.OutputFolder, "openapi.json"));
752770
options.TerseOutput = true;
753-
WriteOpenApi(options, OpenApiFormat.Json, OpenApiSpecVersion.OpenApi3_0, document, logger);
771+
WriteOpenApi(options, OpenApiFormat.Json, OpenApiSpecVersion.OpenApi3_1, document, logger);
754772

755773
// Create OpenAIPluginManifest from ApiDependency and OpenAPI document
756774
var manifest = new OpenAIPluginManifest

src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs

+20-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license.
33

44
using System;
5-
using System.Linq;
65

76
namespace Microsoft.OpenApi.Hidi
87
{
@@ -14,17 +13,30 @@ public static OpenApiSpecVersion TryParseOpenApiSpecVersion(string value)
1413
{
1514
throw new InvalidOperationException("Please provide a version");
1615
}
17-
var res = value.Split('.', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
16+
// Split the version string by the dot
17+
var versionSegments = value.Split('.', StringSplitOptions.RemoveEmptyEntries);
1818

19-
if (int.TryParse(res, out var result))
19+
if (!int.TryParse(versionSegments[0], out var majorVersion)
20+
|| !int.TryParse(versionSegments[1], out var minorVersion))
2021
{
21-
if (result is >= 2 and < 3)
22-
{
23-
return OpenApiSpecVersion.OpenApi2_0;
24-
}
22+
throw new InvalidOperationException("Invalid version format. Please provide a valid OpenAPI version (e.g., 2.0, 3.0, 3.1).");
2523
}
2624

27-
return OpenApiSpecVersion.OpenApi3_0; // default
25+
// Check for specific version matches
26+
if (majorVersion == 2)
27+
{
28+
return OpenApiSpecVersion.OpenApi2_0;
29+
}
30+
else if (majorVersion == 3 && minorVersion == 0)
31+
{
32+
return OpenApiSpecVersion.OpenApi3_0;
33+
}
34+
else if (majorVersion == 3 && minorVersion == 1)
35+
{
36+
return OpenApiSpecVersion.OpenApi3_1;
37+
}
38+
39+
return OpenApiSpecVersion.OpenApi3_1; // default
2840
}
2941
}
3042
}

src/Microsoft.OpenApi.Hidi/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

44
using System.CommandLine;

src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs

-23
This file was deleted.

src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFramework>netstandard2.0</TargetFramework>
44
<LangVersion>latest</LangVersion>
55
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
6-
<Version>1.6.22</Version>
6+
<Version>2.0.0-preview1</Version>
77
<Description>OpenAPI.NET Readers for JSON and YAML documents</Description>
88
<SignAssembly>true</SignAssembly>
99
<!-- https://github.com/dotnet/sourcelink/blob/main/docs/README.md#embeduntrackedsources -->
@@ -17,6 +17,12 @@
1717
<AssemblyOriginatorKeyFile>..\Microsoft.OpenApi.snk</AssemblyOriginatorKeyFile>
1818
</PropertyGroup>
1919

20+
<ItemGroup>
21+
<Compile Remove="V31\**" />
22+
<EmbeddedResource Remove="V31\**" />
23+
<None Remove="V31\**" />
24+
</ItemGroup>
25+
2026
<ItemGroup>
2127

2228
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
@@ -25,6 +31,7 @@
2531
</PackageReference>
2632

2733
<PackageReference Include="SharpYaml" Version="2.1.1" />
34+
<PackageReference Include="System.Text.Json" Version="8.0.5" />
2835
</ItemGroup>
2936

3037
<ItemGroup>

0 commit comments

Comments
 (0)