From b2ee215098635c0dc313a4894000f3a47adf8f8d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:52:35 +0000 Subject: [PATCH 1/9] Initial plan From bffc173788125651f20967388f3e7c169f22d554 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:03:53 +0000 Subject: [PATCH 2/9] chore: initial plan for fix-openapi-schema-reference-description Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index d72c3f669..459fe3e6e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.419" + "version": "8.0.418" } } \ No newline at end of file From 9b422bfbe1459588821ab011ba470336c63e4958 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:15:58 +0000 Subject: [PATCH 3/9] feat(library): add Extensions support for schema references in v3.1/v3.2; add SerializeAsV32 with loop detection - Add Extensions property to JsonSchemaReference (serialize in v3.1/v3.2 only) - Add Extensions setter to OpenApiSchemaReference (checks reference-level extensions first) - Add SerializeAsV32 override to OpenApiSchemaReference with loop detection - Read extension properties from $ref sibling keywords during v3.1 deserialization - Add tests for extensions in v3.1/v3.2 and verify extensions dropped in v3.0/v2 Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> --- .../Models/JsonSchemaReference.cs | 19 +++ .../References/OpenApiSchemaReference.cs | 12 +- src/Microsoft.OpenApi/PublicAPI.Unshipped.txt | 4 + ...orks_produceTerseOutput=False.verified.txt | 1 + ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 12 ++ ...Works_produceTerseOutput=True.verified.txt | 1 + .../References/OpenApiSchemaReferenceTests.cs | 161 +++++++++++++++++- 8 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=True.verified.txt diff --git a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs index 933a4a85b..443a47ab6 100644 --- a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs @@ -52,6 +52,12 @@ public class JsonSchemaReference : OpenApiReferenceWithDescription /// public IList? Examples { get; set; } + /// + /// Extension data for this schema reference. Only allowed in OpenAPI 3.1 and later. + /// Extensions are NOT written when serializing for OpenAPI 2.0 or 3.0. + /// + public IDictionary? Extensions { get; set; } + /// /// Parameterless constructor /// @@ -69,6 +75,7 @@ public JsonSchemaReference(JsonSchemaReference reference) : base(reference) ReadOnly = reference.ReadOnly; WriteOnly = reference.WriteOnly; Examples = reference.Examples; + Extensions = reference.Extensions != null ? new Dictionary(reference.Extensions) : null; } /// @@ -106,6 +113,7 @@ private void SerializeAdditionalV3XProperties(IOpenApiWriter writer, Action w.WriteAny(e)); } + writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_1); } /// @@ -146,5 +154,16 @@ protected override void SetAdditional31MetadataFromMapNode(JsonObject jsonObject { Examples = examplesArray.OfType().ToList(); } + + // Extensions (properties starting with "x-") + foreach (var property in jsonObject) + { + if (property.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase) + && property.Value is JsonNode extensionValue) + { + Extensions ??= new Dictionary(StringComparer.OrdinalIgnoreCase); + Extensions[property.Key] = new JsonNodeExtension(extensionValue.DeepClone()); + } + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 55be30a51..1e5970f3a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -158,7 +158,11 @@ public bool Deprecated /// public OpenApiXml? Xml { get => Target?.Xml; } /// - public IDictionary? Extensions { get => Target?.Extensions; } + public IDictionary? Extensions + { + get => Reference.Extensions ?? Target?.Extensions; + set => Reference.Extensions = value; + } /// public IDictionary? UnrecognizedKeywords { get => Target?.UnrecognizedKeywords; } @@ -172,6 +176,12 @@ public override void SerializeAsV31(IOpenApiWriter writer) SerializeAsWithoutLoops(writer, (w, element) => (element is IOpenApiSchema s ? CopyReferenceAsTargetElementWithOverrides(s) : element).SerializeAsV31(w)); } + /// + public override void SerializeAsV32(IOpenApiWriter writer) + { + SerializeAsWithoutLoops(writer, (w, element) => (element is IOpenApiSchema s ? CopyReferenceAsTargetElementWithOverrides(s) : element).SerializeAsV32(w)); + } + /// public override void SerializeAsV3(IOpenApiWriter writer) { diff --git a/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt index 7dc5c5811..7b7b54aca 100644 --- a/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt @@ -1 +1,5 @@ #nullable enable +Microsoft.OpenApi.JsonSchemaReference.Extensions.get -> System.Collections.Generic.IDictionary? +Microsoft.OpenApi.JsonSchemaReference.Extensions.set -> void +Microsoft.OpenApi.OpenApiSchemaReference.Extensions.set -> void +override Microsoft.OpenApi.OpenApiSchemaReference.SerializeAsV32(Microsoft.OpenApi.IOpenApiWriter! writer) -> void diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt index 3d7372e1b..87dbbe91f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt @@ -7,5 +7,6 @@ "examples": [ "reference example" ], + "x-custom": "custom value", "$ref": "#/components/schemas/Pet" } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt index 2a7cc8e44..c7f7f3cd0 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"description":"Reference Description","default":"reference default","title":"Reference Title","deprecated":true,"readOnly":true,"examples":["reference example"],"$ref":"#/components/schemas/Pet"} \ No newline at end of file +{"description":"Reference Description","default":"reference default","title":"Reference Title","deprecated":true,"readOnly":true,"examples":["reference example"],"x-custom":"custom value","$ref":"#/components/schemas/Pet"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=False.verified.txt new file mode 100644 index 000000000..87dbbe91f --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=False.verified.txt @@ -0,0 +1,12 @@ +{ + "description": "Reference Description", + "default": "reference default", + "title": "Reference Title", + "deprecated": true, + "readOnly": true, + "examples": [ + "reference example" + ], + "x-custom": "custom value", + "$ref": "#/components/schemas/Pet" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=True.verified.txt new file mode 100644 index 000000000..c7f7f3cd0 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV32JsonWorks_produceTerseOutput=True.verified.txt @@ -0,0 +1 @@ +{"description":"Reference Description","default":"reference default","title":"Reference Title","deprecated":true,"readOnly":true,"examples":["reference example"],"x-custom":"custom value","$ref":"#/components/schemas/Pet"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs index 57ccae0cb..f82391b12 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs @@ -133,7 +133,11 @@ public async Task SerializeSchemaReferenceAsV31JsonWorks(bool produceTerseOutput WriteOnly = false, Deprecated = true, Default = JsonValue.Create("reference default"), - Examples = new List { JsonValue.Create("reference example") } + Examples = new List { JsonValue.Create("reference example") }, + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } }; var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); @@ -150,7 +154,7 @@ public async Task SerializeSchemaReferenceAsV31JsonWorks(bool produceTerseOutput [Theory] [InlineData(true)] [InlineData(false)] - public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput) + public async Task SerializeSchemaReferenceAsV32JsonWorks(bool produceTerseOutput) { // Arrange var reference = new OpenApiSchemaReference("Pet", null) @@ -161,7 +165,43 @@ public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput) WriteOnly = false, Deprecated = true, Default = JsonValue.Create("reference default"), - Examples = new List { JsonValue.Create("reference example") } + Examples = new List { JsonValue.Create("reference example") }, + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } + }; + + var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput }); + + // Act + reference.SerializeAsV32(writer); + await writer.FlushAsync(); + + // Assert + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput) + { + // Arrange - Extensions should NOT appear in v3.0 output + var reference = new OpenApiSchemaReference("Pet", null) + { + Title = "Reference Title", + Description = "Reference Description", + ReadOnly = true, + WriteOnly = false, + Deprecated = true, + Default = JsonValue.Create("reference default"), + Examples = new List { JsonValue.Create("reference example") }, + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } }; var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); @@ -256,5 +296,120 @@ public void ParseSchemaReferenceWithAnnotationsWorks() Assert.Equal("Original Pet Title", targetSchema.Title); Assert.Equal("Original Pet Description", targetSchema.Description); } + + [Fact] + public void ParseSchemaReferenceWithExtensionsWorks() + { + // Arrange + var jsonContent = @"{ + ""openapi"": ""3.1.0"", + ""info"": { + ""title"": ""Test API"", + ""version"": ""1.0.0"" + }, + ""paths"": { + ""/test"": { + ""get"": { + ""responses"": { + ""200"": { + ""description"": ""OK"", + ""content"": { + ""application/json"": { + ""schema"": { + ""$ref"": ""#/components/schemas/Pet"", + ""description"": ""A pet object"", + ""x-custom-extension"": ""custom value"", + ""x-another-extension"": 42 + } + } + } + } + } + } + } + }, + ""components"": { + ""schemas"": { + ""Pet"": { + ""type"": ""object"", + ""properties"": { + ""name"": { + ""type"": ""string"" + } + } + } + } + } +}"; + + // Act + var readResult = OpenApiDocument.Parse(jsonContent, "json"); + var document = readResult.Document; + + // Assert + Assert.NotNull(document); + Assert.Empty(readResult.Diagnostic.Errors); + + var schema = document.Paths["/test"].Operations[HttpMethod.Get] + .Responses["200"].Content["application/json"].Schema; + + Assert.IsType(schema); + var schemaRef = (OpenApiSchemaReference)schema; + + // Test that reference-level extensions are parsed + Assert.NotNull(schemaRef.Extensions); + Assert.Contains("x-custom-extension", schemaRef.Extensions.Keys); + Assert.Contains("x-another-extension", schemaRef.Extensions.Keys); + } + + [Fact] + public async Task SchemaReferenceExtensionsNotWrittenInV30() + { + // Arrange + var reference = new OpenApiSchemaReference("Pet", null) + { + Description = "Local description", + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } + }; + + var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = true }); + + // Act + reference.SerializeAsV3(writer); + await writer.FlushAsync(); + var output = outputStringWriter.ToString(); + + // Assert: In v3.0, ONLY $ref should appear - no description, no extensions + Assert.Equal(@"{""$ref"":""#/components/schemas/Pet""}", output); + } + + [Fact] + public async Task SchemaReferenceExtensionsNotWrittenInV2() + { + // Arrange + var reference = new OpenApiSchemaReference("Pet", null) + { + Description = "Local description", + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } + }; + + var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = true }); + + // Act + reference.SerializeAsV2(writer); + await writer.FlushAsync(); + var output = outputStringWriter.ToString(); + + // Assert: In v2, ONLY $ref should appear - no description, no extensions + Assert.Equal(@"{""$ref"":""#/definitions/Pet""}", output); + } } } From fa9c408c2ea8178423b2a67ebb3b4e26c23677fc Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 17 Mar 2026 14:31:39 -0400 Subject: [PATCH 4/9] chore: adds missing interface implementation to OpenAPISchemaReference Signed-off-by: Vincent Biret --- .../Models/References/OpenApiSchemaReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 1e5970f3a..67eb79645 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -10,7 +10,7 @@ namespace Microsoft.OpenApi /// /// Schema reference object /// - public class OpenApiSchemaReference : BaseOpenApiReferenceHolder, IOpenApiSchema, IOpenApiSchemaWithUnevaluatedProperties + public class OpenApiSchemaReference : BaseOpenApiReferenceHolder, IOpenApiSchema, IOpenApiSchemaWithUnevaluatedProperties, IOpenApiExtensible { /// From 27779300f388b3aae0d245bc173d3d9c49a6fac5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 17 Mar 2026 14:35:56 -0400 Subject: [PATCH 5/9] chore: reverts global.json changes --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 459fe3e6e..d72c3f669 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.418" + "version": "8.0.419" } } \ No newline at end of file From 88cbeaa16633aacad7882f5474bf8c5f9401d538 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 17 Mar 2026 14:40:01 -0400 Subject: [PATCH 6/9] tests: adds a negative test for v2 peer keywords serialization of schema references Signed-off-by: Vincent Biret --- ...orks_produceTerseOutput=False.verified.txt | 3 ++ ...Works_produceTerseOutput=True.verified.txt | 1 + .../References/OpenApiSchemaReferenceTests.cs | 32 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt new file mode 100644 index 000000000..ddb324ad6 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/definitions/Pet" +} diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt new file mode 100644 index 000000000..b36112c01 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.SerializeSchemaReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/definitions/Pet"} diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs index f82391b12..488488518 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSchemaReferenceTests.cs @@ -215,6 +215,38 @@ public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput) await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task SerializeSchemaReferenceAsV2JsonWorks(bool produceTerseOutput) + { + // Arrange - Extensions should NOT appear in v2 output + var reference = new OpenApiSchemaReference("Pet", null) + { + Title = "Reference Title", + Description = "Reference Description", + ReadOnly = true, + WriteOnly = false, + Deprecated = true, + Default = JsonValue.Create("reference default"), + Examples = new List { JsonValue.Create("reference example") }, + Extensions = new Dictionary + { + ["x-custom"] = new JsonNodeExtension(JsonValue.Create("custom value")) + } + }; + + var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput }); + + // Act + reference.SerializeAsV2(writer); + await writer.FlushAsync(); + + // Assert + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + } + [Fact] public void ParseSchemaReferenceWithAnnotationsWorks() { From cba3dda0e518500deb966803c54be51725289423 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Mar 2026 09:07:14 -0400 Subject: [PATCH 7/9] chore: linting Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/JsonSchemaReference.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs index 443a47ab6..b3856a3e5 100644 --- a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -156,10 +156,10 @@ protected override void SetAdditional31MetadataFromMapNode(JsonObject jsonObject } // Extensions (properties starting with "x-") - foreach (var property in jsonObject) + foreach (var property in jsonObject + .Where(static p => p.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase))) { - if (property.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase) - && property.Value is JsonNode extensionValue) + if (property.Value is JsonNode extensionValue) { Extensions ??= new Dictionary(StringComparer.OrdinalIgnoreCase); Extensions[property.Key] = new JsonNodeExtension(extensionValue.DeepClone()); From 06fb78ff7b3e28c5c46807013e289b026fadacb7 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Mar 2026 09:36:23 -0400 Subject: [PATCH 8/9] chore: further linting to reduce looping Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/Microsoft.OpenApi/Models/JsonSchemaReference.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs index b3856a3e5..824a3ebe1 100644 --- a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs @@ -157,13 +157,12 @@ protected override void SetAdditional31MetadataFromMapNode(JsonObject jsonObject // Extensions (properties starting with "x-") foreach (var property in jsonObject - .Where(static p => p.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase))) + .Where(static p => p.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase)) + .Where(static p => p.Value is JsonNode)) { - if (property.Value is JsonNode extensionValue) - { - Extensions ??= new Dictionary(StringComparer.OrdinalIgnoreCase); - Extensions[property.Key] = new JsonNodeExtension(extensionValue.DeepClone()); - } + var extensionValue = (JsonNode)property.Value!; + Extensions ??= new Dictionary(StringComparer.OrdinalIgnoreCase); + Extensions[property.Key] = new JsonNodeExtension(extensionValue.DeepClone()); } } } From 45dc6b334ab82f09a951db9388d423a744996bee Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Mar 2026 09:47:39 -0400 Subject: [PATCH 9/9] chore: lints redundant checks Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/JsonSchemaReference.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs index 824a3ebe1..2893a7d22 100644 --- a/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/JsonSchemaReference.cs @@ -157,10 +157,10 @@ protected override void SetAdditional31MetadataFromMapNode(JsonObject jsonObject // Extensions (properties starting with "x-") foreach (var property in jsonObject - .Where(static p => p.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase)) - .Where(static p => p.Value is JsonNode)) + .Where(static p => p.Key.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase) + && p.Value is not null)) { - var extensionValue = (JsonNode)property.Value!; + var extensionValue = property.Value!; Extensions ??= new Dictionary(StringComparer.OrdinalIgnoreCase); Extensions[property.Key] = new JsonNodeExtension(extensionValue.DeepClone()); }