diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9d7db69f9..534c8ff8b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.1.2" + ".": "3.1.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ed99a1173..44e6eba95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,15 @@ # Changelog -## [3.1.2](https://github.com/microsoft/OpenAPI.NET/compare/v3.1.1...v3.1.2) (2026-01-06) +## [3.1.3](https://github.com/microsoft/OpenAPI.NET/compare/v3.1.2...v3.1.3) (2026-01-16) +### Bug Fixes + +* Support custom tag ordering ([008576c](https://github.com/microsoft/OpenAPI.NET/commit/008576c31f8dcecf59363c9c2f85d691601faa73)) +* Support custom tag ordering ([7610d07](https://github.com/microsoft/OpenAPI.NET/commit/7610d07bd11a99a4ce1cc31338d180dbd764d952)) + +## [3.1.2](https://github.com/microsoft/OpenAPI.NET/compare/v3.1.1...v3.1.2) (2026-01-06) + ### Bug Fixes * correct error pointer when extension parser throws OpenApiException ([43c75a9](https://github.com/microsoft/OpenAPI.NET/commit/43c75a90746344fcc975611100e995fe4045edf0)) @@ -57,6 +64,21 @@ * adds support for OpenAPI 3.2.0 ([765a8dd](https://github.com/microsoft/OpenAPI.NET/commit/765a8dd4d6efd1a31b6a76d282ccffa5877a845a)) +## [2.4.3](https://github.com/microsoft/OpenAPI.NET/compare/v2.4.2...v2.4.3) (2026-01-16) + +## Bug Fixes + +* Support custom tag ordering ([008576c](https://github.com/microsoft/OpenAPI.NET/commit/008576c31f8dcecf59363c9c2f85d691601faa73)) +* Support custom tag ordering ([7610d07](https://github.com/microsoft/OpenAPI.NET/commit/7610d07bd11a99a4ce1cc31338d180dbd764d952)) + +## [2.4.2](https://github.com/microsoft/OpenAPI.NET/compare/v2.4.1...v2.4.2) (2025-12-22) + + +### Bug Fixes + +* wrap extension parser calls in try-catch to ensure correct error pointers ([63cf4a3](https://github.com/microsoft/OpenAPI.NET/commit/63cf4a3029fe2d285a6fe2724e30ffcf3bdd2f9f)) +* wrap extension parser calls in try-catch to ensure correct error pointers ([458cabe](https://github.com/microsoft/OpenAPI.NET/commit/458cabe6cd0fbdb192dbd17f2d6ab3b8162d1166)) + ## [2.4.1](https://github.com/microsoft/OpenAPI.NET/compare/v2.4.0...v2.4.1) (2025-12-18) ### Bug Fixes diff --git a/Directory.Build.props b/Directory.Build.props index c1b6e63d1..b0681cf72 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ https://github.com/Microsoft/OpenAPI.NET © Microsoft Corporation. All rights reserved. OpenAPI .NET - 3.1.2 + 3.1.3 diff --git a/global.json b/global.json index 3d946171e..4ca757b0e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.416" + "version": "8.0.417" } } \ No newline at end of file diff --git a/performance/resultsComparer/resultsComparer.csproj b/performance/resultsComparer/resultsComparer.csproj index aab8f01bb..248caf5fa 100644 --- a/performance/resultsComparer/resultsComparer.csproj +++ b/performance/resultsComparer/resultsComparer.csproj @@ -8,12 +8,12 @@ - - - - + + + + - + diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index 458972ef0..2e955f3a6 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -29,10 +29,10 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index c7af543df..96973a701 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -3,6 +3,9 @@ using System; using System.Collections.Generic; +#if NET +using System.Collections.Immutable; +#endif using System.IO; using System.Linq; using System.Security.Cryptography; @@ -88,9 +91,15 @@ public ISet? Tags { return; } - _tags = value is HashSet tags && tags.Comparer is OpenApiTagComparer ? - tags : - new HashSet(value, OpenApiTagComparer.Instance); + _tags = value switch + { + HashSet tags when tags.Comparer != EqualityComparer.Default => value, + SortedSet => value, +#if NET + ImmutableSortedSet => value, +#endif + _ => new HashSet(value, OpenApiTagComparer.Instance), + }; } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj index a49f77ebd..95365132f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj +++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj index 6913fdd97..8792e4404 100644 --- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj +++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index f62407b7b..1acd8ce8c 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -3,8 +3,11 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using VerifyXunit; @@ -2126,6 +2129,79 @@ public void DeduplicatesTags() Assert.Contains(document.Tags, t => t.Name == "tag2"); } + [Fact] + public void TagsSupportsCustomComparer() + { + var document = new OpenApiDocument + { + Tags = new HashSet(new CaseInsensitiveOpenApiTagEqualityComparer()), + }; + + Assert.True(document.Tags.Add(new OpenApiTag { Name = "Tag1" })); + Assert.False(document.Tags.Add(new OpenApiTag { Name = "tag1" })); + Assert.True(document.Tags.Add(new OpenApiTag { Name = "tag2" })); + Assert.False(document.Tags.Add(new OpenApiTag { Name = "TAG1" })); + Assert.Equal(2, document.Tags.Count); + } + + private sealed class CaseInsensitiveOpenApiTagEqualityComparer : IEqualityComparer + { + public bool Equals(OpenApiTag x, OpenApiTag y) + { + return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase); + } + + public int GetHashCode([DisallowNull] OpenApiTag obj) + { + return obj.Name.GetHashCode(StringComparison.OrdinalIgnoreCase); + } + } + + [Fact] + public void TagsSupportsSortedSets() + { + var document = new OpenApiDocument + { + Tags = new SortedSet(new DescendingOpenApiTagComparer()) + { + new OpenApiTag { Name = "tagB" }, + new OpenApiTag { Name = "tagA" }, + new OpenApiTag { Name = "tagC" }, + } + }; + + var names = document.Tags.Select(t => t.Name); + Assert.Equal(["tagC", "tagB", "tagA"], names); + Assert.IsType>(document.Tags); + } + + private sealed class DescendingOpenApiTagComparer : IComparer + { + public int Compare(OpenApiTag x, OpenApiTag y) + { + return string.Compare(y?.Name, x?.Name, StringComparison.Ordinal); + } + } + + [Fact] + public void TagsSupportsImmutableSortedSets() + { + var document = new OpenApiDocument + { + Tags = ImmutableSortedSet.Create( + new DescendingOpenApiTagComparer(), + [ + new OpenApiTag { Name = "tagB" }, + new OpenApiTag { Name = "tagA" }, + new OpenApiTag { Name = "tagC" }, + ]), + }; + + var names = document.Tags.Select(t => t.Name); + Assert.Equal(["tagC", "tagB", "tagA"], names); + Assert.IsType>(document.Tags); + } + public static TheoryData OpenApiSpecVersions() { var values = new TheoryData();