From 52981d4cebf4831f94dd59968231740e7891c5a3 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 22 Jan 2025 10:52:14 -0500 Subject: [PATCH 001/103] fix: a flaky behaviour for format property serialization Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index d2ffa88ed..dcab7de86 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -583,14 +583,7 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.Type, Type.ToIdentifier()); // format - if (string.IsNullOrEmpty(Format)) - { - Format = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? - AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? - OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format; - } - - writer.WriteProperty(OpenApiConstants.Format, Format); + WriteFormatProperty(writer); // items writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w)); @@ -643,6 +636,19 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer) writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi2_0); } + private void WriteFormatProperty(IOpenApiWriter writer) + { + var formatToWrite = Format; + if (string.IsNullOrEmpty(formatToWrite)) + { + formatToWrite = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? + AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? + OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format; + } + + writer.WriteProperty(OpenApiConstants.Format, formatToWrite); + } + /// /// Serialize to Open Api v2.0 and handles not marking the provided property /// as readonly if its included in the provided list of required properties of parent schema. @@ -666,14 +672,7 @@ internal virtual void SerializeAsV2( writer.WriteProperty(OpenApiConstants.Description, Description); // format - if (string.IsNullOrEmpty(Format)) - { - Format = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? - AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? - OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format; - } - - writer.WriteProperty(OpenApiConstants.Format, Format); + WriteFormatProperty(writer); // title writer.WriteProperty(OpenApiConstants.Title, Title); From 8a2b07c81d82a7c2dd0d5eb3e5589b103fbc299c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 21 Jan 2025 15:31:44 -0500 Subject: [PATCH 002/103] chore: linting Signed-off-by: Vincent Biret --- .../Models/References/OpenApiRequestBodyReference.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 598d70310..5b8001990 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -92,7 +92,6 @@ public override void SerializeAsV3(IOpenApiWriter writer) if (!writer.GetSettings().ShouldInlineReference(_reference)) { _reference.SerializeAsV3(writer); - return; } else { @@ -106,7 +105,6 @@ public override void SerializeAsV31(IOpenApiWriter writer) if (!writer.GetSettings().ShouldInlineReference(_reference)) { _reference.SerializeAsV31(writer); - return; } else { From b84ea194a16e03a1f2b6f56af892eb6288d5627a Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 22 Jan 2025 10:24:08 -0500 Subject: [PATCH 003/103] fix: request body references are converted to v2 properly Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiOperation.cs | 4 ++-- src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs | 2 +- .../References/OpenApiRequestBodyReference.cs | 13 +++++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 1ce80f092..047062874 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -283,7 +283,7 @@ public void SerializeAsV2(IOpenApiWriter writer) { foreach (var requestBody in Components.RequestBodies.Where(b => !parameters.ContainsKey(b.Key))) { - parameters.Add(requestBody.Key, requestBody.Value.ConvertToBodyParameter()); + parameters.Add(requestBody.Key, requestBody.Value.ConvertToBodyParameter(writer)); } } writer.WriteOptionalMap( diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index efd586e80..7e3b5d712 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -212,7 +212,7 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version /// public void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); writer.WriteStartObject(); @@ -258,7 +258,7 @@ public void SerializeAsV2(IOpenApiWriter writer) } else { - parameters.Add(RequestBody.ConvertToBodyParameter()); + parameters.Add(RequestBody.ConvertToBodyParameter(writer)); } } else if (RequestBody.Reference != null && RequestBody.Reference.HostDocument is {} hostDocument) diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 037e7d92c..0fb16471f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -112,7 +112,7 @@ public void SerializeAsV2(IOpenApiWriter writer) // RequestBody object does not exist in V2. } - internal OpenApiBodyParameter ConvertToBodyParameter() + internal virtual OpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) { var bodyParameter = new OpenApiBodyParameter { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 5b8001990..59fb27724 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -119,5 +119,18 @@ private void SerializeInternal(IOpenApiWriter writer, Utils.CheckArgumentNull(writer); action(writer, Target); } + + /// + internal override OpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + { + if (writer.GetSettings().ShouldInlineReference(_reference)) + { + return Target.ConvertToBodyParameter(writer); + } + else + { + return new OpenApiParameterReference(_reference.Id, _reference.HostDocument); + } + } } } From 03436cb8560227fd8b2e07b3405e6d077df663b3 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 22 Jan 2025 15:11:53 -0500 Subject: [PATCH 004/103] chore: adds unit test for v2 request body reference fix Signed-off-by: Vincent Biret --- .../V2Tests/OpenApiOperationTests.cs | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index 7c76c424c..1d7fd39d3 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; using Microsoft.OpenApi.Reader.V3; @@ -507,5 +508,99 @@ public async Task LoadV3ExamplesInRequestBodyParameterAsExtensionsWorks() expected = expected.MakeLineBreaksEnvironmentNeutral(); Assert.Equal(expected, actual); } + [Fact] + public async Task SerializesBodyReferencesWorks() + { + var openApiDocument = new OpenApiDocument(); + + var operation = new OpenApiOperation + { + RequestBody = new OpenApiRequestBodyReference("UserRequest", openApiDocument) + { + Description = "User request body" + } + }; + openApiDocument.Paths.Add("/users", new OpenApiPathItem + { + Operations = new Dictionary + { + [OperationType.Post] = operation + } + }); + openApiDocument.AddComponent("UserRequest", new OpenApiRequestBody + { + Description = "User creation request body", + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchemaReference("UserSchema", openApiDocument) + } + } + }); + openApiDocument.AddComponent("UserSchema", new OpenApiSchema + { + Type = JsonSchemaType.Object, + Properties = + { + ["name"] = new OpenApiSchema + { + Type = JsonSchemaType.String + }, + ["email"] = new OpenApiSchema + { + Type = JsonSchemaType.String + } + } + }); + + var actual = await openApiDocument.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); + var expected = +""" +{ + "swagger": "2.0", + "info": { }, + "paths": { + "/users": { + "post": { + "consumes": [ + "application/json" + ], + "parameters": [ + { + "$ref": "#/parameters/UserRequest" + } + ], + "responses": { } + } + } + }, + "definitions": { + "UserSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + } + } + }, + "parameters": { + "UserRequest": { + "in": "body", + "name": "body", + "description": "User creation request body", + "schema": { + "$ref": "#/definitions/UserSchema" + } + } + } +} +"""; + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); + } } } From 42438730a57acada699a017da41838d0d54e141d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 22 Jan 2025 15:39:05 -0500 Subject: [PATCH 005/103] fix: open api response reference should not clone objects --- .../References/OpenApiResponseReference.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index 0e4ac30ac..2ac8aee27 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -28,9 +28,7 @@ public OpenApiResponse Target get { _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); - OpenApiResponse resolved = new OpenApiResponse(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; + return _target; } } @@ -75,21 +73,25 @@ internal OpenApiResponseReference(string referenceId, OpenApiResponse target) /// public override string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; + get => string.IsNullOrEmpty(_description) ? Target?.Description : _description; set => _description = value; } + private IDictionary _content; /// - public override IDictionary Content { get => Target?.Content; set => Target.Content = value; } + public override IDictionary Content { get => _content is not null ? _content : Target?.Content; set => _content = value; } + private IDictionary _headers; /// - public override IDictionary Headers { get => Target.Headers; set => Target.Headers = value; } + public override IDictionary Headers { get => _headers is not null ? _headers : Target?.Headers; set => _headers = value; } + private IDictionary _links; /// - public override IDictionary Links { get => Target.Links; set => Target.Links = value; } + public override IDictionary Links { get => _links is not null ? _links : Target?.Links; set => _links = value; } + private IDictionary _extensions; /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public override IDictionary Extensions { get => _extensions is not null ? _extensions : Target?.Extensions; set => _extensions = value; } /// public override void SerializeAsV3(IOpenApiWriter writer) @@ -97,7 +99,6 @@ public override void SerializeAsV3(IOpenApiWriter writer) if (!writer.GetSettings().ShouldInlineReference(_reference)) { _reference.SerializeAsV3(writer); - return; } else { @@ -111,7 +112,6 @@ public override void SerializeAsV31(IOpenApiWriter writer) if (!writer.GetSettings().ShouldInlineReference(_reference)) { _reference.SerializeAsV31(writer); - return; } else { @@ -125,7 +125,6 @@ public override void SerializeAsV2(IOpenApiWriter writer) if (!writer.GetSettings().ShouldInlineReference(_reference)) { _reference.SerializeAsV2(writer); - return; } else { From 7405f3c0c2d48b9b124a28796c3a7e9bce909aa7 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Jan 2025 08:56:00 -0500 Subject: [PATCH 006/103] feat: makes the reference interface covariant Signed-off-by: Vincent Biret --- .../Interfaces/IOpenApiReferenceableWithTarget.cs | 2 +- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs index fc4c1daed..85bc1987d 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs @@ -7,7 +7,7 @@ namespace Microsoft.OpenApi.Interfaces /// A generic interface for OpenApiReferenceable objects that have a target. /// /// - public interface IOpenApiReferenceableWithTarget : IOpenApiReferenceable + public interface IOpenApiReferenceableWithTarget : IOpenApiReferenceable { /// /// Gets the resolved target object. diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 887fb3db8..4ffbcd4ff 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -223,7 +223,7 @@ namespace Microsoft.OpenApi.Interfaces Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } bool UnresolvedReference { get; set; } } - public interface IOpenApiReferenceableWithTarget : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public interface IOpenApiReferenceableWithTarget : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { T Target { get; } } From dc8a7572ec436c1ed35f5a6208c6aa868702dc0f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Jan 2025 09:56:54 -0500 Subject: [PATCH 007/103] fix: visibility of serialize internal methods Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiExample.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiParameter.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiResponse.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 4 +--- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 2 -- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index 1fc7ca900..594813765 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -97,7 +97,7 @@ public virtual void SerializeAsV3(IOpenApiWriter writer) /// /// /// - public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version) + private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version) { Utils.CheckArgumentNull(writer); diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index bdaba739e..a7db89ef2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -358,7 +358,7 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) foreach (var example in Examples) { writer.WritePropertyName(example.Key); - example.Value.SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); + example.Value.SerializeAsV2(writer); } writer.WriteEndObject(); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index 2fab33fd5..0aed7bb0d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -162,7 +162,7 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) .SelectMany(mediaTypePair => mediaTypePair.Value.Examples)) { writer.WritePropertyName(example.Key); - example.Value.SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); + example.Value.SerializeAsV2(writer); } writer.WriteEndObject(); diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index dcab7de86..5d1fb9ee2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -411,9 +411,7 @@ public virtual void SerializeAsV3(IOpenApiWriter writer) SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } -/// - - public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { writer.WriteStartObject(); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 4ffbcd4ff..396feddeb 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -614,7 +614,6 @@ namespace Microsoft.OpenApi.Models public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeInternal(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version) { } } public abstract class OpenApiExtensibleDictionary : System.Collections.Generic.Dictionary, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where T : Microsoft.OpenApi.Interfaces.IOpenApiSerializable @@ -927,7 +926,6 @@ namespace Microsoft.OpenApi.Models public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeInternal(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version, System.Action callback) { } } public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { From cc28ff27446dae0fc0e9f9f44dafd6df6e8fc243 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 13:17:42 -0500 Subject: [PATCH 008/103] fix: proxy design pattern implementation for OpenAPiExample Signed-off-by: Vincent Biret --- .../OpenApiReferencableExtensions.cs | 27 ++-- .../Interfaces/IOpenApiReadOnlyExtensible.cs | 15 +++ .../Interfaces/IOpenApiReferenceHolder.cs | 47 +++++++ .../Interfaces/IOpenApiReferenceable.cs | 11 -- .../IOpenApiReferenceableWithTarget.cs | 17 --- .../Interfaces/IOpenApiDescribedElement.cs | 20 +++ .../Models/Interfaces/IOpenApiExample.cs | 26 ++++ .../Models/OpenApiComponents.cs | 7 +- .../Models/OpenApiDocument.cs | 10 +- .../Models/OpenApiExample.cs | 83 +++--------- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 5 +- .../Models/OpenApiMediaType.cs | 7 +- .../Models/OpenApiParameter.cs | 5 +- .../Models/OpenApiReference.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 4 +- src/Microsoft.OpenApi/Models/OpenApiTag.cs | 2 +- .../References/OpenApiCallbackReference.cs | 2 +- .../References/OpenApiExampleReference.cs | 98 +++++++++----- .../References/OpenApiHeaderReference.cs | 5 +- .../Models/References/OpenApiLinkReference.cs | 2 +- .../References/OpenApiParameterReference.cs | 5 +- .../References/OpenApiPathItemReference.cs | 2 +- .../References/OpenApiRequestBodyReference.cs | 2 +- .../References/OpenApiResponseReference.cs | 2 +- .../References/OpenApiSchemaReference.cs | 2 +- .../OpenApiSecuritySchemeReference.cs | 2 +- .../Models/References/OpenApiTagReference.cs | 2 +- .../Reader/ParseNodes/MapNode.cs | 2 +- .../OpenApiRemoteReferenceCollector.cs | 9 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 3 +- .../Reader/V2/OpenApiResponseDeserializer.cs | 9 +- .../Reader/V3/OpenApiExampleDeserializer.cs | 3 +- .../Reader/V3/OpenApiMediaTypeDeserializer.cs | 5 +- .../Reader/V3/OpenApiParameterDeserializer.cs | 5 +- .../Reader/V31/OpenApiExampleDeserializer.cs | 3 +- .../V31/OpenApiMediaTypeDeserializer.cs | 9 +- .../V31/OpenApiParameterDeserializer.cs | 9 +- .../Services/CopyReferences.cs | 18 ++- .../Services/OpenApiVisitorBase.cs | 15 ++- .../Services/OpenApiWalker.cs | 72 +++++----- .../Services/ReferenceHostDocumentSetter.cs | 11 +- .../Validations/OpenApiValidator.cs | 11 +- .../Rules/OpenApiNonDefaultRules.cs | 3 +- .../Services/OpenApiFilterServiceTests.cs | 4 +- .../V3Tests/OpenApiDocumentTests.cs | 2 +- .../V3Tests/OpenApiMediaTypeTests.cs | 4 +- .../V3Tests/OpenApiParameterTests.cs | 4 +- .../Models/OpenApiMediaTypeTests.cs | 5 +- .../Models/OpenApiParameterTests.cs | 12 +- .../PublicApi/PublicApi.approved.txt | 123 +++++++++++------- .../OpenApiHeaderValidationTests.cs | 8 +- .../OpenApiMediaTypeValidationTests.cs | 8 +- .../OpenApiParameterValidationTests.cs | 8 +- .../Visitors/InheritanceTests.cs | 19 +-- .../Walkers/WalkerLocationTests.cs | 2 +- .../Workspaces/OpenApiReferencableTests.cs | 4 +- 56 files changed, 462 insertions(+), 340 deletions(-) create mode 100644 src/Microsoft.OpenApi/Interfaces/IOpenApiReadOnlyExtensible.cs create mode 100644 src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs delete mode 100644 src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs index aca76f979..3a160b135 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Exceptions; @@ -13,7 +14,7 @@ namespace Microsoft.OpenApi.Extensions /// /// Extension methods for resolving references on elements. /// - public static class OpenApiReferencableExtensions + public static class OpenApiReferenceableExtensions { /// /// Resolves a JSON Pointer with respect to an element, returning the referenced element. @@ -57,13 +58,15 @@ private static IOpenApiReferenceable ResolveReferenceOnHeaderElement( string mapKey, JsonPointer pointer) { - switch (propertyName) + if (OpenApiConstants.Examples.Equals(propertyName, StringComparison.Ordinal) && + !string.IsNullOrEmpty(mapKey) && + headerElement?.Examples != null && + headerElement.Examples.TryGetValue(mapKey, out var exampleElement) && + exampleElement is IOpenApiReferenceable referenceable) { - case OpenApiConstants.Examples when mapKey != null: - return headerElement.Examples[mapKey]; - default: - throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); + return referenceable; } + throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); } private static IOpenApiReferenceable ResolveReferenceOnParameterElement( @@ -72,13 +75,15 @@ private static IOpenApiReferenceable ResolveReferenceOnParameterElement( string mapKey, JsonPointer pointer) { - switch (propertyName) + if (OpenApiConstants.Examples.Equals(propertyName, StringComparison.Ordinal) && + !string.IsNullOrEmpty(mapKey) && + parameterElement?.Examples != null && + parameterElement.Examples.TryGetValue(mapKey, out var exampleElement) && + exampleElement is IOpenApiReferenceable referenceable) { - case OpenApiConstants.Examples when mapKey != null: - return parameterElement.Examples[mapKey]; - default: - throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); + return referenceable; } + throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); } private static IOpenApiReferenceable ResolveReferenceOnResponseElement( diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReadOnlyExtensible.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReadOnlyExtensible.cs new file mode 100644 index 000000000..367c84a96 --- /dev/null +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReadOnlyExtensible.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Microsoft.OpenApi.Interfaces; + +/// +/// Represents an Extensible Open API element elements can be rad from. +/// +public interface IOpenApiReadOnlyExtensible +{ + /// + /// Specification extensions. + /// + IDictionary Extensions { get; } + +} diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs new file mode 100644 index 000000000..99b5dde2d --- /dev/null +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Interfaces +{ + /// + /// A generic interface for OpenApiReferenceable objects that have a target. + /// + /// Type of the target being referenced + public interface IOpenApiReferenceHolder : IOpenApiReferenceHolder where T : IOpenApiReferenceable + { + /// + /// Gets the resolved target object. + /// + T Target { get; } + } + /// + /// A generic interface for OpenApiReferenceable objects that have a target. + /// + /// The type of the target being referenced + /// The type of the interface implemented by both the target and the reference type + public interface IOpenApiReferenceHolder : IOpenApiReferenceHolder where T : IOpenApiReferenceable, V + { + //TODO merge this interface with the previous once all implementations are updated + /// + /// Copy the reference as a target element with overrides. + /// + V CopyReferenceAsTargetElementWithOverrides(V source); + } + /// + /// A generic interface for OpenApiReferenceable objects that have a target. + /// + public interface IOpenApiReferenceHolder : IOpenApiSerializable + { + /// + /// Indicates if object is populated with data or is just a reference to the data + /// + bool UnresolvedReference { get; set; } + + /// + /// Reference object. + /// + OpenApiReference Reference { get; set; } + } +} diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs index 43088bf6b..38e888dc8 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Microsoft.OpenApi.Models; - namespace Microsoft.OpenApi.Interfaces { /// @@ -10,14 +8,5 @@ namespace Microsoft.OpenApi.Interfaces /// public interface IOpenApiReferenceable : IOpenApiSerializable { - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - bool UnresolvedReference { get; set; } - - /// - /// Reference object. - /// - OpenApiReference Reference { get; set; } } } diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs deleted file mode 100644 index 85bc1987d..000000000 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -namespace Microsoft.OpenApi.Interfaces -{ - /// - /// A generic interface for OpenApiReferenceable objects that have a target. - /// - /// - public interface IOpenApiReferenceableWithTarget : IOpenApiReferenceable - { - /// - /// Gets the resolved target object. - /// - T Target { get; } - } -} diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs new file mode 100644 index 000000000..76a945548 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs @@ -0,0 +1,20 @@ +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Describes an element that has a summary and description. +/// +public interface IOpenApiDescribedElement : IOpenApiElement +{ + /// + /// Short description for the example. + /// + public string Summary { get; set; } + + /// + /// Long description for the example. + /// CommonMark syntax MAY be used for rich text representation. + /// + public string Description { get; set; } +} diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs new file mode 100644 index 000000000..3711df4b8 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Nodes; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the example object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiExample : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// Embedded literal example. The value field and externalValue field are mutually + /// exclusive. To represent examples of media types that cannot naturally represented + /// in JSON or YAML, use a string value to contain the example, escaping where necessary. + /// + public JsonNode Value { get; } + + /// + /// A URL that points to the literal example. + /// This provides the capability to reference examples that cannot easily be + /// included in JSON or YAML documents. + /// The value field and externalValue field are mutually exclusive. + /// + public string ExternalValue { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 5b43b5187..6ca0089b4 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -35,7 +36,7 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Examples { get; set; } = new Dictionary(); + public virtual IDictionary? Examples { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -87,7 +88,7 @@ public OpenApiComponents(OpenApiComponents? components) Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; - Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; + Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; @@ -160,7 +161,7 @@ public void SerializeAsV3(IOpenApiWriter writer) /// Serialize . /// private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, - Action callback, Action action) + Action callback, Action action) { // Serialize each referenceable object as full object without reference if the reference in the object points to itself. // If the reference exists but points to other objects, the object is serialized to just that reference. diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 047062874..9b7099f56 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Services; @@ -615,7 +616,7 @@ public bool AddComponent(string id, T componentToRegister) Components.PathItems.Add(id, openApiPathItem); break; case OpenApiExample openApiExample: - Components.Examples ??= new Dictionary(); + Components.Examples ??= new Dictionary(); Components.Examples.Add(id, openApiExample); break; case OpenApiHeader openApiHeader: @@ -645,9 +646,10 @@ public static void ResolveSchemas(OpenApiComponents? components, Dictionary + public override void Visit(IOpenApiReferenceHolder referenceHolder) { - switch (referenceable) + switch (referenceHolder) { case OpenApiSchema schema: if (!Schemas.ContainsKey(schema.Reference.Id)) @@ -659,7 +661,7 @@ public override void Visit(IOpenApiReferenceable referenceable) default: break; } - base.Visit(referenceable); + base.Visit(referenceHolder); } public override void Visit(OpenApiSchema schema) diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index 594813765..c35480fc2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -5,6 +5,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -12,48 +13,22 @@ namespace Microsoft.OpenApi.Models /// /// Example Object. /// - public class OpenApiExample : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiExample : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiExample { - /// - /// Short description for the example. - /// - public virtual string Summary { get; set; } - - /// - /// Long description for the example. - /// CommonMark syntax MAY be used for rich text representation. - /// - public virtual string Description { get; set; } - - /// - /// Embedded literal example. The value field and externalValue field are mutually - /// exclusive. To represent examples of media types that cannot naturally represented - /// in JSON or YAML, use a string value to contain the example, escaping where necessary. - /// - public virtual JsonNode Value { get; set; } + /// + public string Summary { get; set; } - /// - /// A URL that points to the literal example. - /// This provides the capability to reference examples that cannot easily be - /// included in JSON or YAML documents. - /// The value field and externalValue field are mutually exclusive. - /// - public virtual string ExternalValue { get; set; } + /// + public string Description { get; set; } - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public string ExternalValue { get; set; } - /// - /// Reference object. - /// - public virtual OpenApiReference Reference { get; set; } + /// + public JsonNode Value { get; set; } - /// - /// Indicates object is a placeholder reference to an actual object and does not contain valid data. - /// - public virtual bool UnresolvedReference { get; set; } = false; + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -63,40 +38,28 @@ public OpenApiExample() { } /// /// Initializes a copy of object /// - public OpenApiExample(OpenApiExample example) + /// The object + public OpenApiExample(IOpenApiExample example) { Summary = example?.Summary ?? Summary; Description = example?.Description ?? Description; Value = example?.Value != null ? JsonNodeCloneHelper.Clone(example.Value) : null; ExternalValue = example?.ExternalValue ?? ExternalValue; Extensions = example?.Extensions != null ? new Dictionary(example.Extensions) : null; - Reference = example?.Reference != null ? new(example.Reference) : null; - UnresolvedReference = example?.UnresolvedReference ?? UnresolvedReference; } - /// - /// Serialize to Open Api v3.1 - /// - /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + /// + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1); } - /// - /// Serialize to Open Api v3.0 - /// - /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + /// + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0); } - /// - /// Writes out existing examples in a mediatype object - /// - /// - /// private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version) { Utils.CheckArgumentNull(writer); @@ -121,14 +84,10 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteEndObject(); } - /// - /// Serialize to Open Api v2.0 - /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + /// + public void SerializeAsV2(IOpenApiWriter writer) { - // Example object of this form does not exist in V2. - // V2 Example object requires knowledge of media type and exists only - // in Response object, so it will be serialized as a part of the Response object. + SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 268878b1b..c27d18f8d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -82,7 +83,7 @@ public virtual OpenApiSchema Schema /// /// Examples of the media type. /// - public virtual IDictionary Examples { get; set; } = new Dictionary(); + public virtual IDictionary Examples { get; set; } = new Dictionary(); /// /// A map containing the representations for the header. @@ -115,7 +116,7 @@ public OpenApiHeader(OpenApiHeader header) AllowReserved = header?.AllowReserved ?? AllowReserved; _schema = header?.Schema != null ? new(header.Schema) : null; Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; - Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; + Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; Extensions = header?.Extensions != null ? new Dictionary(header.Extensions) : null; } diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 671a0dcfc..23acd0de9 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -7,6 +7,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; #nullable enable @@ -39,7 +40,7 @@ public virtual OpenApiSchema? Schema /// Examples of the media type. /// Each example object SHOULD match the media type and specified schema if present. /// - public IDictionary? Examples { get; set; } = new Dictionary(); + public IDictionary? Examples { get; set; } = new Dictionary(); /// /// A map between a property name and its encoding information. @@ -66,7 +67,7 @@ public OpenApiMediaType(OpenApiMediaType? mediaType) { _schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; - Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; + Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; Encoding = mediaType?.Encoding != null ? new Dictionary(mediaType.Encoding) : null; Extensions = mediaType?.Extensions != null ? new Dictionary(mediaType.Extensions) : null; } @@ -126,7 +127,7 @@ public void SerializeAsV2(IOpenApiWriter writer) // Media type does not exist in V2. } - private static void SerializeExamples(IOpenApiWriter writer, IDictionary examples) + private static void SerializeExamples(IOpenApiWriter writer, IDictionary examples) { /* Special case for writing out empty arrays as valid response examples * Check if there is any example with an empty array as its value and set the flag `hasEmptyArray` to true diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index a7db89ef2..66d03746e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -120,7 +121,7 @@ public virtual OpenApiSchema Schema /// Furthermore, if referencing a schema which contains an example, /// the examples value SHALL override the example provided by the schema. /// - public virtual IDictionary Examples { get; set; } = new Dictionary(); + public virtual IDictionary Examples { get; set; } = new Dictionary(); /// /// Example of the media type. The example SHOULD match the specified schema and encoding properties @@ -168,7 +169,7 @@ public OpenApiParameter(OpenApiParameter parameter) Explode = parameter?.Explode ?? Explode; AllowReserved = parameter?.AllowReserved ?? AllowReserved; _schema = parameter?.Schema != null ? new(parameter.Schema) : null; - Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null; + Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null; Example = parameter?.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; Content = parameter?.Content != null ? new Dictionary(parameter.Content) : null; Extensions = parameter?.Extensions != null ? new Dictionary(parameter.Extensions) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index 8a1ae4a43..9c65bf9e2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -200,7 +200,7 @@ private void SerializeInternal(IOpenApiWriter writer) /// public void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); if (Type == ReferenceType.Tag) { diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 5d1fb9ee2..ff5a8eb48 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -15,8 +15,8 @@ namespace Microsoft.OpenApi.Models /// /// The Schema Object allows the definition of input and output data types. /// - public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiReferenceable - { + public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiReferenceable, IOpenApiReferenceHolder + {//TODO remove the implementation of IOpenAPiReferenceHolder when we have removed the inheritance from the inheritance type to this type /// /// Follow JSON Schema definition. Short text providing information about the data. /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs index 58fa99694..057cf6d49 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models /// /// Tag Object. /// - public class OpenApiTag : IOpenApiSerializable, IOpenApiExtensible + public class OpenApiTag : IOpenApiReferenceable, IOpenApiExtensible { /// /// The name of the tag. diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 81985cb12..13cea041a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Callback Object Reference: A reference to a map of possible out-of band callbacks related to the parent operation. /// - public class OpenApiCallbackReference : OpenApiCallback, IOpenApiReferenceableWithTarget + public class OpenApiCallbackReference : OpenApiCallback, IOpenApiReferenceHolder { #nullable enable internal OpenApiCallback _target; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index c36c43d9a..0f8638c3e 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -12,12 +13,14 @@ namespace Microsoft.OpenApi.Models.References /// /// Example Object Reference. /// - public class OpenApiExampleReference : OpenApiExample, IOpenApiReferenceableWithTarget + public class OpenApiExampleReference : IOpenApiReferenceHolder, IOpenApiExample { + /// + public OpenApiReference Reference { get; set; } + + /// + public bool UnresolvedReference { get; set; } = false; internal OpenApiExample _target; - private readonly OpenApiReference _reference; - private string _summary; - private string _description; /// /// Gets the target example. @@ -29,11 +32,8 @@ public OpenApiExample Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiExample resolved = new OpenApiExample(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - if (!string.IsNullOrEmpty(_summary)) resolved.Summary = _summary; - return resolved; + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + return _target; } } @@ -51,22 +51,33 @@ public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Example, ExternalResource = externalResource }; + } - Reference = _reference; + /// + /// Copy constructor + /// + /// The reference to copy. + public OpenApiExampleReference(OpenApiExampleReference example) + { + Utils.CheckArgumentNull(example); + Reference = example?.Reference != null ? new(example.Reference) : null; + UnresolvedReference = example?.UnresolvedReference ?? UnresolvedReference; + //no need to copy summary and description as if they are not overridden, they will be fetched from the target + //if they are, the reference copy will handle it } internal OpenApiExampleReference(OpenApiExample target, string referenceId) { _target = target; - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, Type = ReferenceType.Example, @@ -74,59 +85,82 @@ internal OpenApiExampleReference(OpenApiExample target, string referenceId) } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override string Summary + public string Summary { - get => string.IsNullOrEmpty(_summary) ? Target.Summary : _summary; - set => _summary = value; + get => string.IsNullOrEmpty(Reference?.Summary) ? Target?.Summary : Reference.Summary; + set + { + if (Reference is not null) + { + Reference.Summary = value; + } + } } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public IDictionary Extensions { get => Target?.Extensions; } /// - public override string ExternalValue { get => Target.ExternalValue; set => Target.ExternalValue = value; } + public string ExternalValue { get => Target?.ExternalValue; } /// - public override JsonNode Value { get => Target.Value; set => Target.Value = value; } + public JsonNode Value { get => Target?.Value; } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV3(writer)); + SerializeInternal(writer, (writer, referenceElement) => CopyReferenceAsTargetElementWithOverrides(referenceElement).SerializeAsV3(writer)); } } /// - public override void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV31(writer)); + SerializeInternal(writer, (writer, referenceElement) => CopyReferenceAsTargetElementWithOverrides(referenceElement).SerializeAsV31(writer)); } } + + /// + public IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample openApiExample) + { + return openApiExample is OpenApiExample ? new OpenApiExample(this) : openApiExample; + } + + /// + public void SerializeAsV2(IOpenApiWriter writer) + { + // examples components are not supported in OAS 2.0 + Reference.SerializeAsV2(writer); + } /// private void SerializeInternal(IOpenApiWriter writer, - Action action) + Action action) { Utils.CheckArgumentNull(writer); action(writer, Target); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index e8275c23c..d9f451c0a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -12,7 +13,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Header Object Reference. /// - public class OpenApiHeaderReference : OpenApiHeader, IOpenApiReferenceableWithTarget + public class OpenApiHeaderReference : OpenApiHeader, IOpenApiReferenceHolder { internal OpenApiHeader _target; private readonly OpenApiReference _reference; @@ -103,7 +104,7 @@ public override string Description public override JsonNode Example { get => Target.Example; set => Target.Example = value; } /// - public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } + public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } /// public override IDictionary Content { get => Target.Content; set => Target.Content = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 05817ddc9..614ab1446 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Link Object Reference. /// - public class OpenApiLinkReference : OpenApiLink, IOpenApiReferenceableWithTarget + public class OpenApiLinkReference : OpenApiLink, IOpenApiReferenceHolder { internal OpenApiLink _target; private readonly OpenApiReference _reference; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 9df1e7be2..93d1163db 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -12,7 +13,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Parameter Object Reference. /// - public class OpenApiParameterReference : OpenApiParameter, IOpenApiReferenceableWithTarget + public class OpenApiParameterReference : OpenApiParameter, IOpenApiReferenceHolder { internal OpenApiParameter _target; private readonly OpenApiReference _reference; @@ -99,7 +100,7 @@ public override string Description public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } /// - public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } + public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } /// public override JsonNode Example { get => Target.Example; set => Target.Example = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index fad8922ae..bc7e8904e 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Path Item Object Reference: to describe the operations available on a single path. /// - public class OpenApiPathItemReference : OpenApiPathItem, IOpenApiReferenceableWithTarget + public class OpenApiPathItemReference : OpenApiPathItem, IOpenApiReferenceHolder { internal OpenApiPathItem _target; private readonly OpenApiReference _reference; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 59fb27724..7025ec373 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Request Body Object Reference. /// - public class OpenApiRequestBodyReference : OpenApiRequestBody, IOpenApiReferenceableWithTarget + public class OpenApiRequestBodyReference : OpenApiRequestBody, IOpenApiReferenceHolder { internal OpenApiRequestBody _target; private readonly OpenApiReference _reference; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index 2ac8aee27..0983bd3b6 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Response Object Reference. /// - public class OpenApiResponseReference : OpenApiResponse, IOpenApiReferenceableWithTarget + public class OpenApiResponseReference : OpenApiResponse, IOpenApiReferenceHolder { internal OpenApiResponse _target; private readonly OpenApiReference _reference; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index da2f9b745..731f9c1af 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Schema reference object /// - public class OpenApiSchemaReference : OpenApiSchema, IOpenApiReferenceableWithTarget + public class OpenApiSchemaReference : OpenApiSchema, IOpenApiReferenceHolder { #nullable enable private OpenApiSchema? _target; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index dcd5009b1..c1dafa80f 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Security Scheme Object Reference. /// - public class OpenApiSecuritySchemeReference : OpenApiSecurityScheme, IOpenApiReferenceableWithTarget + public class OpenApiSecuritySchemeReference : OpenApiSecurityScheme, IOpenApiReferenceHolder { internal OpenApiSecurityScheme _target; private readonly OpenApiReference _reference; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index ae15b4085..09afa3655 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Tag Object Reference /// - public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceableWithTarget + public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceHolder { internal OpenApiTag _target; diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs index f39d9c345..d8740857b 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs @@ -120,7 +120,7 @@ public override string GetRaw() } public T GetReferencedObject(ReferenceType referenceType, string referenceId, string summary = null, string description = null) - where T : IOpenApiReferenceable, new() + where T : IOpenApiReferenceHolder, new() { return new() { diff --git a/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs b/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs index bb66cf9b2..8690735b8 100644 --- a/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs +++ b/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs @@ -26,13 +26,10 @@ public IEnumerable References } } - /// - /// Collect reference for each reference - /// - /// - public override void Visit(IOpenApiReferenceable referenceable) + /// + public override void Visit(IOpenApiReferenceHolder referenceHolder) { - AddExternalReferences(referenceable.Reference); + AddExternalReferences(referenceHolder.Reference); } /// diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 6a5411070..247d68679 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -6,6 +6,7 @@ using System.Globalization; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -215,7 +216,7 @@ public static OpenApiParameter LoadParameter(ParseNode node, bool loadRequestBod } // load examples from storage and add them to the parameter - var examples = node.Context.GetFromTempStorage>(TempStorageKeys.Examples, parameter); + var examples = node.Context.GetFromTempStorage>(TempStorageKeys.Examples, parameter); if (examples != null) { parameter.Examples = examples; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index 11b12e8f8..2716c499b 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -74,8 +75,8 @@ private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, P ?? context.DefaultContentType ?? new List { "application/octet-stream" }; var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); - var examples = context.GetFromTempStorage>(TempStorageKeys.Examples, response) - ?? new Dictionary(); + var examples = context.GetFromTempStorage>(TempStorageKeys.Examples, response) + ?? new Dictionary(); foreach (var produce in produces) { @@ -110,10 +111,10 @@ private static void LoadResponseExamplesExtension(OpenApiResponse response, Pars node.Context.SetTempStorage(TempStorageKeys.Examples, examples, response); } - private static Dictionary LoadExamplesExtension(ParseNode node) + private static Dictionary LoadExamplesExtension(ParseNode node) { var mapNode = node.CheckMapNode(OpenApiConstants.ExamplesExtension); - var examples = new Dictionary(); + var examples = new Dictionary(); foreach (var examplesNode in mapNode) { diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs index 06d1d284a..344565884 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -40,7 +41,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("example"); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs index 69fc53179..b30dc88e0 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V3 @@ -51,7 +52,7 @@ internal static partial class OpenApiV3Deserializer } }; - private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields = + private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields = new() { { @@ -59,7 +60,7 @@ internal static partial class OpenApiV3Deserializer new( m => m.Examples, e => e.Value, - (e, v) => e.Value = v, + (e, v) => {if (e is OpenApiExample ex) {ex.Value = v;}}, m => m.Schema) } }; diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs index a71f633e5..915314d35 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -101,7 +102,7 @@ internal static partial class OpenApiV3Deserializer } }; - private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields = + private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields = new() { { @@ -109,7 +110,7 @@ internal static partial class OpenApiV3Deserializer new( m => m.Examples, e => e.Value, - (e, v) => e.Value = v, + (e, v) => {if (e is OpenApiExample ex) {ex.Value = v;}}, m => m.Schema) } }; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs index 820c58985..f6511d8b9 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -46,7 +47,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("example"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs index 36f90383c..a9024f9ed 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V31 @@ -57,15 +58,15 @@ internal static partial class OpenApiV31Deserializer }; - private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields = - new AnyMapFieldMap + private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields = + new AnyMapFieldMap { { OpenApiConstants.Examples, - new AnyMapFieldMapParameter( + new AnyMapFieldMapParameter( m => m.Examples, e => e.Value, - (e, v) => e.Value = v, + (e, v) => {if (e is OpenApiExample ex) {ex.Value = v;}}, m => m.Schema) } }; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs index 7a2c3d90e..fecaf58c2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -119,15 +120,15 @@ internal static partial class OpenApiV31Deserializer } }; - private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields = - new AnyMapFieldMap + private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields = + new AnyMapFieldMap { { OpenApiConstants.Examples, - new AnyMapFieldMapParameter( + new AnyMapFieldMapParameter( m => m.Examples, e => e.Value, - (e, v) => e.Value = v, + (e, v) => {if (e is OpenApiExample ex) {ex.Value = v;}}, m => m.Schema) } }; diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 22f1c5ad3..086961a94 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Services; @@ -12,13 +13,10 @@ internal class CopyReferences(OpenApiDocument target) : OpenApiVisitorBase private readonly OpenApiDocument _target = target; public OpenApiComponents Components = new(); - /// - /// Visits IOpenApiReferenceable instances that are references and not in components. - /// - /// An IOpenApiReferenceable object. - public override void Visit(IOpenApiReferenceable referenceable) + /// + public override void Visit(IOpenApiReferenceHolder referenceHolder) { - switch (referenceable) + switch (referenceHolder) { case OpenApiSchemaReference openApiSchemaReference: AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id); @@ -84,7 +82,7 @@ public override void Visit(IOpenApiReferenceable referenceable) break; } - base.Visit(referenceable); + base.Visit(referenceHolder); } private void AddSchemaToComponents(OpenApiSchema schema, string referenceId = null) @@ -156,9 +154,9 @@ private void AddExampleToComponents(OpenApiExample example, string referenceId = { EnsureComponentsExist(); EnsureExamplesExist(); - if (!Components.Examples.ContainsKey(referenceId ?? example.Reference.Id)) + if (!Components.Examples.ContainsKey(referenceId)) { - Components.Examples.Add(referenceId ?? example.Reference.Id, example); + Components.Examples.Add(referenceId, example); } } private void AddPathItemToComponents(OpenApiPathItem pathItem, string referenceId = null) @@ -222,7 +220,7 @@ private void EnsureRequestBodiesExist() private void EnsureExamplesExist() { - _target.Components.Examples ??= new Dictionary(); + _target.Components.Examples ??= new Dictionary(); } private void EnsureHeadersExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index a889628b3..8f0c24de5 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -7,6 +7,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Services @@ -210,7 +211,7 @@ public virtual void Visit(OpenApiEncoding encoding) /// /// Visits the examples. /// - public virtual void Visit(IDictionary examples) + public virtual void Visit(IDictionary examples) { } @@ -299,9 +300,9 @@ public virtual void Visit(OpenApiSecurityScheme securityScheme) } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiExample example) + public virtual void Visit(IOpenApiExample example) { } @@ -341,9 +342,9 @@ public virtual void Visit(IOpenApiExtension openApiExtension) } /// - /// Visits list of + /// Visits list of /// - public virtual void Visit(IList example) + public virtual void Visit(IList example) { } @@ -365,8 +366,8 @@ public virtual void Visit(IDictionary encodings) /// /// Visits IOpenApiReferenceable instances that are references and not in components /// - /// referenced object - public virtual void Visit(IOpenApiReferenceable referenceable) + /// Referencing object + public virtual void Visit(IOpenApiReferenceHolder referenceHolder) { } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 9321b3b17..94a263bd0 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Services @@ -17,7 +18,6 @@ namespace Microsoft.OpenApi.Services /// public class OpenApiWalker { - private OpenApiDocument _hostDocument; private readonly OpenApiVisitorBase _visitor; private readonly Stack _schemaLoop = new(); private readonly Stack _pathItemLoop = new(); @@ -41,7 +41,6 @@ public void Walk(OpenApiDocument doc) return; } - _hostDocument = doc; _schemaLoop.Clear(); _pathItemLoop.Clear(); @@ -416,9 +415,9 @@ internal void Walk(OpenApiCallback callback, bool isComponent = false) return; } - if (callback is OpenApiCallbackReference) + if (callback is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(callback as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -461,7 +460,10 @@ internal void Walk(OpenApiTagReference tag) return; } - Walk(tag as IOpenApiReferenceable); + if (tag is IOpenApiReferenceHolder openApiReferenceHolder) + { + Walk(openApiReferenceHolder); + } } /// @@ -526,9 +528,9 @@ internal void Walk(OpenApiPathItem pathItem, bool isComponent = false) return; } - if (pathItem is OpenApiPathItemReference) + if (pathItem is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(pathItem as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -649,9 +651,9 @@ internal void Walk(OpenApiParameter parameter, bool isComponent = false) return; } - if (parameter is OpenApiParameterReference) + if (parameter is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(parameter as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -697,9 +699,9 @@ internal void Walk(OpenApiResponse response, bool isComponent = false) return; } - if (response is OpenApiResponseReference) + if (response is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(response as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -720,9 +722,9 @@ internal void Walk(OpenApiRequestBody requestBody, bool isComponent = false) return; } - if (requestBody is OpenApiRequestBodyReference) + if (requestBody is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(requestBody as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -932,9 +934,9 @@ internal void Walk(OpenApiSchema schema, bool isComponent = false) /// - /// Visits dictionary of + /// Visits dictionary of /// - internal void Walk(IDictionary examples) + internal void Walk(IDictionary examples) { if (examples == null) { @@ -968,18 +970,18 @@ internal void Walk(JsonNode example) } /// - /// Visits and child objects + /// Visits and child objects /// - internal void Walk(OpenApiExample example, bool isComponent = false) + internal void Walk(IOpenApiExample example, bool isComponent = false) { if (example == null) { return; } - if (example is OpenApiExampleReference) + if (example is OpenApiExampleReference reference) { - Walk(example as IOpenApiReferenceable); + Walk(reference); return; } @@ -988,9 +990,9 @@ internal void Walk(OpenApiExample example, bool isComponent = false) } /// - /// Visits the list of and child objects + /// Visits the list of and child objects /// - internal void Walk(IList examples) + internal void Walk(IList examples) { if (examples == null) { @@ -1089,9 +1091,9 @@ internal void Walk(OpenApiLink link, bool isComponent = false) return; } - if (link is OpenApiLinkReference) + if (link is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(link as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -1110,9 +1112,9 @@ internal void Walk(OpenApiHeader header, bool isComponent = false) return; } - if (header is OpenApiHeaderReference) + if (header is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(header as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -1153,9 +1155,9 @@ internal void Walk(OpenApiSecurityScheme securityScheme, bool isComponent = fals return; } - if (securityScheme is OpenApiSecuritySchemeReference) + if (securityScheme is IOpenApiReferenceHolder openApiReferenceHolder) { - Walk(securityScheme as IOpenApiReferenceable); + Walk(openApiReferenceHolder); return; } @@ -1166,9 +1168,9 @@ internal void Walk(OpenApiSecurityScheme securityScheme, bool isComponent = fals /// /// Visits and child objects /// - internal void Walk(IOpenApiReferenceable referenceable) + internal void Walk(IOpenApiReferenceHolder referenceableHolder) { - _visitor.Visit(referenceable); + _visitor.Visit(referenceableHolder); } /// @@ -1191,8 +1193,8 @@ internal void Walk(IOpenApiElement element) case OpenApiContact e: Walk(e); break; case OpenApiCallback e: Walk(e); break; case OpenApiEncoding e: Walk(e); break; - case OpenApiExample e: Walk(e); break; - case IDictionary e: Walk(e); break; + case IOpenApiExample e: Walk(e); break; + case IDictionary e: Walk(e); break; case OpenApiExternalDocs e: Walk(e); break; case OpenApiHeader e: Walk(e); break; case OpenApiLink e: Walk(e); break; @@ -1232,13 +1234,13 @@ private void Walk(string context, Action walk) /// /// Identify if an element is just a reference to a component, or an actual component /// - private bool ProcessAsReference(IOpenApiReferenceable referenceable, bool isComponent = false) + private bool ProcessAsReference(IOpenApiReferenceHolder referenceableHolder, bool isComponent = false) { - var isReference = referenceable.Reference != null && - (!isComponent || referenceable.UnresolvedReference); + var isReference = referenceableHolder.Reference != null && + (!isComponent || referenceableHolder.UnresolvedReference); if (isReference) { - Walk(referenceable); + Walk(referenceableHolder); } return isReference; } diff --git a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs index 1d9bb8e8e..146c8941d 100644 --- a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs +++ b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs @@ -18,15 +18,12 @@ public ReferenceHostDocumentSetter(OpenApiDocument currentDocument) _currentDocument = currentDocument; } - /// - /// Visits the referenceable element in the host document - /// - /// The referenceable element in the doc. - public override void Visit(IOpenApiReferenceable referenceable) + /// + public override void Visit(IOpenApiReferenceHolder referenceHolder) { - if (referenceable.Reference != null) + if (referenceHolder.Reference != null) { - referenceable.Reference.HostDocument = _currentDocument; + referenceHolder.Reference.HostDocument = _currentDocument; } } } diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 7281ef258..0cc7ade2b 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; namespace Microsoft.OpenApi.Validations @@ -125,7 +126,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(IOpenApiExtension openApiExtension) => Validate(openApiExtension, openApiExtension.GetType()); /// - public override void Visit(IList example) => Validate(example, example.GetType()); + public override void Visit(IList example) => Validate(example, example.GetType()); /// public override void Visit(OpenApiPathItem pathItem) => Validate(pathItem); @@ -149,7 +150,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiLink link) => Validate(link); /// - public override void Visit(OpenApiExample example) => Validate(example); + public override void Visit(IOpenApiExample example) => Validate(example); /// public override void Visit(OpenApiOperation operation) => Validate(operation); @@ -162,7 +163,7 @@ public void AddWarning(OpenApiValidatorWarning warning) /// public override void Visit(IDictionary content) => Validate(content, content.GetType()); /// - public override void Visit(IDictionary examples) => Validate(examples, examples.GetType()); + public override void Visit(IDictionary examples) => Validate(examples, examples.GetType()); /// public override void Visit(IDictionary links) => Validate(links, links.GetType()); /// @@ -189,9 +190,9 @@ private void Validate(object item, Type type) } // Validate unresolved references as references - if (item is IOpenApiReferenceable { UnresolvedReference: true }) + if (item is IOpenApiReferenceHolder { UnresolvedReference: true }) { - type = typeof(IOpenApiReferenceable); + type = typeof(IOpenApiReferenceHolder); } var rules = _ruleSet.FindRules(type); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs index f02be33ee..759aafe47 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json.Nodes; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Validations.Rules { @@ -89,7 +90,7 @@ public static class OpenApiNonDefaultRules private static void ValidateMismatchedDataType(IValidationContext context, string ruleName, JsonNode example, - IDictionary examples, + IDictionary examples, OpenApiSchema schema) { // example diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index 77f2c9ae9..e8c49bbc8 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Tests.UtilityFiles; using Moq; @@ -243,7 +244,8 @@ public async Task CopiesOverAllReferencedComponentsToTheSubsetDocumentCorrectly( // Assert Assert.Same(doc.Servers, subsetOpenApiDocument.Servers); Assert.False(responseHeader?.UnresolvedReference); - Assert.False(mediaTypeExample?.UnresolvedReference); + var exampleReference = Assert.IsType(mediaTypeExample); + Assert.False(exampleReference?.UnresolvedReference); Assert.NotNull(targetHeaders); Assert.Single(targetHeaders); Assert.NotNull(targetExamples); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index a46b32f09..41f2c6a1e 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1147,7 +1147,7 @@ public async Task HeaderParameterShouldAllowExample() AllowReserved = true, Style = ParameterStyle.Simple, Explode = true, - Examples = new Dictionary() + Examples = { { "uuid1", new OpenApiExample() { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index e3c1435fd..e10c78a25 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -57,11 +57,11 @@ public async Task ParseMediaTypeWithExamplesShouldSucceed() { Examples = { - ["example1"] = new() + ["example1"] = new OpenApiExample() { Value = 5 }, - ["example2"] = new() + ["example2"] = new OpenApiExample() { Value = 7.5 } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 8a30fc9ba..4b19c2e66 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -277,11 +277,11 @@ public async Task ParseParameterWithExamplesShouldSucceed() Required = true, Examples = { - ["example1"] = new() + ["example1"] = new OpenApiExample() { Value = 5.0 }, - ["example2"] = new() + ["example2"] = new OpenApiExample() { Value = (float) 7.5 } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs index b1f6ca474..ef1ebb420 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Xunit; using Xunit.Abstractions; @@ -79,7 +80,7 @@ public class OpenApiMediaTypeTests public static OpenApiMediaType MediaTypeWithObjectExamples = new() { Examples = { - ["object1"] = new() + ["object1"] = new OpenApiExample() { Value = new JsonObject { @@ -433,7 +434,7 @@ public void MediaTypeCopyConstructorWorks() var clone = new OpenApiMediaType(MediaTypeWithObjectExamples) { Example = 42, - Examples = new Dictionary(), + Examples = new Dictionary(), Encoding = new Dictionary(), Extensions = new Dictionary() }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index 1c2e3329f..b76dcf342 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -50,9 +50,9 @@ public class OpenApiParameterTests new() { Type = JsonSchemaType.String } } }, - Examples = new Dictionary + Examples = { - ["test"] = new() + ["test"] = new OpenApiExample() { Summary = "summary3", Description = "description3" @@ -135,9 +135,9 @@ public class OpenApiParameterTests }, UnresolvedReference = true }, - Examples = new Dictionary + Examples = { - ["test"] = new() + ["test"] = new OpenApiExample() { Summary = "summary3", Description = "description3" @@ -159,9 +159,9 @@ public class OpenApiParameterTests { Type = JsonSchemaType.Object }, - Examples = new Dictionary + Examples = { - ["test"] = new() + ["test"] = new OpenApiExample() { Summary = "summary3", Description = "description3" diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 396feddeb..9ad9336d3 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -159,7 +159,7 @@ namespace Microsoft.OpenApi.Extensions public static void AddExtension(this T element, string name, Microsoft.OpenApi.Interfaces.IOpenApiExtension any) where T : Microsoft.OpenApi.Interfaces.IOpenApiExtensible { } } - public static class OpenApiReferencableExtensions + public static class OpenApiReferenceableExtensions { public static Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(this Microsoft.OpenApi.Interfaces.IOpenApiReferenceable element, Microsoft.OpenApi.JsonPointer pointer) { } } @@ -211,6 +211,10 @@ namespace Microsoft.OpenApi.Interfaces { void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion); } + public interface IOpenApiReadOnlyExtensible + { + System.Collections.Generic.IDictionary Extensions { get; } + } public interface IOpenApiReader { Microsoft.OpenApi.Reader.ReadResult Read(System.IO.MemoryStream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings); @@ -218,15 +222,22 @@ namespace Microsoft.OpenApi.Interfaces T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement; } - public interface IOpenApiReferenceable : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } bool UnresolvedReference { get; set; } } - public interface IOpenApiReferenceableWithTarget : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable { T Target { get; } } + public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V + { + V CopyReferenceAsTargetElementWithOverrides(V source); + } + public interface IOpenApiReferenceable : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { } public interface IOpenApiSerializable : Microsoft.OpenApi.Interfaces.IOpenApiElement { void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer); @@ -324,6 +335,19 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiReservedParameterExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } } +namespace Microsoft.OpenApi.Models.Interfaces +{ + public interface IOpenApiDescribedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement + { + string Description { get; set; } + string Summary { get; set; } + } + public interface IOpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + string ExternalValue { get; } + System.Text.Json.Nodes.JsonNode Value { get; } + } +} namespace Microsoft.OpenApi.Models { [System.Flags] @@ -356,7 +380,7 @@ namespace Microsoft.OpenApi.Models public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents? components) { } public System.Collections.Generic.IDictionary? Schemas { get; set; } public virtual System.Collections.Generic.IDictionary? Callbacks { get; set; } - public virtual System.Collections.Generic.IDictionary? Examples { get; set; } + public virtual System.Collections.Generic.IDictionary? Examples { get; set; } public virtual System.Collections.Generic.IDictionary? Extensions { get; set; } public virtual System.Collections.Generic.IDictionary? Headers { get; set; } public virtual System.Collections.Generic.IDictionary? Links { get; set; } @@ -600,20 +624,18 @@ namespace Microsoft.OpenApi.Models public string Pointer { get; set; } public override string ToString() { } } - public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample { public OpenApiExample() { } - public OpenApiExample(Microsoft.OpenApi.Models.OpenApiExample example) { } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual string ExternalValue { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual string Summary { get; set; } - public virtual bool UnresolvedReference { get; set; } - public virtual System.Text.Json.Nodes.JsonNode Value { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiExample(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public string ExternalValue { get; set; } + public string Summary { get; set; } + public System.Text.Json.Nodes.JsonNode Value { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public abstract class OpenApiExtensibleDictionary : System.Collections.Generic.Dictionary, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where T : Microsoft.OpenApi.Interfaces.IOpenApiSerializable @@ -647,7 +669,7 @@ namespace Microsoft.OpenApi.Models public virtual bool Deprecated { get; set; } public virtual string Description { get; set; } public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } - public virtual System.Collections.Generic.IDictionary Examples { get; set; } + public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } @@ -709,7 +731,7 @@ namespace Microsoft.OpenApi.Models public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType? mediaType) { } public System.Collections.Generic.IDictionary? Encoding { get; set; } public System.Text.Json.Nodes.JsonNode? Example { get; set; } - public System.Collections.Generic.IDictionary? Examples { get; set; } + public System.Collections.Generic.IDictionary? Examples { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } public virtual Microsoft.OpenApi.Models.OpenApiSchema? Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -776,7 +798,7 @@ namespace Microsoft.OpenApi.Models public virtual bool Deprecated { get; set; } public virtual string Description { get; set; } public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } - public virtual System.Collections.Generic.IDictionary Examples { get; set; } + public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } @@ -864,7 +886,7 @@ namespace Microsoft.OpenApi.Models public OpenApiResponses() { } public OpenApiResponses(Microsoft.OpenApi.Models.OpenApiResponses openApiResponses) { } } - public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSchema() { } public OpenApiSchema(Microsoft.OpenApi.Models.OpenApiSchema schema) { } @@ -977,7 +999,7 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiTag() { } public OpenApiTag(Microsoft.OpenApi.Models.OpenApiTag tag) { } @@ -1098,7 +1120,7 @@ namespace Microsoft.OpenApi.Models } namespace Microsoft.OpenApi.Models.References { - public class OpenApiCallbackReference : Microsoft.OpenApi.Models.OpenApiCallback, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiCallbackReference : Microsoft.OpenApi.Models.OpenApiCallback, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiCallback Target { get; } @@ -1107,19 +1129,24 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiExampleReference : Microsoft.OpenApi.Models.OpenApiExample, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiExampleReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample { + public OpenApiExampleReference(Microsoft.OpenApi.Models.References.OpenApiExampleReference example) { } public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public string ExternalValue { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public string Summary { get; set; } public Microsoft.OpenApi.Models.OpenApiExample Target { get; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override string ExternalValue { get; set; } - public override string Summary { get; set; } - public override System.Text.Json.Nodes.JsonNode Value { get; set; } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public bool UnresolvedReference { get; set; } + public System.Text.Json.Nodes.JsonNode Value { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample openApiExample) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeaderReference : Microsoft.OpenApi.Models.OpenApiHeader, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiHeaderReference : Microsoft.OpenApi.Models.OpenApiHeader, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiHeader Target { get; } @@ -1129,7 +1156,7 @@ namespace Microsoft.OpenApi.Models.References public override bool Deprecated { get; set; } public override string Description { get; set; } public override System.Text.Json.Nodes.JsonNode Example { get; set; } - public override System.Collections.Generic.IDictionary Examples { get; set; } + public override System.Collections.Generic.IDictionary Examples { get; set; } public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override bool Required { get; set; } @@ -1139,7 +1166,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiLink Target { get; } @@ -1153,7 +1180,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiParameter Target { get; } @@ -1163,7 +1190,7 @@ namespace Microsoft.OpenApi.Models.References public override bool Deprecated { get; set; } public override string Description { get; set; } public override System.Text.Json.Nodes.JsonNode Example { get; set; } - public override System.Collections.Generic.IDictionary Examples { get; set; } + public override System.Collections.Generic.IDictionary Examples { get; set; } public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } @@ -1175,7 +1202,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiPathItem Target { get; } @@ -1187,7 +1214,7 @@ namespace Microsoft.OpenApi.Models.References public override string Summary { get; set; } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiRequestBody Target { get; } @@ -1198,7 +1225,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiResponse Target { get; } @@ -1211,7 +1238,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiSchema? Target { get; } @@ -1270,7 +1297,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiSecurityScheme Target { get; } @@ -1287,7 +1314,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiTagReference(Microsoft.OpenApi.Models.References.OpenApiTagReference source) { } public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { } @@ -1478,13 +1505,13 @@ namespace Microsoft.OpenApi.Services public virtual void Exit() { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } - public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceable referenceable) { } + public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder referenceHolder) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiCallback callback) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiEncoding encoding) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiExample example) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiHeader header) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } @@ -1507,15 +1534,15 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } public virtual void Visit(Microsoft.OpenApi.Models.References.OpenApiTagReference tag) { } public virtual void Visit(System.Collections.Generic.IDictionary operations) { } + public virtual void Visit(System.Collections.Generic.IDictionary examples) { } public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } - public virtual void Visit(System.Collections.Generic.IDictionary examples) { } public virtual void Visit(System.Collections.Generic.IDictionary headers) { } public virtual void Visit(System.Collections.Generic.IDictionary links) { } public virtual void Visit(System.Collections.Generic.IDictionary content) { } public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } public virtual void Visit(System.Collections.Generic.IDictionary serverVariables) { } - public virtual void Visit(System.Collections.Generic.IList example) { } + public virtual void Visit(System.Collections.Generic.IList example) { } public virtual void Visit(System.Collections.Generic.IList parameters) { } public virtual void Visit(System.Collections.Generic.IList openApiSecurityRequirements) { } public virtual void Visit(System.Collections.Generic.IList servers) { } @@ -1578,12 +1605,12 @@ namespace Microsoft.OpenApi.Validations public void AddWarning(Microsoft.OpenApi.Validations.OpenApiValidatorWarning warning) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiCallback callback) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiEncoding encoding) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiExample example) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiHeader header) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } @@ -1605,14 +1632,14 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiServerVariable serverVariable) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } public override void Visit(System.Collections.Generic.IDictionary operations) { } + public override void Visit(System.Collections.Generic.IDictionary examples) { } public override void Visit(System.Collections.Generic.IDictionary callbacks) { } public override void Visit(System.Collections.Generic.IDictionary encodings) { } - public override void Visit(System.Collections.Generic.IDictionary examples) { } public override void Visit(System.Collections.Generic.IDictionary headers) { } public override void Visit(System.Collections.Generic.IDictionary links) { } public override void Visit(System.Collections.Generic.IDictionary content) { } public override void Visit(System.Collections.Generic.IDictionary serverVariables) { } - public override void Visit(System.Collections.Generic.IList example) { } + public override void Visit(System.Collections.Generic.IList example) { } } public class OpenApiValidatorError : Microsoft.OpenApi.Models.OpenApiError { diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index 3a685f3a8..485f8587c 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -63,11 +63,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() }, Examples = { - ["example0"] = new() + ["example0"] = new OpenApiExample() { Value = "1", }, - ["example1"] = new() + ["example1"] = new OpenApiExample() { Value = new JsonObject() { @@ -76,11 +76,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() ["z"] = "200" } }, - ["example2"] = new() + ["example2"] = new OpenApiExample() { Value = new JsonArray(){3} }, - ["example3"] = new() + ["example3"] = new OpenApiExample() { Value = new JsonObject() { diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index 834443135..96afcb301 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -57,11 +57,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() }, Examples = { - ["example0"] = new() + ["example0"] = new OpenApiExample() { Value = "1", }, - ["example1"] = new() + ["example1"] = new OpenApiExample() { Value = new JsonObject() { @@ -70,11 +70,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() ["z"] = "200" } }, - ["example2"] = new() + ["example2"] = new OpenApiExample() { Value = new JsonArray(){3} }, - ["example3"] = new() + ["example3"] = new OpenApiExample() { Value = new JsonObject() { diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index cacf3d7fa..c08c88471 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -110,11 +110,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() }, Examples = { - ["example0"] = new() + ["example0"] = new OpenApiExample() { Value = "1", }, - ["example1"] = new() + ["example1"] = new OpenApiExample() { Value = new JsonObject() { @@ -123,11 +123,11 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() ["z"] = "200" } }, - ["example2"] = new() + ["example2"] = new OpenApiExample() { Value = new JsonArray(){3} }, - ["example3"] = new() + ["example3"] = new OpenApiExample() { Value = new JsonObject() { diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index e805d4673..342fb317a 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; using Xunit; @@ -39,7 +40,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiMediaType)); visitor.Visit(default(OpenApiEncoding)); - visitor.Visit(default(IDictionary)); + visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiComponents)); visitor.Visit(default(OpenApiExternalDocs)); visitor.Visit(default(OpenApiSchema)); @@ -51,17 +52,17 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiOAuthFlow)); visitor.Visit(default(OpenApiSecurityRequirement)); visitor.Visit(default(OpenApiSecurityScheme)); - visitor.Visit(default(OpenApiExample)); + visitor.Visit(default(IOpenApiExample)); visitor.Visit(default(IList)); visitor.Visit(default(IList)); visitor.Visit(default(IOpenApiExtensible)); visitor.Visit(default(IOpenApiExtension)); - visitor.Visit(default(IList)); + visitor.Visit(default(IList)); visitor.Visit(default(IDictionary)); visitor.Visit(default(IDictionary)); - visitor.Visit(default(IOpenApiReferenceable)); + visitor.Visit(default(IOpenApiReferenceHolder)); visitor.Exit(); - Assert.True(42 < ((TestVisitor)visitor).CallStack.Count()); + Assert.True(42 < ((TestVisitor)visitor).CallStack.Count); } internal protected class TestVisitor : OpenApiVisitorBase @@ -213,7 +214,7 @@ public override void Visit(OpenApiEncoding encoding) base.Visit(encoding); } - public override void Visit(IDictionary examples) + public override void Visit(IDictionary examples) { EncodeCall(); base.Visit(examples); @@ -285,7 +286,7 @@ public override void Visit(OpenApiSecurityScheme securityScheme) base.Visit(securityScheme); } - public override void Visit(OpenApiExample example) + public override void Visit(IOpenApiExample example) { EncodeCall(); base.Visit(example); @@ -315,7 +316,7 @@ public override void Visit(IOpenApiExtension openApiExtension) base.Visit(openApiExtension); } - public override void Visit(IList example) + public override void Visit(IList example) { EncodeCall(); base.Visit(example); @@ -333,7 +334,7 @@ public override void Visit(IDictionary encodings) base.Visit(encodings); } - public override void Visit(IOpenApiReferenceable referenceable) + public override void Visit(IOpenApiReferenceHolder referenceable) { EncodeCall(); base.Visit(referenceable); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index f90d058b2..c307229cf 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -293,7 +293,7 @@ public override void Visit(OpenApiResponse response) Locations.Add(this.PathString); } - public override void Visit(IOpenApiReferenceable referenceable) + public override void Visit(IOpenApiReferenceHolder referenceable) { Locations.Add("referenceAt: " + this.PathString); } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs index f93b10375..cb554d4f6 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs @@ -20,7 +20,7 @@ public class OpenApiReferencableTests private static readonly OpenApiHeader _headerFragment = new() { Schema = new OpenApiSchema(), - Examples = new Dictionary + Examples = { { "example1", new OpenApiExample() } } @@ -28,7 +28,7 @@ public class OpenApiReferencableTests private static readonly OpenApiParameter _parameterFragment = new() { Schema = new OpenApiSchema(), - Examples = new Dictionary + Examples = { { "example1", new OpenApiExample() } } From 2cbb0fa352ecaf09014f26ab5fddc8ca89e63c2c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 13:49:34 -0500 Subject: [PATCH 009/103] fix: callback reference proxy implementation --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 3 +- .../StatsVisitor.cs | 3 +- .../Models/Interfaces/IOpenApiCallback.cs | 18 ++++++ .../Models/OpenApiCallback.cs | 30 +++------- .../Models/OpenApiComponents.cs | 4 +- .../Models/OpenApiDocument.cs | 2 +- .../Models/OpenApiOperation.cs | 5 +- .../References/OpenApiCallbackReference.cs | 59 ++++++++++++++----- .../References/OpenApiExampleReference.cs | 4 +- .../Reader/V3/OpenApiCallbackDeserializer.cs | 3 +- .../Reader/V31/OpenApiCallbackDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 6 +- .../Services/OpenApiWalker.cs | 10 ++-- .../Validations/OpenApiValidator.cs | 4 +- .../V3Tests/OpenApiCallbackTests.cs | 17 +----- .../PublicApi/PublicApi.approved.txt | 45 ++++++++------ .../Visitors/InheritanceTests.cs | 8 +-- 18 files changed, 132 insertions(+), 98 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index d1f6f7f64..a0dc1ae0e 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; namespace Microsoft.OpenApi.Hidi @@ -68,7 +69,7 @@ public override void Visit(OpenApiLink link) public int CallbackCount { get; set; } - public override void Visit(OpenApiCallback callback) + public override void Visit(IOpenApiCallback callback) { CallbackCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index fafbc8188..db9f1add9 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; namespace Microsoft.OpenApi.Workbench @@ -68,7 +69,7 @@ public override void Visit(OpenApiLink link) public int CallbackCount { get; set; } - public override void Visit(OpenApiCallback callback) + public override void Visit(IOpenApiCallback callback) { CallbackCount++; } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs new file mode 100644 index 000000000..a8fde7697 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs @@ -0,0 +1,18 @@ + +using System.Collections.Generic; +using Microsoft.OpenApi.Expressions; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the callback object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiCallback : IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// A Path Item Object used to define a callback request and expected responses. + /// + public Dictionary PathItems { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs index f538d90c0..953792a79 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -12,28 +13,17 @@ namespace Microsoft.OpenApi.Models /// /// Callback Object: A map of possible out-of band callbacks related to the parent operation. /// - public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiCallback { - /// - /// A Path Item Object used to define a callback request and expected responses. - /// - public virtual Dictionary PathItems { get; set; } - = new(); + /// + public Dictionary PathItems { get; set; } + = []; - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public virtual bool UnresolvedReference { get; set; } - - /// - /// Reference pointer. - /// - public OpenApiReference Reference { get; set; } /// /// This object MAY be extended with Specification Extensions. /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -43,11 +33,9 @@ public OpenApiCallback() { } /// /// Initializes a copy of an object /// - public OpenApiCallback(OpenApiCallback callback) + public OpenApiCallback(IOpenApiCallback callback) { PathItems = callback?.PathItems != null ? new(callback?.PathItems) : null; - UnresolvedReference = callback?.UnresolvedReference ?? UnresolvedReference; - Reference = callback?.Reference != null ? new(callback?.Reference) : null; Extensions = callback?.Extensions != null ? new Dictionary(callback.Extensions) : null; } @@ -71,7 +59,7 @@ public void AddPathItem(RuntimeExpression expression, OpenApiPathItem pathItem) /// /// /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } @@ -79,7 +67,7 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 6ca0089b4..419bc15a7 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -63,7 +63,7 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Callbacks { get; set; } = new Dictionary(); + public virtual IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// An object to hold reusable Object. @@ -93,7 +93,7 @@ public OpenApiComponents(OpenApiComponents? components) Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; Links = components?.Links != null ? new Dictionary(components.Links) : null; - Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; + Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null; Extensions = components?.Extensions != null ? new Dictionary(components.Extensions) : null; } diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 9b7099f56..0e9f510ea 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -608,7 +608,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Links.Add(id, openApiLink); break; case OpenApiCallback openApiCallback: - Components.Callbacks ??= new Dictionary(); + Components.Callbacks ??= new Dictionary(); Components.Callbacks.Add(id, openApiCallback); break; case OpenApiPathItem openApiPathItem: diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 7e3b5d712..beeb1c7e2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -80,7 +81,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenA /// The key value used to identify the callback object is an expression, evaluated at runtime, /// that identifies a URL to use for the callback operation. /// - public IDictionary? Callbacks { get; set; } = new Dictionary(); + public IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation. @@ -129,7 +130,7 @@ public OpenApiOperation(OpenApiOperation? operation) Parameters = operation?.Parameters != null ? new List(operation.Parameters) : null; RequestBody = operation?.RequestBody != null ? new(operation?.RequestBody) : null; Responses = operation?.Responses != null ? new(operation?.Responses) : null; - Callbacks = operation?.Callbacks != null ? new Dictionary(operation.Callbacks) : null; + Callbacks = operation?.Callbacks != null ? new Dictionary(operation.Callbacks) : null; Deprecated = operation?.Deprecated ?? Deprecated; Security = operation?.Security != null ? new List(operation.Security) : null; Servers = operation?.Servers != null ? new List(operation.Servers) : null; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 13cea041a..bc75e8e5c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -12,11 +13,15 @@ namespace Microsoft.OpenApi.Models.References /// /// Callback Object Reference: A reference to a map of possible out-of band callbacks related to the parent operation. /// - public class OpenApiCallbackReference : OpenApiCallback, IOpenApiReferenceHolder + public class OpenApiCallbackReference : IOpenApiCallback, IOpenApiReferenceHolder { #nullable enable internal OpenApiCallback _target; - private readonly OpenApiReference _reference; + /// + public OpenApiReference Reference { get; set; } + + /// + public bool UnresolvedReference { get; set; } /// /// Gets the target callback. @@ -29,7 +34,7 @@ public OpenApiCallback Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); return _target; } } @@ -48,22 +53,31 @@ public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Callback, ExternalResource = externalResource }; + } - Reference = _reference; + /// + /// Copy constructor + /// + /// The callback reference to copy + public OpenApiCallbackReference(OpenApiCallbackReference callback) + { + Utils.CheckArgumentNull(callback); + Reference = callback?.Reference != null ? new(callback.Reference) : null; + UnresolvedReference = callback?.UnresolvedReference ?? false; } internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) { _target = target; - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, Type = ReferenceType.Callback, @@ -71,18 +85,17 @@ internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) } /// - public override Dictionary PathItems { get => Target.PathItems; set => Target.PathItems = value; } + public Dictionary PathItems { get => Target.PathItems; } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public IDictionary Extensions { get => Target.Extensions; } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { @@ -91,12 +104,11 @@ public override void SerializeAsV3(IOpenApiWriter writer) } /// - public override void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { @@ -104,6 +116,21 @@ public override void SerializeAsV31(IOpenApiWriter writer) } } + /// + public IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback openApiExample) + { + // the copy here is never called since callbacks do not have any overridable fields. + // if the spec evolves to include overridable fields for callbacks, the serialize methods will need to call this copy method. + return openApiExample is OpenApiCallback ? new OpenApiCallback(this) : openApiExample; + } + + /// + public void SerializeAsV2(IOpenApiWriter writer) + { + // examples components are not supported in OAS 2.0 + Reference.SerializeAsV2(writer); + } + /// private void SerializeInternal(IOpenApiWriter writer, Action action) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 0f8638c3e..dc1a22ee9 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -19,7 +19,7 @@ public class OpenApiExampleReference : IOpenApiReferenceHolder - public bool UnresolvedReference { get; set; } = false; + public bool UnresolvedReference { get; set; } internal OpenApiExample _target; /// @@ -68,7 +68,7 @@ public OpenApiExampleReference(OpenApiExampleReference example) { Utils.CheckArgumentNull(example); Reference = example?.Reference != null ? new(example.Reference) : null; - UnresolvedReference = example?.UnresolvedReference ?? UnresolvedReference; + UnresolvedReference = example?.UnresolvedReference ?? false; //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs index bdf4a8716..adab9ccab 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs @@ -4,6 +4,7 @@ using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -24,7 +25,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; - public static OpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("callback"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs index c0d4c5951..49407e339 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs @@ -4,6 +4,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Reader.V31 { @@ -23,7 +24,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; - public static OpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("callback"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 086961a94..944fabe87 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -136,9 +136,9 @@ private void AddCallbackToComponents(OpenApiCallback callback, string referenceI { EnsureComponentsExist(); EnsureCallbacksExist(); - if (!Components.Callbacks.ContainsKey(referenceId ?? callback.Reference.Id)) + if (!Components.Callbacks.ContainsKey(referenceId)) { - Components.Callbacks.Add(referenceId ?? callback.Reference.Id, callback); + Components.Callbacks.Add(referenceId, callback); } } private void AddHeaderToComponents(OpenApiHeader header, string referenceId = null) @@ -230,7 +230,7 @@ private void EnsureHeadersExist() private void EnsureCallbacksExist() { - _target.Components.Callbacks ??= new Dictionary(); + _target.Components.Callbacks ??= new Dictionary(); } private void EnsureLinksExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 8f0c24de5..1bd202ff7 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -169,7 +169,7 @@ public virtual void Visit(IDictionary headers) /// /// Visits callbacks. /// - public virtual void Visit(IDictionary callbacks) + public virtual void Visit(IDictionary callbacks) { } @@ -251,9 +251,9 @@ public virtual void Visit(OpenApiLink link) } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiCallback callback) + public virtual void Visit(IOpenApiCallback callback) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 94a263bd0..47a4f4c2e 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -406,9 +406,9 @@ internal void Walk(OpenApiContact contact) } /// - /// Visits and child objects + /// Visits and child objects /// - internal void Walk(OpenApiCallback callback, bool isComponent = false) + internal void Walk(IOpenApiCallback callback, bool isComponent = false) { if (callback == null) { @@ -760,9 +760,9 @@ internal void Walk(IDictionary headers) } /// - /// Visits dictionary of + /// Visits dictionary of /// - internal void Walk(IDictionary callbacks) + internal void Walk(IDictionary callbacks) { if (callbacks == null) { @@ -1191,7 +1191,7 @@ internal void Walk(IOpenApiElement element) case OpenApiInfo e: Walk(e); break; case OpenApiComponents e: Walk(e); break; case OpenApiContact e: Walk(e); break; - case OpenApiCallback e: Walk(e); break; + case IOpenApiCallback e: Walk(e); break; case OpenApiEncoding e: Walk(e); break; case IOpenApiExample e: Walk(e); break; case IDictionary e: Walk(e); break; diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 0cc7ade2b..8ec8d4ca0 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -117,7 +117,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiEncoding encoding) => Validate(encoding); /// - public override void Visit(OpenApiCallback callback) => Validate(callback); + public override void Visit(IOpenApiCallback callback) => Validate(callback); /// public override void Visit(IOpenApiExtensible openApiExtensible) => Validate(openApiExtensible); @@ -159,7 +159,7 @@ public void AddWarning(OpenApiValidatorWarning warning) /// public override void Visit(IDictionary headers) => Validate(headers, headers.GetType()); /// - public override void Visit(IDictionary callbacks) => Validate(callbacks, callbacks.GetType()); + public override void Visit(IDictionary callbacks) => Validate(callbacks, callbacks.GetType()); /// public override void Visit(IDictionary content) => Validate(content, content.GetType()); /// diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 7a1b43f2f..4476d23a8 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Xunit; @@ -79,7 +80,7 @@ public async Task ParseCallbackWithReferenceShouldSucceed() new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, result.Diagnostic); Assert.Equivalent( - new OpenApiCallback + new OpenApiCallbackReference("simpleHook", result.Document) { PathItems = { @@ -110,12 +111,6 @@ public async Task ParseCallbackWithReferenceShouldSucceed() } } }, - Reference = new OpenApiReference - { - Type = ReferenceType.Callback, - Id = "simpleHook", - HostDocument = result.Document - } }, callback); } @@ -135,7 +130,7 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() var callback1 = subscribeOperation.Callbacks["simpleHook"]; Assert.Equivalent( - new OpenApiCallback + new OpenApiCallbackReference("simpleHook", result.Document) { PathItems = { @@ -166,12 +161,6 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() } } }, - Reference = new OpenApiReference - { - Type = ReferenceType.Callback, - Id = "simpleHook", - HostDocument = result.Document - } }, callback1); var callback2 = subscribeOperation.Callbacks["callback2"]; diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 9ad9336d3..c58260228 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -337,6 +337,10 @@ namespace Microsoft.OpenApi.MicrosoftExtensions } namespace Microsoft.OpenApi.Models.Interfaces { + public interface IOpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + { + System.Collections.Generic.Dictionary PathItems { get; } + } public interface IOpenApiDescribedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Description { get; set; } @@ -361,25 +365,23 @@ namespace Microsoft.OpenApi.Models Object = 32, Array = 64, } - public class OpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { public OpenApiCallback() { } - public OpenApiCallback(Microsoft.OpenApi.Models.OpenApiCallback callback) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual System.Collections.Generic.Dictionary PathItems { get; set; } - public virtual bool UnresolvedReference { get; set; } + public OpenApiCallback(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public System.Collections.Generic.Dictionary PathItems { get; set; } public void AddPathItem(Microsoft.OpenApi.Expressions.RuntimeExpression expression, Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiComponents : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiComponents() { } public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents? components) { } public System.Collections.Generic.IDictionary? Schemas { get; set; } - public virtual System.Collections.Generic.IDictionary? Callbacks { get; set; } + public virtual System.Collections.Generic.IDictionary? Callbacks { get; set; } public virtual System.Collections.Generic.IDictionary? Examples { get; set; } public virtual System.Collections.Generic.IDictionary? Extensions { get; set; } public virtual System.Collections.Generic.IDictionary? Headers { get; set; } @@ -770,7 +772,7 @@ namespace Microsoft.OpenApi.Models public OpenApiOperation() { } public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation? operation) { } public System.Collections.Generic.IDictionary? Annotations { get; set; } - public System.Collections.Generic.IDictionary? Callbacks { get; set; } + public System.Collections.Generic.IDictionary? Callbacks { get; set; } public bool Deprecated { get; set; } public string? Description { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } @@ -1120,14 +1122,19 @@ namespace Microsoft.OpenApi.Models } namespace Microsoft.OpenApi.Models.References { - public class OpenApiCallbackReference : Microsoft.OpenApi.Models.OpenApiCallback, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiCallbackReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { + public OpenApiCallbackReference(Microsoft.OpenApi.Models.References.OpenApiCallbackReference callback) { } public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public System.Collections.Generic.IDictionary Extensions { get; } + public System.Collections.Generic.Dictionary PathItems { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public Microsoft.OpenApi.Models.OpenApiCallback Target { get; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override System.Collections.Generic.Dictionary PathItems { get; set; } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public bool UnresolvedReference { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback openApiExample) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiExampleReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample { @@ -1506,8 +1513,8 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder referenceHolder) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiCallback callback) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1534,8 +1541,8 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } public virtual void Visit(Microsoft.OpenApi.Models.References.OpenApiTagReference tag) { } public virtual void Visit(System.Collections.Generic.IDictionary operations) { } + public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary examples) { } - public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } public virtual void Visit(System.Collections.Generic.IDictionary headers) { } public virtual void Visit(System.Collections.Generic.IDictionary links) { } @@ -1605,8 +1612,8 @@ namespace Microsoft.OpenApi.Validations public void AddWarning(Microsoft.OpenApi.Validations.OpenApiValidatorWarning warning) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiCallback callback) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1632,8 +1639,8 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiServerVariable serverVariable) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } public override void Visit(System.Collections.Generic.IDictionary operations) { } + public override void Visit(System.Collections.Generic.IDictionary callbacks) { } public override void Visit(System.Collections.Generic.IDictionary examples) { } - public override void Visit(System.Collections.Generic.IDictionary callbacks) { } public override void Visit(System.Collections.Generic.IDictionary encodings) { } public override void Visit(System.Collections.Generic.IDictionary headers) { } public override void Visit(System.Collections.Generic.IDictionary links) { } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 342fb317a..4acb0aadf 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -34,7 +34,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiParameter)); visitor.Visit(default(OpenApiRequestBody)); visitor.Visit(default(IDictionary)); - visitor.Visit(default(IDictionary)); + visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiResponse)); visitor.Visit(default(OpenApiResponses)); visitor.Visit(default(IDictionary)); @@ -46,7 +46,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiSchema)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiLink)); - visitor.Visit(default(OpenApiCallback)); + visitor.Visit(default(IOpenApiCallback)); visitor.Visit(default(OpenApiTag)); visitor.Visit(default(OpenApiHeader)); visitor.Visit(default(OpenApiOAuthFlow)); @@ -178,7 +178,7 @@ public override void Visit(IDictionary headers) base.Visit(headers); } - public override void Visit(IDictionary callbacks) + public override void Visit(IDictionary callbacks) { EncodeCall(); base.Visit(callbacks); @@ -250,7 +250,7 @@ public override void Visit(OpenApiLink link) base.Visit(link); } - public override void Visit(OpenApiCallback callback) + public override void Visit(IOpenApiCallback callback) { EncodeCall(); base.Visit(callback); From dc2ce696167e7eb4caf0a8f1c94ccc66870c9604 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 13:54:31 -0500 Subject: [PATCH 010/103] chore: adds a todo for later Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs index 99b5dde2d..74a38e04a 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs @@ -38,6 +38,7 @@ public interface IOpenApiReferenceHolder : IOpenApiSerializable /// Indicates if object is populated with data or is just a reference to the data /// bool UnresolvedReference { get; set; } + //TODO the UnresolvedReference property setter should be removed and a default implementation that checks whether the target is null for the getter should be provided instead /// /// Reference object. From af3038a0fcee46c4806382fe061e4f2e7059fdbe Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 13:57:15 -0500 Subject: [PATCH 011/103] fix: removes useless virtual definitions in components Signed-off-by: Vincent Biret --- .../Models/OpenApiComponents.cs | 20 +++++++++---------- .../PublicApi/PublicApi.approved.txt | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 419bc15a7..686ed1326 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -25,55 +25,55 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Responses { get; set; } = new Dictionary(); + public IDictionary? Responses { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Parameters { get; set; } = + public IDictionary? Parameters { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Examples { get; set; } = new Dictionary(); + public IDictionary? Examples { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? RequestBodies { get; set; } = + public IDictionary? RequestBodies { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Headers { get; set; } = new Dictionary(); + public IDictionary? Headers { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? SecuritySchemes { get; set; } = + public IDictionary? SecuritySchemes { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Links { get; set; } = new Dictionary(); + public IDictionary? Links { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary? Callbacks { get; set; } = new Dictionary(); + public IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// An object to hold reusable Object. /// - public virtual IDictionary? PathItems { get; set; } = new Dictionary(); + public IDictionary? PathItems { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. /// - public virtual IDictionary? Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index c58260228..69d509df5 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -380,17 +380,17 @@ namespace Microsoft.OpenApi.Models { public OpenApiComponents() { } public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents? components) { } + public System.Collections.Generic.IDictionary? Callbacks { get; set; } + public System.Collections.Generic.IDictionary? Examples { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public System.Collections.Generic.IDictionary? Headers { get; set; } + public System.Collections.Generic.IDictionary? Links { get; set; } + public System.Collections.Generic.IDictionary? Parameters { get; set; } + public System.Collections.Generic.IDictionary? PathItems { get; set; } + public System.Collections.Generic.IDictionary? RequestBodies { get; set; } + public System.Collections.Generic.IDictionary? Responses { get; set; } public System.Collections.Generic.IDictionary? Schemas { get; set; } - public virtual System.Collections.Generic.IDictionary? Callbacks { get; set; } - public virtual System.Collections.Generic.IDictionary? Examples { get; set; } - public virtual System.Collections.Generic.IDictionary? Extensions { get; set; } - public virtual System.Collections.Generic.IDictionary? Headers { get; set; } - public virtual System.Collections.Generic.IDictionary? Links { get; set; } - public virtual System.Collections.Generic.IDictionary? Parameters { get; set; } - public virtual System.Collections.Generic.IDictionary? PathItems { get; set; } - public virtual System.Collections.Generic.IDictionary? RequestBodies { get; set; } - public virtual System.Collections.Generic.IDictionary? Responses { get; set; } - public virtual System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } + public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From 2a10cd95d254001c397a7cd28568e468800e6644 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 14:19:09 -0500 Subject: [PATCH 012/103] feat: splits described and summarized interfaces Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiDescribedElement.cs | 7 +------ .../Models/Interfaces/IOpenApiExample.cs | 2 +- .../Models/Interfaces/IOpenApiSummarizedElement.cs | 13 +++++++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSummarizedElement.cs diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs index 76a945548..ca035cc51 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs @@ -3,15 +3,10 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// -/// Describes an element that has a summary and description. +/// Describes an element that has a description. /// public interface IOpenApiDescribedElement : IOpenApiElement { - /// - /// Short description for the example. - /// - public string Summary { get; set; } - /// /// Long description for the example. /// CommonMark syntax MAY be used for rich text representation. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs index 3711df4b8..bc7639c04 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs @@ -7,7 +7,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the example object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiExample : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiExample : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible { /// /// Embedded literal example. The value field and externalValue field are mutually diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSummarizedElement.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSummarizedElement.cs new file mode 100644 index 000000000..3273b03f5 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSummarizedElement.cs @@ -0,0 +1,13 @@ +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; +/// +/// Describes an element that has a summary. +/// +public interface IOpenApiSummarizedElement : IOpenApiElement +{ + /// + /// Short description for the example. + /// + public string Summary { get; set; } +} From 68b25cc5cc9ffd809a45ce532200ce3262f39ad2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 14:22:38 -0500 Subject: [PATCH 013/103] fix: aligns callback parameter name with interface Signed-off-by: Vincent Biret --- .../Models/References/OpenApiCallbackReference.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index bc75e8e5c..536b30086 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -117,11 +117,11 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback openApiExample) + public IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback source) { // the copy here is never called since callbacks do not have any overridable fields. // if the spec evolves to include overridable fields for callbacks, the serialize methods will need to call this copy method. - return openApiExample is OpenApiCallback ? new OpenApiCallback(this) : openApiExample; + return source is OpenApiCallback ? new OpenApiCallback(this) : source; } /// From d7e1f919ee61e7cd4596f216890e16c7719e99c9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 14:22:56 -0500 Subject: [PATCH 014/103] fix: aligns parameter name with interface definition for example Signed-off-by: Vincent Biret --- .../Models/References/OpenApiExampleReference.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index dc1a22ee9..8d4eeabb1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -146,9 +146,9 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample openApiExample) + public IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample source) { - return openApiExample is OpenApiExample ? new OpenApiExample(this) : openApiExample; + return source is OpenApiExample ? new OpenApiExample(this) : source; } /// From 77e0ad10ca213c449523e9ff1802da6a6bd800e2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 14:51:08 -0500 Subject: [PATCH 015/103] fix: Open API header proxy design pattern implementation Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../OpenApiReferencableExtensions.cs | 23 ++-- .../Models/Interfaces/IOpenApiHeader.cs | 65 ++++++++++ .../Models/OpenApiComponents.cs | 6 +- .../Models/OpenApiDocument.cs | 2 +- .../Models/OpenApiEncoding.cs | 5 +- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 105 +++++----------- .../Models/OpenApiResponse.cs | 5 +- .../References/OpenApiHeaderReference.cs | 103 ++++++++------- .../References/OpenApiResponseReference.cs | 5 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 3 +- .../Reader/V3/OpenApiHeaderDeserializer.cs | 3 +- .../Reader/V31/OpenApiHeaderDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 4 +- .../Validations/OpenApiValidator.cs | 4 +- .../Rules/OpenApiNonDefaultRules.cs | 2 +- .../Services/OpenApiFilterServiceTests.cs | 3 +- .../V3Tests/OpenApiDocumentTests.cs | 3 +- .../V3Tests/OpenApiEncodingTests.cs | 2 +- .../References/OpenApiHeaderReferenceTests.cs | 2 +- .../PublicApi/PublicApi.approved.txt | 118 ++++++++++-------- .../OpenApiHeaderValidationTests.cs | 12 +- .../Visitors/InheritanceTests.cs | 8 +- .../Walkers/WalkerLocationTests.cs | 16 +-- .../Workspaces/OpenApiReferencableTests.cs | 4 +- .../Workspaces/OpenApiWorkspaceTests.cs | 2 +- 29 files changed, 294 insertions(+), 228 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index a0dc1ae0e..a6ea032f1 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -27,7 +27,7 @@ public override void Visit(OpenApiSchema schema) public int HeaderCount { get; set; } - public override void Visit(IDictionary headers) + public override void Visit(IDictionary headers) { HeaderCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index db9f1add9..3e3b1cf93 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -27,7 +27,7 @@ public override void Visit(OpenApiSchema schema) public int HeaderCount { get; set; } - public override void Visit(IDictionary headers) + public override void Visit(IDictionary headers) { HeaderCount++; } diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs index 3a160b135..da51f3b55 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs @@ -92,15 +92,24 @@ private static IOpenApiReferenceable ResolveReferenceOnResponseElement( string mapKey, JsonPointer pointer) { - switch (propertyName) + if (!string.IsNullOrEmpty(mapKey)) { - case OpenApiConstants.Headers when mapKey != null: - return responseElement.Headers[mapKey]; - case OpenApiConstants.Links when mapKey != null: - return responseElement.Links[mapKey]; - default: - throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); + if (OpenApiConstants.Headers.Equals(propertyName, StringComparison.Ordinal) && + responseElement?.Headers != null && + responseElement.Headers.TryGetValue(mapKey, out var headerElement) && + headerElement is IOpenApiReferenceable referenceable) + { + return referenceable; + } + if (OpenApiConstants.Links.Equals(propertyName, StringComparison.Ordinal) && + responseElement?.Links != null && + responseElement.Links.TryGetValue(mapKey, out var linkElement) && + linkElement is IOpenApiReferenceable referenceable2) + { + return referenceable2; + } } + throw new OpenApiException(string.Format(SRResource.InvalidReferenceId, pointer)); } } } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs new file mode 100644 index 000000000..9931775c7 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs @@ -0,0 +1,65 @@ + +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the headers object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// Determines whether this header is mandatory. + /// + public bool Required { get; } + + /// + /// Specifies that a header is deprecated and SHOULD be transitioned out of usage. + /// + public bool Deprecated { get; } + + /// + /// Sets the ability to pass empty-valued headers. + /// + public bool AllowEmptyValue { get; } + + /// + /// Describes how the header value will be serialized depending on the type of the header value. + /// + public ParameterStyle? Style { get; } + + /// + /// When this is true, header values of type array or object generate separate parameters + /// for each value of the array or key-value pair of the map. + /// + public bool Explode { get; } + + /// + /// Determines whether the header value SHOULD allow reserved characters, as defined by RFC3986. + /// + public bool AllowReserved { get; } + + /// + /// The schema defining the type used for the request body. + /// + public OpenApiSchema Schema { get; } + + /// + /// Example of the media type. + /// + public JsonNode Example { get; } + + /// + /// Examples of the media type. + /// + public IDictionary Examples { get; } + + /// + /// A map containing the representations for the header. + /// + public IDictionary Content { get; } + +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 686ed1326..c578ddc9a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -45,9 +45,9 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? Headers { get; set; } = new Dictionary(); + public IDictionary? Headers { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -90,7 +90,7 @@ public OpenApiComponents(OpenApiComponents? components) Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; - Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; + Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; Links = components?.Links != null ? new Dictionary(components.Links) : null; Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 0e9f510ea..6985aea1a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -620,7 +620,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Examples.Add(id, openApiExample); break; case OpenApiHeader openApiHeader: - Components.Headers ??= new Dictionary(); + Components.Headers ??= new Dictionary(); Components.Headers.Add(id, openApiHeader); break; case OpenApiSecurityScheme openApiSecurityScheme: diff --git a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs index 9ab0e7468..bb8bfab17 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -24,7 +25,7 @@ public class OpenApiEncoding : IOpenApiSerializable, IOpenApiExtensible /// /// A map allowing additional information to be provided as headers. /// - public IDictionary Headers { get; set; } = new Dictionary(); + public IDictionary Headers { get; set; } = new Dictionary(); /// /// Describes how a specific property value will be serialized depending on its type. @@ -64,7 +65,7 @@ public OpenApiEncoding() { } public OpenApiEncoding(OpenApiEncoding encoding) { ContentType = encoding?.ContentType ?? ContentType; - Headers = encoding?.Headers != null ? new Dictionary(encoding.Headers) : null; + Headers = encoding?.Headers != null ? new Dictionary(encoding.Headers) : null; Style = encoding?.Style ?? Style; Explode = encoding?.Explode ?? Explode; AllowReserved = encoding?.AllowReserved ?? AllowReserved; diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index c27d18f8d..1f382220b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -16,84 +16,43 @@ namespace Microsoft.OpenApi.Models /// Header Object. /// The Header Object follows the structure of the Parameter Object. /// - public class OpenApiHeader : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiHeader : IOpenApiHeader, IOpenApiReferenceable, IOpenApiExtensible { - private OpenApiSchema _schema; + /// + public string Description { get; set; } - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public virtual bool UnresolvedReference { get; set; } - - /// - /// Reference pointer. - /// - public OpenApiReference Reference { get; set; } - - /// - /// A brief description of the header. - /// - public virtual string Description { get; set; } + /// + public bool Required { get; set; } - /// - /// Determines whether this header is mandatory. - /// - public virtual bool Required { get; set; } - - /// - /// Specifies that a header is deprecated and SHOULD be transitioned out of usage. - /// - public virtual bool Deprecated { get; set; } + /// + public bool Deprecated { get; set; } - /// - /// Sets the ability to pass empty-valued headers. - /// - public virtual bool AllowEmptyValue { get; set; } + /// + public bool AllowEmptyValue { get; set; } - /// - /// Describes how the header value will be serialized depending on the type of the header value. - /// - public virtual ParameterStyle? Style { get; set; } + /// + public ParameterStyle? Style { get; set; } - /// - /// When this is true, header values of type array or object generate separate parameters - /// for each value of the array or key-value pair of the map. - /// - public virtual bool Explode { get; set; } + /// + public bool Explode { get; set; } - /// - /// Determines whether the header value SHOULD allow reserved characters, as defined by RFC3986. - /// - public virtual bool AllowReserved { get; set; } + /// + public bool AllowReserved { get; set; } - /// - /// The schema defining the type used for the request body. - /// - public virtual OpenApiSchema Schema - { - get => _schema; - set => _schema = value; - } + /// + public OpenApiSchema Schema { get; set; } - /// - /// Example of the media type. - /// - public virtual JsonNode Example { get; set; } + /// + public JsonNode Example { get; set; } - /// - /// Examples of the media type. - /// - public virtual IDictionary Examples { get; set; } = new Dictionary(); + /// + public IDictionary Examples { get; set; } = new Dictionary(); - /// - /// A map containing the representations for the header. - /// - public virtual IDictionary Content { get; set; } = new Dictionary(); + /// + public IDictionary Content { get; set; } = new Dictionary(); - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -103,10 +62,8 @@ public OpenApiHeader() { } /// /// Initializes a copy of an object /// - public OpenApiHeader(OpenApiHeader header) + public OpenApiHeader(IOpenApiHeader header) { - UnresolvedReference = header?.UnresolvedReference ?? UnresolvedReference; - Reference = header?.Reference != null ? new(header?.Reference) : null; Description = header?.Description ?? Description; Required = header?.Required ?? Required; Deprecated = header?.Deprecated ?? Deprecated; @@ -114,7 +71,7 @@ public OpenApiHeader(OpenApiHeader header) Style = header?.Style ?? Style; Explode = header?.Explode ?? Explode; AllowReserved = header?.AllowReserved ?? AllowReserved; - _schema = header?.Schema != null ? new(header.Schema) : null; + Schema = header?.Schema != null ? new(header.Schema) : null; Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; @@ -124,7 +81,7 @@ public OpenApiHeader(OpenApiHeader header) /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV31(writer)); } @@ -132,12 +89,12 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { Utils.CheckArgumentNull(writer); @@ -186,7 +143,7 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio /// /// Serialize to OpenAPI V2 document without using reference. /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index 0aed7bb0d..755af74cd 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -22,7 +23,7 @@ public class OpenApiResponse : IOpenApiReferenceable, IOpenApiExtensible /// /// Maps a header name to its definition. /// - public virtual IDictionary Headers { get; set; } = new Dictionary(); + public virtual IDictionary Headers { get; set; } = new Dictionary(); /// /// A map containing descriptions of potential response payloads. @@ -63,7 +64,7 @@ public OpenApiResponse() { } public OpenApiResponse(OpenApiResponse response) { Description = response?.Description ?? Description; - Headers = response?.Headers != null ? new Dictionary(response.Headers) : null; + Headers = response?.Headers != null ? new Dictionary(response.Headers) : null; Content = response?.Content != null ? new Dictionary(response.Content) : null; Links = response?.Links != null ? new Dictionary(response.Links) : null; Extensions = response?.Extensions != null ? new Dictionary(response.Extensions) : null; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index d9f451c0a..3650190f3 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -13,12 +13,14 @@ namespace Microsoft.OpenApi.Models.References /// /// Header Object Reference. /// - public class OpenApiHeaderReference : OpenApiHeader, IOpenApiReferenceHolder + public class OpenApiHeaderReference : IOpenApiHeader, IOpenApiReferenceHolder { - internal OpenApiHeader _target; - private readonly OpenApiReference _reference; - private string _description; + /// + public OpenApiReference Reference { get; set; } + /// + public bool UnresolvedReference { get; set; } + internal OpenApiHeader _target; /// /// Gets the target header. /// @@ -29,10 +31,8 @@ public OpenApiHeader Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiHeader resolved = new OpenApiHeader(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + return _target; } } @@ -50,22 +50,33 @@ public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument, { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Header, ExternalResource = externalResource }; + } - Reference = _reference; + /// + /// Copy constructor + /// + /// The object to copy + public OpenApiHeaderReference(OpenApiHeaderReference header) + { + Utils.CheckArgumentNull(header); + Reference = header.Reference != null ? new(header.Reference) : null; + UnresolvedReference = header.UnresolvedReference; + //no need to copy description as if they are not overridden, they will be fetched from the target + //if they are, the reference copy will handle it } internal OpenApiHeaderReference(OpenApiHeader target, string referenceId) { _target = target; - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, Type = ReferenceType.Header, @@ -73,90 +84,98 @@ internal OpenApiHeaderReference(OpenApiHeader target, string referenceId) } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override bool Required { get => Target.Required; set => Target.Required = value; } + public bool Required { get => Target.Required; } /// - public override bool Deprecated { get => Target.Deprecated; set => Target.Deprecated = value; } + public bool Deprecated { get => Target.Deprecated; } /// - public override bool AllowEmptyValue { get => Target.AllowEmptyValue; set => Target.AllowEmptyValue = value; } + public bool AllowEmptyValue { get => Target.AllowEmptyValue; } /// - public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public OpenApiSchema Schema { get => Target.Schema; } /// - public override ParameterStyle? Style { get => Target.Style; set => Target.Style = value; } + public ParameterStyle? Style { get => Target.Style; } /// - public override bool Explode { get => Target.Explode; set => Target.Explode = value; } + public bool Explode { get => Target.Explode; } /// - public override bool AllowReserved { get => Target.AllowReserved; set => Target.AllowReserved = value; } + public bool AllowReserved { get => Target.AllowReserved; } /// - public override JsonNode Example { get => Target.Example; set => Target.Example = value; } + public JsonNode Example { get => Target.Example; } /// - public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } + public IDictionary Examples { get => Target.Examples; } /// - public override IDictionary Content { get => Target.Content; set => Target.Content = value; } + public IDictionary Content { get => Target.Content; } /// - public override IDictionary Extensions { get => base.Extensions; set => base.Extensions = value; } - + public IDictionary Extensions { get => Target.Extensions; } + /// - public override void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); } } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); } } /// - public override void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV2(writer); - return; + Reference.SerializeAsV2(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); } } + /// + public IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenApiHeader source) + { + return source is OpenApiHeader ? new OpenApiHeader(this) : source; + } /// private void SerializeInternal(IOpenApiWriter writer, - Action action) + Action action) { Utils.CheckArgumentNull(writer); action(writer, Target); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index 0983bd3b6..0f74e3ad5 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -81,9 +82,9 @@ public override string Description /// public override IDictionary Content { get => _content is not null ? _content : Target?.Content; set => _content = value; } - private IDictionary _headers; + private IDictionary _headers; /// - public override IDictionary Headers { get => _headers is not null ? _headers : Target?.Headers; set => _headers = value; } + public override IDictionary Headers { get => _headers is not null ? _headers : Target?.Headers; set => _headers = value; } private IDictionary _links; /// diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index 4a994bdc5..bc2333e46 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Reader.V2 { @@ -102,7 +103,7 @@ private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) return p.Schema ??= new(); } - public static OpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("header"); var header = new OpenApiHeader(); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs index 7830c394e..8553c1b70 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -70,7 +71,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("header"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs index 32c2b73fc..43a4f3292 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -84,7 +85,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("header"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 944fabe87..2575a6f77 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -145,9 +145,9 @@ private void AddHeaderToComponents(OpenApiHeader header, string referenceId = nu { EnsureComponentsExist(); EnsureHeadersExist(); - if (!Components.Headers.ContainsKey(referenceId ?? header.Reference.Id)) + if (!Components.Headers.ContainsKey(referenceId)) { - Components.Headers.Add(referenceId ?? header.Reference.Id, header); + Components.Headers.Add(referenceId, header); } } private void AddExampleToComponents(OpenApiExample example, string referenceId = null) @@ -225,7 +225,7 @@ private void EnsureExamplesExist() private void EnsureHeadersExist() { - _target.Components.Headers ??= new Dictionary(); + _target.Components.Headers ??= new Dictionary(); } private void EnsureCallbacksExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 1bd202ff7..30fe66774 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -162,7 +162,7 @@ public virtual void Visit(OpenApiRequestBody requestBody) /// /// Visits headers. /// - public virtual void Visit(IDictionary headers) + public virtual void Visit(IDictionary headers) { } @@ -274,7 +274,7 @@ public virtual void Visit(OpenApiTagReference tag) /// /// Visits /// - public virtual void Visit(OpenApiHeader header) + public virtual void Visit(IOpenApiHeader header) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 47a4f4c2e..3451a9690 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -740,7 +740,7 @@ internal void Walk(OpenApiRequestBody requestBody, bool isComponent = false) /// /// Visits dictionary of /// - internal void Walk(IDictionary headers) + internal void Walk(IDictionary headers) { if (headers == null) { @@ -1105,7 +1105,7 @@ internal void Walk(OpenApiLink link, bool isComponent = false) /// /// Visits and child objects /// - internal void Walk(OpenApiHeader header, bool isComponent = false) + internal void Walk(IOpenApiHeader header, bool isComponent = false) { if (header == null) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 8ec8d4ca0..e93113536 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -81,7 +81,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiComponents components) => Validate(components); /// - public override void Visit(OpenApiHeader header) => Validate(header); + public override void Visit(IOpenApiHeader header) => Validate(header); /// public override void Visit(OpenApiResponse response) => Validate(response); @@ -157,7 +157,7 @@ public void AddWarning(OpenApiValidatorWarning warning) /// public override void Visit(IDictionary operations) => Validate(operations, operations.GetType()); /// - public override void Visit(IDictionary headers) => Validate(headers, headers.GetType()); + public override void Visit(IDictionary headers) => Validate(headers, headers.GetType()); /// public override void Visit(IDictionary callbacks) => Validate(callbacks, callbacks.GetType()); /// diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs index 759aafe47..1d38af4ce 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs @@ -17,7 +17,7 @@ public static class OpenApiNonDefaultRules /// /// Validate the data matches with the given data type. /// - public static ValidationRule HeaderMismatchedDataType => + public static ValidationRule HeaderMismatchedDataType => new(nameof(HeaderMismatchedDataType), (context, header) => { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index e8c49bbc8..8f0d04004 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -243,7 +243,8 @@ public async Task CopiesOverAllReferencedComponentsToTheSubsetDocumentCorrectly( // Assert Assert.Same(doc.Servers, subsetOpenApiDocument.Servers); - Assert.False(responseHeader?.UnresolvedReference); + var headerReference = Assert.IsType(responseHeader); + Assert.False(headerReference.UnresolvedReference); var exampleReference = Assert.IsType(mediaTypeExample); Assert.False(exampleReference?.UnresolvedReference); Assert.NotNull(targetHeaders); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 41f2c6a1e..3622d572b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1132,8 +1132,7 @@ public async Task HeaderParameterShouldAllowExample() Format = "uuid" }, }, options => options.IgnoringCyclicReferences() - .Excluding(e => e.Example.Parent) - .Excluding(x => x.Reference)); + .Excluding(e => e.Example.Parent)); var examplesHeader = result.Document.Components?.Headers?["examples-header"]; Assert.NotNull(examplesHeader); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs index 874cf6b04..c103db5d8 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs @@ -49,7 +49,7 @@ public async Task ParseAdvancedEncodingShouldSucceed() Headers = { ["X-Rate-Limit-Limit"] = - new() + new OpenApiHeader() { Description = "The number of allowed requests in the current period", Schema = new() diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs index d7fef6396..daff6e479 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs @@ -166,7 +166,7 @@ public void OpenApiHeaderTargetShouldResolveReference() { Components = new OpenApiComponents { - Headers = new System.Collections.Generic.Dictionary + Headers = { { "header1", new OpenApiHeader { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 69d509df5..3ae26aa75 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -344,13 +344,29 @@ namespace Microsoft.OpenApi.Models.Interfaces public interface IOpenApiDescribedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Description { get; set; } - string Summary { get; set; } } - public interface IOpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { string ExternalValue { get; } System.Text.Json.Nodes.JsonNode Value { get; } } + public interface IOpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + bool AllowEmptyValue { get; } + bool AllowReserved { get; } + System.Collections.Generic.IDictionary Content { get; } + bool Deprecated { get; } + System.Text.Json.Nodes.JsonNode Example { get; } + System.Collections.Generic.IDictionary Examples { get; } + bool Explode { get; } + bool Required { get; } + Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + Microsoft.OpenApi.Models.ParameterStyle? Style { get; } + } + public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement + { + string Summary { get; set; } + } } namespace Microsoft.OpenApi.Models { @@ -383,7 +399,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Callbacks { get; set; } public System.Collections.Generic.IDictionary? Examples { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } - public System.Collections.Generic.IDictionary? Headers { get; set; } + public System.Collections.Generic.IDictionary? Headers { get; set; } public System.Collections.Generic.IDictionary? Links { get; set; } public System.Collections.Generic.IDictionary? Parameters { get; set; } public System.Collections.Generic.IDictionary? PathItems { get; set; } @@ -611,7 +627,7 @@ namespace Microsoft.OpenApi.Models public string ContentType { get; set; } public bool? Explode { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } - public System.Collections.Generic.IDictionary Headers { get; set; } + public System.Collections.Generic.IDictionary Headers { get; set; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -626,7 +642,7 @@ namespace Microsoft.OpenApi.Models public string Pointer { get; set; } public override string ToString() { } } - public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample + public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiExample() { } public OpenApiExample(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } @@ -660,27 +676,25 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { public OpenApiHeader() { } - public OpenApiHeader(Microsoft.OpenApi.Models.OpenApiHeader header) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual bool AllowEmptyValue { get; set; } - public virtual bool AllowReserved { get; set; } - public virtual System.Collections.Generic.IDictionary Content { get; set; } - public virtual bool Deprecated { get; set; } - public virtual string Description { get; set; } - public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } - public virtual System.Collections.Generic.IDictionary Examples { get; set; } - public virtual bool Explode { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual bool Required { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } - public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } - public virtual bool UnresolvedReference { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiHeader(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } + public bool AllowEmptyValue { get; set; } + public bool AllowReserved { get; set; } + public System.Collections.Generic.IDictionary Content { get; set; } + public bool Deprecated { get; set; } + public string Description { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; set; } + public System.Collections.Generic.IDictionary Examples { get; set; } + public bool Explode { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public bool Required { get; set; } + public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiInfo : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -877,7 +891,7 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IDictionary Content { get; set; } public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual System.Collections.Generic.IDictionary Headers { get; set; } + public virtual System.Collections.Generic.IDictionary Headers { get; set; } public virtual System.Collections.Generic.IDictionary Links { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1131,12 +1145,12 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public Microsoft.OpenApi.Models.OpenApiCallback Target { get; } public bool UnresolvedReference { get; set; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback openApiExample) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiExampleReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample + public class OpenApiExampleReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiExampleReference(Microsoft.OpenApi.Models.References.OpenApiExampleReference example) { } public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1148,30 +1162,34 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.OpenApiExample Target { get; } public bool UnresolvedReference { get; set; } public System.Text.Json.Nodes.JsonNode Value { get; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample openApiExample) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample source) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeaderReference : Microsoft.OpenApi.Models.OpenApiHeader, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiHeaderReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { + public OpenApiHeaderReference(Microsoft.OpenApi.Models.References.OpenApiHeaderReference header) { } public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public bool AllowEmptyValue { get; } + public bool AllowReserved { get; } + public System.Collections.Generic.IDictionary Content { get; } + public bool Deprecated { get; } + public string Description { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; } + public System.Collections.Generic.IDictionary Examples { get; } + public bool Explode { get; } + public System.Collections.Generic.IDictionary Extensions { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public bool Required { get; } + public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public Microsoft.OpenApi.Models.OpenApiHeader Target { get; } - public override bool AllowEmptyValue { get; set; } - public override bool AllowReserved { get; set; } - public override System.Collections.Generic.IDictionary Content { get; set; } - public override bool Deprecated { get; set; } - public override string Description { get; set; } - public override System.Text.Json.Nodes.JsonNode Example { get; set; } - public override System.Collections.Generic.IDictionary Examples { get; set; } - public override bool Explode { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override bool Required { get; set; } - public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } - public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public bool UnresolvedReference { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1239,7 +1257,7 @@ namespace Microsoft.OpenApi.Models.References public override System.Collections.Generic.IDictionary Content { get; set; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override System.Collections.Generic.IDictionary Headers { get; set; } + public override System.Collections.Generic.IDictionary Headers { get; set; } public override System.Collections.Generic.IDictionary Links { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1515,12 +1533,12 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder referenceHolder) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiEncoding encoding) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiHeader header) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiLicense license) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiLink link) { } @@ -1543,8 +1561,8 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IDictionary operations) { } public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary examples) { } + public virtual void Visit(System.Collections.Generic.IDictionary headers) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } - public virtual void Visit(System.Collections.Generic.IDictionary headers) { } public virtual void Visit(System.Collections.Generic.IDictionary links) { } public virtual void Visit(System.Collections.Generic.IDictionary content) { } public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } @@ -1614,12 +1632,12 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiEncoding encoding) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiHeader header) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiLicense license) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiLink link) { } @@ -1641,8 +1659,8 @@ namespace Microsoft.OpenApi.Validations public override void Visit(System.Collections.Generic.IDictionary operations) { } public override void Visit(System.Collections.Generic.IDictionary callbacks) { } public override void Visit(System.Collections.Generic.IDictionary examples) { } + public override void Visit(System.Collections.Generic.IDictionary headers) { } public override void Visit(System.Collections.Generic.IDictionary encodings) { } - public override void Visit(System.Collections.Generic.IDictionary headers) { } public override void Visit(System.Collections.Generic.IDictionary links) { } public override void Visit(System.Collections.Generic.IDictionary content) { } public override void Visit(System.Collections.Generic.IDictionary serverVariables) { } @@ -1735,7 +1753,7 @@ namespace Microsoft.OpenApi.Validations.Rules } public static class OpenApiNonDefaultRules { - public static Microsoft.OpenApi.Validations.ValidationRule HeaderMismatchedDataType { get; } + public static Microsoft.OpenApi.Validations.ValidationRule HeaderMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule MediaTypeMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule ParameterMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index 485f8587c..6c96c3d97 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json.Nodes; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations.Rules; using Xunit; @@ -17,7 +18,6 @@ public class OpenApiHeaderValidationTests public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange - IEnumerable errors; var header = new OpenApiHeader { Required = true, @@ -30,18 +30,14 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() // Act var defaultRuleSet = ValidationRuleSet.GetDefaultRuleSet(); - defaultRuleSet.Add(typeof(OpenApiHeader), OpenApiNonDefaultRules.HeaderMismatchedDataType); + defaultRuleSet.Add(typeof(IOpenApiHeader), OpenApiNonDefaultRules.HeaderMismatchedDataType); var validator = new OpenApiValidator(defaultRuleSet); var walker = new OpenApiWalker(validator); - walker.Walk(header); - - errors = validator.Errors; - var warnings = validator.Warnings; - var result = !warnings.Any(); + walker.Walk((IOpenApiHeader)header); // Assert - Assert.False(result); + Assert.NotEmpty(validator.Warnings); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 4acb0aadf..c78e41f19 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -33,7 +33,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IList)); visitor.Visit(default(OpenApiParameter)); visitor.Visit(default(OpenApiRequestBody)); - visitor.Visit(default(IDictionary)); + visitor.Visit(default(IDictionary)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiResponse)); visitor.Visit(default(OpenApiResponses)); @@ -48,7 +48,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiLink)); visitor.Visit(default(IOpenApiCallback)); visitor.Visit(default(OpenApiTag)); - visitor.Visit(default(OpenApiHeader)); + visitor.Visit(default(IOpenApiHeader)); visitor.Visit(default(OpenApiOAuthFlow)); visitor.Visit(default(OpenApiSecurityRequirement)); visitor.Visit(default(OpenApiSecurityScheme)); @@ -172,7 +172,7 @@ public override void Visit(OpenApiRequestBody requestBody) base.Visit(requestBody); } - public override void Visit(IDictionary headers) + public override void Visit(IDictionary headers) { EncodeCall(); base.Visit(headers); @@ -262,7 +262,7 @@ public override void Visit(OpenApiTag tag) base.Visit(tag); } - public override void Visit(OpenApiHeader header) + public override void Visit(IOpenApiHeader header) { EncodeCall(); base.Visit(header); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index c307229cf..cbb61987d 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -172,16 +172,12 @@ public void LocateReferences() }, UnresolvedReference = false }; + var testHeader = new OpenApiHeader() { Schema = derivedSchema, - Reference = new() - { - Id = "test-header", - Type = ReferenceType.Header - }, - UnresolvedReference = false }; + var testHeaderReference = new OpenApiHeaderReference(testHeader, "test-header"); var doc = new OpenApiDocument { @@ -204,9 +200,9 @@ public void LocateReferences() Schema = derivedSchema } }, - Headers = new Dictionary + Headers = { - ["test-header"] = testHeader + ["test-header"] = testHeaderReference } } } @@ -221,7 +217,7 @@ public void LocateReferences() ["derived"] = derivedSchema, ["base"] = baseSchema, }, - Headers = new Dictionary + Headers = { ["test-header"] = testHeader }, @@ -238,7 +234,7 @@ public void LocateReferences() Assert.Equivalent(new List { "referenceAt: #/paths/~1/get/responses/200/content/application~1json/schema", - "referenceAt: #/paths/~1/get/responses/200/headers/test-header/schema", + "referenceAt: #/paths/~1/get/responses/200/headers/test-header", "referenceAt: #/components/schemas/derived/anyOf/0", "referenceAt: #/components/securitySchemes/test-secScheme", "referenceAt: #/components/headers/test-header/schema" diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs index cb554d4f6..167d5e359 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs @@ -36,11 +36,11 @@ public class OpenApiReferencableTests private static readonly OpenApiRequestBody _requestBodyFragment = new(); private static readonly OpenApiResponse _responseFragment = new() { - Headers = new Dictionary + Headers = { { "header1", new OpenApiHeader() } }, - Links = new Dictionary + Links = { { "link1", new OpenApiLink() } } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index f8bde4f85..05f8dda64 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -112,7 +112,7 @@ public void OpenApiWorkspacesCanResolveReferencesToDocumentFragmentsWithJsonPoin var workspace = new OpenApiWorkspace(); var responseFragment = new OpenApiResponse { - Headers = new Dictionary + Headers = { { "header1", new OpenApiHeader() } } From aa80b1968d9ec6ad26f8b45578040026883d5890 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 15:11:08 -0500 Subject: [PATCH 016/103] fix: do not allow null argument for example copy constructor Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiExample.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index c35480fc2..be543c525 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -41,11 +41,12 @@ public OpenApiExample() { } /// The object public OpenApiExample(IOpenApiExample example) { - Summary = example?.Summary ?? Summary; - Description = example?.Description ?? Description; - Value = example?.Value != null ? JsonNodeCloneHelper.Clone(example.Value) : null; - ExternalValue = example?.ExternalValue ?? ExternalValue; - Extensions = example?.Extensions != null ? new Dictionary(example.Extensions) : null; + Utils.CheckArgumentNull(example); + Summary = example.Summary ?? Summary; + Description = example.Description ?? Description; + Value = example.Value != null ? JsonNodeCloneHelper.Clone(example.Value) : null; + ExternalValue = example.ExternalValue ?? ExternalValue; + Extensions = example.Extensions != null ? new Dictionary(example.Extensions) : null; } /// From 0cb4ccb925ab54e15351cbf2b0f4ae58c6b866c8 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 15:18:28 -0500 Subject: [PATCH 017/103] fix: adds missing null propagation operators for callback and header references Signed-off-by: Vincent Biret --- .../References/OpenApiCallbackReference.cs | 4 ++-- .../References/OpenApiHeaderReference.cs | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 536b30086..b9d9758f1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -85,10 +85,10 @@ internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) } /// - public Dictionary PathItems { get => Target.PathItems; } + public Dictionary PathItems { get => Target?.PathItems; } /// - public IDictionary Extensions { get => Target.Extensions; } + public IDictionary Extensions { get => Target?.Extensions; } /// public void SerializeAsV3(IOpenApiWriter writer) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 3650190f3..71e8cace0 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -97,37 +97,37 @@ public string Description } /// - public bool Required { get => Target.Required; } + public bool Required { get => Target?.Required ?? default; } /// - public bool Deprecated { get => Target.Deprecated; } + public bool Deprecated { get => Target?.Deprecated ?? default; } /// - public bool AllowEmptyValue { get => Target.AllowEmptyValue; } + public bool AllowEmptyValue { get => Target?.AllowEmptyValue ?? default; } /// - public OpenApiSchema Schema { get => Target.Schema; } + public OpenApiSchema Schema { get => Target?.Schema; } /// - public ParameterStyle? Style { get => Target.Style; } + public ParameterStyle? Style { get => Target?.Style; } /// - public bool Explode { get => Target.Explode; } + public bool Explode { get => Target?.Explode ?? default; } /// - public bool AllowReserved { get => Target.AllowReserved; } + public bool AllowReserved { get => Target?.AllowReserved ?? default; } /// - public JsonNode Example { get => Target.Example; } + public JsonNode Example { get => Target?.Example; } /// - public IDictionary Examples { get => Target.Examples; } + public IDictionary Examples { get => Target?.Examples; } /// - public IDictionary Content { get => Target.Content; } + public IDictionary Content { get => Target?.Content; } /// - public IDictionary Extensions { get => Target.Extensions; } + public IDictionary Extensions { get => Target?.Extensions; } /// public void SerializeAsV31(IOpenApiWriter writer) From 376e54de6d419c4e6673111538140bedafd7896e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 15:30:48 -0500 Subject: [PATCH 018/103] fix: open API link reference proxy design pattern implementation Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../Models/Interfaces/IOpenApiLink.cs | 37 +++++++ .../Models/OpenApiComponents.cs | 6 +- .../Models/OpenApiDocument.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiLink.cs | 95 ++++++------------ .../Models/OpenApiResponse.cs | 4 +- .../Models/References/OpenApiLinkReference.cs | 98 ++++++++++++------- .../References/OpenApiResponseReference.cs | 4 +- .../Reader/V3/OpenApiLinkDeserializer.cs | 3 +- .../Reader/V31/OpenApiLinkDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 6 +- .../Services/OpenApiWalker.cs | 8 +- .../Validations/OpenApiValidator.cs | 4 +- .../Models/OpenApiLinkTests.cs | 5 - .../PublicApi/PublicApi.approved.txt | 71 ++++++++------ .../Visitors/InheritanceTests.cs | 8 +- 18 files changed, 202 insertions(+), 162 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index a6ea032f1..700918f4e 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -62,7 +62,7 @@ public override void Visit(OpenApiOperation operation) public int LinkCount { get; set; } - public override void Visit(OpenApiLink link) + public override void Visit(IOpenApiLink link) { LinkCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index 3e3b1cf93..41d14fe1d 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -62,7 +62,7 @@ public override void Visit(OpenApiOperation operation) public int LinkCount { get; set; } - public override void Visit(OpenApiLink link) + public override void Visit(IOpenApiLink link) { LinkCount++; } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs new file mode 100644 index 000000000..854c945f8 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the link object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiLink : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// A relative or absolute reference to an OAS operation. + /// This field is mutually exclusive of the operationId field, and MUST point to an Operation Object. + /// + public string OperationRef { get; } + + /// + /// The name of an existing, resolvable OAS operation, as defined with a unique operationId. + /// This field is mutually exclusive of the operationRef field. + /// + public string OperationId { get; } + + /// + /// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef. + /// + public IDictionary Parameters { get; } + + /// + /// A literal value or {expression} to use as a request body when calling the target operation. + /// + public RuntimeExpressionAnyWrapper RequestBody { get; } + /// + /// A server object to be used by the target operation. + /// + public OpenApiServer Server { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index c578ddc9a..b171cef5b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -56,9 +56,9 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? Links { get; set; } = new Dictionary(); + public IDictionary? Links { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -92,7 +92,7 @@ public OpenApiComponents(OpenApiComponents? components) RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; - Links = components?.Links != null ? new Dictionary(components.Links) : null; + Links = components?.Links != null ? new Dictionary(components.Links) : null; Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null; Extensions = components?.Extensions != null ? new Dictionary(components.Extensions) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 6985aea1a..ae92bb60f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -604,7 +604,7 @@ public bool AddComponent(string id, T componentToRegister) Components.RequestBodies.Add(id, openApiRequestBody); break; case OpenApiLink openApiLink: - Components.Links ??= new Dictionary(); + Components.Links ??= new Dictionary(); Components.Links.Add(id, openApiLink); break; case OpenApiCallback openApiCallback: diff --git a/src/Microsoft.OpenApi/Models/OpenApiLink.cs b/src/Microsoft.OpenApi/Models/OpenApiLink.cs index 715826c67..fec27dd67 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiLink.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiLink.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -11,55 +12,28 @@ namespace Microsoft.OpenApi.Models /// /// Link Object. /// - public class OpenApiLink : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiLink : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiLink { - /// - /// A relative or absolute reference to an OAS operation. - /// This field is mutually exclusive of the operationId field, and MUST point to an Operation Object. - /// - public virtual string OperationRef { get; set; } + /// + public string OperationRef { get; set; } - /// - /// The name of an existing, resolvable OAS operation, as defined with a unique operationId. - /// This field is mutually exclusive of the operationRef field. - /// - public virtual string OperationId { get; set; } + /// + public string OperationId { get; set; } - /// - /// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef. - /// - public virtual Dictionary Parameters { get; set; } = - new(); + /// + public IDictionary Parameters { get; set; } = new Dictionary(); - /// - /// A literal value or {expression} to use as a request body when calling the target operation. - /// - public virtual RuntimeExpressionAnyWrapper RequestBody { get; set; } - - /// - /// A description of the link. - /// - public virtual string Description { get; set; } - - /// - /// A server object to be used by the target operation. - /// - public virtual OpenApiServer Server { get; set; } + /// + public RuntimeExpressionAnyWrapper RequestBody { get; set; } - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public string Description { get; set; } - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public virtual bool UnresolvedReference { get; set; } + /// + public OpenApiServer Server { get; set; } - /// - /// Reference pointer. - /// - public OpenApiReference Reference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -69,36 +43,31 @@ public OpenApiLink() { } /// /// Initializes a copy of an object /// - public OpenApiLink(OpenApiLink link) + public OpenApiLink(IOpenApiLink link) { - OperationRef = link?.OperationRef ?? OperationRef; - OperationId = link?.OperationId ?? OperationId; - Parameters = link?.Parameters != null ? new(link?.Parameters) : null; - RequestBody = link?.RequestBody != null ? new(link?.RequestBody) : null; - Description = link?.Description ?? Description; - Server = link?.Server != null ? new(link?.Server) : null; - Extensions = link?.Extensions != null ? new Dictionary(link.Extensions) : null; - UnresolvedReference = link?.UnresolvedReference ?? UnresolvedReference; - Reference = link?.Reference != null ? new(link?.Reference) : null; + Utils.CheckArgumentNull(link); + OperationRef = link.OperationRef ?? OperationRef; + OperationId = link.OperationId ?? OperationId; + Parameters = link.Parameters != null ? new Dictionary(link.Parameters) : null; + RequestBody = link.RequestBody != null ? new(link.RequestBody) : null; + Description = link.Description ?? Description; + Server = link.Server != null ? new(link.Server) : null; + Extensions = link.Extensions != null ? new Dictionary(link.Extensions) : null; } - /// - /// Serialize to Open Api v3.1 - /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + /// + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } - /// - /// Serialize to Open Api v3.0 - /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + /// + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, Action callback) + internal void SerializeInternal(IOpenApiWriter writer, Action callback) { Utils.CheckArgumentNull(writer); @@ -128,9 +97,7 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, Action - /// Serialize to Open Api v2.0 - /// + /// public void SerializeAsV2(IOpenApiWriter writer) { // Link object does not exist in V2. diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index 755af74cd..3896c6b76 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -36,7 +36,7 @@ public class OpenApiResponse : IOpenApiReferenceable, IOpenApiExtensible /// The key of the map is a short name for the link, /// following the naming constraints of the names for Component Objects. /// - public virtual IDictionary Links { get; set; } = new Dictionary(); + public virtual IDictionary Links { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. @@ -66,7 +66,7 @@ public OpenApiResponse(OpenApiResponse response) Description = response?.Description ?? Description; Headers = response?.Headers != null ? new Dictionary(response.Headers) : null; Content = response?.Content != null ? new Dictionary(response.Content) : null; - Links = response?.Links != null ? new Dictionary(response.Links) : null; + Links = response?.Links != null ? new Dictionary(response.Links) : null; Extensions = response?.Extensions != null ? new Dictionary(response.Extensions) : null; UnresolvedReference = response?.UnresolvedReference ?? UnresolvedReference; Reference = response?.Reference != null ? new(response?.Reference) : null; diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 614ab1446..a862cdfef 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -11,12 +12,14 @@ namespace Microsoft.OpenApi.Models.References /// /// Link Object Reference. /// - public class OpenApiLinkReference : OpenApiLink, IOpenApiReferenceHolder + public class OpenApiLinkReference : IOpenApiLink, IOpenApiReferenceHolder { - internal OpenApiLink _target; - private readonly OpenApiReference _reference; - private string _description; + /// + public OpenApiReference Reference { get; set; } + /// + public bool UnresolvedReference { get; set; } + internal OpenApiLink _target; /// /// Gets the target link. /// @@ -27,10 +30,8 @@ public OpenApiLink Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiLink resolved = new OpenApiLink(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + return _target; } } @@ -48,22 +49,33 @@ public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, st { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Link, ExternalResource = externalResource }; + } + /// + /// Copy constructor. + /// + /// The reference to copy + public OpenApiLinkReference(OpenApiLinkReference reference) + { + Utils.CheckArgumentNull(reference); - Reference = _reference; + Reference = reference?.Reference != null ? new(reference.Reference) : null; + UnresolvedReference = reference?.UnresolvedReference ?? false; + //no need to copy summary and description as if they are not overridden, they will be fetched from the target + //if they are, the reference copy will handle it } internal OpenApiLinkReference(OpenApiLink target, string referenceId) { _target = target; - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, Type = ReferenceType.Link, @@ -71,63 +83,79 @@ internal OpenApiLinkReference(OpenApiLink target, string referenceId) } /// - public override string OperationRef { get => Target.OperationRef; set => Target.OperationRef = value; } + public string Description + { + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } + } /// - public override string OperationId { get => Target.OperationId; set => Target.OperationId = value; } + public string OperationRef { get => Target?.OperationRef; } /// - public override OpenApiServer Server { get => Target.Server; set => Target.Server = value; } + public string OperationId { get => Target?.OperationId; } /// - public override string Description - { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; - } + public OpenApiServer Server { get => Target?.Server; } /// - public override Dictionary Parameters { get => Target.Parameters; set => Target.Parameters = value; } + public IDictionary Parameters { get => Target?.Parameters; } /// - public override RuntimeExpressionAnyWrapper RequestBody { get => Target.RequestBody; set => Target.RequestBody = value; } + public RuntimeExpressionAnyWrapper RequestBody { get => Target?.RequestBody; } /// - public override IDictionary Extensions { get => base.Extensions; set => base.Extensions = value; } + public IDictionary Extensions { get => Target?.Extensions; } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); } } /// - public override void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); } - } + } + + /// + public void SerializeAsV2(IOpenApiWriter writer) + { + // Link object does not exist in V2. + } + + /// + public IOpenApiLink CopyReferenceAsTargetElementWithOverrides(IOpenApiLink source) + { + return source is OpenApiLink ? new OpenApiLink(this) : source; + } /// private void SerializeInternal(IOpenApiWriter writer, - Action action) + Action action) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); action(writer, Target); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index 0f74e3ad5..57d8fba2b 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -86,9 +86,9 @@ public override string Description /// public override IDictionary Headers { get => _headers is not null ? _headers : Target?.Headers; set => _headers = value; } - private IDictionary _links; + private IDictionary _links; /// - public override IDictionary Links { get => _links is not null ? _links : Target?.Links; set => _links = value; } + public override IDictionary Links { get => _links is not null ? _links : Target?.Links; set => _links = value; } private IDictionary _extensions; /// diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs index 049ecc8cc..9744ea256 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -44,7 +45,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; - public static OpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("link"); var link = new OpenApiLink(); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs index a849985fb..3924a41c7 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -51,7 +52,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; - public static OpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("link"); var link = new OpenApiLink(); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 2575a6f77..3125d75cc 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -127,9 +127,9 @@ private void AddLinkToComponents(OpenApiLink link, string referenceId = null) { EnsureComponentsExist(); EnsureLinksExist(); - if (!Components.Links.ContainsKey(referenceId ?? link.Reference.Id)) + if (!Components.Links.ContainsKey(referenceId)) { - Components.Links.Add(referenceId ?? link.Reference.Id, link); + Components.Links.Add(referenceId, link); } } private void AddCallbackToComponents(OpenApiCallback callback, string referenceId = null) @@ -235,7 +235,7 @@ private void EnsureCallbacksExist() private void EnsureLinksExist() { - _target.Components.Links ??= new Dictionary(); + _target.Components.Links ??= new Dictionary(); } private void EnsureSecuritySchemesExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 30fe66774..62ecb4c5d 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -239,14 +239,14 @@ public virtual void Visit(OpenApiSchema schema) /// /// Visits the links. /// - public virtual void Visit(IDictionary links) + public virtual void Visit(IDictionary links) { } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiLink link) + public virtual void Visit(IOpenApiLink link) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 3451a9690..c578a7653 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -1059,9 +1059,9 @@ internal void Walk(OpenApiOAuthFlow oAuthFlow) } /// - /// Visits dictionary of and child objects + /// Visits dictionary of and child objects /// - internal void Walk(IDictionary links) + internal void Walk(IDictionary links) { if (links == null) { @@ -1084,7 +1084,7 @@ internal void Walk(IDictionary links) /// /// Visits and child objects /// - internal void Walk(OpenApiLink link, bool isComponent = false) + internal void Walk(IOpenApiLink link, bool isComponent = false) { if (link == null) { @@ -1198,7 +1198,7 @@ internal void Walk(IOpenApiElement element) case OpenApiExternalDocs e: Walk(e); break; case OpenApiHeader e: Walk(e); break; case OpenApiLink e: Walk(e); break; - case IDictionary e: Walk(e); break; + case IDictionary e: Walk(e); break; case OpenApiMediaType e: Walk(e); break; case OpenApiOAuthFlows e: Walk(e); break; case OpenApiOAuthFlow e: Walk(e); break; diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index e93113536..594d87eaa 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -147,7 +147,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiPaths paths) => Validate(paths); /// - public override void Visit(OpenApiLink link) => Validate(link); + public override void Visit(IOpenApiLink link) => Validate(link); /// public override void Visit(IOpenApiExample example) => Validate(example); @@ -165,7 +165,7 @@ public void AddWarning(OpenApiValidatorWarning warning) /// public override void Visit(IDictionary examples) => Validate(examples, examples.GetType()); /// - public override void Visit(IDictionary links) => Validate(links, links.GetType()); + public override void Visit(IDictionary links) => Validate(links, links.GetType()); /// public override void Visit(IDictionary serverVariables) => Validate(serverVariables, serverVariables.GetType()); /// diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs index e1a949348..e97fbb6b8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs @@ -45,11 +45,6 @@ public class OpenApiLinkTests public static readonly OpenApiLinkReference LinkReference = new(ReferencedLink, "example1"); public static readonly OpenApiLink ReferencedLink = new() { - Reference = new() - { - Type = ReferenceType.Link, - Id = "example1", - }, OperationId = "operationId1", Parameters = { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 3ae26aa75..e881f649d 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -363,6 +363,14 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } + public interface IOpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + string OperationId { get; } + string OperationRef { get; } + System.Collections.Generic.IDictionary Parameters { get; } + Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } + Microsoft.OpenApi.Models.OpenApiServer Server { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -400,7 +408,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Examples { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } public System.Collections.Generic.IDictionary? Headers { get; set; } - public System.Collections.Generic.IDictionary? Links { get; set; } + public System.Collections.Generic.IDictionary? Links { get; set; } public System.Collections.Generic.IDictionary? Parameters { get; set; } public System.Collections.Generic.IDictionary? PathItems { get; set; } public System.Collections.Generic.IDictionary? RequestBodies { get; set; } @@ -724,22 +732,20 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { public OpenApiLink() { } - public OpenApiLink(Microsoft.OpenApi.Models.OpenApiLink link) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual string OperationId { get; set; } - public virtual string OperationRef { get; set; } - public virtual System.Collections.Generic.Dictionary Parameters { get; set; } - public virtual Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiServer Server { get; set; } - public virtual bool UnresolvedReference { get; set; } + public OpenApiLink(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public string OperationId { get; set; } + public string OperationRef { get; set; } + public System.Collections.Generic.IDictionary Parameters { get; set; } + public Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; set; } + public Microsoft.OpenApi.Models.OpenApiServer Server { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiMediaType : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -892,7 +898,7 @@ namespace Microsoft.OpenApi.Models public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual System.Collections.Generic.IDictionary Headers { get; set; } - public virtual System.Collections.Generic.IDictionary Links { get; set; } + public virtual System.Collections.Generic.IDictionary Links { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1191,19 +1197,24 @@ namespace Microsoft.OpenApi.Models.References public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiLinkReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { + public OpenApiLinkReference(Microsoft.OpenApi.Models.References.OpenApiLinkReference reference) { } public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public string OperationId { get; } + public string OperationRef { get; } + public System.Collections.Generic.IDictionary Parameters { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } + public Microsoft.OpenApi.Models.OpenApiServer Server { get; } public Microsoft.OpenApi.Models.OpenApiLink Target { get; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override string OperationId { get; set; } - public override string OperationRef { get; set; } - public override System.Collections.Generic.Dictionary Parameters { get; set; } - public override Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; set; } - public override Microsoft.OpenApi.Models.OpenApiServer Server { get; set; } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public bool UnresolvedReference { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink source) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1258,7 +1269,7 @@ namespace Microsoft.OpenApi.Models.References public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override System.Collections.Generic.IDictionary Headers { get; set; } - public override System.Collections.Generic.IDictionary Links { get; set; } + public override System.Collections.Generic.IDictionary Links { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1534,6 +1545,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1541,7 +1553,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiLicense license) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiLink link) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } @@ -1562,8 +1573,8 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary examples) { } public virtual void Visit(System.Collections.Generic.IDictionary headers) { } + public virtual void Visit(System.Collections.Generic.IDictionary links) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } - public virtual void Visit(System.Collections.Generic.IDictionary links) { } public virtual void Visit(System.Collections.Generic.IDictionary content) { } public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } public virtual void Visit(System.Collections.Generic.IDictionary serverVariables) { } @@ -1633,6 +1644,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1640,7 +1652,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiInfo info) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiLicense license) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiLink link) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } @@ -1660,8 +1671,8 @@ namespace Microsoft.OpenApi.Validations public override void Visit(System.Collections.Generic.IDictionary callbacks) { } public override void Visit(System.Collections.Generic.IDictionary examples) { } public override void Visit(System.Collections.Generic.IDictionary headers) { } + public override void Visit(System.Collections.Generic.IDictionary links) { } public override void Visit(System.Collections.Generic.IDictionary encodings) { } - public override void Visit(System.Collections.Generic.IDictionary links) { } public override void Visit(System.Collections.Generic.IDictionary content) { } public override void Visit(System.Collections.Generic.IDictionary serverVariables) { } public override void Visit(System.Collections.Generic.IList example) { } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index c78e41f19..f2634be52 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -44,8 +44,8 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiComponents)); visitor.Visit(default(OpenApiExternalDocs)); visitor.Visit(default(OpenApiSchema)); - visitor.Visit(default(IDictionary)); - visitor.Visit(default(OpenApiLink)); + visitor.Visit(default(IDictionary)); + visitor.Visit(default(IOpenApiLink)); visitor.Visit(default(IOpenApiCallback)); visitor.Visit(default(OpenApiTag)); visitor.Visit(default(IOpenApiHeader)); @@ -238,13 +238,13 @@ public override void Visit(OpenApiSchema schema) base.Visit(schema); } - public override void Visit(IDictionary links) + public override void Visit(IDictionary links) { EncodeCall(); base.Visit(links); } - public override void Visit(OpenApiLink link) + public override void Visit(IOpenApiLink link) { EncodeCall(); base.Visit(link); From aa993b10ff72fb18f7dc3f49d87586662188a381 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 15:56:39 -0500 Subject: [PATCH 019/103] fix: removes unnecessary null prop in copy constructor Signed-off-by: Vincent Biret --- .../Models/References/OpenApiCallbackReference.cs | 4 ++-- .../Models/References/OpenApiExampleReference.cs | 4 ++-- .../Models/References/OpenApiLinkReference.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index b9d9758f1..f357c4532 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -69,8 +69,8 @@ public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument public OpenApiCallbackReference(OpenApiCallbackReference callback) { Utils.CheckArgumentNull(callback); - Reference = callback?.Reference != null ? new(callback.Reference) : null; - UnresolvedReference = callback?.UnresolvedReference ?? false; + Reference = callback.Reference != null ? new(callback.Reference) : null; + UnresolvedReference = callback.UnresolvedReference; } internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 8d4eeabb1..9f1842001 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -67,8 +67,8 @@ public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, public OpenApiExampleReference(OpenApiExampleReference example) { Utils.CheckArgumentNull(example); - Reference = example?.Reference != null ? new(example.Reference) : null; - UnresolvedReference = example?.UnresolvedReference ?? false; + Reference = example.Reference != null ? new(example.Reference) : null; + UnresolvedReference = example.UnresolvedReference; //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index a862cdfef..57a4b1e4f 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -65,8 +65,8 @@ public OpenApiLinkReference(OpenApiLinkReference reference) { Utils.CheckArgumentNull(reference); - Reference = reference?.Reference != null ? new(reference.Reference) : null; - UnresolvedReference = reference?.UnresolvedReference ?? false; + Reference = reference.Reference != null ? new(reference.Reference) : null; + UnresolvedReference = reference.UnresolvedReference; //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } From eeb79a4a7700d6fb56fbcbbe6913d224fa126167 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 17:33:09 -0500 Subject: [PATCH 020/103] fix: parameter reference proxy design pattern implementation Signed-off-by: Vincent Biret --- .../Formatters/PowerShellFormatter.cs | 14 +- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../Models/Interfaces/IOpenApiParameter.cs | 106 ++++++++++ .../Models/OpenApiComponents.cs | 8 +- .../Models/OpenApiDocument.cs | 6 +- .../Models/OpenApiOperation.cs | 6 +- .../Models/OpenApiParameter.cs | 199 +++++------------- .../Models/OpenApiPathItem.cs | 5 +- .../Models/OpenApiRequestBody.cs | 3 +- .../References/OpenApiParameterReference.cs | 115 +++++----- .../References/OpenApiPathItemReference.cs | 3 +- .../References/OpenApiRequestBodyReference.cs | 3 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 5 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 3 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 4 +- .../Reader/V3/OpenApiParameterDeserializer.cs | 2 +- .../V31/OpenApiParameterDeserializer.cs | 2 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 6 +- .../Services/OperationSearch.cs | 5 +- .../Services/SearchResult.cs | 3 +- .../Validations/OpenApiValidator.cs | 2 +- .../Rules/OpenApiParameterRules.cs | 7 +- .../Formatters/PowerShellFormatterTests.cs | 9 +- .../Services/OpenApiFilterServiceTests.cs | 9 +- .../UtilityFiles/OpenApiDocumentMock.cs | 35 +-- .../TryLoadReferenceV2Tests.cs | 5 +- .../V2Tests/OpenApiOperationTests.cs | 13 +- .../V2Tests/OpenApiPathItemTests.cs | 27 +-- .../V31Tests/OpenApiDocumentTests.cs | 13 +- .../V3Tests/OpenApiDocumentTests.cs | 94 ++++----- .../V3Tests/OpenApiParameterTests.cs | 56 +++-- ...sync_produceTerseOutput=False.verified.txt | 1 - ...Async_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiDocumentTests.cs | 53 ++--- .../Models/OpenApiOperationTests.cs | 29 +-- ...sync_produceTerseOutput=False.verified.txt | 1 - ...Async_produceTerseOutput=True.verified.txt | 2 +- ...sync_produceTerseOutput=False.verified.txt | 1 - ...Async_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiParameterTests.cs | 1 - ...orks_produceTerseOutput=False.verified.txt | 1 - ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 1 - ...Works_produceTerseOutput=True.verified.txt | 2 +- .../PublicApi/PublicApi.approved.txt | 119 ++++++----- .../OpenApiParameterValidationTests.cs | 27 +-- .../Visitors/InheritanceTests.cs | 8 +- 50 files changed, 533 insertions(+), 501 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index c2bbc97d0..109799381 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -7,6 +7,7 @@ using Humanizer.Inflections; using Microsoft.OpenApi.Hidi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; namespace Microsoft.OpenApi.Hidi.Formatters @@ -69,13 +70,13 @@ public override void Visit(OpenApiOperation operation) var operationId = operation.OperationId; var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type"); - if (operationTypeExtension.IsEquals("function")) - operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List()); + if (operationTypeExtension.IsEquals("function") && operation.Parameters is { Count :> 0}) + ResolveFunctionParameters(operation.Parameters); // Order matters. Resolve operationId. operationId = RemoveHashSuffix(operationId); if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function")) - operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List()); + operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List()); operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.')); operationId = ResolveODataCastOperationId(operationId); operationId = ResolveByRefOperationId(operationId); @@ -143,7 +144,7 @@ private static string RemoveHashSuffix(string operationId) return s_hashSuffixRegex.Match(operationId).Value; } - private static string RemoveKeyTypeSegment(string operationId, IList parameters) + private static string RemoveKeyTypeSegment(string operationId, IList parameters) { var segments = operationId.SplitByChar('.'); foreach (var parameter in parameters) @@ -157,9 +158,9 @@ private static string RemoveKeyTypeSegment(string operationId, IList ResolveFunctionParameters(IList parameters) + private static void ResolveFunctionParameters(IList parameters) { - foreach (var parameter in parameters.Where(static p => p.Content?.Any() ?? false)) + foreach (var parameter in parameters.OfType().Where(static p => p.Content?.Any() ?? false)) { // Replace content with a schema object of type array // for structured or collection-valued function parameters @@ -173,7 +174,6 @@ private static IList ResolveFunctionParameters(IList +/// Defines the base properties for the example object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// REQUIRED. The name of the parameter. Parameter names are case sensitive. + /// If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object. + /// If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition SHALL be ignored. + /// For all other cases, the name corresponds to the parameter name used by the in property. + /// + public string Name { get; } + + /// + /// REQUIRED. The location of the parameter. + /// Possible values are "query", "header", "path" or "cookie". + /// + public ParameterLocation? In { get; } + + /// + /// Determines whether this parameter is mandatory. + /// If the parameter location is "path", this property is REQUIRED and its value MUST be true. + /// Otherwise, the property MAY be included and its default value is false. + /// + public bool Required { get; } + + /// + /// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage. + /// + public bool Deprecated { get; } + + /// + /// Sets the ability to pass empty-valued parameters. + /// This is valid only for query parameters and allows sending a parameter with an empty value. + /// Default value is false. + /// If style is used, and if behavior is n/a (cannot be serialized), + /// the value of allowEmptyValue SHALL be ignored. + /// + public bool AllowEmptyValue { get; } + + /// + /// Describes how the parameter value will be serialized depending on the type of the parameter value. + /// Default values (based on value of in): for query - form; for path - simple; for header - simple; + /// for cookie - form. + /// + public ParameterStyle? Style { get; } + + /// + /// When this is true, parameter values of type array or object generate separate parameters + /// for each value of the array or key-value pair of the map. + /// For other types of parameters this property has no effect. + /// When style is form, the default value is true. + /// For all other styles, the default value is false. + /// + public bool Explode { get; } + + /// + /// Determines whether the parameter value SHOULD allow reserved characters, + /// as defined by RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding. + /// This property only applies to parameters with an in value of query. + /// The default value is false. + /// + public bool AllowReserved { get; } + + /// + /// The schema defining the type used for the parameter. + /// + public OpenApiSchema Schema { get; } + + /// + /// Examples of the media type. Each example SHOULD contain a value + /// in the correct format as specified in the parameter encoding. + /// The examples object is mutually exclusive of the example object. + /// Furthermore, if referencing a schema which contains an example, + /// the examples value SHALL override the example provided by the schema. + /// + public IDictionary Examples { get; } + + /// + /// Example of the media type. The example SHOULD match the specified schema and encoding properties + /// if present. The example object is mutually exclusive of the examples object. + /// Furthermore, if referencing a schema which contains an example, + /// the example value SHALL override the example provided by the schema. + /// To represent examples of media types that cannot naturally be represented in JSON or YAML, + /// a string value can contain the example with escaping where necessary. + /// + public JsonNode Example { get; } + + /// + /// A map containing the representations for the parameter. + /// The key is the media type and the value describes it. + /// The map MUST only contain one entry. + /// For more complex scenarios, the content property can define the media type and schema of the parameter. + /// A parameter MUST contain either a schema property, or a content property, but not both. + /// When example or examples are provided in conjunction with the schema object, + /// the example MUST follow the prescribed serialization strategy for the parameter. + /// + public IDictionary Content { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index b171cef5b..f45ecbedd 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -28,10 +28,10 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible public IDictionary? Responses { get; set; } = new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? Parameters { get; set; } = - new Dictionary(); + public IDictionary? Parameters { get; set; } = + new Dictionary(); /// /// An object to hold reusable Objects. @@ -87,7 +87,7 @@ public OpenApiComponents(OpenApiComponents? components) { Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; - Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; + Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index ae92bb60f..1dbc0e23c 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -277,8 +277,8 @@ public void SerializeAsV2(IOpenApiWriter writer) // parameters var parameters = Components?.Parameters != null - ? new Dictionary(Components.Parameters) - : new Dictionary(); + ? new Dictionary(Components.Parameters) + : []; if (Components?.RequestBodies != null) { @@ -592,7 +592,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Schemas.Add(id, openApiSchema); break; case OpenApiParameter openApiParameter: - Components.Parameters ??= new Dictionary(); + Components.Parameters ??= new Dictionary(); Components.Parameters.Add(id, openApiParameter); break; case OpenApiResponse openApiResponse: diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index beeb1c7e2..0a2f4259b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -58,7 +58,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenA /// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location. /// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters. /// - public IList? Parameters { get; set; } = new List(); + public IList? Parameters { get; set; } = []; /// /// The request body applicable for this operation. @@ -127,7 +127,7 @@ public OpenApiOperation(OpenApiOperation? operation) Description = operation?.Description ?? Description; ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; OperationId = operation?.OperationId ?? OperationId; - Parameters = operation?.Parameters != null ? new List(operation.Parameters) : null; + Parameters = operation?.Parameters != null ? new List(operation.Parameters) : null; RequestBody = operation?.RequestBody != null ? new(operation?.RequestBody) : null; Responses = operation?.Responses != null ? new(operation?.Responses) : null; Callbacks = operation?.Callbacks != null ? new Dictionary(operation.Callbacks) : null; @@ -235,7 +235,7 @@ public void SerializeAsV2(IOpenApiWriter writer) // operationId writer.WriteProperty(OpenApiConstants.OperationId, OperationId); - List parameters; + List parameters; if (Parameters == null) { parameters = []; diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 66d03746e..87a761c8b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -16,138 +16,60 @@ namespace Microsoft.OpenApi.Models /// /// Parameter Object. /// - public class OpenApiParameter : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiParameter : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiParameter { private bool? _explode; private ParameterStyle? _style; - private OpenApiSchema _schema; - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public virtual bool UnresolvedReference { get; set; } + /// + public string Name { get; set; } - /// - /// Reference object. - /// - public OpenApiReference Reference { get; set; } + /// + public ParameterLocation? In { get; set; } - /// - /// REQUIRED. The name of the parameter. Parameter names are case sensitive. - /// If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object. - /// If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition SHALL be ignored. - /// For all other cases, the name corresponds to the parameter name used by the in property. - /// - public virtual string Name { get; set; } + /// + public string Description { get; set; } - /// - /// REQUIRED. The location of the parameter. - /// Possible values are "query", "header", "path" or "cookie". - /// - public virtual ParameterLocation? In { get; set; } + /// + public bool Required { get; set; } - /// - /// A brief description of the parameter. This could contain examples of use. - /// CommonMark syntax MAY be used for rich text representation. - /// - public virtual string Description { get; set; } + /// + public bool Deprecated { get; set; } - /// - /// Determines whether this parameter is mandatory. - /// If the parameter location is "path", this property is REQUIRED and its value MUST be true. - /// Otherwise, the property MAY be included and its default value is false. - /// - public virtual bool Required { get; set; } - - /// - /// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage. - /// - public virtual bool Deprecated { get; set; } = false; - - /// - /// Sets the ability to pass empty-valued parameters. - /// This is valid only for query parameters and allows sending a parameter with an empty value. - /// Default value is false. - /// If style is used, and if behavior is n/a (cannot be serialized), - /// the value of allowEmptyValue SHALL be ignored. - /// - public virtual bool AllowEmptyValue { get; set; } = false; + /// + public bool AllowEmptyValue { get; set; } - /// - /// Describes how the parameter value will be serialized depending on the type of the parameter value. - /// Default values (based on value of in): for query - form; for path - simple; for header - simple; - /// for cookie - form. - /// - public virtual ParameterStyle? Style + /// + public ParameterStyle? Style { get => _style ?? GetDefaultStyleValue(); set => _style = value; } - /// - /// When this is true, parameter values of type array or object generate separate parameters - /// for each value of the array or key-value pair of the map. - /// For other types of parameters this property has no effect. - /// When style is form, the default value is true. - /// For all other styles, the default value is false. - /// - public virtual bool Explode + /// + public bool Explode { get => _explode ?? Style == ParameterStyle.Form; set => _explode = value; } - /// - /// Determines whether the parameter value SHOULD allow reserved characters, - /// as defined by RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding. - /// This property only applies to parameters with an in value of query. - /// The default value is false. - /// - public virtual bool AllowReserved { get; set; } + /// + public bool AllowReserved { get; set; } - /// - /// The schema defining the type used for the parameter. - /// - public virtual OpenApiSchema Schema - { - get => _schema; - set => _schema = value; - } + /// + public OpenApiSchema Schema { get; set; } - /// - /// Examples of the media type. Each example SHOULD contain a value - /// in the correct format as specified in the parameter encoding. - /// The examples object is mutually exclusive of the example object. - /// Furthermore, if referencing a schema which contains an example, - /// the examples value SHALL override the example provided by the schema. - /// - public virtual IDictionary Examples { get; set; } = new Dictionary(); + /// + public IDictionary Examples { get; set; } = new Dictionary(); - /// - /// Example of the media type. The example SHOULD match the specified schema and encoding properties - /// if present. The example object is mutually exclusive of the examples object. - /// Furthermore, if referencing a schema which contains an example, - /// the example value SHALL override the example provided by the schema. - /// To represent examples of media types that cannot naturally be represented in JSON or YAML, - /// a string value can contain the example with escaping where necessary. - /// - public virtual JsonNode Example { get; set; } + /// + public JsonNode Example { get; set; } - /// - /// A map containing the representations for the parameter. - /// The key is the media type and the value describes it. - /// The map MUST only contain one entry. - /// For more complex scenarios, the content property can define the media type and schema of the parameter. - /// A parameter MUST contain either a schema property, or a content property, but not both. - /// When example or examples are provided in conjunction with the schema object, - /// the example MUST follow the prescribed serialization strategy for the parameter. - /// - public virtual IDictionary Content { get; set; } = new Dictionary(); + /// + public IDictionary Content { get; set; } = new Dictionary(); - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// A parameterless constructor @@ -157,43 +79,38 @@ public OpenApiParameter() { } /// /// Initializes a clone instance of object /// - public OpenApiParameter(OpenApiParameter parameter) + public OpenApiParameter(IOpenApiParameter parameter) { - UnresolvedReference = parameter?.UnresolvedReference ?? UnresolvedReference; - Reference = parameter?.Reference != null ? new(parameter?.Reference) : null; - Name = parameter?.Name ?? Name; - In = parameter?.In ?? In; - Description = parameter?.Description ?? Description; - Required = parameter?.Required ?? Required; - Style = parameter?.Style ?? Style; - Explode = parameter?.Explode ?? Explode; - AllowReserved = parameter?.AllowReserved ?? AllowReserved; - _schema = parameter?.Schema != null ? new(parameter.Schema) : null; - Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null; - Example = parameter?.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; - Content = parameter?.Content != null ? new Dictionary(parameter.Content) : null; - Extensions = parameter?.Extensions != null ? new Dictionary(parameter.Extensions) : null; - AllowEmptyValue = parameter?.AllowEmptyValue ?? AllowEmptyValue; - Deprecated = parameter?.Deprecated ?? Deprecated; + Utils.CheckArgumentNull(parameter); + Name = parameter.Name ?? Name; + In = parameter.In ?? In; + Description = parameter.Description ?? Description; + Required = parameter.Required; + Style = parameter.Style ?? Style; + Explode = parameter.Explode; + AllowReserved = parameter.AllowReserved; + Schema = parameter.Schema != null ? new(parameter.Schema) : null; + Examples = parameter.Examples != null ? new Dictionary(parameter.Examples) : null; + Example = parameter.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; + Content = parameter.Content != null ? new Dictionary(parameter.Content) : null; + Extensions = parameter.Extensions != null ? new Dictionary(parameter.Extensions) : null; + AllowEmptyValue = parameter.AllowEmptyValue; + Deprecated = parameter.Deprecated; } - /// - /// Serialize to Open Api v3.1 - /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + /// + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } - /// - /// Serialize to Open Api v3.0 - /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + /// + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { Utils.CheckArgumentNull(writer); @@ -219,13 +136,13 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio writer.WriteProperty(OpenApiConstants.AllowEmptyValue, AllowEmptyValue, false); // style - if (_style.HasValue) + if (Style.HasValue && Style != GetDefaultStyleValue()) { - writer.WriteProperty(OpenApiConstants.Style, _style.Value.GetDisplayName()); + writer.WriteProperty(OpenApiConstants.Style, Style.Value.GetDisplayName()); } // explode - writer.WriteProperty(OpenApiConstants.Explode, _explode, _style is ParameterStyle.Form); + writer.WriteProperty(OpenApiConstants.Explode, _explode, Style is ParameterStyle.Form); // allowReserved writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); @@ -248,10 +165,8 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio writer.WriteEndObject(); } - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + /// + public void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); @@ -372,7 +287,7 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) internal virtual ParameterStyle? GetDefaultStyleValue() { - Style = In switch + return In switch { ParameterLocation.Query => ParameterStyle.Form, ParameterLocation.Header => ParameterStyle.Simple, @@ -380,8 +295,6 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) ParameterLocation.Cookie => ParameterStyle.Form, _ => (ParameterStyle?)ParameterStyle.Simple, }; - - return Style; } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs index ea7d628ea..b9fac8c56 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -39,7 +40,7 @@ public class OpenApiPathItem : IOpenApiExtensible, IOpenApiReferenceable /// A list of parameters that are applicable for all the operations described under this path. /// These parameters can be overridden at the operation level, but cannot be removed there. /// - public virtual IList Parameters { get; set; } = new List(); + public virtual IList Parameters { get; set; } = new List(); /// /// This object MAY be extended with Specification Extensions. @@ -80,7 +81,7 @@ public OpenApiPathItem(OpenApiPathItem pathItem) Description = pathItem?.Description ?? Description; Operations = pathItem?.Operations != null ? new Dictionary(pathItem.Operations) : null; Servers = pathItem?.Servers != null ? new List(pathItem.Servers) : null; - Parameters = pathItem?.Parameters != null ? new List(pathItem.Parameters) : null; + Parameters = pathItem?.Parameters != null ? new List(pathItem.Parameters) : null; Extensions = pathItem?.Extensions != null ? new Dictionary(pathItem.Extensions) : null; UnresolvedReference = pathItem?.UnresolvedReference ?? UnresolvedReference; Reference = pathItem?.Reference != null ? new(pathItem?.Reference) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 0fb16471f..2524c41d6 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -112,7 +113,7 @@ public void SerializeAsV2(IOpenApiWriter writer) // RequestBody object does not exist in V2. } - internal virtual OpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + internal virtual IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) { var bodyParameter = new OpenApiBodyParameter { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 93d1163db..1e687c276 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -13,13 +13,14 @@ namespace Microsoft.OpenApi.Models.References /// /// Parameter Object Reference. /// - public class OpenApiParameterReference : OpenApiParameter, IOpenApiReferenceHolder + public class OpenApiParameterReference : IOpenApiParameter, IOpenApiReferenceHolder { + /// + public OpenApiReference Reference { get; set; } + + /// + public bool UnresolvedReference { get; set; } internal OpenApiParameter _target; - private readonly OpenApiReference _reference; - private string _description; - private bool? _explode; - private ParameterStyle? _style; /// /// Gets the target parameter. @@ -31,10 +32,8 @@ public OpenApiParameter Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiParameter resolved = new OpenApiParameter(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + return _target; } } @@ -52,22 +51,33 @@ public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocumen { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Parameter, ExternalResource = externalResource }; + } - Reference = _reference; + /// + /// Copy constructor + /// + /// The parameter reference to copy + public OpenApiParameterReference(OpenApiParameterReference parameter) + { + Utils.CheckArgumentNull(parameter); + Reference = parameter.Reference != null ? new(parameter.Reference) : null; + UnresolvedReference = parameter?.UnresolvedReference ?? false; + //no need to copy summary and description as if they are not overridden, they will be fetched from the target + //if they are, the reference copy will handle it } internal OpenApiParameterReference(OpenApiParameter target, string referenceId) { _target = target; - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, Type = ReferenceType.Parameter, @@ -75,104 +85,105 @@ internal OpenApiParameterReference(OpenApiParameter target, string referenceId) } /// - public override string Name { get => Target.Name; set => Target.Name = value; } + public string Name { get => Target.Name; } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override bool Required { get => Target.Required; set => Target.Required = value; } + public bool Required { get => Target?.Required ?? default; } /// - public override bool Deprecated { get => Target.Deprecated; set => Target.Deprecated = value; } + public bool Deprecated { get => Target?.Deprecated ?? default; } /// - public override bool AllowEmptyValue { get => Target.AllowEmptyValue; set => Target.AllowEmptyValue = value; } + public bool AllowEmptyValue { get => Target?.AllowEmptyValue ?? default; } /// - public override bool AllowReserved { get => Target.AllowReserved; set => Target.AllowReserved = value; } + public bool AllowReserved { get => Target?.AllowReserved ?? default; } /// - public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public OpenApiSchema Schema { get => Target?.Schema; } /// - public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } + public IDictionary Examples { get => Target?.Examples; } /// - public override JsonNode Example { get => Target.Example; set => Target.Example = value; } + public JsonNode Example { get => Target?.Example; } /// - public override ParameterLocation? In { get => Target.In; set => Target.In = value; } + public ParameterLocation? In { get => Target?.In; } /// - public override ParameterStyle? Style - { - get => _style ?? GetDefaultStyleValue(); - set => _style = value; - } + public ParameterStyle? Style { get => Target?.Style; } /// - public override bool Explode - { - get => _explode ?? Style == ParameterStyle.Form; - set => _explode = value; - } + public bool Explode { get => Target?.Explode ?? default; } /// - public override IDictionary Content { get => Target.Content; set => Target.Content = value; } + public IDictionary Content { get => Target.Content; } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public IDictionary Extensions { get => Target.Extensions; } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); } } /// - public override void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); } } /// - public override void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV2(writer); - return; + Reference.SerializeAsV2(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); } } + /// + public IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpenApiParameter source) + { + return source is OpenApiParameter ? new OpenApiParameter(this) : source; + } + /// private void SerializeInternal(IOpenApiWriter writer, - Action action) + Action action) { Utils.CheckArgumentNull(writer); action(writer, Target); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index bc7e8904e..97383efcd 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -93,7 +94,7 @@ public override string Description public override IList Servers { get => Target.Servers; set => Target.Servers = value; } /// - public override IList Parameters { get => Target.Parameters; set => Target.Parameters = value; } + public override IList Parameters { get => Target.Parameters; set => Target.Parameters = value; } /// public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 7025ec373..5aa466415 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References @@ -121,7 +122,7 @@ private void SerializeInternal(IOpenApiWriter writer, } /// - internal override OpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + internal override IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) { if (writer.GetSettings().ShouldInlineReference(_reference)) { diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index 37e146793..e24c10227 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Services; @@ -302,7 +303,7 @@ private static bool IsHostValid(string host) internal class RequestBodyReferenceFixer : OpenApiVisitorBase { - private IDictionary _requestBodies; + private readonly IDictionary _requestBodies; public RequestBodyReferenceFixer(IDictionary requestBodies) { _requestBodies = requestBodies; @@ -310,7 +311,7 @@ public RequestBodyReferenceFixer(IDictionary request public override void Visit(OpenApiOperation operation) { - var body = operation.Parameters.FirstOrDefault( + var body = operation.Parameters.OfType().FirstOrDefault( p => p.UnresolvedReference && _requestBodies.ContainsKey(p.Reference.Id)); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 35d20ca4a..3fd5743c9 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Reader.V2 { @@ -180,7 +181,7 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List>(TempStorageKeys.OperationConsumes) ?? context.GetFromTempStorage>(TempStorageKeys.GlobalConsumes) ?? diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 247d68679..2153d37d2 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -184,12 +184,12 @@ private static void ProcessIn(OpenApiParameter o, ParseNode n, OpenApiDocument h } } - public static OpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) { return LoadParameter(node, false, hostDocument); } - public static OpenApiParameter LoadParameter(ParseNode node, bool loadRequestBody, OpenApiDocument hostDocument) + public static IOpenApiParameter LoadParameter(ParseNode node, bool loadRequestBody, OpenApiDocument hostDocument) { // Reset the local variables every time this method is called. node.Context.SetTempStorage(TempStorageKeys.ParameterIsBodyOrFormData, false); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs index 915314d35..c8660d899 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs @@ -115,7 +115,7 @@ internal static partial class OpenApiV3Deserializer } }; - public static OpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("parameter"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs index fecaf58c2..cf5f5b294 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs @@ -133,7 +133,7 @@ internal static partial class OpenApiV31Deserializer } }; - public static OpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiParameter LoadParameter(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("parameter"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 3125d75cc..d520e6f19 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -99,9 +99,9 @@ private void AddParameterToComponents(OpenApiParameter parameter, string referen { EnsureComponentsExist(); EnsureParametersExist(); - if (!Components.Parameters.ContainsKey(referenceId ?? parameter.Reference.Id)) + if (!Components.Parameters.ContainsKey(referenceId)) { - Components.Parameters.Add(referenceId ?? parameter.Reference.Id, parameter); + Components.Parameters.Add(referenceId, parameter); } } @@ -205,7 +205,7 @@ private void EnsureSchemasExist() private void EnsureParametersExist() { - _target.Components.Parameters ??= new Dictionary(); + _target.Components.Parameters ??= new Dictionary(); } private void EnsureResponsesExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 62ecb4c5d..b35163ca0 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -141,14 +141,14 @@ public virtual void Visit(OpenApiOperation operation) /// /// Visits list of /// - public virtual void Visit(IList parameters) + public virtual void Visit(IList parameters) { } /// /// Visits /// - public virtual void Visit(OpenApiParameter parameter) + public virtual void Visit(IOpenApiParameter parameter) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index c578a7653..6173ad3cb 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -623,7 +623,7 @@ internal void Walk(IList securityRequirements) /// /// Visits list of /// - internal void Walk(IList parameters) + internal void Walk(IList parameters) { if (parameters == null) { @@ -644,7 +644,7 @@ internal void Walk(IList parameters) /// /// Visits and child objects /// - internal void Walk(OpenApiParameter parameter, bool isComponent = false) + internal void Walk(IOpenApiParameter parameter, bool isComponent = false) { if (parameter == null) { @@ -1203,7 +1203,7 @@ internal void Walk(IOpenApiElement element) case OpenApiOAuthFlows e: Walk(e); break; case OpenApiOAuthFlow e: Walk(e); break; case OpenApiOperation e: Walk(e); break; - case OpenApiParameter e: Walk(e); break; + case IOpenApiParameter e: Walk(e); break; case OpenApiPaths e: Walk(e); break; case OpenApiRequestBody e: Walk(e); break; case OpenApiResponse e: Walk(e); break; diff --git a/src/Microsoft.OpenApi/Services/OperationSearch.cs b/src/Microsoft.OpenApi/Services/OperationSearch.cs index 8b1dbd1ee..e0512bf72 100644 --- a/src/Microsoft.OpenApi/Services/OperationSearch.cs +++ b/src/Microsoft.OpenApi/Services/OperationSearch.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Services { @@ -57,14 +58,14 @@ public override void Visit(OpenApiPathItem pathItem) /// Visits list of . /// /// The target list of . - public override void Visit(IList parameters) + public override void Visit(IList parameters) { /* The Parameter.Explode property should be true * if Parameter.Style == Form; but OData query params * as used in Microsoft Graph implement explode: false * ex: $select=id,displayName,givenName */ - foreach (var parameter in parameters.Where(x => x.Style == ParameterStyle.Form)) + foreach (var parameter in parameters.OfType().Where(static x => x.Style == ParameterStyle.Form)) { parameter.Explode = false; } diff --git a/src/Microsoft.OpenApi/Services/SearchResult.cs b/src/Microsoft.OpenApi/Services/SearchResult.cs index 47fff14df..6bbeed27a 100644 --- a/src/Microsoft.OpenApi/Services/SearchResult.cs +++ b/src/Microsoft.OpenApi/Services/SearchResult.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Services { @@ -24,6 +25,6 @@ public class SearchResult /// /// Parameters object /// - public IList Parameters { get; set; } + public IList Parameters { get; set; } } } diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 594d87eaa..7deb2ddcb 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -105,7 +105,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiTag tag) => Validate(tag); /// - public override void Visit(OpenApiParameter parameter) => Validate(parameter); + public override void Visit(IOpenApiParameter parameter) => Validate(parameter); /// public override void Visit(OpenApiSchema schema) => Validate(schema); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index 812bc7f12..26fa30005 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -3,6 +3,7 @@ using System; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules @@ -16,7 +17,7 @@ public static class OpenApiParameterRules /// /// Validate the field is required. /// - public static ValidationRule ParameterRequiredFields => + public static ValidationRule ParameterRequiredFields => new(nameof(ParameterRequiredFields), (context, item) => { @@ -42,7 +43,7 @@ public static class OpenApiParameterRules /// /// Validate the "required" field is true when "in" is path. /// - public static ValidationRule RequiredMustBeTrueWhenInIsPath => + public static ValidationRule RequiredMustBeTrueWhenInIsPath => new(nameof(RequiredMustBeTrueWhenInIsPath), (context, item) => { @@ -61,7 +62,7 @@ public static class OpenApiParameterRules /// /// Validate that a path parameter should always appear in the path /// - public static ValidationRule PathParameterShouldBeInThePath => + public static ValidationRule PathParameterShouldBeInThePath => new(nameof(PathParameterShouldBeInThePath), (context, parameter) => { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index 110cac88c..8d0e6010a 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -2,6 +2,7 @@ using Microsoft.OpenApi.Hidi.Formatters; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; using Xunit; @@ -109,9 +110,9 @@ private static OpenApiDocument GetSampleOpenApiDocument() OperationType.Get, new() { OperationId = "Foo.GetFoo", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "ids", In = ParameterLocation.Query, @@ -133,7 +134,7 @@ private static OpenApiDocument GetSampleOpenApiDocument() } } } - }, + ], Extensions = new Dictionary { { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index 8f0d04004..0dceb6127 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Tests.UtilityFiles; @@ -121,9 +122,9 @@ public void CreateFilteredDocumentUsingPredicateFromRequestUrl() { OperationType.Get, new() }, { OperationType.Patch, new() } }, - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "id", In = ParameterLocation.Path, @@ -133,7 +134,7 @@ public void CreateFilteredDocumentUsingPredicateFromRequestUrl() Type = JsonSchemaType.String } } - } + ] } diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index edbf143fe..f2f6386c4 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -4,6 +4,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Tests.UtilityFiles @@ -78,10 +79,10 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationId = "reports.getTeamsUserActivityCounts", Summary = "Invoke function getTeamsUserActivityUserCounts", - Parameters = new List + Parameters = new List { { - new() + new OpenApiParameter() { Name = "period", In = ParameterLocation.Path, @@ -118,10 +119,10 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - Parameters = new List + Parameters = new List { { - new() + new OpenApiParameter() { Name = "period", In = ParameterLocation.Path, @@ -143,10 +144,10 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationId = "reports.getTeamsUserActivityUserDetail-a3f1", Summary = "Invoke function getTeamsUserActivityUserDetail", - Parameters = new List + Parameters = new List { { - new() + new OpenApiParameter() { Name = "period", In = ParameterLocation.Path, @@ -183,9 +184,9 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "period", In = ParameterLocation.Path, @@ -316,9 +317,9 @@ public static OpenApiDocument CreateOpenApiDocument() OperationId = "users.GetMessages", Summary = "Get messages from users", Description = "The messages in a mailbox or folder. Read-only. Nullable.", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "$select", In = ParameterLocation.Query, @@ -370,10 +371,10 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationId = "administrativeUnits.restore", Summary = "Invoke action restore", - Parameters = new List + Parameters = new List { { - new() + new OpenApiParameter() { Name = "administrativeUnit-id", In = ParameterLocation.Path, @@ -504,9 +505,9 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationId = "communications.calls.call.keepAlive", Summary = "Invoke action keepAlive", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "call-id", In = ParameterLocation.Path, @@ -552,9 +553,9 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationId = "groups.group.events.event.calendar.events.delta", Summary = "Invoke function delta", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "group-id", In = ParameterLocation.Path, @@ -571,7 +572,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - new() + new OpenApiParameter() { Name = "event-id", In = ParameterLocation.Path, diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 356f4268d..ad8495494 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -30,7 +30,7 @@ public async Task LoadParameterReference() var reference = new OpenApiParameterReference("skipParam", result.Document); // Assert - reference.Should().BeEquivalentTo( + Assert.Equivalent( new OpenApiParameter { Name = "skip", @@ -43,7 +43,8 @@ public async Task LoadParameterReference() Format = "int32" } - }, options => options.Excluding(x => x.Reference) + }, + reference ); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index 1d7fd39d3..ce7382b65 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -30,8 +31,8 @@ public class OpenApiOperationTests Summary = "Updates a pet in the store", Description = "", OperationId = "updatePet", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "petId", @@ -43,7 +44,7 @@ public class OpenApiOperationTests Type = JsonSchemaType.String } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -63,8 +64,8 @@ public class OpenApiOperationTests Summary = "Updates a pet in the store with request body", Description = "", OperationId = "updatePetWithBody", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "petId", @@ -76,7 +77,7 @@ public class OpenApiOperationTests Type = JsonSchemaType.String } }, - }, + ], RequestBody = new OpenApiRequestBody { Description = "Pet to update with", diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index d33b9964f..be19365d5 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; using Xunit; @@ -19,9 +20,9 @@ public class OpenApiPathItemTests private static readonly OpenApiPathItem _basicPathItemWithFormData = new() { - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "id", In = ParameterLocation.Path, @@ -37,7 +38,7 @@ public class OpenApiPathItemTests }, Style = ParameterStyle.Simple } - }, + ], Operations = { [OperationType.Put] = new() @@ -45,9 +46,9 @@ public class OpenApiPathItemTests Summary = "Puts a pet in the store with form data", Description = "", OperationId = "putPetWithForm", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "petId", In = ParameterLocation.Path, @@ -58,7 +59,7 @@ public class OpenApiPathItemTests Type = JsonSchemaType.String } } - }, + ], RequestBody = new() { Content = @@ -140,9 +141,9 @@ public class OpenApiPathItemTests Summary = "Posts a pet in the store with form data", Description = "", OperationId = "postPetWithForm", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "petId", In = ParameterLocation.Path, @@ -153,7 +154,7 @@ public class OpenApiPathItemTests Type = JsonSchemaType.String } }, - new() + new OpenApiParameter() { Name = "petName", In = ParameterLocation.Path, @@ -164,7 +165,7 @@ public class OpenApiPathItemTests Type = JsonSchemaType.String } } - }, + ], RequestBody = new() { Content = diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 5f8c9e9bb..c2bbf6db6 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -12,6 +12,7 @@ using Xunit; using VerifyXunit; using VerifyTests; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Readers.Tests.V31Tests { @@ -106,8 +107,8 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "tags", @@ -135,7 +136,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() Format = "int32" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -280,8 +281,8 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "tags", @@ -309,7 +310,7 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() Format = "int32" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 3622d572b..1b8f26c64 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; @@ -322,8 +323,8 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "tags", @@ -351,7 +352,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() Format = "int32" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -465,8 +466,8 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() Description = "Returns a user based on a single ID, if the user does not have access to the pet", OperationId = "findPetById", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -479,7 +480,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -525,8 +526,8 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() { Description = "deletes a single pet based on the ID supplied", OperationId = "deletePet", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -539,7 +540,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["204"] = new OpenApiResponse @@ -769,8 +770,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() }, Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "tags", @@ -798,7 +799,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() Format = "int32" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -929,8 +930,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() Description = "Returns a user based on a single ID, if the user does not have access to the pet", OperationId = "findPetById", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -943,7 +944,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -989,8 +990,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Description = "deletes a single pet based on the ID supplied", OperationId = "deletePet", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -1003,7 +1004,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["204"] = new OpenApiResponse @@ -1224,6 +1225,19 @@ public async Task ValidateExampleShouldNotHaveDataTypeMismatch() [Fact] public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() { + var parameter = new OpenApiParameter + { + Name = "limit", + In = ParameterLocation.Query, + Description = "Limit the number of pets returned", + Required = false, + Schema = new() + { + Type = JsonSchemaType.Integer, + Format = "int32", + Default = 10 + }, + }; // Arrange var expected = new OpenApiDocument { @@ -1243,24 +1257,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() Summary = "Returns all pets", Parameters = [ - new OpenApiParameter - { - Name = "limit", - In = ParameterLocation.Query, - Description = "Limit the number of pets returned", - Required = false, - Schema = new() - { - Type = JsonSchemaType.Integer, - Format = "int32", - Default = 10 - }, - Reference = new OpenApiReference - { - Id = "LimitParameter", - Type = ReferenceType.Parameter - } - } + new OpenApiParameterReference(parameter, "LimitParameter"), ], Responses = new OpenApiResponses() } @@ -1269,21 +1266,9 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() }, Components = new OpenApiComponents { - Parameters = new Dictionary + Parameters = new Dictionary { - ["LimitParameter"] = new OpenApiParameter - { - Name = "limit", - In = ParameterLocation.Query, - Description = "Limit the number of pets returned", - Required = false, - Schema = new() - { - Type = JsonSchemaType.Integer, - Format = "int32", - Default = 10 - }, - } + ["LimitParameter"] = parameter } } }; @@ -1317,10 +1302,15 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() var actualParam = doc.Paths["/pets"].Operations[OperationType.Get].Parameters[0]; var outputDoc = (await doc.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0)).MakeLineBreaksEnvironmentNeutral(); var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters[0]; + var expectedParamReference = Assert.IsType(expectedParam); + expectedParamReference.Reference.HostDocument = doc; + + var actualParamReference = Assert.IsType(actualParam); // Assert - actualParam.Should().BeEquivalentTo(expectedParam, options => options - .Excluding(x => x.Reference.HostDocument) + actualParamReference.Should().BeEquivalentTo(expectedParamReference, options => options + .Excluding(x => x.Reference) + .Excluding(x => x.Target) .Excluding(x => x.Schema.Default.Parent) .Excluding(x => x.Schema.Default.Options) .IgnoringCyclicReferences()); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 4b19c2e66..17411a859 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -9,6 +9,8 @@ using Xunit; using Microsoft.OpenApi.Reader.V3; using System.Threading.Tasks; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Readers.Tests.V3Tests { @@ -300,6 +302,21 @@ public async Task ParseParameterWithExamplesShouldSucceed() public void ParseParameterWithReferenceWorks() { // Arrange + var parameter = new OpenApiParameter + { + Name = "tags", + In = ParameterLocation.Query, + Description = "tags to filter by", + Required = false, + Schema = new() + { + Type = JsonSchemaType.Array, + Items = new OpenApiSchema + { + Type = JsonSchemaType.String + } + } + }; var document = new OpenApiDocument { Info = new OpenApiInfo @@ -324,44 +341,19 @@ public void ParseParameterWithReferenceWorks() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { - new() { - Reference = new OpenApiReference - { - Type = ReferenceType.Parameter, - Id = "tagsParameter" - } - } - }, + Parameters = + [ + new OpenApiParameterReference (parameter, "tagsParameter"), + ], } } } }, Components = new OpenApiComponents { - Parameters = new Dictionary() + Parameters = new Dictionary() { - ["tagsParameter"] = new OpenApiParameter - { - Name = "tags", - In = ParameterLocation.Query, - Description = "tags to filter by", - Required = false, - Schema = new() - { - Type = JsonSchemaType.Array, - Items = new OpenApiSchema - { - Type = JsonSchemaType.String - } - }, - Reference = new OpenApiReference - { - Type = ReferenceType.Parameter, - Id = "tagsParameter" - } - } + ["tagsParameter"] = parameter, } } }; @@ -377,7 +369,7 @@ public void ParseParameterWithReferenceWorks() var param = OpenApiV3Deserializer.LoadParameter(node, document); // Assert - param.Should().BeEquivalentTo(expected, options => options.Excluding(p => p.Reference.HostDocument)); + Assert.Equivalent(expected, param); } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt index c63fb3250..5d9d7f3da 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -30,7 +30,6 @@ "name": "tags", "in": "query", "description": "tags to filter by", - "style": "form", "schema": { "type": "array", "items": { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt index f7d8a3f47..5fd0d1e26 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"openapi":"3.0.4","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","style":"form","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"application/xml":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"application/xml":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} +{"openapi":"3.0.4","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"application/xml":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"application/xml":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 752ec7d9f..f43843051 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; @@ -252,8 +253,8 @@ public OpenApiDocumentTests() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "tags", @@ -281,7 +282,7 @@ public OpenApiDocumentTests() Format = "int32" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -395,8 +396,8 @@ public OpenApiDocumentTests() Description = "Returns a user based on a single ID, if the user does not have access to the pet", OperationId = "findPetById", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -409,7 +410,7 @@ public OpenApiDocumentTests() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse @@ -455,8 +456,8 @@ public OpenApiDocumentTests() { Description = "deletes a single pet based on the ID supplied", OperationId = "deletePet", - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -469,7 +470,7 @@ public OpenApiDocumentTests() Format = "int64" } } - }, + ], Responses = new OpenApiResponses { ["204"] = new OpenApiResponse @@ -628,7 +629,7 @@ public OpenApiDocumentTests() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List + Parameters = new List { new OpenApiParameter { @@ -771,7 +772,7 @@ public OpenApiDocumentTests() Description = "Returns a user based on a single ID, if the user does not have access to the pet", OperationId = "findPetById", - Parameters = new List + Parameters = new List { new OpenApiParameter { @@ -831,7 +832,7 @@ public OpenApiDocumentTests() { Description = "deletes a single pet based on the ID supplied", OperationId = "deletePet", - Parameters = new List + Parameters = new List { new OpenApiParameter { @@ -975,7 +976,7 @@ public OpenApiDocumentTests() [OperationType.Get] = new OpenApiOperation { OperationId = "addByOperand1AndByOperand2", - Parameters = new List + Parameters = new List { new OpenApiParameter { @@ -1087,9 +1088,9 @@ public OpenApiDocumentTests() { Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "tags", In = ParameterLocation.Query, @@ -1104,7 +1105,7 @@ public OpenApiDocumentTests() } } }, - new() + new OpenApiParameter() { Name = "limit", In = ParameterLocation.Query, @@ -1230,9 +1231,9 @@ public OpenApiDocumentTests() Description = "Returns a user based on a single ID, if the user does not have access to the pet", OperationId = "findPetById", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "id", In = ParameterLocation.Path, @@ -1290,9 +1291,9 @@ public OpenApiDocumentTests() { Description = "deletes a single pet based on the ID supplied", OperationId = "deletePet", - Parameters = new List + Parameters = new List { - new() + new OpenApiParameter() { Name = "id", In = ParameterLocation.Path, @@ -1732,8 +1733,8 @@ public async Task SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollec { [OperationType.Get] = new OpenApiOperation { - Parameters = new List - { + Parameters = + [ new OpenApiParameter { In = ParameterLocation.Query, @@ -1742,7 +1743,7 @@ public async Task SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollec Type = JsonSchemaType.String } } - }, + ], Responses = new OpenApiResponses() } } @@ -1799,8 +1800,8 @@ public async Task SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { [OperationType.Get] = new OpenApiOperation { - Parameters = new List - { + Parameters = + [ new OpenApiParameter { Name = "id", @@ -1814,7 +1815,7 @@ public async Task SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() } } } - }, + ], Responses = new OpenApiResponses { ["200"] = new OpenApiResponse diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 1b0b27ada..81da044bf 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Xunit; @@ -25,19 +26,19 @@ public class OpenApiOperationTests Url = new("http://external.com") }, OperationId = "operationId1", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { In = ParameterLocation.Path, Name = "parameter1", }, - new() + new OpenApiParameter() { In = ParameterLocation.Header, Name = "parameter2" } - }, + ], RequestBody = new() { Description = "description2", @@ -99,19 +100,19 @@ public class OpenApiOperationTests Url = new("http://external.com") }, OperationId = "operationId1", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { In = ParameterLocation.Path, Name = "parameter1" }, - new() + new OpenApiParameter() { In = ParameterLocation.Header, Name = "parameter2" } - }, + ], RequestBody = new() { Description = "description2", @@ -176,9 +177,9 @@ public class OpenApiOperationTests Summary = "Updates a pet in the store with form data", Description = "", OperationId = "updatePetWithForm", - Parameters = new List - { - new() + Parameters = + [ + new OpenApiParameter() { Name = "petId", In = ParameterLocation.Path, @@ -189,7 +190,7 @@ public class OpenApiOperationTests Type = JsonSchemaType.String } } - }, + ], RequestBody = new() { Content = diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=False.verified.txt index 5d3060ec5..d450bda88 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=False.verified.txt @@ -2,7 +2,6 @@ "name": "name1", "in": "query", "description": "description1", - "style": "form", "explode": false, "schema": { "type": "array", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=True.verified.txt index a4b87db10..33a58c93f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeFalseWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"name":"name1","in":"query","description":"description1","style":"form","explode":false,"schema":{"type":"array","items":{"enum":["value1","value2"]}}} \ No newline at end of file +{"name":"name1","in":"query","description":"description1","explode":false,"schema":{"type":"array","items":{"enum":["value1","value2"]}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=False.verified.txt index 36a9c0168..56944b8db 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=False.verified.txt @@ -2,7 +2,6 @@ "name": "name1", "in": "query", "description": "description1", - "style": "form", "schema": { "type": "array", "items": { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=True.verified.txt index 206902b7b..b9e1ee95f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.SerializeParameterWithFormStyleAndExplodeTrueWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"name":"name1","in":"query","description":"description1","style":"form","schema":{"type":"array","items":{"enum":["value1","value2"]}}} \ No newline at end of file +{"name":"name1","in":"query","description":"description1","schema":{"type":"array","items":{"enum":["value1","value2"]}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index b76dcf342..edec7bbd8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -260,7 +260,6 @@ public async Task SerializeAdvancedParameterAsV3JsonWorks() "in": "path", "description": "description1", "required": true, - "style": "simple", "explode": true, "schema": { "title": "title2", diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt index 237298009..cd30a5fc2 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt @@ -2,7 +2,6 @@ "name": "limit", "in": "query", "description": "Results to return", - "style": "form", "schema": { "maximum": 100, "minimum": 1, diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt index e8eac1b64..da4f04c14 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"name":"limit","in":"query","description":"Results to return","style":"form","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file +{"name":"limit","in":"query","description":"Results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt index 237298009..cd30a5fc2 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt @@ -2,7 +2,6 @@ "name": "limit", "in": "query", "description": "Results to return", - "style": "form", "schema": { "maximum": 100, "minimum": 1, diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt index e8eac1b64..da4f04c14 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"name":"limit","in":"query","description":"Results to return","style":"form","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file +{"name":"limit","in":"query","description":"Results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index e881f649d..f89d60453 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -371,6 +371,21 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } Microsoft.OpenApi.Models.OpenApiServer Server { get; } } + public interface IOpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + bool AllowEmptyValue { get; } + bool AllowReserved { get; } + System.Collections.Generic.IDictionary Content { get; } + bool Deprecated { get; } + System.Text.Json.Nodes.JsonNode Example { get; } + System.Collections.Generic.IDictionary Examples { get; } + bool Explode { get; } + Microsoft.OpenApi.Models.ParameterLocation? In { get; } + string Name { get; } + bool Required { get; } + Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + Microsoft.OpenApi.Models.ParameterStyle? Style { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -409,7 +424,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Extensions { get; set; } public System.Collections.Generic.IDictionary? Headers { get; set; } public System.Collections.Generic.IDictionary? Links { get; set; } - public System.Collections.Generic.IDictionary? Parameters { get; set; } + public System.Collections.Generic.IDictionary? Parameters { get; set; } public System.Collections.Generic.IDictionary? PathItems { get; set; } public System.Collections.Generic.IDictionary? RequestBodies { get; set; } public System.Collections.Generic.IDictionary? Responses { get; set; } @@ -798,7 +813,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Extensions { get; set; } public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } public string? OperationId { get; set; } - public System.Collections.Generic.IList? Parameters { get; set; } + public System.Collections.Generic.IList? Parameters { get; set; } public Microsoft.OpenApi.Models.OpenApiRequestBody? RequestBody { get; set; } public Microsoft.OpenApi.Models.OpenApiResponses? Responses { get; set; } public System.Collections.Generic.IList? Security { get; set; } @@ -809,29 +824,27 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { public OpenApiParameter() { } - public OpenApiParameter(Microsoft.OpenApi.Models.OpenApiParameter parameter) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual bool AllowEmptyValue { get; set; } - public virtual bool AllowReserved { get; set; } - public virtual System.Collections.Generic.IDictionary Content { get; set; } - public virtual bool Deprecated { get; set; } - public virtual string Description { get; set; } - public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } - public virtual System.Collections.Generic.IDictionary Examples { get; set; } - public virtual bool Explode { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } - public virtual string Name { get; set; } - public virtual bool Required { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } - public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } - public virtual bool UnresolvedReference { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiParameter(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } + public bool AllowEmptyValue { get; set; } + public bool AllowReserved { get; set; } + public System.Collections.Generic.IDictionary Content { get; set; } + public bool Deprecated { get; set; } + public string Description { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; set; } + public System.Collections.Generic.IDictionary Examples { get; set; } + public bool Explode { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } + public string Name { get; set; } + public bool Required { get; set; } + public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -842,7 +855,7 @@ namespace Microsoft.OpenApi.Models public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual System.Collections.Generic.IDictionary Operations { get; set; } - public virtual System.Collections.Generic.IList Parameters { get; set; } + public virtual System.Collections.Generic.IList Parameters { get; set; } public virtual System.Collections.Generic.IList Servers { get; set; } public virtual string Summary { get; set; } public void AddOperation(Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operation) { } @@ -1216,27 +1229,31 @@ namespace Microsoft.OpenApi.Models.References public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiParameterReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { + public OpenApiParameterReference(Microsoft.OpenApi.Models.References.OpenApiParameterReference parameter) { } public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public bool AllowEmptyValue { get; } + public bool AllowReserved { get; } + public System.Collections.Generic.IDictionary Content { get; } + public bool Deprecated { get; } + public string Description { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; } + public System.Collections.Generic.IDictionary Examples { get; } + public bool Explode { get; } + public System.Collections.Generic.IDictionary Extensions { get; } + public Microsoft.OpenApi.Models.ParameterLocation? In { get; } + public string Name { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public bool Required { get; } + public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public Microsoft.OpenApi.Models.OpenApiParameter Target { get; } - public override bool AllowEmptyValue { get; set; } - public override bool AllowReserved { get; set; } - public override System.Collections.Generic.IDictionary Content { get; set; } - public override bool Deprecated { get; set; } - public override string Description { get; set; } - public override System.Text.Json.Nodes.JsonNode Example { get; set; } - public override System.Collections.Generic.IDictionary Examples { get; set; } - public override bool Explode { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } - public override string Name { get; set; } - public override bool Required { get; set; } - public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } - public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public bool UnresolvedReference { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1245,7 +1262,7 @@ namespace Microsoft.OpenApi.Models.References public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override System.Collections.Generic.IDictionary Operations { get; set; } - public override System.Collections.Generic.IList Parameters { get; set; } + public override System.Collections.Generic.IList Parameters { get; set; } public override System.Collections.Generic.IList Servers { get; set; } public override string Summary { get; set; } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1546,6 +1563,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1556,7 +1574,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiParameter parameter) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } @@ -1579,7 +1596,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } public virtual void Visit(System.Collections.Generic.IDictionary serverVariables) { } public virtual void Visit(System.Collections.Generic.IList example) { } - public virtual void Visit(System.Collections.Generic.IList parameters) { } + public virtual void Visit(System.Collections.Generic.IList parameters) { } public virtual void Visit(System.Collections.Generic.IList openApiSecurityRequirements) { } public virtual void Visit(System.Collections.Generic.IList servers) { } public virtual void Visit(System.Collections.Generic.IList openApiTags) { } @@ -1610,14 +1627,14 @@ namespace Microsoft.OpenApi.Services public OperationSearch(System.Func predicate) { } public System.Collections.Generic.IList SearchResults { get; } public override void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } - public override void Visit(System.Collections.Generic.IList parameters) { } + public override void Visit(System.Collections.Generic.IList parameters) { } } public class SearchResult { public SearchResult() { } public Microsoft.OpenApi.Services.CurrentKeys CurrentKeys { get; set; } public Microsoft.OpenApi.Models.OpenApiOperation Operation { get; set; } - public System.Collections.Generic.IList Parameters { get; set; } + public System.Collections.Generic.IList Parameters { get; set; } } } namespace Microsoft.OpenApi.Validations @@ -1645,6 +1662,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1655,7 +1673,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiParameter parameter) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } @@ -1777,9 +1794,9 @@ namespace Microsoft.OpenApi.Validations.Rules [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiParameterRules { - public static Microsoft.OpenApi.Validations.ValidationRule ParameterRequiredFields { get; } - public static Microsoft.OpenApi.Validations.ValidationRule PathParameterShouldBeInThePath { get; } - public static Microsoft.OpenApi.Validations.ValidationRule RequiredMustBeTrueWhenInIsPath { get; } + public static Microsoft.OpenApi.Validations.ValidationRule ParameterRequiredFields { get; } + public static Microsoft.OpenApi.Validations.ValidationRule PathParameterShouldBeInThePath { get; } + public static Microsoft.OpenApi.Validations.ValidationRule RequiredMustBeTrueWhenInIsPath { get; } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiPathsRules diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index c08c88471..13328046e 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -6,6 +6,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations.Rules; @@ -49,7 +50,7 @@ public void ValidateRequiredIsTrueWhenInIsPathInParameter() var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); validator.Enter("{name}"); var walker = new OpenApiWalker(validator); - walker.Walk(parameter); + walker.Walk((IOpenApiParameter)parameter); var errors = validator.Errors; // Assert Assert.NotEmpty(errors); @@ -93,8 +94,6 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange - IEnumerable warnings; - var parameter = new OpenApiParameter { Name = "parameter1", @@ -140,26 +139,21 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() // Act var defaultRuleSet = ValidationRuleSet.GetDefaultRuleSet(); - defaultRuleSet.Add(typeof(OpenApiParameter), OpenApiNonDefaultRules.ParameterMismatchedDataType); + defaultRuleSet.Add(typeof(IOpenApiParameter), OpenApiNonDefaultRules.ParameterMismatchedDataType); var validator = new OpenApiValidator(defaultRuleSet); validator.Enter("{parameter1}"); var walker = new OpenApiWalker(validator); - walker.Walk(parameter); - - warnings = validator.Warnings; - var result = !warnings.Any(); + walker.Walk((IOpenApiParameter)parameter); // Assert - Assert.False(result); + Assert.NotEmpty(validator.Warnings); } [Fact] public void PathParameterNotInThePathShouldReturnAnError() { // Arrange - IEnumerable errors; - var parameter = new OpenApiParameter { Name = "parameter1", @@ -175,21 +169,18 @@ public void PathParameterNotInThePathShouldReturnAnError() var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); var walker = new OpenApiWalker(validator); - walker.Walk(parameter); - - errors = validator.Errors; - var result = errors.Any(); + walker.Walk((IOpenApiParameter)parameter); // Assert - Assert.True(result); + Assert.NotEmpty(validator.Errors); Assert.Equivalent(new[] { "PathParameterShouldBeInThePath" - }, errors.OfType().Select(e => e.RuleName)); + }, validator.Errors.OfType().Select(e => e.RuleName)); Assert.Equivalent(new[] { "#/in" - }, errors.Select(e => e.Pointer)); + }, validator.Errors.Select(e => e.Pointer)); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index f2634be52..302f8937a 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -30,8 +30,8 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiServerVariable)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiOperation)); - visitor.Visit(default(IList)); - visitor.Visit(default(OpenApiParameter)); + visitor.Visit(default(IList)); + visitor.Visit(default(IOpenApiParameter)); visitor.Visit(default(OpenApiRequestBody)); visitor.Visit(default(IDictionary)); visitor.Visit(default(IDictionary)); @@ -154,13 +154,13 @@ public override void Visit(OpenApiOperation operation) base.Visit(operation); } - public override void Visit(IList parameters) + public override void Visit(IList parameters) { EncodeCall(); base.Visit(parameters); } - public override void Visit(OpenApiParameter parameter) + public override void Visit(IOpenApiParameter parameter) { EncodeCall(); base.Visit(parameter); From 10068797577e14ed4ebf6909face0aef7e3f7d56 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Jan 2025 17:38:41 -0500 Subject: [PATCH 021/103] fix: extraneous null prop removal Signed-off-by: Vincent Biret --- .../Models/References/OpenApiParameterReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 1e687c276..da9d1dabd 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -68,7 +68,7 @@ public OpenApiParameterReference(OpenApiParameterReference parameter) { Utils.CheckArgumentNull(parameter); Reference = parameter.Reference != null ? new(parameter.Reference) : null; - UnresolvedReference = parameter?.UnresolvedReference ?? false; + UnresolvedReference = parameter.UnresolvedReference; //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } From 4df4b264ae5bf65f67a9029df39d67e1d5170168 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 08:58:15 -0500 Subject: [PATCH 022/103] chore: refactors common reference work to a base class to reduce duplication Signed-off-by: Vincent Biret --- .../References/BaseOpenApiReferenceHolder.cs | 79 +++++++++++++++++++ .../References/OpenApiCallbackReference.cs | 59 ++------------ .../References/OpenApiExampleReference.cs | 59 ++------------ .../References/OpenApiHeaderReference.cs | 58 ++------------ .../Models/References/OpenApiLinkReference.cs | 60 ++------------ .../References/OpenApiParameterReference.cs | 59 ++------------ .../PublicApi/PublicApi.approved.txt | 78 +++++++++--------- 7 files changed, 157 insertions(+), 295 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs new file mode 100644 index 000000000..98df8bbbd --- /dev/null +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -0,0 +1,79 @@ +using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Writers; + +namespace Microsoft.OpenApi.Models.References; +/// +/// Base class for OpenApiReferenceHolder. +/// +/// The concrete class implementation type for the model. +/// The interface type for the model. +public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V +{ + internal T _target; + /// + public T Target + { + get + { + _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + return _target; + } + } + /// + /// Copy constructor + /// + /// The parameter reference to copy + protected BaseOpenApiReferenceHolder(BaseOpenApiReferenceHolder source) + { + Utils.CheckArgumentNull(source); + Reference = source.Reference != null ? new(source.Reference) : null; + UnresolvedReference = source.UnresolvedReference; + //no need to copy summary and description as if they are not overridden, they will be fetched from the target + //if they are, the reference copy will handle it + } + private protected BaseOpenApiReferenceHolder(T target, string referenceId, ReferenceType referenceType) + { + _target = target; + + Reference = new OpenApiReference() + { + Id = referenceId, + Type = referenceType, + }; + } + /// + /// Constructor initializing the reference object. + /// + /// The reference Id. + /// The host OpenAPI document. + /// The reference type. + /// Optional: External resource in the reference. + /// It may be: + /// 1. a absolute/relative file path, for example: ../commons/pet.json + /// 2. a Url, for example: http://localhost/pet.json + /// + protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDocument, ReferenceType referenceType, string externalResource = null) + { + Utils.CheckArgumentNullOrEmpty(referenceId); + + Reference = new OpenApiReference() + { + Id = referenceId, + HostDocument = hostDocument, + Type = referenceType, + ExternalResource = externalResource + }; + } + /// + public bool UnresolvedReference { get; set; } + /// + public OpenApiReference Reference { get; set; } + /// + public abstract V CopyReferenceAsTargetElementWithOverrides(V source); + /// + public abstract void SerializeAsV2(IOpenApiWriter writer); + /// + public abstract void SerializeAsV3(IOpenApiWriter writer); + /// + public abstract void SerializeAsV31(IOpenApiWriter writer); +} diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index f357c4532..bb6e38869 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -13,32 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Callback Object Reference: A reference to a map of possible out-of band callbacks related to the parent operation. /// - public class OpenApiCallbackReference : IOpenApiCallback, IOpenApiReferenceHolder + public class OpenApiCallbackReference : BaseOpenApiReferenceHolder, IOpenApiCallback { -#nullable enable - internal OpenApiCallback _target; - /// - public OpenApiReference Reference { get; set; } - - /// - public bool UnresolvedReference { get; set; } - - /// - /// Gets the target callback. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiCallback Target -#nullable restore - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -49,39 +25,20 @@ public OpenApiCallback Target /// 1. an absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Callback, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Callback, - ExternalResource = externalResource - }; } /// /// Copy constructor /// /// The callback reference to copy - public OpenApiCallbackReference(OpenApiCallbackReference callback) + public OpenApiCallbackReference(OpenApiCallbackReference callback):base(callback) { - Utils.CheckArgumentNull(callback); - Reference = callback.Reference != null ? new(callback.Reference) : null; - UnresolvedReference = callback.UnresolvedReference; } - internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) + internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):base(target, referenceId, ReferenceType.Callback) { - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Callback, - }; } /// @@ -91,7 +48,7 @@ internal OpenApiCallbackReference(OpenApiCallback target, string referenceId) public IDictionary Extensions { get => Target?.Extensions; } /// - public void SerializeAsV3(IOpenApiWriter writer) + public override void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -104,7 +61,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -117,7 +74,7 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback source) + public override IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback source) { // the copy here is never called since callbacks do not have any overridable fields. // if the spec evolves to include overridable fields for callbacks, the serialize methods will need to call this copy method. @@ -125,7 +82,7 @@ public IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallba } /// - public void SerializeAsV2(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 9f1842001..60c35f760 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -13,30 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Example Object Reference. /// - public class OpenApiExampleReference : IOpenApiReferenceHolder, IOpenApiExample + public class OpenApiExampleReference : BaseOpenApiReferenceHolder, IOpenApiExample { - /// - public OpenApiReference Reference { get; set; } - - /// - public bool UnresolvedReference { get; set; } - internal OpenApiExample _target; - - /// - /// Gets the target example. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiExample Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -47,41 +25,20 @@ public OpenApiExample Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Example, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Example, - ExternalResource = externalResource - }; } /// /// Copy constructor /// /// The reference to copy. - public OpenApiExampleReference(OpenApiExampleReference example) + public OpenApiExampleReference(OpenApiExampleReference example):base(example) { - Utils.CheckArgumentNull(example); - Reference = example.Reference != null ? new(example.Reference) : null; - UnresolvedReference = example.UnresolvedReference; - //no need to copy summary and description as if they are not overridden, they will be fetched from the target - //if they are, the reference copy will handle it } - internal OpenApiExampleReference(OpenApiExample target, string referenceId) + internal OpenApiExampleReference(OpenApiExample target, string referenceId):base(target, referenceId, ReferenceType.Example) { - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Example, - }; } /// @@ -120,7 +77,7 @@ public string Summary public JsonNode Value { get => Target?.Value; } /// - public void SerializeAsV3(IOpenApiWriter writer) + public override void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -133,7 +90,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -146,13 +103,13 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample source) + public override IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample source) { return source is OpenApiExample ? new OpenApiExample(this) : source; } /// - public void SerializeAsV2(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 71e8cace0..0e53dfb03 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -13,29 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Header Object Reference. /// - public class OpenApiHeaderReference : IOpenApiHeader, IOpenApiReferenceHolder + public class OpenApiHeaderReference : BaseOpenApiReferenceHolder, IOpenApiHeader { - /// - public OpenApiReference Reference { get; set; } - - /// - public bool UnresolvedReference { get; set; } - internal OpenApiHeader _target; - /// - /// Gets the target header. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiHeader Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -46,41 +25,20 @@ public OpenApiHeader Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Header, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Header, - ExternalResource = externalResource - }; } /// /// Copy constructor /// /// The object to copy - public OpenApiHeaderReference(OpenApiHeaderReference header) + public OpenApiHeaderReference(OpenApiHeaderReference header):base(header) { - Utils.CheckArgumentNull(header); - Reference = header.Reference != null ? new(header.Reference) : null; - UnresolvedReference = header.UnresolvedReference; - //no need to copy description as if they are not overridden, they will be fetched from the target - //if they are, the reference copy will handle it } - internal OpenApiHeaderReference(OpenApiHeader target, string referenceId) + internal OpenApiHeaderReference(OpenApiHeader target, string referenceId):base(target, referenceId, ReferenceType.Header) { - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Header, - }; } /// @@ -130,7 +88,7 @@ public string Description public IDictionary Extensions { get => Target?.Extensions; } /// - public void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -143,7 +101,7 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public void SerializeAsV3(IOpenApiWriter writer) + public override void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -156,7 +114,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV2(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -168,7 +126,7 @@ public void SerializeAsV2(IOpenApiWriter writer) } } /// - public IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenApiHeader source) + public override IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenApiHeader source) { return source is OpenApiHeader ? new OpenApiHeader(this) : source; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 57a4b1e4f..4d805592d 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -12,29 +12,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Link Object Reference. /// - public class OpenApiLinkReference : IOpenApiLink, IOpenApiReferenceHolder + public class OpenApiLinkReference : BaseOpenApiReferenceHolder, IOpenApiLink { - /// - public OpenApiReference Reference { get; set; } - - /// - public bool UnresolvedReference { get; set; } - internal OpenApiLink _target; - /// - /// Gets the target link. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiLink Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -45,41 +24,18 @@ public OpenApiLink Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Link, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Link, - ExternalResource = externalResource - }; } /// /// Copy constructor. /// /// The reference to copy - public OpenApiLinkReference(OpenApiLinkReference reference) + public OpenApiLinkReference(OpenApiLinkReference reference):base(reference) { - Utils.CheckArgumentNull(reference); - - Reference = reference.Reference != null ? new(reference.Reference) : null; - UnresolvedReference = reference.UnresolvedReference; - //no need to copy summary and description as if they are not overridden, they will be fetched from the target - //if they are, the reference copy will handle it } - - internal OpenApiLinkReference(OpenApiLink target, string referenceId) + internal OpenApiLinkReference(OpenApiLink target, string referenceId):base(target, referenceId, ReferenceType.Link) { - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Link, - }; } /// @@ -114,7 +70,7 @@ public string Description public IDictionary Extensions { get => Target?.Extensions; } /// - public void SerializeAsV3(IOpenApiWriter writer) + public override void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -127,7 +83,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -140,13 +96,13 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public void SerializeAsV2(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { // Link object does not exist in V2. } /// - public IOpenApiLink CopyReferenceAsTargetElementWithOverrides(IOpenApiLink source) + public override IOpenApiLink CopyReferenceAsTargetElementWithOverrides(IOpenApiLink source) { return source is OpenApiLink ? new OpenApiLink(this) : source; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index da9d1dabd..c5d9bed57 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -13,30 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Parameter Object Reference. /// - public class OpenApiParameterReference : IOpenApiParameter, IOpenApiReferenceHolder + public class OpenApiParameterReference : BaseOpenApiReferenceHolder, IOpenApiParameter { - /// - public OpenApiReference Reference { get; set; } - - /// - public bool UnresolvedReference { get; set; } - internal OpenApiParameter _target; - - /// - /// Gets the target parameter. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiParameter Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -47,41 +25,20 @@ public OpenApiParameter Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Parameter, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Parameter, - ExternalResource = externalResource - }; } /// /// Copy constructor /// /// The parameter reference to copy - public OpenApiParameterReference(OpenApiParameterReference parameter) + public OpenApiParameterReference(OpenApiParameterReference parameter):base(parameter) { - Utils.CheckArgumentNull(parameter); - Reference = parameter.Reference != null ? new(parameter.Reference) : null; - UnresolvedReference = parameter.UnresolvedReference; - //no need to copy summary and description as if they are not overridden, they will be fetched from the target - //if they are, the reference copy will handle it } - internal OpenApiParameterReference(OpenApiParameter target, string referenceId) + internal OpenApiParameterReference(OpenApiParameter target, string referenceId):base(target, referenceId, ReferenceType.Parameter) { - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Parameter, - }; } /// @@ -137,7 +94,7 @@ public string Description public IDictionary Extensions { get => Target.Extensions; } /// - public void SerializeAsV3(IOpenApiWriter writer) + public override void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -150,7 +107,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -163,7 +120,7 @@ public void SerializeAsV31(IOpenApiWriter writer) } /// - public void SerializeAsV2(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -176,7 +133,7 @@ public void SerializeAsV2(IOpenApiWriter writer) } /// - public IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpenApiParameter source) + public override IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpenApiParameter source) { return source is OpenApiParameter ? new OpenApiParameter(this) : source; } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index f89d60453..9783e5de8 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1155,38 +1155,45 @@ namespace Microsoft.OpenApi.Models } namespace Microsoft.OpenApi.Models.References { - public class OpenApiCallbackReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback + public abstract class BaseOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V + { + protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } + protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public T Target { get; } + public bool UnresolvedReference { get; set; } + public abstract V CopyReferenceAsTargetElementWithOverrides(V source); + public abstract void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + public abstract void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + public abstract void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + } + public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { public OpenApiCallbackReference(Microsoft.OpenApi.Models.References.OpenApiCallbackReference callback) { } public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public System.Collections.Generic.IDictionary Extensions { get; } public System.Collections.Generic.Dictionary PathItems { get; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public Microsoft.OpenApi.Models.OpenApiCallback Target { get; } - public bool UnresolvedReference { get; set; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiExampleReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiExampleReference(Microsoft.OpenApi.Models.References.OpenApiExampleReference example) { } public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } public string ExternalValue { get; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public string Summary { get; set; } - public Microsoft.OpenApi.Models.OpenApiExample Target { get; } - public bool UnresolvedReference { get; set; } public System.Text.Json.Nodes.JsonNode Value { get; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample source) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeaderReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader + public class OpenApiHeaderReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { public OpenApiHeaderReference(Microsoft.OpenApi.Models.References.OpenApiHeaderReference header) { } public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1199,18 +1206,15 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IDictionary Examples { get; } public bool Explode { get; } public System.Collections.Generic.IDictionary Extensions { get; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public bool Required { get; } public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } - public Microsoft.OpenApi.Models.OpenApiHeader Target { get; } - public bool UnresolvedReference { get; set; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLinkReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink + public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { public OpenApiLinkReference(Microsoft.OpenApi.Models.References.OpenApiLinkReference reference) { } public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1219,17 +1223,14 @@ namespace Microsoft.OpenApi.Models.References public string OperationId { get; } public string OperationRef { get; } public System.Collections.Generic.IDictionary Parameters { get; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } public Microsoft.OpenApi.Models.OpenApiServer Server { get; } - public Microsoft.OpenApi.Models.OpenApiLink Target { get; } - public bool UnresolvedReference { get; set; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink source) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameterReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter + public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { public OpenApiParameterReference(Microsoft.OpenApi.Models.References.OpenApiParameterReference parameter) { } public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1244,16 +1245,13 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IDictionary Extensions { get; } public Microsoft.OpenApi.Models.ParameterLocation? In { get; } public string Name { get; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public bool Required { get; } public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } - public Microsoft.OpenApi.Models.OpenApiParameter Target { get; } - public bool UnresolvedReference { get; set; } - public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { From 8c2c1888c64a7421e40d82bf9c58ae71dbdcbf3b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 09:20:43 -0500 Subject: [PATCH 023/103] chore: typo fix Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs index 9044f26a9..363cc1cd4 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs @@ -5,7 +5,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// -/// Defines the base properties for the example object. +/// Defines the base properties for the parameter object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible From aad26b4d45da3baa162ca63456b2e637f0fb5eeb Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 09:25:46 -0500 Subject: [PATCH 024/103] chore: removes duplicated serialize internal method Signed-off-by: Vincent Biret --- .../References/BaseOpenApiReferenceHolder.cs | 14 ++++++++++++++ .../Models/References/OpenApiCallbackReference.cs | 8 -------- .../Models/References/OpenApiExampleReference.cs | 8 -------- .../Models/References/OpenApiHeaderReference.cs | 8 -------- .../Models/References/OpenApiLinkReference.cs | 8 -------- .../Models/References/OpenApiParameterReference.cs | 8 -------- 6 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 98df8bbbd..0a7f7b983 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -76,4 +77,17 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc public abstract void SerializeAsV3(IOpenApiWriter writer); /// public abstract void SerializeAsV31(IOpenApiWriter writer); + + /// + /// Serialize the reference as a reference or the target object. + /// This method is used to accelerate the serialization methods implementations. + /// + /// The OpenApiWriter. + /// The action to serialize the target object. + private protected void SerializeInternal(IOpenApiWriter writer, + Action action) + { + Utils.CheckArgumentNull(writer); + action(writer, Target); + } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index bb6e38869..6a193f2e6 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -87,13 +87,5 @@ public override void SerializeAsV2(IOpenApiWriter writer) // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 60c35f760..e35291b9a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -114,13 +114,5 @@ public override void SerializeAsV2(IOpenApiWriter writer) // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 0e53dfb03..405853c5f 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -130,13 +130,5 @@ public override IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenAp { return source is OpenApiHeader ? new OpenApiHeader(this) : source; } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 4d805592d..5dacc6112 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -106,13 +106,5 @@ public override IOpenApiLink CopyReferenceAsTargetElementWithOverrides(IOpenApiL { return source is OpenApiLink ? new OpenApiLink(this) : source; } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index c5d9bed57..edf5086d7 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -137,13 +137,5 @@ public override IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpe { return source is OpenApiParameter ? new OpenApiParameter(this) : source; } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } } } From a72aa29048b4b28a736af032f4fd0849ff31a50f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 09:34:18 -0500 Subject: [PATCH 025/103] chore: removes duplicated serialization method implementation for references Signed-off-by: Vincent Biret --- .../References/BaseOpenApiReferenceHolder.cs | 40 ++++++++++++++++-- .../References/OpenApiCallbackReference.cs | 28 ------------- .../References/OpenApiExampleReference.cs | 26 ------------ .../References/OpenApiHeaderReference.cs | 38 ----------------- .../Models/References/OpenApiLinkReference.cs | 26 ------------ .../References/OpenApiParameterReference.cs | 41 ------------------- .../PublicApi/PublicApi.approved.txt | 19 ++------- 7 files changed, 40 insertions(+), 178 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 0a7f7b983..6b1f02575 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.References; /// /// The concrete class implementation type for the model. /// The interface type for the model. -public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V +public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V where V : IOpenApiSerializable { internal T _target; /// @@ -72,11 +72,43 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc /// public abstract V CopyReferenceAsTargetElementWithOverrides(V source); /// - public abstract void SerializeAsV2(IOpenApiWriter writer); + public void SerializeAsV3(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(Reference)) + { + Reference.SerializeAsV3(writer); + } + else + { + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); + } + } + /// - public abstract void SerializeAsV3(IOpenApiWriter writer); + public void SerializeAsV31(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(Reference)) + { + Reference.SerializeAsV31(writer); + } + else + { + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); + } + } + /// - public abstract void SerializeAsV31(IOpenApiWriter writer); + public virtual void SerializeAsV2(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(Reference)) + { + Reference.SerializeAsV2(writer); + } + else + { + SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); + } + } /// /// Serialize the reference as a reference or the target object. diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 6a193f2e6..14b96c9e6 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -47,37 +47,9 @@ internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):ba /// public IDictionary Extensions { get => Target?.Extensions; } - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - } - } - /// public override IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(IOpenApiCallback source) { - // the copy here is never called since callbacks do not have any overridable fields. - // if the spec evolves to include overridable fields for callbacks, the serialize methods will need to call this copy method. return source is OpenApiCallback ? new OpenApiCallback(this) : source; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index e35291b9a..9a1c5ae16 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -76,32 +76,6 @@ public string Summary /// public JsonNode Value { get => Target?.Value; } - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, referenceElement) => CopyReferenceAsTargetElementWithOverrides(referenceElement).SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, referenceElement) => CopyReferenceAsTargetElementWithOverrides(referenceElement).SerializeAsV31(writer)); - } - } - /// public override IOpenApiExample CopyReferenceAsTargetElementWithOverrides(IOpenApiExample source) { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 405853c5f..dfbee5ce7 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -87,44 +87,6 @@ public string Description /// public IDictionary Extensions { get => Target?.Extensions; } - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); - } - } - - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV2(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV2(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); - } - } /// public override IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenApiHeader source) { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 5dacc6112..f177bee2c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -69,32 +69,6 @@ public string Description /// public IDictionary Extensions { get => Target?.Extensions; } - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); - } - } - /// public override void SerializeAsV2(IOpenApiWriter writer) { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index edf5086d7..82c73afda 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -1,12 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using System; using System.Collections.Generic; using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; -using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References { @@ -93,45 +91,6 @@ public string Description /// public IDictionary Extensions { get => Target.Extensions; } - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV31(writer)); - } - } - - /// - public override void SerializeAsV2(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV2(writer); - } - else - { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); - } - } - /// public override IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpenApiParameter source) { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 9783e5de8..3e8451080 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1157,6 +1157,7 @@ namespace Microsoft.OpenApi.Models.References { public abstract class BaseOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V + where V : Microsoft.OpenApi.Interfaces.IOpenApiSerializable { protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } @@ -1164,9 +1165,9 @@ namespace Microsoft.OpenApi.Models.References public T Target { get; } public bool UnresolvedReference { get; set; } public abstract V CopyReferenceAsTargetElementWithOverrides(V source); - public abstract void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer); - public abstract void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer); - public abstract void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { @@ -1176,8 +1177,6 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.Dictionary PathItems { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { @@ -1190,8 +1189,6 @@ namespace Microsoft.OpenApi.Models.References public System.Text.Json.Nodes.JsonNode Value { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiHeaderReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { @@ -1210,9 +1207,6 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { @@ -1227,8 +1221,6 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.OpenApiServer Server { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { @@ -1249,9 +1241,6 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { From c7252677814eec7a9a8ff6f0f3a51f5e113f5f19 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 12:21:56 -0500 Subject: [PATCH 026/103] fix: path item reference implementation Signed-off-by: Vincent Biret --- .../Formatters/PowerShellFormatter.cs | 6 +- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../Models/Interfaces/IOpenApiCallback.cs | 2 +- .../Models/Interfaces/IOpenApiPathItem.cs | 28 ++++++ .../Models/OpenApiCallback.cs | 6 +- .../Models/OpenApiComponents.cs | 6 +- .../Models/OpenApiDocument.cs | 6 +- .../Models/OpenApiPathItem.cs | 58 ++++------- src/Microsoft.OpenApi/Models/OpenApiPaths.cs | 4 +- .../References/OpenApiCallbackReference.cs | 2 +- .../References/OpenApiPathItemReference.cs | 99 ++++++------------- .../Reader/V2/OpenApiPathItemDeserializer.cs | 10 +- .../Reader/V3/OpenApiPathItemDeserializer.cs | 9 +- .../Reader/V31/OpenApiPathItemDeserializer.cs | 9 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiFilterService.cs | 7 +- .../Services/OpenApiUrlTreeNode.cs | 7 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 6 +- .../Services/OperationSearch.cs | 7 +- .../Validations/OpenApiValidator.cs | 2 +- .../Formatters/PowerShellFormatterTests.cs | 4 +- .../Services/OpenApiFilterServiceTests.cs | 4 +- .../UtilityFiles/OpenApiDocumentMock.cs | 24 ++--- .../V2Tests/OpenApiDocumentTests.cs | 2 +- .../V31Tests/OpenApiDocumentTests.cs | 7 +- .../Models/OpenApiCallbackTests.cs | 4 +- .../Models/OpenApiComponentsTests.cs | 3 +- .../Models/OpenApiDocumentTests.cs | 6 +- .../PublicApi/PublicApi.approved.txt | 72 +++++++------- .../Services/OpenApiUrlTreeNodeTests.cs | 36 +++---- .../Services/OpenApiValidatorTests.cs | 2 +- .../OpenApiReferenceValidationTests.cs | 4 +- .../Visitors/InheritanceTests.cs | 4 +- .../Walkers/WalkerLocationTests.cs | 7 +- .../Workspaces/OpenApiWorkspaceTests.cs | 3 +- .../Writers/OpenApiYamlWriterTests.cs | 2 +- 38 files changed, 213 insertions(+), 259 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index 109799381..a6b6380d6 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -51,7 +51,7 @@ public override void Visit(OpenApiSchema schema) base.Visit(schema); } - public override void Visit(OpenApiPathItem pathItem) + public override void Visit(IOpenApiPathItem pathItem) { if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) && value.OperationId != null) @@ -81,13 +81,13 @@ public override void Visit(OpenApiOperation operation) operationId = ResolveODataCastOperationId(operationId); operationId = ResolveByRefOperationId(operationId); // Verb segment resolution should always be last. user.get -> user_Get - operationId = ResolveVerbSegmentInOpertationId(operationId); + operationId = ResolveVerbSegmentInOperationId(operationId); operation.OperationId = operationId; base.Visit(operation); } - private static string ResolveVerbSegmentInOpertationId(string operationId) + private static string ResolveVerbSegmentInOperationId(string operationId) { var charPos = operationId.LastIndexOf('.', operationId.Length - 1); if (operationId.Contains('_', StringComparison.OrdinalIgnoreCase) || charPos < 0) diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index 7ffe77062..53f52ab3d 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -34,7 +34,7 @@ public override void Visit(IDictionary headers) public int PathItemCount { get; set; } - public override void Visit(OpenApiPathItem pathItem) + public override void Visit(IOpenApiPathItem pathItem) { PathItemCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index 6cc895477..6097f1f4e 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -34,7 +34,7 @@ public override void Visit(IDictionary headers) public int PathItemCount { get; set; } - public override void Visit(OpenApiPathItem pathItem) + public override void Visit(IOpenApiPathItem pathItem) { PathItemCount++; } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs index a8fde7697..e4e948c1b 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs @@ -14,5 +14,5 @@ public interface IOpenApiCallback : IOpenApiSerializable, IOpenApiReadOnlyExtens /// /// A Path Item Object used to define a callback request and expected responses. /// - public Dictionary PathItems { get; } + public Dictionary PathItems { get; } } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs new file mode 100644 index 000000000..41b8ab0e6 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs @@ -0,0 +1,28 @@ + +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the path item object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiPathItem : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// Gets the definition of operations on this path. + /// + public IDictionary Operations { get; } + + /// + /// An alternative server array to service all operations in this path. + /// + public IList Servers { get; } + + /// + /// A list of parameters that are applicable for all the operations described under this path. + /// These parameters can be overridden at the operation level, but cannot be removed there. + /// + public IList Parameters { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs index 953792a79..7f06ca277 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.Models public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiCallback { /// - public Dictionary PathItems { get; set; } + public Dictionary PathItems { get; set; } = []; @@ -40,11 +40,11 @@ public OpenApiCallback(IOpenApiCallback callback) } /// - /// Add a into the . + /// Add a into the . /// /// The runtime expression. /// The path item. - public void AddPathItem(RuntimeExpression expression, OpenApiPathItem pathItem) + public void AddPathItem(RuntimeExpression expression, IOpenApiPathItem pathItem) { Utils.CheckArgumentNull(expression); Utils.CheckArgumentNull(pathItem); diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index f45ecbedd..7cd577397 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -66,9 +66,9 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible public IDictionary? Callbacks { get; set; } = new Dictionary(); /// - /// An object to hold reusable Object. + /// An object to hold reusable Object. /// - public IDictionary? PathItems { get; set; } = new Dictionary(); + public IDictionary? PathItems { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. @@ -94,7 +94,7 @@ public OpenApiComponents(OpenApiComponents? components) SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; Links = components?.Links != null ? new Dictionary(components.Links) : null; Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; - PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null; + PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null; Extensions = components?.Extensions != null ? new Dictionary(components.Extensions) : null; } diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 1dbc0e23c..6e733d0fa 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -56,7 +56,7 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenAp /// A map of requests initiated other than by an API call, for example by an out of band registration. /// The key name is a unique string to refer to each webhook, while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider and the expected responses /// - public IDictionary? Webhooks { get; set; } = new Dictionary(); + public IDictionary? Webhooks { get; set; } = new Dictionary(); /// /// An element to hold various schemas for the specification. @@ -113,7 +113,7 @@ public OpenApiDocument(OpenApiDocument? document) JsonSchemaDialect = document?.JsonSchemaDialect ?? JsonSchemaDialect; Servers = document?.Servers != null ? new List(document.Servers) : null; Paths = document?.Paths != null ? new(document?.Paths) : new OpenApiPaths(); - Webhooks = document?.Webhooks != null ? new Dictionary(document.Webhooks) : null; + Webhooks = document?.Webhooks != null ? new Dictionary(document.Webhooks) : null; Components = document?.Components != null ? new(document?.Components) : null; SecurityRequirements = document?.SecurityRequirements != null ? new List(document.SecurityRequirements) : null; Tags = document?.Tags != null ? new List(document.Tags) : null; @@ -612,7 +612,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Callbacks.Add(id, openApiCallback); break; case OpenApiPathItem openApiPathItem: - Components.PathItems ??= new Dictionary(); + Components.PathItems ??= new Dictionary(); Components.PathItems.Add(id, openApiPathItem); break; case OpenApiExample openApiExample: diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs index b9fac8c56..4aa4dedb1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs @@ -13,49 +13,26 @@ namespace Microsoft.OpenApi.Models /// /// Path Item Object: to describe the operations available on a single path. /// - public class OpenApiPathItem : IOpenApiExtensible, IOpenApiReferenceable + public class OpenApiPathItem : IOpenApiExtensible, IOpenApiReferenceable, IOpenApiPathItem { - /// - /// An optional, string summary, intended to apply to all operations in this path. - /// - public virtual string Summary { get; set; } + /// + public string Summary { get; set; } - /// - /// An optional, string description, intended to apply to all operations in this path. - /// - public virtual string Description { get; set; } + /// + public string Description { get; set; } - /// - /// Gets the definition of operations on this path. - /// - public virtual IDictionary Operations { get; set; } + /// + public IDictionary Operations { get; set; } = new Dictionary(); - /// - /// An alternative server array to service all operations in this path. - /// - public virtual IList Servers { get; set; } = new List(); - - /// - /// A list of parameters that are applicable for all the operations described under this path. - /// These parameters can be overridden at the operation level, but cannot be removed there. - /// - public virtual IList Parameters { get; set; } = new List(); + /// + public IList Servers { get; set; } = []; - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public IList Parameters { get; set; } = []; - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public bool UnresolvedReference { get; set; } - - /// - /// Reference object. - /// - public OpenApiReference Reference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Add one operation into this path item. @@ -75,22 +52,21 @@ public OpenApiPathItem() { } /// /// Initializes a clone of an object /// - public OpenApiPathItem(OpenApiPathItem pathItem) + public OpenApiPathItem(IOpenApiPathItem pathItem) { + Utils.CheckArgumentNull(pathItem); Summary = pathItem?.Summary ?? Summary; Description = pathItem?.Description ?? Description; Operations = pathItem?.Operations != null ? new Dictionary(pathItem.Operations) : null; Servers = pathItem?.Servers != null ? new List(pathItem.Servers) : null; Parameters = pathItem?.Parameters != null ? new List(pathItem.Parameters) : null; Extensions = pathItem?.Extensions != null ? new Dictionary(pathItem.Extensions) : null; - UnresolvedReference = pathItem?.UnresolvedReference ?? UnresolvedReference; - Reference = pathItem?.Reference != null ? new(pathItem?.Reference) : null; } /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } @@ -98,7 +74,7 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiPaths.cs b/src/Microsoft.OpenApi/Models/OpenApiPaths.cs index f3a89460a..a15fed843 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPaths.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPaths.cs @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using Microsoft.OpenApi.Models.Interfaces; + namespace Microsoft.OpenApi.Models { /// /// Paths object. /// - public class OpenApiPaths : OpenApiExtensibleDictionary + public class OpenApiPaths : OpenApiExtensibleDictionary { /// /// Parameterless constructor diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 14b96c9e6..afa22d4e2 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -42,7 +42,7 @@ internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):ba } /// - public Dictionary PathItems { get => Target?.PathItems; } + public Dictionary PathItems { get => Target?.PathItems; } /// public IDictionary Extensions { get => Target?.Extensions; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index 97383efcd..015627d42 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; @@ -12,30 +11,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Path Item Object Reference: to describe the operations available on a single path. /// - public class OpenApiPathItemReference : OpenApiPathItem, IOpenApiReferenceHolder + public class OpenApiPathItemReference : BaseOpenApiReferenceHolder, IOpenApiPathItem { - internal OpenApiPathItem _target; - private readonly OpenApiReference _reference; - private string _description; - private string _summary; - - /// - /// Gets the target path item. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiPathItem Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiPathItem resolved = new OpenApiPathItem(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - if (!string.IsNullOrEmpty(_summary)) resolved.Summary = _summary; - return resolved; - } - } /// /// Constructor initializing the reference object. @@ -47,78 +24,62 @@ public OpenApiPathItem Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiPathItemReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiPathItemReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null): base(referenceId, hostDocument, ReferenceType.PathItem, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - _reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.PathItem, - ExternalResource = externalResource - }; - - Reference = _reference; } - internal OpenApiPathItemReference(OpenApiPathItem target, string referenceId) + internal OpenApiPathItemReference(OpenApiPathItem target, string referenceId):base(target, referenceId, ReferenceType.PathItem) { - _target = target; - - _reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.PathItem, - }; } /// - public override string Summary + public string Summary { - get => string.IsNullOrEmpty(_summary) ? Target.Summary : _summary; - set => _summary = value; + get => string.IsNullOrEmpty(Reference?.Summary) ? Target?.Summary : Reference.Summary; + set + { + if (Reference is not null) + { + Reference.Summary = value; + } + } } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override IDictionary Operations { get => Target.Operations; set => Target.Operations = value; } + public IDictionary Operations { get => Target.Operations; } /// - public override IList Servers { get => Target.Servers; set => Target.Servers = value; } + public IList Servers { get => Target.Servers; } /// - public override IList Parameters { get => Target.Parameters; set => Target.Parameters = value; } + public IList Parameters { get => Target.Parameters; } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } - + public IDictionary Extensions { get => Target.Extensions; } + /// - public override void SerializeAsV31(IOpenApiWriter writer) + public override IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(IOpenApiPathItem source) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV31(writer); - return; - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - } + return source is OpenApiPathItem ? new OpenApiPathItem(this) : null; } /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) + public override void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; - action(writer, Target); + Reference.SerializeAsV2(writer); } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs index bc1eb8da6..84f79cc16 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Extensions; @@ -17,13 +18,6 @@ internal static partial class OpenApiV2Deserializer { private static readonly FixedFieldMap _pathItemFixedFields = new() { - { - "$ref", (o, n, t) => - { - o.Reference = new() { ExternalResource = n.GetScalarValue() }; - o.UnresolvedReference =true; - } - }, {"get", (o, n, t) => o.AddOperation(OperationType.Get, LoadOperation(n, t))}, {"put", (o, n, t) => o.AddOperation(OperationType.Put, LoadOperation(n, t))}, {"post", (o, n, t) => o.AddOperation(OperationType.Post, LoadOperation(n, t))}, @@ -40,7 +34,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}, }; public static OpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs index 9673c5f87..4d5815794 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -16,12 +17,6 @@ internal static partial class OpenApiV3Deserializer { private static readonly FixedFieldMap _pathItemFixedFields = new() { - { - "$ref", (o, n, _) => { - o.Reference = new() { ExternalResource = n.GetScalarValue() }; - o.UnresolvedReference =true; - } - }, { "summary", (o, n, _) => o.Summary = n.GetScalarValue() @@ -48,7 +43,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("PathItem"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs index 7c5fb189e..ecaf88bf2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -14,12 +15,6 @@ internal static partial class OpenApiV31Deserializer private static readonly FixedFieldMap _pathItemFixedFields = new() { - { - "$ref", (o,n, _) => { - o.Reference = new OpenApiReference() { ExternalResource = n.GetScalarValue() }; - o.UnresolvedReference =true; - } - }, { "summary", (o, n, _) => { @@ -50,7 +45,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("PathItem"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index d520e6f19..982162442 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -163,9 +163,9 @@ private void AddPathItemToComponents(OpenApiPathItem pathItem, string referenceI { EnsureComponentsExist(); EnsurePathItemsExist(); - if (!Components.PathItems.ContainsKey(referenceId ?? pathItem.Reference.Id)) + if (!Components.PathItems.ContainsKey(referenceId)) { - Components.PathItems.Add(referenceId ?? pathItem.Reference.Id, pathItem); + Components.PathItems.Add(referenceId, pathItem); } } private void AddSecuritySchemeToComponents(OpenApiSecurityScheme securityScheme, string referenceId = null) @@ -244,6 +244,6 @@ private void EnsureSecuritySchemesExist() } private void EnsurePathItemsExist() { - _target.Components.PathItems ??= new Dictionary(); + _target.Components.PathItems ??= new Dictionary(); } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs b/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs index 22916fd7c..20fa54839 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text.RegularExpressions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Services @@ -86,20 +87,20 @@ public static OpenApiDocument CreateFilteredDocument(OpenApiDocument source, Fun var results = FindOperations(source, predicate); foreach (var result in results) { - OpenApiPathItem pathItem; + IOpenApiPathItem pathItem; var pathKey = result.CurrentKeys.Path; if (subset.Paths == null) { subset.Paths = new(); - pathItem = new(); + pathItem = new OpenApiPathItem(); subset.Paths.Add(pathKey, pathItem); } else { if (!subset.Paths.TryGetValue(pathKey, out pathItem)) { - pathItem = new(); + pathItem = new OpenApiPathItem(); subset.Paths.Add(pathKey, pathItem); } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs index ba5d4349d..1d306edfb 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Services { @@ -30,7 +31,7 @@ public class OpenApiUrlTreeNode /// /// Dictionary of labels and Path Item objects that describe the operations available on a node. /// - public IDictionary PathItems { get; } = new Dictionary(); + public IDictionary PathItems { get; } = new Dictionary(); /// /// A dictionary of key value pairs that contain information about a node. @@ -136,7 +137,7 @@ public void Attach(OpenApiDocument doc, string label) /// A name tag for labelling the node. /// An node describing an OpenAPI path. public OpenApiUrlTreeNode Attach(string path, - OpenApiPathItem pathItem, + IOpenApiPathItem pathItem, string label) { Utils.CheckArgumentNullOrEmpty(label); @@ -173,7 +174,7 @@ public OpenApiUrlTreeNode Attach(string path, /// The relative path of a node. /// An node with all constituent properties assembled. private OpenApiUrlTreeNode Attach(IEnumerable segments, - OpenApiPathItem pathItem, + IOpenApiPathItem pathItem, string label, string currentPath) { diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index b35163ca0..63b065bbd 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -106,14 +106,14 @@ public virtual void Visit(OpenApiPaths paths) /// /// Visits Webhooks> /// - public virtual void Visit(IDictionary webhooks) + public virtual void Visit(IDictionary webhooks) { } /// /// Visits /// - public virtual void Visit(OpenApiPathItem pathItem) + public virtual void Visit(IOpenApiPathItem pathItem) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 6173ad3cb..66ca7e6fe 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -20,7 +20,7 @@ public class OpenApiWalker { private readonly OpenApiVisitorBase _visitor; private readonly Stack _schemaLoop = new(); - private readonly Stack _pathItemLoop = new(); + private readonly Stack _pathItemLoop = new(); /// /// Initializes the class. @@ -281,7 +281,7 @@ internal void Walk(OpenApiPaths paths) /// /// Visits Webhooks and child objects /// - internal void Walk(IDictionary webhooks) + internal void Walk(IDictionary webhooks) { if (webhooks == null) { @@ -521,7 +521,7 @@ internal void Walk(OpenApiServerVariable serverVariable) /// /// Visits and child objects /// - internal void Walk(OpenApiPathItem pathItem, bool isComponent = false) + internal void Walk(IOpenApiPathItem pathItem, bool isComponent = false) { if (pathItem == null) { diff --git a/src/Microsoft.OpenApi/Services/OperationSearch.cs b/src/Microsoft.OpenApi/Services/OperationSearch.cs index e0512bf72..c726ac966 100644 --- a/src/Microsoft.OpenApi/Services/OperationSearch.cs +++ b/src/Microsoft.OpenApi/Services/OperationSearch.cs @@ -31,11 +31,8 @@ public OperationSearch(Func pred _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); } - /// - /// Visits - /// - /// The target . - public override void Visit(OpenApiPathItem pathItem) + /// + public override void Visit(IOpenApiPathItem pathItem) { foreach (var item in pathItem.Operations) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 7deb2ddcb..63076ed9d 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -129,7 +129,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(IList example) => Validate(example, example.GetType()); /// - public override void Visit(OpenApiPathItem pathItem) => Validate(pathItem); + public override void Visit(IOpenApiPathItem pathItem) => Validate(pathItem); /// public override void Visit(OpenApiServerVariable serverVariable) => Validate(serverVariable); diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index 8d0e6010a..abf7232d1 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -28,7 +28,7 @@ public void FormatOperationIdsInOpenAPIDocument(string operationId, string expec Servers = new List { new() { Url = "https://localhost/" } }, Paths = new() { - { path, new() { + { path, new OpenApiPathItem() { Operations = new Dictionary { { operationType, new() { OperationId = operationId } } @@ -102,7 +102,7 @@ private static OpenApiDocument GetSampleOpenApiDocument() Info = new() { Title = "Test", Version = "1.0" }, Servers = new List { new() { Url = "https://localhost/" } }, Paths = new() { - { "/foo", new() + { "/foo", new OpenApiPathItem() { Operations = new Dictionary { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index 0dceb6127..ca4416ae6 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -78,7 +78,7 @@ public void TestPredicateFiltersUsingRelativeRequestUrls() Servers = new List { new() { Url = "https://localhost/" } }, Paths = new() { - {"/foo", new() { + {"/foo", new OpenApiPathItem() { Operations = new Dictionary { { OperationType.Get, new() }, @@ -115,7 +115,7 @@ public void CreateFilteredDocumentUsingPredicateFromRequestUrl() Servers = new List { new() { Url = "https://localhost/" } }, Paths = new() { - ["/test/{id}"] = new() + ["/test/{id}"] = new OpenApiPathItem() { Operations = new Dictionary { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index f2f6386c4..3c3644adf 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -49,7 +49,7 @@ public static OpenApiDocument CreateOpenApiDocument() }, Paths = new() { - ["/"] = new() // root path + ["/"] = new OpenApiPathItem() // root path { Operations = new Dictionary { @@ -70,7 +70,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [getTeamsActivityByPeriodPath] = new() + [getTeamsActivityByPeriodPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -135,7 +135,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [getTeamsActivityByDatePath] = new() + [getTeamsActivityByDatePath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -198,7 +198,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [usersPath] = new() + [usersPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -252,7 +252,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [usersByIdPath] = new() + [usersByIdPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -307,7 +307,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [messagesByIdPath] = new() + [messagesByIdPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -362,7 +362,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [administrativeUnitRestorePath] = new() + [administrativeUnitRestorePath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -420,7 +420,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [logoPath] = new() + [logoPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -442,7 +442,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [securityProfilesPath] = new() + [securityProfilesPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -496,7 +496,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [communicationsCallsKeepAlivePath] = new() + [communicationsCallsKeepAlivePath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -544,7 +544,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [eventsDeltaPath] = new() + [eventsDeltaPath] = new OpenApiPathItem() { Operations = new Dictionary { @@ -627,7 +627,7 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - [refPath] = new() + [refPath] = new OpenApiPathItem() { Operations = new Dictionary { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index 02938f4b0..0b14a01f9 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -170,7 +170,7 @@ public async Task ShouldParseProducesInAnyOrder() }, Paths = new() { - ["/items"] = new() + ["/items"] = new OpenApiPathItem() { Operations = { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index c2bbf6db6..cda7e35c3 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -97,7 +97,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() Version = "1.0.0", Title = "Webhook Example" }, - Webhooks = new Dictionary + Webhooks = new Dictionary { ["pets"] = new OpenApiPathItem { @@ -271,7 +271,7 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() var newPetSchema = new OpenApiSchemaReference("newPetSchema", actual.Document); - components.PathItems = new Dictionary + components.PathItems = new Dictionary { ["pets"] = new OpenApiPathItem { @@ -379,7 +379,7 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() Version = "1.0.0" }, JsonSchemaDialect = "http://json-schema.org/draft-07/schema#", - Webhooks = new Dictionary + Webhooks = new Dictionary { ["pets"] = components.PathItems["pets"] }, @@ -388,7 +388,6 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() // Assert actual.Document.Should().BeEquivalentTo(expected, options => options - .Excluding(x => x.Webhooks["pets"].Reference) .Excluding(x => x.Workspace) .Excluding(y => y.BaseUri)); Assert.Equivalent( diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 8c729b7c4..a2ef27222 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -21,7 +21,7 @@ public class OpenApiCallbackTests PathItems = { [RuntimeExpression.Build("$request.body#/url")] - = new() + = new OpenApiPathItem() { Operations = { @@ -61,7 +61,7 @@ public class OpenApiCallbackTests PathItems = { [RuntimeExpression.Build("$request.body#/url")] - = new() + = new OpenApiPathItem() { Operations = { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 738002b1e..45448aa60 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Xunit; @@ -240,7 +241,7 @@ public class OpenApiComponentsTests } } }, - PathItems = new Dictionary + PathItems = new Dictionary { ["/pets"] = new OpenApiPathItem { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index f43843051..19ebca7fb 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -891,7 +891,7 @@ public OpenApiDocumentTests() Title = "Webhook Example", Version = "1.0.0" }, - Webhooks = new Dictionary + Webhooks = new Dictionary { ["newPet"] = new OpenApiPathItem { @@ -1080,7 +1080,7 @@ public OpenApiDocumentTests() }, Paths = new() { - ["/pets"] = new() + ["/pets"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -1222,7 +1222,7 @@ public OpenApiDocumentTests() } } }, - ["/pets/{id}"] = new() + ["/pets/{id}"] = new OpenApiPathItem() { Operations = new Dictionary { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 3e8451080..cf54ef45a 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -339,7 +339,7 @@ namespace Microsoft.OpenApi.Models.Interfaces { public interface IOpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { - System.Collections.Generic.Dictionary PathItems { get; } + System.Collections.Generic.Dictionary PathItems { get; } } public interface IOpenApiDescribedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { @@ -386,6 +386,12 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } + public interface IOpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + { + System.Collections.Generic.IDictionary Operations { get; } + System.Collections.Generic.IList Parameters { get; } + System.Collections.Generic.IList Servers { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -409,8 +415,8 @@ namespace Microsoft.OpenApi.Models public OpenApiCallback() { } public OpenApiCallback(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public System.Collections.Generic.IDictionary Extensions { get; set; } - public System.Collections.Generic.Dictionary PathItems { get; set; } - public void AddPathItem(Microsoft.OpenApi.Expressions.RuntimeExpression expression, Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } + public System.Collections.Generic.Dictionary PathItems { get; set; } + public void AddPathItem(Microsoft.OpenApi.Expressions.RuntimeExpression expression, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -425,7 +431,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Headers { get; set; } public System.Collections.Generic.IDictionary? Links { get; set; } public System.Collections.Generic.IDictionary? Parameters { get; set; } - public System.Collections.Generic.IDictionary? PathItems { get; set; } + public System.Collections.Generic.IDictionary? PathItems { get; set; } public System.Collections.Generic.IDictionary? RequestBodies { get; set; } public System.Collections.Generic.IDictionary? Responses { get; set; } public System.Collections.Generic.IDictionary? Schemas { get; set; } @@ -629,7 +635,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IList? SecurityRequirements { get; set; } public System.Collections.Generic.IList? Servers { get; set; } public System.Collections.Generic.IList? Tags { get; set; } - public System.Collections.Generic.IDictionary? Webhooks { get; set; } + public System.Collections.Generic.IDictionary? Webhooks { get; set; } public Microsoft.OpenApi.Services.OpenApiWorkspace? Workspace { get; set; } public bool AddComponent(string id, T componentToRegister) { } public System.Threading.Tasks.Task GetHashCodeAsync(System.Threading.CancellationToken cancellationToken = default) { } @@ -846,24 +852,22 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiPathItem() { } - public OpenApiPathItem(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public bool UnresolvedReference { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual System.Collections.Generic.IDictionary Operations { get; set; } - public virtual System.Collections.Generic.IList Parameters { get; set; } - public virtual System.Collections.Generic.IList Servers { get; set; } - public virtual string Summary { get; set; } + public OpenApiPathItem(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public System.Collections.Generic.IDictionary Operations { get; set; } + public System.Collections.Generic.IList Parameters { get; set; } + public System.Collections.Generic.IList Servers { get; set; } + public string Summary { get; set; } public void AddOperation(Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operation) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiPaths : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary + public class OpenApiPaths : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary { public OpenApiPaths() { } public OpenApiPaths(Microsoft.OpenApi.Models.OpenApiPaths paths) { } @@ -1174,7 +1178,7 @@ namespace Microsoft.OpenApi.Models.References public OpenApiCallbackReference(Microsoft.OpenApi.Models.References.OpenApiCallbackReference callback) { } public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public System.Collections.Generic.IDictionary Extensions { get; } - public System.Collections.Generic.Dictionary PathItems { get; } + public System.Collections.Generic.Dictionary PathItems { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -1242,17 +1246,17 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } } - public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiPathItemReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiPathItem Target { get; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override System.Collections.Generic.IDictionary Operations { get; set; } - public override System.Collections.Generic.IList Parameters { get; set; } - public override System.Collections.Generic.IList Servers { get; set; } - public override string Summary { get; set; } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public System.Collections.Generic.IDictionary Operations { get; } + public System.Collections.Generic.IList Parameters { get; } + public System.Collections.Generic.IList Servers { get; } + public string Summary { get; set; } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1526,11 +1530,11 @@ namespace Microsoft.OpenApi.Services public System.Collections.Generic.IDictionary Children { get; } public bool IsParameter { get; } public string Path { get; set; } - public System.Collections.Generic.IDictionary PathItems { get; } + public System.Collections.Generic.IDictionary PathItems { get; } public string Segment { get; } public void AddAdditionalData(System.Collections.Generic.Dictionary> additionalData) { } public void Attach(Microsoft.OpenApi.Models.OpenApiDocument doc, string label) { } - public Microsoft.OpenApi.Services.OpenApiUrlTreeNode Attach(string path, Microsoft.OpenApi.Models.OpenApiPathItem pathItem, string label) { } + public Microsoft.OpenApi.Services.OpenApiUrlTreeNode Attach(string path, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem, string label) { } public bool HasOperations(string label) { } public void WriteMermaid(System.IO.TextWriter writer) { } public static Microsoft.OpenApi.Services.OpenApiUrlTreeNode Create() { } @@ -1551,6 +1555,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1561,7 +1566,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } @@ -1578,9 +1582,9 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IDictionary examples) { } public virtual void Visit(System.Collections.Generic.IDictionary headers) { } public virtual void Visit(System.Collections.Generic.IDictionary links) { } + public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } public virtual void Visit(System.Collections.Generic.IDictionary content) { } - public virtual void Visit(System.Collections.Generic.IDictionary webhooks) { } public virtual void Visit(System.Collections.Generic.IDictionary serverVariables) { } public virtual void Visit(System.Collections.Generic.IList example) { } public virtual void Visit(System.Collections.Generic.IList parameters) { } @@ -1613,7 +1617,7 @@ namespace Microsoft.OpenApi.Services { public OperationSearch(System.Func predicate) { } public System.Collections.Generic.IList SearchResults { get; } - public override void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public override void Visit(System.Collections.Generic.IList parameters) { } } public class SearchResult @@ -1650,6 +1654,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1660,7 +1665,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs index 09ef9b04d..7c21e1a6e 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs @@ -18,14 +18,14 @@ public class OpenApiUrlTreeNodeTests { Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = new Dictionary { [OperationType.Get] = new(), } }, - ["/houses"] = new() + ["/houses"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -33,7 +33,7 @@ public class OpenApiUrlTreeNodeTests [OperationType.Post] = new() } }, - ["/cars"] = new() + ["/cars"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -47,9 +47,9 @@ public class OpenApiUrlTreeNodeTests { Paths = new() { - ["/"] = new(), - ["/hotels"] = new(), - ["/offices"] = new() + ["/"] = new OpenApiPathItem(), + ["/hotels"] = new OpenApiPathItem(), + ["/offices"] = new OpenApiPathItem() } }; @@ -68,7 +68,7 @@ public void CreateSingleRootWorks() { Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() } }; @@ -88,7 +88,7 @@ public void CreatePathWithoutRootWorks() { Paths = new() { - ["/houses"] = new() + ["/houses"] = new OpenApiPathItem() } }; @@ -211,9 +211,9 @@ public void CreatePathsWithMultipleSegmentsWorks() { Paths = new() { - ["/"] = new(), - ["/houses/apartments/{apartment-id}"] = new(), - ["/cars/coupes"] = new() + ["/"] = new OpenApiPathItem(), + ["/houses/apartments/{apartment-id}"] = new OpenApiPathItem(), + ["/cars/coupes"] = new OpenApiPathItem() } }; @@ -236,9 +236,9 @@ public void HasOperationsWorks() { Paths = new() { - ["/"] = new(), - ["/houses"] = new(), - ["/cars/{car-id}"] = new() + ["/"] = new OpenApiPathItem(), + ["/houses"] = new OpenApiPathItem(), + ["/cars/{car-id}"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -266,7 +266,7 @@ public void HasOperationsWorks() { Paths = new() { - ["/cars/{car-id}"] = new() + ["/cars/{car-id}"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -330,8 +330,8 @@ public void SegmentIsParameterWorks() { Paths = new() { - ["/"] = new(), - ["/houses/apartments/{apartment-id}"] = new() + ["/"] = new OpenApiPathItem(), + ["/houses/apartments/{apartment-id}"] = new OpenApiPathItem() } }; @@ -482,7 +482,7 @@ public void SupportsTrailingSlashesInPath(string path, string[] childrenBeforeLa { Paths = new() { - [path] = new() + [path] = new OpenApiPathItem() } }; diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs index ca56ff75c..317719fcd 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs @@ -33,7 +33,7 @@ public void ResponseMustHaveADescription() { { "/test", - new() + new OpenApiPathItem() { Operations = { diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index b7597cb31..646acdbcc 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -39,7 +39,7 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() document.Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -97,7 +97,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() document.Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = new Dictionary { diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 302f8937a..fd65e7dd4 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -26,7 +26,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IList)); visitor.Visit(default(OpenApiServer)); visitor.Visit(default(OpenApiPaths)); - visitor.Visit(default(OpenApiPathItem)); + visitor.Visit(default(IOpenApiPathItem)); visitor.Visit(default(OpenApiServerVariable)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiOperation)); @@ -130,7 +130,7 @@ public override void Visit(OpenApiPaths paths) base.Visit(paths); } - public override void Visit(OpenApiPathItem pathItem) + public override void Visit(IOpenApiPathItem pathItem) { EncodeCall(); base.Visit(pathItem); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index cbb61987d..c21233b9a 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Services; using Xunit; @@ -65,7 +66,7 @@ public void LocateTopLevelArrayItems() public void LocatePathOperationContentSchema() { var doc = new OpenApiDocument(); - doc.Paths.Add("/test", new() + doc.Paths.Add("/test", new OpenApiPathItem() { Operations = new Dictionary { @@ -183,7 +184,7 @@ public void LocateReferences() { Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = new Dictionary { @@ -267,7 +268,7 @@ public override void Visit(OpenApiPaths paths) Locations.Add(this.PathString); } - public override void Visit(OpenApiPathItem pathItem) + public override void Visit(IOpenApiPathItem pathItem) { Keys.Add(CurrentKeys.Path); Locations.Add(this.PathString); diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index 05f8dda64..bd74197b0 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -19,7 +19,7 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { Paths = new OpenApiPaths() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = new Dictionary() { @@ -73,7 +73,6 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() [Fact] public void OpenApiWorkspacesCanResolveExternalReferences() { - var refUri = new Uri("https://everything.json/common#/components/schemas/test"); var workspace = new OpenApiWorkspace(); var externalDoc = CreateCommonDocument(); diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index 2210cce59..5fc8be43b 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -458,7 +458,7 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() }, Paths = new() { - ["/"] = new() + ["/"] = new OpenApiPathItem() { Operations = { [OperationType.Get] = new() From 83610696a0c026071308d7247fab914f4db72190 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 12:29:26 -0500 Subject: [PATCH 027/103] fix: adds missing null prop operator to proxy properties Signed-off-by: Vincent Biret --- .../Models/References/OpenApiPathItemReference.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index 015627d42..c3fa428d1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -59,16 +59,16 @@ public string Description } /// - public IDictionary Operations { get => Target.Operations; } + public IDictionary Operations { get => Target?.Operations; } /// - public IList Servers { get => Target.Servers; } + public IList Servers { get => Target?.Servers; } /// - public IList Parameters { get => Target.Parameters; } + public IList Parameters { get => Target?.Parameters; } /// - public IDictionary Extensions { get => Target.Extensions; } + public IDictionary Extensions { get => Target?.Extensions; } /// public override IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(IOpenApiPathItem source) From 45e40fa675570fc382d4a72684a009b567d45118 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 12:35:54 -0500 Subject: [PATCH 028/103] fix: returns reference instead of null Signed-off-by: Vincent Biret --- .../Models/References/OpenApiPathItemReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index c3fa428d1..f36bca3fd 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -73,7 +73,7 @@ public string Description /// public override IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(IOpenApiPathItem source) { - return source is OpenApiPathItem ? new OpenApiPathItem(this) : null; + return source is OpenApiPathItem ? new OpenApiPathItem(this) : source; } /// From 88badd429a8f1e29949399d5628087e614eb7d07 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 13:39:57 -0500 Subject: [PATCH 029/103] chore: aligns test definition with other tests Signed-off-by: Vincent Biret --- ...nWorks_produceTerseOutput=False.verified.txt | 17 ++++++++++++++++- ...onWorks_produceTerseOutput=True.verified.txt | 2 +- .../OpenApiRequestBodyReferenceTests.cs | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt index a9be81418..716f480fd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt @@ -1,3 +1,18 @@ { - "$ref": "#/components/requestBodies/UserRequest" + "description": "User request body", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + } + } + } + } } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt index 04f67afdd..161f80087 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"$ref":"#/components/requestBodies/UserRequest"} \ No newline at end of file +{"description":"User request body","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs index 0f1d8f634..9bcf15a03 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs @@ -145,7 +145,7 @@ public async Task SerializeRequestBodyReferenceAsV31JsonWorks(bool produceTerseO { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); // Act _localRequestBodyReference.SerializeAsV31(writer); From 425335eb46d4a48104046af62265ba0ca6a1ec7b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 13:40:17 -0500 Subject: [PATCH 030/103] fix: proxy design pattern implementation for request body Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../Models/Interfaces/IOpenApiRequestBody.cs | 35 ++++++ .../Models/OpenApiComponents.cs | 8 +- .../Models/OpenApiDocument.cs | 2 +- .../Models/OpenApiOperation.cs | 20 +-- .../Models/OpenApiRequestBody.cs | 61 ++++------ .../References/OpenApiRequestBodyReference.cs | 114 ++++++------------ .../Reader/V2/OpenApiDocumentDeserializer.cs | 15 +-- .../Reader/V2/OpenApiOperationDeserializer.cs | 2 +- .../V3/OpenApiRequestBodyDeserializer.cs | 3 +- .../V31/OpenApiRequestBodyDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 4 +- .../Validations/OpenApiValidator.cs | 2 +- .../V2Tests/OpenApiPathItemTests.cs | 4 +- .../Models/OpenApiCallbackTests.cs | 4 +- .../Models/OpenApiDocumentTests.cs | 2 +- .../Models/OpenApiOperationTests.cs | 6 +- .../PublicApi/PublicApi.approved.txt | 52 ++++---- .../Visitors/InheritanceTests.cs | 4 +- 22 files changed, 161 insertions(+), 194 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index 53f52ab3d..645f94319 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -41,7 +41,7 @@ public override void Visit(IOpenApiPathItem pathItem) public int RequestBodyCount { get; set; } - public override void Visit(OpenApiRequestBody requestBody) + public override void Visit(IOpenApiRequestBody requestBody) { RequestBodyCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index 6097f1f4e..fbf9f3c9a 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -41,7 +41,7 @@ public override void Visit(IOpenApiPathItem pathItem) public int RequestBodyCount { get; set; } - public override void Visit(OpenApiRequestBody requestBody) + public override void Visit(IOpenApiRequestBody requestBody) { RequestBodyCount++; } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs new file mode 100644 index 000000000..f014d2b4d --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Writers; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the request body object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiRequestBody : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// Determines if the request body is required in the request. Defaults to false. + /// + public bool Required { get; } + + /// + /// REQUIRED. The content of the request body. The key is a media type or media type range and the value describes it. + /// For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* + /// + public IDictionary Content { get; } + /// + /// Converts the request body to a body parameter in preparation for a v2 serialization. + /// + /// The writer to use to read settings from. + /// The converted OpenAPI parameter + IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer); + /// + /// Converts the request body to a set of form data parameters in preparation for a v2 serialization. + /// + /// The writer to use to read settings from + /// The converted OpenAPI parameters + IEnumerable ConvertToFormDataParameters(IOpenApiWriter writer); +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 7cd577397..f58d2644a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -39,10 +39,10 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible public IDictionary? Examples { get; set; } = new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? RequestBodies { get; set; } = - new Dictionary(); + public IDictionary? RequestBodies { get; set; } = + new Dictionary(); /// /// An object to hold reusable Objects. @@ -89,7 +89,7 @@ public OpenApiComponents(OpenApiComponents? components) Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; - RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; + RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; Links = components?.Links != null ? new Dictionary(components.Links) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 6e733d0fa..52e2243b7 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -600,7 +600,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Responses.Add(id, openApiResponse); break; case OpenApiRequestBody openApiRequestBody: - Components.RequestBodies ??= new Dictionary(); + Components.RequestBodies ??= new Dictionary(); Components.RequestBodies.Add(id, openApiRequestBody); break; case OpenApiLink openApiLink: diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 0a2f4259b..927bf839a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -66,7 +66,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenA /// has explicitly defined semantics for request bodies. /// In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers. /// - public OpenApiRequestBody? RequestBody { get; set; } + public IOpenApiRequestBody? RequestBody { get; set; } /// /// REQUIRED. The list of possible responses as they are returned from executing this operation. @@ -128,7 +128,7 @@ public OpenApiOperation(OpenApiOperation? operation) ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; OperationId = operation?.OperationId ?? OperationId; Parameters = operation?.Parameters != null ? new List(operation.Parameters) : null; - RequestBody = operation?.RequestBody != null ? new(operation?.RequestBody) : null; + RequestBody = operation?.RequestBody != null ? new OpenApiRequestBody(operation?.RequestBody) : null; Responses = operation?.Responses != null ? new(operation?.Responses) : null; Callbacks = operation?.Callbacks != null ? new Dictionary(operation.Callbacks) : null; Deprecated = operation?.Deprecated ?? Deprecated; @@ -235,15 +235,7 @@ public void SerializeAsV2(IOpenApiWriter writer) // operationId writer.WriteProperty(OpenApiConstants.OperationId, OperationId); - List parameters; - if (Parameters == null) - { - parameters = []; - } - else - { - parameters = [.. Parameters]; - } + List parameters = Parameters is null ? new() : new(Parameters); if (RequestBody != null) { @@ -255,17 +247,17 @@ public void SerializeAsV2(IOpenApiWriter writer) if (consumes.Contains("application/x-www-form-urlencoded") || consumes.Contains("multipart/form-data")) { - parameters.AddRange(RequestBody.ConvertToFormDataParameters()); + parameters.AddRange(RequestBody.ConvertToFormDataParameters(writer)); } else { parameters.Add(RequestBody.ConvertToBodyParameter(writer)); } } - else if (RequestBody.Reference != null && RequestBody.Reference.HostDocument is {} hostDocument) + else if (RequestBody is OpenApiRequestBodyReference requestBodyReference) { parameters.Add( - new OpenApiParameterReference(RequestBody.Reference.Id, hostDocument)); + new OpenApiParameterReference(requestBodyReference.Reference.Id, requestBodyReference.Reference.HostDocument)); } if (consumes.Count > 0) diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 2524c41d6..b5fd3f605 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -15,39 +15,19 @@ namespace Microsoft.OpenApi.Models /// /// Request Body Object /// - public class OpenApiRequestBody : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiRequestBody : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiRequestBody { - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public bool UnresolvedReference { get; set; } - - /// - /// Reference object. - /// - public OpenApiReference Reference { get; set; } - - /// - /// A brief description of the request body. This could contain examples of use. - /// CommonMark syntax MAY be used for rich text representation. - /// - public virtual string Description { get; set; } + /// + public string Description { get; set; } - /// - /// Determines if the request body is required in the request. Defaults to false. - /// - public virtual bool Required { get; set; } + /// + public bool Required { get; set; } - /// - /// REQUIRED. The content of the request body. The key is a media type or media type range and the value describes it. - /// For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* - /// - public virtual IDictionary Content { get; set; } = new Dictionary(); + /// + public IDictionary Content { get; set; } = new Dictionary(); - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -55,12 +35,11 @@ public class OpenApiRequestBody : IOpenApiReferenceable, IOpenApiExtensible public OpenApiRequestBody() { } /// - /// Initializes a copy instance of an object + /// Initializes a copy instance of an object /// - public OpenApiRequestBody(OpenApiRequestBody requestBody) + public OpenApiRequestBody(IOpenApiRequestBody requestBody) { - UnresolvedReference = requestBody?.UnresolvedReference ?? UnresolvedReference; - Reference = requestBody?.Reference != null ? new(requestBody?.Reference) : null; + Utils.CheckArgumentNull(requestBody); Description = requestBody?.Description ?? Description; Required = requestBody?.Required ?? Required; Content = requestBody?.Content != null ? new Dictionary(requestBody.Content) : null; @@ -70,7 +49,7 @@ public OpenApiRequestBody(OpenApiRequestBody requestBody) /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } @@ -78,12 +57,12 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { Utils.CheckArgumentNull(writer); @@ -113,7 +92,8 @@ public void SerializeAsV2(IOpenApiWriter writer) // RequestBody object does not exist in V2. } - internal virtual IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + /// + public IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) { var bodyParameter = new OpenApiBodyParameter { @@ -135,7 +115,8 @@ internal virtual IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) return bodyParameter; } - internal IEnumerable ConvertToFormDataParameters() + /// + public IEnumerable ConvertToFormDataParameters(IOpenApiWriter writer) { if (Content == null || !Content.Any()) yield break; @@ -143,14 +124,14 @@ internal IEnumerable ConvertToFormDataParameters() foreach (var property in Content.First().Value.Schema.Properties) { var paramSchema = property.Value; - if ("string".Equals(paramSchema.Type.ToIdentifier(), StringComparison.OrdinalIgnoreCase) + if ((paramSchema.Type & JsonSchemaType.String) == JsonSchemaType.String && ("binary".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase) || "base64".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase))) { paramSchema.Type = "file".ToJsonSchemaType(); paramSchema.Format = null; } - yield return new() + yield return new OpenApiFormDataParameter() { Description = property.Value.Description, Name = property.Key, diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 5aa466415..d698dd092 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; @@ -12,29 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Request Body Object Reference. /// - public class OpenApiRequestBodyReference : OpenApiRequestBody, IOpenApiReferenceHolder + public class OpenApiRequestBodyReference : BaseOpenApiReferenceHolder, IOpenApiRequestBody { - internal OpenApiRequestBody _target; - private readonly OpenApiReference _reference; - private string _description; - - /// - /// Gets the target request body. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiRequestBody Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiRequestBody resolved = new OpenApiRequestBody(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; - } - } - /// /// Constructor initializing the reference object. /// @@ -45,93 +25,69 @@ public OpenApiRequestBody Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.RequestBody, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - _reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.RequestBody, - ExternalResource = externalResource - }; - - Reference = _reference; } - - internal OpenApiRequestBodyReference(OpenApiRequestBody target, string referenceId) + internal OpenApiRequestBodyReference(OpenApiRequestBody target, string referenceId):base(target, referenceId, ReferenceType.RequestBody) { - _target = target; - - _reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.RequestBody, - }; } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override IDictionary Content { get => Target.Content; set => Target.Content = value; } + public IDictionary Content { get => Target?.Content; } /// - public override bool Required { get => Target.Required; set => Target.Required = value; } + public bool Required { get => Target?.Required ?? false; } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public IDictionary Extensions { get => Target?.Extensions; } /// - public override void SerializeAsV3(IOpenApiWriter writer) + public override IOpenApiRequestBody CopyReferenceAsTargetElementWithOverrides(IOpenApiRequestBody source) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - } + return source is OpenApiRequestBody ? new OpenApiRequestBody(this) : source; } - /// - public override void SerializeAsV31(IOpenApiWriter writer) + public override void SerializeAsV2(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + // doesn't exist in v2 + } + /// + public IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + { + if (writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); + return Target.ConvertToBodyParameter(writer); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + return new OpenApiParameterReference(Reference.Id, Reference.HostDocument); } } - - /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) - { - Utils.CheckArgumentNull(writer); - action(writer, Target); - } - /// - internal override IOpenApiParameter ConvertToBodyParameter(IOpenApiWriter writer) + public IEnumerable ConvertToFormDataParameters(IOpenApiWriter writer) { - if (writer.GetSettings().ShouldInlineReference(_reference)) + if (writer.GetSettings().ShouldInlineReference(Reference)) { - return Target.ConvertToBodyParameter(writer); - } - else - { - return new OpenApiParameterReference(_reference.Id, _reference.HostDocument); + return Target.ConvertToFormDataParameters(writer); } + + if (Content == null || !Content.Any()) + return []; + + return Content.First().Value.Schema.Properties.Select(x => new OpenApiParameterReference(x.Key, Reference.HostDocument)); } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index e24c10227..ee0bf0c8f 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Services; @@ -303,8 +304,8 @@ private static bool IsHostValid(string host) internal class RequestBodyReferenceFixer : OpenApiVisitorBase { - private readonly IDictionary _requestBodies; - public RequestBodyReferenceFixer(IDictionary requestBodies) + private readonly IDictionary _requestBodies; + public RequestBodyReferenceFixer(IDictionary requestBodies) { _requestBodies = requestBodies; } @@ -318,15 +319,7 @@ public override void Visit(OpenApiOperation operation) if (body != null) { operation.Parameters.Remove(body); - operation.RequestBody = new() - { - UnresolvedReference = true, - Reference = new() - { - Id = body.Reference.Id, - Type = ReferenceType.RequestBody - } - }; + operation.RequestBody = new OpenApiRequestBodyReference(body.Reference.Id, body.Reference.HostDocument); } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 3fd5743c9..957a02ab7 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -179,7 +179,7 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("requestBody"); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs index e26ec20f9..db6792a5f 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -40,7 +41,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("requestBody"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 982162442..eadabbaaf 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -118,9 +118,9 @@ private void AddRequestBodyToComponents(OpenApiRequestBody requestBody, string r { EnsureComponentsExist(); EnsureRequestBodiesExist(); - if (!Components.RequestBodies.ContainsKey(referenceId ?? requestBody.Reference.Id)) + if (!Components.RequestBodies.ContainsKey(referenceId)) { - Components.RequestBodies.Add(referenceId ?? requestBody.Reference.Id, requestBody); + Components.RequestBodies.Add(referenceId, requestBody); } } private void AddLinkToComponents(OpenApiLink link, string referenceId = null) @@ -215,7 +215,7 @@ private void EnsureResponsesExist() private void EnsureRequestBodiesExist() { - _target.Components.RequestBodies ??= new Dictionary(); + _target.Components.RequestBodies ??= new Dictionary(); } private void EnsureExamplesExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 63b065bbd..f118a3f06 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -153,9 +153,9 @@ public virtual void Visit(IOpenApiParameter parameter) } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiRequestBody requestBody) + public virtual void Visit(IOpenApiRequestBody requestBody) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 66ca7e6fe..b76f33ad9 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -713,9 +713,9 @@ internal void Walk(OpenApiResponse response, bool isComponent = false) } /// - /// Visits and child objects + /// Visits and child objects /// - internal void Walk(OpenApiRequestBody requestBody, bool isComponent = false) + internal void Walk(IOpenApiRequestBody requestBody, bool isComponent = false) { if (requestBody == null) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 63076ed9d..a5a4885de 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -141,7 +141,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiSecurityRequirement securityRequirement) => Validate(securityRequirement); /// - public override void Visit(OpenApiRequestBody requestBody) => Validate(requestBody); + public override void Visit(IOpenApiRequestBody requestBody) => Validate(requestBody); /// public override void Visit(OpenApiPaths paths) => Validate(paths); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index be19365d5..35ffd15d5 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -60,7 +60,7 @@ public class OpenApiPathItemTests } } ], - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Content = { @@ -166,7 +166,7 @@ public class OpenApiPathItemTests } } ], - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Content = { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index a2ef27222..267e29ede 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -28,7 +28,7 @@ public class OpenApiCallbackTests [OperationType.Post] = new() { - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Content = { @@ -68,7 +68,7 @@ public class OpenApiCallbackTests [OperationType.Post] = new() { - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Content = { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 19ebca7fb..c333fcdb7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -1171,7 +1171,7 @@ public OpenApiDocumentTests() { Description = "Creates a new pet in the store. Duplicates are allowed", OperationId = "addPet", - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Description = "Pet to add to the store", Required = true, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 81da044bf..6b3c61417 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -39,7 +39,7 @@ public class OpenApiOperationTests Name = "parameter2" } ], - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Description = "description2", Required = true, @@ -113,7 +113,7 @@ public class OpenApiOperationTests Name = "parameter2" } ], - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Description = "description2", Required = true, @@ -191,7 +191,7 @@ public class OpenApiOperationTests } } ], - RequestBody = new() + RequestBody = new OpenApiRequestBody() { Content = { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index cf54ef45a..93aef1c4b 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -392,6 +392,13 @@ namespace Microsoft.OpenApi.Models.Interfaces System.Collections.Generic.IList Parameters { get; } System.Collections.Generic.IList Servers { get; } } + public interface IOpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + System.Collections.Generic.IDictionary Content { get; } + bool Required { get; } + Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer); + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -432,7 +439,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Links { get; set; } public System.Collections.Generic.IDictionary? Parameters { get; set; } public System.Collections.Generic.IDictionary? PathItems { get; set; } - public System.Collections.Generic.IDictionary? RequestBodies { get; set; } + public System.Collections.Generic.IDictionary? RequestBodies { get; set; } public System.Collections.Generic.IDictionary? Responses { get; set; } public System.Collections.Generic.IDictionary? Schemas { get; set; } public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } @@ -820,7 +827,7 @@ namespace Microsoft.OpenApi.Models public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } public string? OperationId { get; set; } public System.Collections.Generic.IList? Parameters { get; set; } - public Microsoft.OpenApi.Models.OpenApiRequestBody? RequestBody { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody? RequestBody { get; set; } public Microsoft.OpenApi.Models.OpenApiResponses? Responses { get; set; } public System.Collections.Generic.IList? Security { get; set; } public System.Collections.Generic.IList? Servers { get; set; } @@ -891,19 +898,19 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody { public OpenApiRequestBody() { } - public OpenApiRequestBody(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public bool UnresolvedReference { get; set; } - public virtual System.Collections.Generic.IDictionary Content { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual bool Required { get; set; } + public OpenApiRequestBody(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } + public System.Collections.Generic.IDictionary Content { get; set; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public bool Required { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1258,16 +1265,17 @@ namespace Microsoft.OpenApi.Models.References public override Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody { public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiRequestBody Target { get; } - public override System.Collections.Generic.IDictionary Content { get; set; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override bool Required { get; set; } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public System.Collections.Generic.IDictionary Content { get; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public bool Required { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody source) { } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1556,6 +1564,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1567,7 +1576,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } @@ -1655,6 +1663,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1666,7 +1675,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index fd65e7dd4..49595a1be 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -32,7 +32,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(OpenApiOperation)); visitor.Visit(default(IList)); visitor.Visit(default(IOpenApiParameter)); - visitor.Visit(default(OpenApiRequestBody)); + visitor.Visit(default(IOpenApiRequestBody)); visitor.Visit(default(IDictionary)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiResponse)); @@ -166,7 +166,7 @@ public override void Visit(IOpenApiParameter parameter) base.Visit(parameter); } - public override void Visit(OpenApiRequestBody requestBody) + public override void Visit(IOpenApiRequestBody requestBody) { EncodeCall(); base.Visit(requestBody); From 704943c28f87257e896d1a79eb6962d60f719bec Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 13:56:04 -0500 Subject: [PATCH 031/103] fix: fixes inlining override when they should not happen Signed-off-by: Vincent Biret --- .../Models/OpenApiReference.cs | 17 ++++++++----- .../References/BaseOpenApiReferenceHolder.cs | 4 ++-- ...e_inlineLocalReferences=False.verified.txt | 4 ++++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ..._inlineLocalReferences=False.verified.txt} | 0 ...se_inlineLocalReferences=True.verified.txt | 18 ++++++++++++++ ..._inlineLocalReferences=False.verified.txt} | 0 ...ue_inlineLocalReferences=True.verified.txt | 1 + .../OpenApiRequestBodyReferenceTests.cs | 24 +++++++++++-------- 11 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt => OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index 9c65bf9e2..0802e2ca2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -158,11 +158,12 @@ public OpenApiReference(OpenApiReference reference) /// public void SerializeAsV31(IOpenApiWriter writer) { - // summary and description are in 3.1 but not in 3.0 - writer.WriteProperty(OpenApiConstants.Summary, Summary); - writer.WriteProperty(OpenApiConstants.Description, Description); - - SerializeInternal(writer); + SerializeInternal(writer, x => + { + // summary and description are in 3.1 but not in 3.0 + writer.WriteProperty(OpenApiConstants.Summary, Summary); + writer.WriteProperty(OpenApiConstants.Description, Description); + }); } /// @@ -176,7 +177,7 @@ public void SerializeAsV3(IOpenApiWriter writer) /// /// Serialize /// - private void SerializeInternal(IOpenApiWriter writer) + private void SerializeInternal(IOpenApiWriter writer, Action callback = null) { Utils.CheckArgumentNull(writer); @@ -188,6 +189,10 @@ private void SerializeInternal(IOpenApiWriter writer) } writer.WriteStartObject(); + if (callback is not null) + { + callback(writer); + } // $ref writer.WriteProperty(OpenApiConstants.DollarRef, ReferenceV3); diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 6b1f02575..d7205f37c 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -80,7 +80,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV3(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -106,7 +106,7 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => CopyReferenceAsTargetElementWithOverrides(element).SerializeAsV2(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..7d881453b --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,4 @@ +{ + "description": "User request body", + "$ref": "#/components/requestBodies/UserRequest" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..ac2c2d9ac --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"description":"User request body","$ref":"#/components/requestBodies/UserRequest"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..c4d9bef00 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -0,0 +1,18 @@ +{ + "description": "User creation request body", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..3d91acf86 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.SerializeRequestBodyReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"description":"User creation request body","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs index 9bcf15a03..4f8e24f6e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs @@ -122,37 +122,41 @@ public void RequestBodyReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeRequestBodyReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeRequestBodyReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput}); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localRequestBodyReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeRequestBodyReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeRequestBodyReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localRequestBodyReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } From 9b6147abe8db58a3e4aafe157f9f86579cba55d6 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:01:55 -0500 Subject: [PATCH 032/103] chore: adds additional test cases for parameter reference inlining Signed-off-by: Vincent Biret --- ...e_inlineLocalReferences=False.verified.txt | 3 ++ ...e_inlineLocalReferences=True.verified.txt} | 2 +- ...Async_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...ue_inlineLocalReferences=True.verified.txt | 1 + ...e_inlineLocalReferences=False.verified.txt | 4 +++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 3 ++ ...e_inlineLocalReferences=True.verified.txt} | 2 +- ...Works_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...ue_inlineLocalReferences=True.verified.txt | 1 + .../OpenApiParameterReferenceTests.cs | 36 +++++++++++-------- 15 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt => OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (66%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (71%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..9ef7c70ed --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/parameters/limitParam" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 66% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt index 2a64ba6d9..992c2f047 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -1,7 +1,7 @@ { "in": "query", "name": "limit", - "description": "Results to return", + "description": "Number of results to return", "type": "integer", "maximum": 100, "minimum": 1 diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index 8d3cb1803..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"in":"query","name":"limit","description":"Results to return","type":"integer","maximum":100,"minimum":1} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..7463c6c0e --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/parameters/limitParam"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..995eb077e --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"in":"query","name":"limit","description":"Number of results to return","type":"integer","maximum":100,"minimum":1} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..045ad6d1d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,4 @@ +{ + "description": "Results to return", + "$ref": "#/components/parameters/limitParam" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..6fdeee0c3 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"description":"Results to return","$ref":"#/components/parameters/limitParam"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..24f3c7a74 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/components/parameters/limitParam" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 71% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt index cd30a5fc2..f0066344e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -1,7 +1,7 @@ { "name": "limit", "in": "query", - "description": "Results to return", + "description": "Number of results to return", "schema": { "maximum": 100, "minimum": 1, diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index da4f04c14..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"name":"limit","in":"query","description":"Results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..1eb2fda7d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/components/parameters/limitParam"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..2b7ff1cfb --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"name":"limit","in":"query","description":"Number of results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs index 5e95246ae..8afc96f04 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs @@ -111,54 +111,60 @@ public void ParameterReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeParameterReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeParameterReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localParameterReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeParameterReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeParameterReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localParameterReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeParameterReferenceAsV2JsonWorksAsync(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeParameterReferenceAsV2JsonWorksAsync(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput , InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput , InlineLocalReferences = inlineLocalReferences }); // Act _localParameterReference.SerializeAsV2(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } From 66dcb215661dbe272aabad528d64a19072e190b5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:13:09 -0500 Subject: [PATCH 033/103] chore: adds unit tests for callback and path item Signed-off-by: Vincent Biret --- ..._inlineLocalReferences=False.verified.txt} | 0 ...e_inlineLocalReferences=True.verified.txt} | 0 ..._inlineLocalReferences=False.verified.txt} | 0 ...e_inlineLocalReferences=True.verified.txt} | 0 ..._inlineLocalReferences=False.verified.txt} | 0 ...e_inlineLocalReferences=True.verified.txt} | 0 ..._inlineLocalReferences=False.verified.txt} | 0 ...e_inlineLocalReferences=True.verified.txt} | 0 .../OpenApiCallbackReferenceTests.cs | 24 +++++++++------- ...orks_produceTerseOutput=False.verified.txt | 28 ------------------- ...Works_produceTerseOutput=True.verified.txt | 1 - ...orks_produceTerseOutput=False.verified.txt | 28 ------------------- ...Works_produceTerseOutput=True.verified.txt | 1 - ...sync_produceTerseOutput=False.verified.txt | 28 ------------------- ...Async_produceTerseOutput=True.verified.txt | 1 - ...sync_produceTerseOutput=False.verified.txt | 28 ------------------- ...Async_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 5 ++++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...orks_produceTerseOutput=False.verified.txt | 28 ------------------- ...Works_produceTerseOutput=True.verified.txt | 1 - .../OpenApiPathItemReferenceTests.cs | 12 ++++---- 24 files changed, 27 insertions(+), 160 deletions(-) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt} (100%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=True.verified.txt => OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeReferencedCallbackAsV3JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs index 38bf27215..34284b9bd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs @@ -159,37 +159,41 @@ public void CallbackReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeCallbackReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeCallbackReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true, InlineLocalReferences = inlineLocalReferences }); // Act _externalCallbackReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeCallbackReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeCallbackReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true, InlineLocalReferences = inlineLocalReferences}); // Act _externalCallbackReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 844f5ee81..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,28 +0,0 @@ -{ - "summary": "User path item summary", - "description": "User path item description", - "get": { - "summary": "Get users", - "responses": { - "200": { - "description": "Successful operation" - } - } - }, - "post": { - "summary": "Create a user", - "responses": { - "201": { - "description": "User created successfully" - } - } - }, - "delete": { - "summary": "Delete a user", - "responses": { - "204": { - "description": "User deleted successfully" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index f43044ef8..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"summary":"User path item summary","description":"User path item description","get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 844f5ee81..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,28 +0,0 @@ -{ - "summary": "User path item summary", - "description": "User path item description", - "get": { - "summary": "Get users", - "responses": { - "200": { - "description": "Successful operation" - } - } - }, - "post": { - "summary": "Create a user", - "responses": { - "201": { - "description": "User created successfully" - } - } - }, - "delete": { - "summary": "Delete a user", - "responses": { - "204": { - "description": "User deleted successfully" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index f43044ef8..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"summary":"User path item summary","description":"User path item description","get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index 86685c051..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,28 +0,0 @@ -{ - "get": { - "summary": "Get users", - "responses": { - "200": { - "description": "Successful operation" - } - } - }, - "post": { - "summary": "Create a user", - "responses": { - "201": { - "description": "User created successfully" - } - } - }, - "delete": { - "summary": "Delete a user", - "responses": { - "204": { - "description": "User deleted successfully" - } - } - }, - "x-summary": "Local reference: User path item summary", - "x-description": "Local reference: User path item description" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index efa477cae..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}},"x-summary":"Local reference: User path item summary","x-description":"Local reference: User path item description"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index 86685c051..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,28 +0,0 @@ -{ - "get": { - "summary": "Get users", - "responses": { - "200": { - "description": "Successful operation" - } - } - }, - "post": { - "summary": "Create a user", - "responses": { - "201": { - "description": "User created successfully" - } - } - }, - "delete": { - "summary": "Delete a user", - "responses": { - "204": { - "description": "User deleted successfully" - } - } - }, - "x-summary": "Local reference: User path item summary", - "x-description": "Local reference: User path item description" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index efa477cae..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}},"x-summary":"Local reference: User path item summary","x-description":"Local reference: User path item description"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..e02b91f3c --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,5 @@ +{ + "summary": "Local reference: User path item summary", + "description": "Local reference: User path item description", + "$ref": "#/components/pathItems/userPathItem" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..0eeb858e3 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"summary":"Local reference: User path item summary","description":"Local reference: User path item description","$ref":"#/components/pathItems/userPathItem"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 844f5ee81..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,28 +0,0 @@ -{ - "summary": "User path item summary", - "description": "User path item description", - "get": { - "summary": "Get users", - "responses": { - "200": { - "description": "Successful operation" - } - } - }, - "post": { - "summary": "Create a user", - "responses": { - "201": { - "description": "User created successfully" - } - } - }, - "delete": { - "summary": "Delete a user", - "responses": { - "204": { - "description": "User deleted successfully" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index f43044ef8..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"summary":"User path item summary","description":"User path item description","get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs index 510dfbda3..55c5bc7b5 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs @@ -119,20 +119,22 @@ public void PathItemReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializePathItemReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializePathItemReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localPathItemReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } From 2faeb0b0e3e7b453488f8c14f761e9c67002985e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:15:49 -0500 Subject: [PATCH 034/103] chore: adds tests for example reference inlining Signed-off-by: Vincent Biret --- ...orks_produceTerseOutput=False.verified.txt | 10 -------- ...Works_produceTerseOutput=True.verified.txt | 1 - ..._inlineLocalReferences=False.verified.txt} | 7 +----- ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 3 +++ ...e_inlineLocalReferences=True.verified.txt} | 2 +- ...Works_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 2 +- .../OpenApiExampleReferenceTests.cs | 24 +++++++++++-------- 12 files changed, 22 insertions(+), 30 deletions(-) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (59%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (89%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (52%) diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index f71202885..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,10 +0,0 @@ -{ - "summary": "Example of a user", - "description": "This is is an example of a user", - "value": [ - { - "id": "1", - "name": "John Doe" - } - ] -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index cddf257f8..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"summary":"Example of a user","description":"This is is an example of a user","value":[{"id":"1","name":"John Doe"}]} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 59% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt index d3d85c6b5..cb7caa304 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -1,10 +1,5 @@ { "summary": "Example of a local user", "description": "This is an example of a local user", - "value": [ - { - "id": 1, - "name": "John Doe" - } - ] + "$ref": "#/components/examples/UserExample" } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..def86be23 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"summary":"Example of a local user","description":"This is an example of a local user","$ref":"#/components/examples/UserExample"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..fcff4230d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/components/examples/UserExample" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 89% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt index f71202885..8d9c12611 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -3,7 +3,7 @@ "description": "This is is an example of a user", "value": [ { - "id": "1", + "id": 1, "name": "John Doe" } ] diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index 0c1962929..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"summary":"Example of a local user","description":"This is an example of a local user","value":[{"id":1,"name":"John Doe"}]} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..0efca4639 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/components/examples/UserExample"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 52% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt index cddf257f8..c1549bf7c 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -1 +1 @@ -{"summary":"Example of a user","description":"This is is an example of a user","value":[{"id":"1","name":"John Doe"}]} \ No newline at end of file +{"summary":"Example of a user","description":"This is is an example of a user","value":[{"id":1,"name":"John Doe"}]} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs index 2cb0ff189..a52c027f9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs @@ -150,37 +150,41 @@ public void ExampleReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeExampleReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeExampleReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localExampleReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeExampleReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeExampleReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localExampleReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } From cbda1f46683ed56df1d0694b92f8fba47f958205 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:18:35 -0500 Subject: [PATCH 035/103] chore: adds unit tests for headers reference inlining Signed-off-by: Vincent Biret --- ...Works_produceTerseOutput=True.verified.txt | 1 - ...sync_produceTerseOutput=False.verified.txt | 4 --- ...e_inlineLocalReferences=False.verified.txt | 3 ++ ...e_inlineLocalReferences=True.verified.txt} | 4 +-- ...Async_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...ue_inlineLocalReferences=True.verified.txt | 1 + ..._inlineLocalReferences=False.verified.txt} | 4 +-- ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 3 ++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...Works_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...sync_produceTerseOutput=False.verified.txt | 4 --- ...Async_produceTerseOutput=True.verified.txt | 1 - .../References/OpenApiHeaderReferenceTests.cs | 36 +++++++++++-------- 19 files changed, 33 insertions(+), 33 deletions(-) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (60%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (57%) rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index 1b29be17d..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"description":"The URL of the newly created post","schema":{"type":"string"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index b957bd951..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,4 +0,0 @@ -{ - "description": "Location of the locally referenced post", - "type": "string" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..38d7a64f2 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/headers/LocationHeader" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 60% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt index f43e25a40..8bd613186 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -1,6 +1,4 @@ { "description": "The URL of the newly created post", - "schema": { - "type": "string" - } + "type": "string" } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index 17f59471d..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"description":"Location of the locally referenced post","type":"string"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..cfae04d2b --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/headers/LocationHeader"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..9d510cb80 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"description":"The URL of the newly created post","type":"string"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 57% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt index badfda7f7..0959c10ea 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -1,6 +1,4 @@ { "description": "Location of the locally referenced post", - "schema": { - "type": "string" - } + "$ref": "#/components/headers/LocationHeader" } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..eabf641fd --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"description":"Location of the locally referenced post","$ref":"#/components/headers/LocationHeader"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..74963dc5e --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/components/headers/LocationHeader" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index cf7cf9e25..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"description":"Location of the locally referenced post","schema":{"type":"string"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..da8e23f86 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/components/headers/LocationHeader"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index 8b29b212e..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,4 +0,0 @@ -{ - "description": "Location of the locally created post", - "type": "string" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index 243908873..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"description":"Location of the locally created post","type":"string"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs index daff6e479..9b3c6c544 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs @@ -109,54 +109,60 @@ public void HeaderReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeHeaderReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeHeaderReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localHeaderReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeHeaderReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeHeaderReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localHeaderReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeHeaderReferenceAsV2JsonWorksAsync(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeHeaderReferenceAsV2JsonWorksAsync(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localHeaderReference.SerializeAsV2(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Fact] From 7afeabe003658ae3c8c7e626141124b140579856 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:20:17 -0500 Subject: [PATCH 036/103] chore: adds unit tests for link reference inlining Signed-off-by: Vincent Biret --- ...orks_produceTerseOutput=False.verified.txt | 7 ------ ...Works_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 4 ++++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 ...orks_produceTerseOutput=False.verified.txt | 7 ------ ...e_inlineLocalReferences=False.verified.txt | 3 +++ ...e_inlineLocalReferences=True.verified.txt} | 0 ...Works_produceTerseOutput=True.verified.txt | 1 - ...e_inlineLocalReferences=False.verified.txt | 1 + ...e_inlineLocalReferences=True.verified.txt} | 0 .../References/OpenApiLinkReferenceTests.cs | 24 +++++++++++-------- 13 files changed, 23 insertions(+), 26 deletions(-) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt} (100%) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt} (100%) diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 6fe727ea0..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,7 +0,0 @@ -{ - "operationId": "getUser", - "parameters": { - "userId": "$response.body#/id" - }, - "description": "The id value returned in the response can be used as the userId parameter in GET /users/{userId}" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index e3df412e9..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"The id value returned in the response can be used as the userId parameter in GET /users/{userId}"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..2b8d39932 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,4 @@ +{ + "description": "Use the id returned as the userId in `GET /users/{userId}`", + "$ref": "#/components/links/GetUserByUserId" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..3130ca88d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"description":"Use the id returned as the userId in `GET /users/{userId}`","$ref":"#/components/links/GetUserByUserId"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 89319843f..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,7 +0,0 @@ -{ - "operationId": "getUser", - "parameters": { - "userId": "$response.body#/id" - }, - "description": "Use the id returned as the userId in `GET /users/{userId}`" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..2fa856caf --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "#/components/links/GetUserByUserId" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index 93208a391..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"Use the id returned as the userId in `GET /users/{userId}`"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..431f49da4 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"#/components/links/GetUserByUserId"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeCallbackReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs index 4845c2311..44822454f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs @@ -158,37 +158,41 @@ public void LinkReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeLinkReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeLinkReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localLinkReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeLinkReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task SerializeLinkReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localLinkReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } From 88ad99759d8735824c7a70321ed7efc164633f06 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 14:22:13 -0500 Subject: [PATCH 037/103] fix: references callback writer Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiReference.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index 0802e2ca2..191f884ea 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -158,11 +158,11 @@ public OpenApiReference(OpenApiReference reference) /// public void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, x => + SerializeInternal(writer, w => { // summary and description are in 3.1 but not in 3.0 - writer.WriteProperty(OpenApiConstants.Summary, Summary); - writer.WriteProperty(OpenApiConstants.Description, Description); + w.WriteProperty(OpenApiConstants.Summary, Summary); + w.WriteProperty(OpenApiConstants.Description, Description); }); } From 5b4003bd04d59fd460280fa06e6151b0203680cb Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Jan 2025 15:27:58 -0500 Subject: [PATCH 038/103] fix: response reference proxy design pattern implementation Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiResponse.cs | 29 +++++ .../Models/OpenApiComponents.cs | 6 +- .../Models/OpenApiDocument.cs | 2 +- .../Models/OpenApiOperation.cs | 6 +- .../Models/OpenApiResponse.cs | 60 +++------ .../Models/OpenApiResponses.cs | 4 +- .../References/OpenApiResponseReference.cs | 115 +++--------------- .../Reader/V2/OpenApiDocumentDeserializer.cs | 6 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 2 +- .../Reader/V2/OpenApiResponseDeserializer.cs | 2 +- .../Reader/V3/OpenApiResponseDeserializer.cs | 3 +- .../Reader/V3/OpenApiResponsesDeserializer.cs | 5 +- .../Reader/V31/OpenApiResponseDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 2 +- .../Services/OpenApiWalker.cs | 2 +- .../Validations/OpenApiValidator.cs | 2 +- .../Validations/Rules/OpenApiResponseRules.cs | 3 +- .../UtilityFiles/OpenApiDocumentMock.cs | 24 ++-- .../TryLoadReferenceV2Tests.cs | 13 +- .../V2Tests/OpenApiDocumentTests.cs | 12 +- .../V2Tests/OpenApiPathItemTests.cs | 7 +- .../Models/OpenApiCallbackTests.cs | 4 +- .../Models/OpenApiDocumentTests.cs | 24 ++-- .../Models/OpenApiOperationTests.cs | 40 +++++- .../Models/OpenApiResponseTests.cs | 4 +- ..._inlineLocalReferences=False.verified.txt} | 1 + ...se_inlineLocalReferences=True.verified.txt | 15 +++ ...e_inlineLocalReferences=False.verified.txt | 1 + ...ue_inlineLocalReferences=True.verified.txt | 1 + ..._inlineLocalReferences=False.verified.txt} | 0 ...se_inlineLocalReferences=True.verified.txt | 15 +++ ...Works_produceTerseOutput=True.verified.txt | 1 - ..._inlineLocalReferences=False.verified.txt} | 0 ...ue_inlineLocalReferences=True.verified.txt | 1 + .../OpenApiResponseReferenceTest.cs | 24 ++-- .../PublicApi/PublicApi.approved.txt | 55 +++++---- .../Services/OpenApiUrlTreeNodeTests.cs | 10 +- .../Services/OpenApiValidatorTests.cs | 32 ++--- .../OpenApiComponentsValidationTests.cs | 3 +- .../OpenApiReferenceValidationTests.cs | 4 +- .../OpenApiResponseValidationTests.cs | 9 +- .../Visitors/InheritanceTests.cs | 4 +- .../Walkers/WalkerLocationTests.cs | 6 +- .../Workspaces/OpenApiWorkspaceTests.cs | 2 +- .../Writers/OpenApiYamlWriterTests.cs | 2 +- 46 files changed, 285 insertions(+), 287 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt => OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (61%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt => OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt rename test/Microsoft.OpenApi.Tests/Models/References/{OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt => OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt} (100%) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs new file mode 100644 index 000000000..5a1f33e7a --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the response object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiResponse : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// Maps a header name to its definition. + /// + public IDictionary Headers { get; } + + /// + /// A map containing descriptions of potential response payloads. + /// The key is a media type or media type range and the value describes it. + /// + public IDictionary Content { get; } + + /// + /// A map of operations links that can be followed from the response. + /// The key of the map is a short name for the link, + /// following the naming constraints of the names for Component Objects. + /// + public IDictionary Links { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index f58d2644a..6d65ef7b1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -23,9 +23,9 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible public IDictionary? Schemas { get; set; } = new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? Responses { get; set; } = new Dictionary(); + public IDictionary? Responses { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -86,7 +86,7 @@ public OpenApiComponents() { } public OpenApiComponents(OpenApiComponents? components) { Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; - Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; + Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 52e2243b7..32afbdf90 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -596,7 +596,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Parameters.Add(id, openApiParameter); break; case OpenApiResponse openApiResponse: - Components.Responses ??= new Dictionary(); + Components.Responses ??= new Dictionary(); Components.Responses.Add(id, openApiResponse); break; case OpenApiRequestBody openApiRequestBody: diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 927bf839a..a3ded96eb 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -279,8 +279,10 @@ public void SerializeAsV2(IOpenApiWriter writer) .SelectMany(static r => r.Value.Content?.Keys ?? []) .Concat( Responses - .Where(static r => r.Value.Reference is {HostDocument: not null}) - .SelectMany(static r => r.Value.Content?.Keys ?? [])) + .Select(static r => r.Value) + .OfType() + .Where(static r => r.Reference is {HostDocument: not null}) + .SelectMany(static r => r.Content?.Keys ?? [])) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index 3896c6b76..cf2a54cfb 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -13,45 +13,22 @@ namespace Microsoft.OpenApi.Models /// /// Response object. /// - public class OpenApiResponse : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiResponse : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiResponse { - /// - /// REQUIRED. A short description of the response. - /// - public virtual string Description { get; set; } - - /// - /// Maps a header name to its definition. - /// - public virtual IDictionary Headers { get; set; } = new Dictionary(); - - /// - /// A map containing descriptions of potential response payloads. - /// The key is a media type or media type range and the value describes it. - /// - public virtual IDictionary Content { get; set; } = new Dictionary(); + /// + public string Description { get; set; } - /// - /// A map of operations links that can be followed from the response. - /// The key of the map is a short name for the link, - /// following the naming constraints of the names for Component Objects. - /// - public virtual IDictionary Links { get; set; } = new Dictionary(); + /// + public IDictionary Headers { get; set; } = new Dictionary(); - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public IDictionary Content { get; set; } = new Dictionary(); - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public bool UnresolvedReference { get; set; } + /// + public IDictionary Links { get; set; } = new Dictionary(); - /// - /// Reference pointer. - /// - public OpenApiReference Reference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -59,23 +36,22 @@ public class OpenApiResponse : IOpenApiReferenceable, IOpenApiExtensible public OpenApiResponse() { } /// - /// Initializes a copy of object + /// Initializes a copy of object /// - public OpenApiResponse(OpenApiResponse response) + public OpenApiResponse(IOpenApiResponse response) { + Utils.CheckArgumentNull(response); Description = response?.Description ?? Description; Headers = response?.Headers != null ? new Dictionary(response.Headers) : null; Content = response?.Content != null ? new Dictionary(response.Content) : null; Links = response?.Links != null ? new Dictionary(response.Links) : null; Extensions = response?.Extensions != null ? new Dictionary(response.Extensions) : null; - UnresolvedReference = response?.UnresolvedReference ?? UnresolvedReference; - Reference = response?.Reference != null ? new(response?.Reference) : null; } /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } @@ -83,12 +59,12 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0. /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { Utils.CheckArgumentNull(writer); @@ -116,7 +92,7 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio /// /// Serialize to OpenAPI V2 document without using reference. /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponses.cs b/src/Microsoft.OpenApi/Models/OpenApiResponses.cs index 8880c244f..855ac6834 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponses.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponses.cs @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using Microsoft.OpenApi.Models.Interfaces; + namespace Microsoft.OpenApi.Models { /// /// Responses object. /// - public class OpenApiResponses : OpenApiExtensibleDictionary + public class OpenApiResponses : OpenApiExtensibleDictionary { /// /// Parameterless constructor diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index 57d8fba2b..ef6b68fff 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -5,34 +5,14 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; -using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References { /// /// Response Object Reference. /// - public class OpenApiResponseReference : OpenApiResponse, IOpenApiReferenceHolder + public class OpenApiResponseReference : BaseOpenApiReferenceHolder, IOpenApiResponse { - internal OpenApiResponse _target; - private readonly OpenApiReference _reference; - private string _description; - - /// - /// Gets the target response. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiResponse Target - { - get - { - _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -43,102 +23,43 @@ public OpenApiResponse Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiResponseReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiResponseReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Response, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - _reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Response, - ExternalResource = externalResource - }; - - Reference = _reference; } - internal OpenApiResponseReference(string referenceId, OpenApiResponse target) + internal OpenApiResponseReference(OpenApiResponse target, string referenceId):base(target, referenceId, ReferenceType.Response) { - _target ??= target; - - _reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Response, - }; - - Reference = _reference; } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target?.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } - private IDictionary _content; /// - public override IDictionary Content { get => _content is not null ? _content : Target?.Content; set => _content = value; } + public IDictionary Content { get => Target?.Content; } - private IDictionary _headers; /// - public override IDictionary Headers { get => _headers is not null ? _headers : Target?.Headers; set => _headers = value; } + public IDictionary Headers { get => Target?.Headers; } - private IDictionary _links; /// - public override IDictionary Links { get => _links is not null ? _links : Target?.Links; set => _links = value; } + public IDictionary Links { get => Target?.Links; } - private IDictionary _extensions; - /// - public override IDictionary Extensions { get => _extensions is not null ? _extensions : Target?.Extensions; set => _extensions = value; } - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - } - } - - /// - public override void SerializeAsV2(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV2(writer); - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); - } - } + public IDictionary Extensions { get => Target?.Extensions; } /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) + public override IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(IOpenApiResponse source) { - Utils.CheckArgumentNull(writer); - action(writer, this); + return source is OpenApiResponse ? new OpenApiResponse(this) : source; } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index ee0bf0c8f..a09d2eab9 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -235,7 +235,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode) rootNode.GetMap(), openApiDoc.Paths.Values .SelectMany(path => path.Operations?.Values ?? Enumerable.Empty()) - .SelectMany(operation => operation.Responses?.Values ?? Enumerable.Empty()), + .SelectMany(operation => operation.Responses?.Values ?? Enumerable.Empty()), openApiNode.Context); } @@ -257,11 +257,11 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode) return openApiDoc; } - private static void ProcessResponsesMediaTypes(MapNode mapNode, IEnumerable responses, ParsingContext context) + private static void ProcessResponsesMediaTypes(MapNode mapNode, IEnumerable responses, ParsingContext context) { if (responses != null) { - foreach (var response in responses) + foreach (var response in responses.OfType()) { ProcessProduces(mapNode, response, context); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 957a02ab7..140ad9f3d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -121,7 +121,7 @@ internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument h } } - foreach (var response in operation.Responses.Values) + foreach (var response in operation.Responses.Values.OfType()) { ProcessProduces(node.CheckMapNode("responses"), response, node.Context); } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index 2716c499b..d730c8227 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -179,7 +179,7 @@ private static void LoadExample(OpenApiResponse response, string mediaType, Pars mediaTypeObject.Example = exampleNode; } - public static OpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("response"); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs index c159443ad..a85ed5fe1 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -40,7 +41,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("response"); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs index 7288c04b1..6d03fe86b 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -17,8 +18,8 @@ internal static partial class OpenApiV3Deserializer public static readonly PatternFieldMap ResponsesPatternFields = new() { - {s => !s.StartsWith("x-"), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiResponses LoadResponses(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs index 8e4057a91..a71fd5369 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -45,7 +46,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("response"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index eadabbaaf..6fbcbcc4a 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -109,9 +109,9 @@ private void AddResponseToComponents(OpenApiResponse response, string referenceI { EnsureComponentsExist(); EnsureResponsesExist(); - if (!Components.Responses.ContainsKey(referenceId ?? response.Reference.Id)) + if (!Components.Responses.ContainsKey(referenceId)) { - Components.Responses.Add(referenceId ?? response.Reference.Id, response); + Components.Responses.Add(referenceId, response); } } private void AddRequestBodyToComponents(OpenApiRequestBody requestBody, string referenceId = null) @@ -210,7 +210,7 @@ private void EnsureParametersExist() private void EnsureResponsesExist() { - _target.Components.Responses ??= new Dictionary(); + _target.Components.Responses ??= new Dictionary(); } private void EnsureRequestBodiesExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index f118a3f06..b2eb9eab1 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -176,7 +176,7 @@ public virtual void Visit(IDictionary callbacks) /// /// Visits /// - public virtual void Visit(OpenApiResponse response) + public virtual void Visit(IOpenApiResponse response) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index b76f33ad9..41d7561ab 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -692,7 +692,7 @@ internal void Walk(OpenApiResponses responses) /// /// Visits and child objects /// - internal void Walk(OpenApiResponse response, bool isComponent = false) + internal void Walk(IOpenApiResponse response, bool isComponent = false) { if (response == null) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index a5a4885de..0e1251d2e 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -84,7 +84,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(IOpenApiHeader header) => Validate(header); /// - public override void Visit(OpenApiResponse response) => Validate(response); + public override void Visit(IOpenApiResponse response) => Validate(response); /// public override void Visit(OpenApiMediaType mediaType) => Validate(mediaType); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs index f30b49ea0..ff0503f9b 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs @@ -3,6 +3,7 @@ using System; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules @@ -16,7 +17,7 @@ public static class OpenApiResponseRules /// /// Validate the field is required. /// - public static ValidationRule ResponseRequiredFields => + public static ValidationRule ResponseRequiredFields => new(nameof(ResponseRequiredFields), (context, response) => { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index 3c3644adf..0d25c7704 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -60,7 +60,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200",new() + "200",new OpenApiResponse() { Description = "OK" } @@ -97,7 +97,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Success", Content = new Dictionary @@ -162,7 +162,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Success", Content = new Dictionary @@ -210,7 +210,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entities", Content = new Dictionary @@ -264,7 +264,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entity", Content = new Dictionary @@ -297,7 +297,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "204", new() + "204", new OpenApiResponse() { Description = "Success" } @@ -335,7 +335,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved navigation property", Content = new Dictionary @@ -390,7 +390,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Success", Content = new Dictionary @@ -432,7 +432,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "204", new() + "204", new OpenApiResponse() { Description = "Success" } @@ -454,7 +454,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved navigation property", Content = new Dictionary @@ -528,7 +528,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "204", new() + "204", new OpenApiResponse() { Description = "Success" } @@ -593,7 +593,7 @@ public static OpenApiDocument CreateOpenApiDocument() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Success", Content = new Dictionary diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index ad8495494..8440e8df4 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -74,7 +74,7 @@ public async Task LoadResponseReference() var reference = new OpenApiResponseReference("NotFound", result.Document); // Assert - reference.Should().BeEquivalentTo( + Assert.Equivalent( new OpenApiResponse { Description = "Entity not found.", @@ -82,7 +82,7 @@ public async Task LoadResponseReference() { ["application/json"] = new() } - }, options => options.Excluding(x => x.Reference) + }, reference ); } @@ -93,7 +93,7 @@ public async Task LoadResponseAndSchemaReference() var reference = new OpenApiResponseReference("GeneralError", result.Document); // Assert - reference.Should().BeEquivalentTo( + Assert.Equivalent( new OpenApiResponse { Description = "General Error", @@ -124,13 +124,8 @@ public async Task LoadResponseAndSchemaReference() } } } - }, - Reference = new() - { - Type = ReferenceType.Response, - Id = "GeneralError" } - }, options => options.Excluding(x => x.Reference) + }, reference ); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index 0b14a01f9..5993d4e2c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -178,7 +178,7 @@ public async Task ShouldParseProducesInAnyOrder() { Responses = { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "An OK response", Content = @@ -187,7 +187,7 @@ public async Task ShouldParseProducesInAnyOrder() ["application/xml"] = okMediaType, } }, - ["default"] = new() + ["default"] = new OpenApiResponse() { Description = "An error response", Content = @@ -202,7 +202,7 @@ public async Task ShouldParseProducesInAnyOrder() { Responses = { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "An OK response", Content = @@ -210,7 +210,7 @@ public async Task ShouldParseProducesInAnyOrder() ["html/text"] = okMediaType } }, - ["default"] = new() + ["default"] = new OpenApiResponse() { Description = "An error response", Content = @@ -224,7 +224,7 @@ public async Task ShouldParseProducesInAnyOrder() { Responses = { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "An OK response", Content = @@ -233,7 +233,7 @@ public async Task ShouldParseProducesInAnyOrder() ["application/xml"] = okMediaType, } }, - ["default"] = new() + ["default"] = new OpenApiResponse() { Description = "An error response", Content = diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index 35ffd15d5..a86d84bdd 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; using Xunit; @@ -116,7 +115,7 @@ public class OpenApiPathItemTests }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "Pet updated.", Content = new Dictionary @@ -125,7 +124,7 @@ public class OpenApiPathItemTests ["application/xml"] = new() } }, - ["405"] = new() + ["405"] = new OpenApiResponse() { Description = "Invalid input", Content = new Dictionary @@ -232,7 +231,7 @@ public class OpenApiPathItemTests }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "Pet updated.", Content = new Dictionary diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 267e29ede..c84788ba8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -43,7 +43,7 @@ public class OpenApiCallbackTests }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "Success" } @@ -83,7 +83,7 @@ public class OpenApiCallbackTests }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "Success" } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index c333fcdb7..5c905f238 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -1120,7 +1120,7 @@ public OpenApiDocumentTests() }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "pet response", Content = new Dictionary @@ -1143,7 +1143,7 @@ public OpenApiDocumentTests() } } }, - ["4XX"] = new() + ["4XX"] = new OpenApiResponse() { Description = "unexpected client error", Content = new Dictionary @@ -1154,7 +1154,7 @@ public OpenApiDocumentTests() } } }, - ["5XX"] = new() + ["5XX"] = new OpenApiResponse() { Description = "unexpected server error", Content = new Dictionary @@ -1185,7 +1185,7 @@ public OpenApiDocumentTests() }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "pet response", Content = new Dictionary @@ -1196,7 +1196,7 @@ public OpenApiDocumentTests() }, } }, - ["4XX"] = new() + ["4XX"] = new OpenApiResponse() { Description = "unexpected client error", Content = new Dictionary @@ -1207,7 +1207,7 @@ public OpenApiDocumentTests() } } }, - ["5XX"] = new() + ["5XX"] = new OpenApiResponse() { Description = "unexpected server error", Content = new Dictionary @@ -1248,7 +1248,7 @@ public OpenApiDocumentTests() }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "pet response", Content = new Dictionary @@ -1263,7 +1263,7 @@ public OpenApiDocumentTests() } } }, - ["4XX"] = new() + ["4XX"] = new OpenApiResponse() { Description = "unexpected client error", Content = new Dictionary @@ -1274,7 +1274,7 @@ public OpenApiDocumentTests() } } }, - ["5XX"] = new() + ["5XX"] = new OpenApiResponse() { Description = "unexpected server error", Content = new Dictionary @@ -1308,11 +1308,11 @@ public OpenApiDocumentTests() }, Responses = new() { - ["204"] = new() + ["204"] = new OpenApiResponse() { Description = "pet deleted" }, - ["4XX"] = new() + ["4XX"] = new OpenApiResponse() { Description = "unexpected client error", Content = new Dictionary @@ -1323,7 +1323,7 @@ public OpenApiDocumentTests() } } }, - ["5XX"] = new() + ["5XX"] = new OpenApiResponse() { Description = "unexpected server error", Content = new Dictionary diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 6b3c61417..df6b069ed 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -58,8 +58,22 @@ public class OpenApiOperationTests }, Responses = new() { - ["200"] = new OpenApiResponseReference("response1", hostDocument: null), - ["400"] = new() + ["200"] = new OpenApiResponseReference(new OpenApiResponse() + { + Content = new Dictionary + { + ["application/json"] = new() + { + Schema = new() + { + Type = JsonSchemaType.Number, + Minimum = 5, + Maximum = 10 + } + } + } + }, "response1"), + ["400"] = new OpenApiResponse() { Content = new Dictionary { @@ -132,8 +146,22 @@ public class OpenApiOperationTests }, Responses = new() { - ["200"] = new OpenApiResponseReference("response1", hostDocument: null), - ["400"] = new() + ["200"] = new OpenApiResponseReference(new OpenApiResponse() + { + Content = new Dictionary + { + ["application/json"] = new() + { + Schema = new() + { + Type = JsonSchemaType.Number, + Minimum = 5, + Maximum = 10 + } + } + } + }, "response1"), + ["400"] = new OpenApiResponse() { Content = new Dictionary { @@ -245,11 +273,11 @@ public class OpenApiOperationTests }, Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "Pet updated." }, - ["405"] = new() + ["405"] = new OpenApiResponse() { Description = "Invalid input" } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index 14d14e4be..f0991a1cb 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -101,7 +101,7 @@ public class OpenApiResponseTests } }; - public static OpenApiResponseReference V2OpenApiResponseReference = new OpenApiResponseReference("example1", ReferencedV2Response); + public static OpenApiResponseReference V2OpenApiResponseReference = new OpenApiResponseReference(ReferencedV2Response, "example1"); public static OpenApiResponse ReferencedV2Response = new OpenApiResponse { Description = "A complex object array response", @@ -136,7 +136,7 @@ public class OpenApiResponseTests }, } }; - public static OpenApiResponseReference V3OpenApiResponseReference = new OpenApiResponseReference("example1", ReferencedV3Response); + public static OpenApiResponseReference V3OpenApiResponseReference = new OpenApiResponseReference(ReferencedV3Response, "example1"); public static OpenApiResponse ReferencedV3Response = new OpenApiResponse { diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 61% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt index 3b61b5a39..a3164d20f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -1,3 +1,4 @@ { + "description": "OK response", "$ref": "#/components/responses/OkResponse" } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..851a6a027 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -0,0 +1,15 @@ +{ + "description": "OK response", + "content": { + "text/plain": { + "schema": { + "type": "object", + "properties": { + "sound": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..4d825baf4 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"description":"OK response","$ref":"#/components/responses/OkResponse"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..04256c77a --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"description":"OK response","content":{"text/plain":{"schema":{"type":"object","properties":{"sound":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..2408f8a10 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -0,0 +1,15 @@ +{ + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "object", + "properties": { + "sound": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index d4776f5df..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"$ref":"#/components/responses/OkResponse"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt similarity index 100% rename from test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt rename to test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..c83ea5371 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.SerializeResponseReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"description":"OK","content":{"text/plain":{"schema":{"type":"object","properties":{"sound":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs index b39d6040b..196759540 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs @@ -104,37 +104,41 @@ public void ResponseReferenceResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeResponseReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, false)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(false, true)] + public async Task SerializeResponseReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput}); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localResponseReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeResponseReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, false)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(false, true)] + public async Task SerializeResponseReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput}); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _localResponseReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 93aef1c4b..e5c9f7bb1 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -399,6 +399,12 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer); System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer); } + public interface IOpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + System.Collections.Generic.IDictionary Content { get; } + System.Collections.Generic.IDictionary Headers { get; } + System.Collections.Generic.IDictionary Links { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -440,7 +446,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? Parameters { get; set; } public System.Collections.Generic.IDictionary? PathItems { get; set; } public System.Collections.Generic.IDictionary? RequestBodies { get; set; } - public System.Collections.Generic.IDictionary? Responses { get; set; } + public System.Collections.Generic.IDictionary? Responses { get; set; } public System.Collections.Generic.IDictionary? Schemas { get; set; } public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -912,22 +918,20 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse { public OpenApiResponse() { } - public OpenApiResponse(Microsoft.OpenApi.Models.OpenApiResponse response) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public bool UnresolvedReference { get; set; } - public virtual System.Collections.Generic.IDictionary Content { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual System.Collections.Generic.IDictionary Headers { get; set; } - public virtual System.Collections.Generic.IDictionary Links { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiResponse(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } + public System.Collections.Generic.IDictionary Content { get; set; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public System.Collections.Generic.IDictionary Headers { get; set; } + public System.Collections.Generic.IDictionary Links { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponses : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary + public class OpenApiResponses : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary { public OpenApiResponses() { } public OpenApiResponses(Microsoft.OpenApi.Models.OpenApiResponses openApiResponses) { } @@ -1277,18 +1281,15 @@ namespace Microsoft.OpenApi.Models.References public override Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiResponseReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse { public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiResponse Target { get; } - public override System.Collections.Generic.IDictionary Content { get; set; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override System.Collections.Generic.IDictionary Headers { get; set; } - public override System.Collections.Generic.IDictionary Links { get; set; } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public System.Collections.Generic.IDictionary Content { get; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public System.Collections.Generic.IDictionary Headers { get; } + public System.Collections.Generic.IDictionary Links { get; } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse source) { } } public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1565,6 +1566,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1576,7 +1578,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } @@ -1664,6 +1665,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1675,7 +1677,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiOAuthFlow openApiOAuthFlow) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } @@ -1806,7 +1807,7 @@ namespace Microsoft.OpenApi.Validations.Rules [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiResponseRules { - public static Microsoft.OpenApi.Validations.ValidationRule ResponseRequiredFields { get; } + public static Microsoft.OpenApi.Validations.ValidationRule ResponseRequiredFields { get; } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiResponsesRules diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs index 7c21e1a6e..33296cfed6 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs @@ -157,7 +157,7 @@ public void AttachPathWorks() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entities" } @@ -182,7 +182,7 @@ public void AttachPathWorks() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entities" } @@ -249,7 +249,7 @@ public void HasOperationsWorks() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entity" } @@ -277,7 +277,7 @@ public void HasOperationsWorks() Responses = new() { { - "200", new() + "200", new OpenApiResponse() { Description = "Retrieved entity" } @@ -292,7 +292,7 @@ public void HasOperationsWorks() Responses = new() { { - "204", new() + "204", new OpenApiResponse() { Description = "Success." } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs index 317719fcd..d11786d5b 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs @@ -23,28 +23,30 @@ public class OpenApiValidatorTests [Fact] public void ResponseMustHaveADescription() { - var openApiDocument = new OpenApiDocument(); - openApiDocument.Info = new() - { - Title = "foo", - Version = "1.2.2" - }; - openApiDocument.Paths = new() + var openApiDocument = new OpenApiDocument { + Info = new() + { + Title = "foo", + Version = "1.2.2" + }, + Paths = new() { - "/test", - new OpenApiPathItem() - { - Operations = { - [OperationType.Get] = new() + "/test", + new OpenApiPathItem() { - Responses = + Operations = + { + [OperationType.Get] = new() { - ["200"] = new() + Responses = + { + ["200"] = new OpenApiResponse() + } } } - } + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiComponentsValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiComponentsValidationTests.cs index fe2a230e2..de83299fc 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiComponentsValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiComponentsValidationTests.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Validations.Rules; using Xunit; @@ -21,7 +22,7 @@ public void ValidateKeyMustMatchRegularExpressionInComponents() var components = new OpenApiComponents { - Responses = new Dictionary + Responses = new Dictionary { { key, new OpenApiResponse { Description = "any" } } } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index 646acdbcc..de9d58443 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -47,7 +47,7 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() { Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Content = new Dictionary { @@ -105,7 +105,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() { Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Content = new Dictionary { diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiResponseValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiResponseValidationTests.cs index c1b4ce62d..2350c184b 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiResponseValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiResponseValidationTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; using Xunit; @@ -22,15 +23,15 @@ public void ValidateDescriptionIsRequiredInResponse() // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); var walker = new OpenApiWalker(validator); - walker.Walk(response); + walker.Walk((IOpenApiResponse)response); errors = validator.Errors; - var result = !errors.Any(); // Assert - Assert.False(result); + Assert.NotEmpty(errors); Assert.NotNull(errors); - var error = Assert.Single(errors) as OpenApiValidatorError; + Assert.Single(errors); + var error = Assert.IsType(errors.First()); Assert.Equal(string.Format(SRResource.Validation_FieldIsRequired, "description", "response"), error.Message); Assert.Equal("#/description", error.Pointer); } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 49595a1be..fbe0abf14 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -35,7 +35,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IOpenApiRequestBody)); visitor.Visit(default(IDictionary)); visitor.Visit(default(IDictionary)); - visitor.Visit(default(OpenApiResponse)); + visitor.Visit(default(IOpenApiResponse)); visitor.Visit(default(OpenApiResponses)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiMediaType)); @@ -184,7 +184,7 @@ public override void Visit(IDictionary callbacks) base.Visit(callbacks); } - public override void Visit(OpenApiResponse response) + public override void Visit(IOpenApiResponse response) { EncodeCall(); base.Visit(response); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index c21233b9a..c4ed91658 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -74,7 +74,7 @@ public void LocatePathOperationContentSchema() { Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Content = new Dictionary { @@ -192,7 +192,7 @@ public void LocateReferences() { Responses = new() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Content = new Dictionary { @@ -284,7 +284,7 @@ public override void Visit(OpenApiOperation operation) Keys.Add(CurrentKeys.Operation.ToString()); Locations.Add(this.PathString); } - public override void Visit(OpenApiResponse response) + public override void Visit(IOpenApiResponse response) { Keys.Add(CurrentKeys.Response); Locations.Add(this.PathString); diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index bd74197b0..14e017fe9 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -27,7 +27,7 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { Responses = new OpenApiResponses() { - ["200"] = new() + ["200"] = new OpenApiResponse() { Content = new Dictionary() { diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index 5fc8be43b..f10dba764 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -464,7 +464,7 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() [OperationType.Get] = new() { Responses = { - ["200"] = new() + ["200"] = new OpenApiResponse() { Description = "OK", Content = { From 4060938e5f6e871d5d4c3931f91ce4a89f4f1e97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 21:53:38 +0000 Subject: [PATCH 039/103] chore(deps): bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge-dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index 3d9334e96..df4b487a7 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.2.0 + uses: dependabot/fetch-metadata@v2.3.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" From bf00f921a7eb490d506ab6bb4243ecf0c770762f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 21:53:41 +0000 Subject: [PATCH 040/103] chore(deps): bump docker/build-push-action from 6.12.0 to 6.13.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.12.0 to 6.13.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v6.12.0...v6.13.0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b4f6003dc..93c8f3e87 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -30,13 +30,13 @@ jobs: id: getversion - name: Push to registry - Nightly if: ${{ github.ref == 'refs/heads/dev' }} - uses: docker/build-push-action@v6.12.0 + uses: docker/build-push-action@v6.13.0 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly - name: Push to registry - Release if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/support/v1' }} - uses: docker/build-push-action@v6.12.0 + uses: docker/build-push-action@v6.13.0 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.getversion.outputs.version }} From 61e6a402f73304dbd7727fbf24640a99c12727cd Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 22:08:19 +0000 Subject: [PATCH 041/103] Updated for https://dev.azure.com/microsoftgraph/0985d294-5762-4bc2-a565-161ef349ca3e/_build?definitionId=107 by using baselines generated in https://dev.azure.com/microsoftgraph/0985d294-5762-4bc2-a565-161ef349ca3e/_build/results?buildId=178197 --- .config/1espt/PipelineAutobaseliningConfig.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.config/1espt/PipelineAutobaseliningConfig.yml b/.config/1espt/PipelineAutobaseliningConfig.yml index 2425160a4..a4d9608c6 100644 --- a/.config/1espt/PipelineAutobaseliningConfig.yml +++ b/.config/1espt/PipelineAutobaseliningConfig.yml @@ -13,3 +13,10 @@ pipelines: lastModifiedDate: 2024-09-13 armory: lastModifiedDate: 2024-09-13 + binary: + credscan: + lastModifiedDate: 2025-01-27 + binskim: + lastModifiedDate: 2025-01-27 + spotbugs: + lastModifiedDate: 2025-01-27 From aebefb76094e71718b1d60691e9ac12a95a25283 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Jan 2025 16:52:02 -0500 Subject: [PATCH 042/103] fix: open api schema reference proxy design pattern implementation Signed-off-by: Vincent Biret --- .../Formatters/PowerShellFormatter.cs | 46 +- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 2 +- .../StatsVisitor.cs | 2 +- .../Models/Interfaces/IOpenApiHeader.cs | 2 +- .../Models/Interfaces/IOpenApiParameter.cs | 2 +- .../Models/Interfaces/IOpenApiSchema.cs | 304 +++++++++++++ .../Models/OpenApiComponents.cs | 6 +- .../Models/OpenApiDocument.cs | 20 +- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 12 +- .../Models/OpenApiMediaType.cs | 10 +- .../Models/OpenApiParameter.cs | 16 +- .../Models/OpenApiRequestBody.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 417 ++++++------------ .../References/BaseOpenApiReferenceHolder.cs | 6 +- .../References/OpenApiHeaderReference.cs | 2 +- .../References/OpenApiParameterReference.cs | 2 +- .../References/OpenApiSchemaReference.cs | 287 ++++-------- .../Reader/ParseNodes/AnyFieldMapParameter.cs | 5 +- .../ParseNodes/AnyMapFieldMapParameter.cs | 5 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 9 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 21 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 7 +- .../Reader/V2/OpenApiResponseDeserializer.cs | 4 +- .../Reader/V2/OpenApiSchemaDeserializer.cs | 6 +- .../Reader/V3/OpenApiSchemaDeserializer.cs | 6 +- .../Reader/V31/OpenApiSchemaDeserializer.cs | 6 +- .../Services/CopyReferences.cs | 12 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 12 +- .../Validations/OpenApiValidator.cs | 2 +- .../Rules/OpenApiNonDefaultRules.cs | 4 +- .../Validations/Rules/OpenApiSchemaRules.cs | 12 +- .../Validations/Rules/RuleHelpers.cs | 3 +- .../Formatters/PowerShellFormatterTests.cs | 20 +- .../Services/OpenApiFilterServiceTests.cs | 2 +- .../UtilityFiles/OpenApiDocumentMock.cs | 91 ++-- .../TryLoadReferenceV2Tests.cs | 30 +- .../V2Tests/OpenApiDocumentTests.cs | 21 +- .../V2Tests/OpenApiHeaderTests.cs | 4 +- .../V2Tests/OpenApiOperationTests.cs | 14 +- .../V2Tests/OpenApiParameterTests.cs | 16 +- .../V2Tests/OpenApiPathItemTests.cs | 45 +- .../V2Tests/OpenApiSchemaTests.cs | 5 +- .../V31Tests/OpenApiDocumentTests.cs | 62 +-- .../V31Tests/OpenApiSchemaTests.cs | 37 +- .../V3Tests/OpenApiCallbackTests.cs | 8 +- .../V3Tests/OpenApiDocumentTests.cs | 163 ++++--- .../V3Tests/OpenApiEncodingTests.cs | 2 +- .../V3Tests/OpenApiMediaTypeTests.cs | 4 +- .../V3Tests/OpenApiOperationTests.cs | 4 +- .../V3Tests/OpenApiParameterTests.cs | 32 +- .../V3Tests/OpenApiSchemaTests.cs | 30 +- .../Models/OpenApiCallbackTests.cs | 4 +- .../Models/OpenApiComponentsTests.cs | 54 +-- .../Models/OpenApiDocumentTests.cs | 171 ++++--- .../Models/OpenApiHeaderTests.cs | 4 +- .../Models/OpenApiOperationTests.cs | 26 +- .../Models/OpenApiParameterTests.cs | 50 +-- .../Models/OpenApiRequestBodyTests.cs | 4 +- .../Models/OpenApiResponseTests.cs | 31 +- .../Models/OpenApiSchemaTests.cs | 75 ++-- .../OpenApiRequestBodyReferenceTests.cs | 6 +- .../OpenApiResponseReferenceTest.cs | 6 +- .../PublicApi/PublicApi.approved.txt | 310 +++++++------ .../OpenApiMediaTypeValidationTests.cs | 6 +- .../OpenApiParameterValidationTests.cs | 10 +- .../OpenApiReferenceValidationTests.cs | 25 +- .../OpenApiSchemaValidationTests.cs | 48 +- .../Visitors/InheritanceTests.cs | 4 +- .../Walkers/WalkerLocationTests.cs | 24 +- .../Workspaces/OpenApiWorkspaceTests.cs | 26 +- .../Writers/OpenApiYamlWriterTests.cs | 9 +- 72 files changed, 1365 insertions(+), 1374 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index a6b6380d6..2224f6f96 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -16,7 +16,7 @@ internal class PowerShellFormatter : OpenApiVisitorBase { private const string DefaultPutPrefix = ".Update"; private const string PowerShellPutPrefix = ".Set"; - private readonly Stack _schemaLoop = new(); + private readonly Stack _schemaLoop = new(); private static readonly Regex s_oDataCastRegex = new("(.*(?<=[a-z]))\\.(As(?=[A-Z]).*)", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); private static readonly Regex s_hashSuffixRegex = new(@"^[^-]+", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); private static readonly Regex s_oDataRefRegex = new("(?<=[a-z])Ref(?=[A-Z])", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); @@ -42,7 +42,7 @@ static PowerShellFormatter() // 5. Fix anyOf and oneOf schema. // 6. Add AdditionalProperties to object schemas. - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { AddAdditionalPropertiesToSchema(schema); ResolveAnyOfSchema(schema); @@ -165,10 +165,10 @@ private static void ResolveFunctionParameters(IList parameter // Replace content with a schema object of type array // for structured or collection-valued function parameters parameter.Content = null; - parameter.Schema = new() + parameter.Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -176,11 +176,11 @@ private static void ResolveFunctionParameters(IList parameter } } - private void AddAdditionalPropertiesToSchema(OpenApiSchema schema) + private void AddAdditionalPropertiesToSchema(IOpenApiSchema schema) { - if (schema != null && !_schemaLoop.Contains(schema) && schema.Type.Equals(JsonSchemaType.Object)) + if (schema is OpenApiSchema openApiSchema && !_schemaLoop.Contains(schema) && schema.Type.Equals(JsonSchemaType.Object)) { - schema.AdditionalProperties = new() { Type = JsonSchemaType.Object }; + openApiSchema.AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Object }; /* Because 'additionalProperties' are now being walked, * we need a way to keep track of visited schemas to avoid @@ -190,39 +190,29 @@ private void AddAdditionalPropertiesToSchema(OpenApiSchema schema) } } - private static void ResolveOneOfSchema(OpenApiSchema schema) + private static void ResolveOneOfSchema(IOpenApiSchema schema) { - if (schema.OneOf?.FirstOrDefault() is { } newSchema) + if (schema is OpenApiSchema openApiSchema && schema.OneOf?.FirstOrDefault() is OpenApiSchema newSchema) { - schema.OneOf = null; - FlattenSchema(schema, newSchema); + openApiSchema.OneOf = null; + FlattenSchema(openApiSchema, newSchema); } } - private static void ResolveAnyOfSchema(OpenApiSchema schema) + private static void ResolveAnyOfSchema(IOpenApiSchema schema) { - if (schema.AnyOf?.FirstOrDefault() is { } newSchema) + if (schema is OpenApiSchema openApiSchema && schema.AnyOf?.FirstOrDefault() is OpenApiSchema newSchema) { - schema.AnyOf = null; - FlattenSchema(schema, newSchema); + openApiSchema.AnyOf = null; + FlattenSchema(openApiSchema, newSchema); } } private static void FlattenSchema(OpenApiSchema schema, OpenApiSchema newSchema) { - if (newSchema != null) - { - if (newSchema.Reference != null) - { - schema.Reference = newSchema.Reference; - schema.UnresolvedReference = true; - } - else - { - // Copies schema properties based on https://github.com/microsoft/OpenAPI.NET.OData/pull/264. - CopySchema(schema, newSchema); - } - } + if (newSchema is null) return; + // Copies schema properties based on https://github.com/microsoft/OpenAPI.NET.OData/pull/264. + CopySchema(schema, newSchema); } private static void CopySchema(OpenApiSchema schema, OpenApiSchema newSchema) diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index 645f94319..d157a6c42 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -20,7 +20,7 @@ public override void Visit(IOpenApiParameter parameter) public int SchemaCount { get; set; } - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { SchemaCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs index fbf9f3c9a..85dc824a4 100644 --- a/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Workbench/StatsVisitor.cs @@ -20,7 +20,7 @@ public override void Visit(IOpenApiParameter parameter) public int SchemaCount { get; set; } - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { SchemaCount++; } diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs index 9931775c7..9caca85f6 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs @@ -45,7 +45,7 @@ public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiSerializable /// /// The schema defining the type used for the request body. /// - public OpenApiSchema Schema { get; } + public IOpenApiSchema Schema { get; } /// /// Example of the media type. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs index 363cc1cd4..ff6c2994f 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs @@ -72,7 +72,7 @@ public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializa /// /// The schema defining the type used for the parameter. /// - public OpenApiSchema Schema { get; } + public IOpenApiSchema Schema { get; } /// /// Examples of the media type. Each example SHOULD contain a value diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs new file mode 100644 index 000000000..5495ab307 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs @@ -0,0 +1,304 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the schema object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + + /// + /// Follow JSON Schema definition. Short text providing information about the data. + /// + public string Title { get; } + + /// + /// $schema, a JSON Schema dialect identifier. Value must be a URI + /// + public string Schema { get; } + + /// + /// $id - Identifies a schema resource with its canonical URI. + /// + public string Id { get; } + + /// + /// $comment - reserves a location for comments from schema authors to readers or maintainers of the schema. + /// + public string Comment { get; } + + /// + /// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema. + /// + public IDictionary Vocabulary { get; } + + /// + /// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance + /// + public string DynamicRef { get; } + + /// + /// $dynamicAnchor - used to create plain name fragments that are not tied to any particular structural location for referencing purposes, which are taken into consideration for dynamic referencing. + /// + public string DynamicAnchor { get; } + + /// + /// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema. + /// The keyword does not directly affect the validation result + /// + public IDictionary Definitions { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public decimal? V31ExclusiveMaximum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public decimal? V31ExclusiveMinimum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public bool UnEvaluatedProperties { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Value MUST be a string in V2 and V3. + /// + public JsonSchemaType? Type { get; } + + /// + /// Follow JSON Schema definition: https://json-schema.org/draft/2020-12/json-schema-validation + /// + public string Const { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// While relying on JSON Schema's defined formats, + /// the OAS offers a few additional predefined formats. + /// + public string Format { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public decimal? Maximum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public bool? ExclusiveMaximum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public decimal? Minimum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public bool? ExclusiveMinimum { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MaxLength { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MinLength { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect + /// + public string Pattern { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public decimal? MultipleOf { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided. + /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. + /// For example, if type is string, then default can be "foo" but cannot be 1. + /// + public JsonNode Default { get; } + + /// + /// Relevant only for Schema "properties" definitions. Declares the property as "read only". + /// This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request. + /// If the property is marked as readOnly being true and is in the required list, + /// the required will take effect on the response only. + /// A property MUST NOT be marked as both readOnly and writeOnly being true. + /// Default value is false. + /// + public bool ReadOnly { get; } + + /// + /// Relevant only for Schema "properties" definitions. Declares the property as "write only". + /// Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response. + /// If the property is marked as writeOnly being true and is in the required list, + /// the required will take effect on the request only. + /// A property MUST NOT be marked as both readOnly and writeOnly being true. + /// Default value is false. + /// + public bool WriteOnly { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. + /// + public IList AllOf { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. + /// + public IList OneOf { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. + /// + public IList AnyOf { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. + /// + public IOpenApiSchema Not { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public ISet Required { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object + /// and not a standard JSON Schema. items MUST be present if the type is array. + /// + public IOpenApiSchema Items { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MaxItems { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MinItems { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public bool? UniqueItems { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced). + /// + public IDictionary Properties { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// PatternProperty definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced) + /// Each property name of this object SHOULD be a valid regular expression according to the ECMA 262 r + /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST + /// be a valid Schema Object not a standard JSON Schema. + /// + public IDictionary PatternProperties { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MaxProperties { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public int? MinProperties { get; } + + /// + /// Indicates if the schema can contain properties other than those defined by the properties map. + /// + public bool AdditionalPropertiesAllowed { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// Value can be boolean or object. Inline or referenced schema + /// MUST be of a Schema Object and not a standard JSON Schema. + /// + public IOpenApiSchema AdditionalProperties { get; } + + /// + /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate + /// between other schemas which may satisfy the payload description. + /// + public OpenApiDiscriminator Discriminator { get; } + + /// + /// A free-form property to include an example of an instance for this schema. + /// To represent examples that cannot be naturally represented in JSON or YAML, + /// a string value can be used to contain the example with escaping where necessary. + /// + public JsonNode Example { get; } + + /// + /// A free-form property to include examples of an instance for this schema. + /// To represent examples that cannot be naturally represented in JSON or YAML, + /// a list of values can be used to contain the examples with escaping where necessary. + /// + public IList Examples { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public IList Enum { get; } + + /// + /// Allows sending a null value for the defined schema. Default value is false. + /// + public bool Nullable { get; } + + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// + public bool UnevaluatedProperties { get; } + + /// + /// Additional external documentation for this schema. + /// + public OpenApiExternalDocs ExternalDocs { get; } + + /// + /// Specifies that a schema is deprecated and SHOULD be transitioned out of usage. + /// Default value is false. + /// + public bool Deprecated { get; } + + /// + /// This MAY be used only on properties schemas. It has no effect on root schemas. + /// Adds additional metadata to describe the XML representation of this property. + /// + public OpenApiXml Xml { get; } + + /// + /// This object stores any unrecognized keywords found in the schema. + /// + public IDictionary UnrecognizedKeywords { get; } + + /// + public IDictionary Annotations { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 6d65ef7b1..6b735087e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -18,9 +18,9 @@ namespace Microsoft.OpenApi.Models public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible { /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? Schemas { get; set; } = new Dictionary(); + public IDictionary? Schemas { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -85,7 +85,7 @@ public OpenApiComponents() { } /// public OpenApiComponents(OpenApiComponents? components) { - Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; + Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 32afbdf90..eaf436793 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -239,10 +239,10 @@ public void SerializeAsV2(IOpenApiWriter writer) { var loops = writer.GetSettings().LoopDetector.Loops; - if (loops.TryGetValue(typeof(OpenApiSchema), out var schemas)) + if (loops.TryGetValue(typeof(IOpenApiSchema), out var schemas)) { - var openApiSchemas = schemas.Cast().Distinct().ToList() - .ToDictionary(k => k.Reference.Id); + var openApiSchemas = schemas.Cast().Distinct().OfType() + .ToDictionary(k => k.Reference.Id, v => v); foreach (var schema in openApiSchemas.Values.ToList()) { @@ -588,7 +588,7 @@ public bool AddComponent(string id, T componentToRegister) switch (componentToRegister) { case OpenApiSchema openApiSchema: - Components.Schemas ??= new Dictionary(); + Components.Schemas ??= new Dictionary(); Components.Schemas.Add(id, openApiSchema); break; case OpenApiParameter openApiParameter: @@ -636,9 +636,9 @@ public bool AddComponent(string id, T componentToRegister) internal class FindSchemaReferences : OpenApiVisitorBase { - private Dictionary Schemas = new(); + private Dictionary Schemas = new(StringComparer.Ordinal); - public static void ResolveSchemas(OpenApiComponents? components, Dictionary schemas) + public static void ResolveSchemas(OpenApiComponents? components, Dictionary schemas) { var visitor = new FindSchemaReferences(); visitor.Schemas = schemas; @@ -651,7 +651,7 @@ public override void Visit(IOpenApiReferenceHolder referenceHolder) { switch (referenceHolder) { - case OpenApiSchema schema: + case OpenApiSchemaReference schema: if (!Schemas.ContainsKey(schema.Reference.Id)) { Schemas.Add(schema.Reference.Id, schema); @@ -664,12 +664,12 @@ public override void Visit(IOpenApiReferenceHolder referenceHolder) base.Visit(referenceHolder); } - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { // This is needed to handle schemas used in Responses in components - if (schema.Reference != null && !Schemas.ContainsKey(schema.Reference.Id)) + if (schema is OpenApiSchemaReference {Reference: not null} schemaReference && !Schemas.ContainsKey(schemaReference.Reference.Id)) { - Schemas.Add(schema.Reference.Id, schema); + Schemas.Add(schemaReference.Reference.Id, schema); } base.Visit(schema); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 1f382220b..d1240bbd0 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -40,7 +41,7 @@ public class OpenApiHeader : IOpenApiHeader, IOpenApiReferenceable, IOpenApiExte public bool AllowReserved { get; set; } /// - public OpenApiSchema Schema { get; set; } + public IOpenApiSchema Schema { get; set; } /// public JsonNode Example { get; set; } @@ -71,7 +72,7 @@ public OpenApiHeader(IOpenApiHeader header) Style = header?.Style ?? Style; Explode = header?.Explode ?? Explode; AllowReserved = header?.AllowReserved ?? AllowReserved; - Schema = header?.Schema != null ? new(header.Schema) : null; + Schema = header?.Schema != null ? new OpenApiSchema(header.Schema) : null; Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; @@ -171,7 +172,12 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); // schema - Schema.WriteAsItemsProperties(writer); + var targetSchema = Schema switch { + OpenApiSchemaReference schemaReference => schemaReference.Target, + OpenApiSchema schema => schema, + _ => null, + }; + targetSchema?.WriteAsItemsProperties(writer); // example writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, s) => w.WriteAny(s)); diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 23acd0de9..d350c3251 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -19,16 +19,10 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible { - private OpenApiSchema? _schema; - /// /// The schema defining the type used for the request body. /// - public virtual OpenApiSchema? Schema - { - get => _schema; - set => _schema = value; - } + public virtual IOpenApiSchema? Schema { get; set; } /// /// Example of the media type. @@ -65,7 +59,7 @@ public OpenApiMediaType() { } /// public OpenApiMediaType(OpenApiMediaType? mediaType) { - _schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; + Schema = mediaType?.Schema != null ? new OpenApiSchema(mediaType.Schema) : null; Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; Encoding = mediaType?.Encoding != null ? new Dictionary(mediaType.Encoding) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 87a761c8b..27c443a5b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -9,6 +9,7 @@ using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -57,7 +58,7 @@ public bool Explode public bool AllowReserved { get; set; } /// - public OpenApiSchema Schema { get; set; } + public IOpenApiSchema Schema { get; set; } /// public IDictionary Examples { get; set; } = new Dictionary(); @@ -89,7 +90,7 @@ public OpenApiParameter(IOpenApiParameter parameter) Style = parameter.Style ?? Style; Explode = parameter.Explode; AllowReserved = parameter.AllowReserved; - Schema = parameter.Schema != null ? new(parameter.Schema) : null; + Schema = parameter.Schema != null ? new OpenApiSchema(parameter.Schema) : null; Examples = parameter.Examples != null ? new Dictionary(parameter.Examples) : null; Example = parameter.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; Content = parameter.Content != null ? new Dictionary(parameter.Content) : null; @@ -207,7 +208,7 @@ public void SerializeAsV2(IOpenApiWriter writer) } // In V2 parameter's type can't be a reference to a custom object schema or can't be of type object // So in that case map the type as string. - else if (Schema?.UnresolvedReference == true || Schema?.Type == JsonSchemaType.Object) + else if (Schema is OpenApiSchemaReference { UnresolvedReference: true } || (Schema?.Type & JsonSchemaType.Object) == JsonSchemaType.Object) { writer.WriteProperty(OpenApiConstants.Type, "string"); } @@ -230,9 +231,14 @@ public void SerializeAsV2(IOpenApiWriter writer) // uniqueItems // enum // multipleOf - if (Schema != null) + var targetSchema = Schema switch { + OpenApiSchemaReference schemaReference => schemaReference.Target, + OpenApiSchema schema => schema, + _ => null, + }; + if (targetSchema is not null) { - Schema.WriteAsItemsProperties(writer); + targetSchema.WriteAsItemsProperties(writer); var extensions = Schema.Extensions; if (extensions != null) { diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index b5fd3f605..029a6d407 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -123,7 +123,7 @@ public IEnumerable ConvertToFormDataParameters(IOpenApiWriter foreach (var property in Content.First().Value.Schema.Properties) { - var paramSchema = property.Value; + var paramSchema = new OpenApiSchema(property.Value); if ((paramSchema.Type & JsonSchemaType.String) == JsonSchemaType.String && ("binary".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase) || "base64".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase))) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index ff5a8eb48..aae5723e8 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -15,316 +16,163 @@ namespace Microsoft.OpenApi.Models /// /// The Schema Object allows the definition of input and output data types. /// - public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiReferenceable, IOpenApiReferenceHolder - {//TODO remove the implementation of IOpenAPiReferenceHolder when we have removed the inheritance from the inheritance type to this type - /// - /// Follow JSON Schema definition. Short text providing information about the data. - /// - public virtual string Title { get; set; } - - /// - /// $schema, a JSON Schema dialect identifier. Value must be a URI - /// - public virtual string Schema { get; set; } - - /// - /// $id - Identifies a schema resource with its canonical URI. - /// - public virtual string Id { get; set; } + public class OpenApiSchema : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiSchema + { + /// + public string Title { get; set; } - /// - /// $comment - reserves a location for comments from schema authors to readers or maintainers of the schema. - /// - public virtual string Comment { get; set; } + /// + public string Schema { get; set; } - /// - /// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema. - /// - public virtual IDictionary Vocabulary { get; set; } + /// + public string Id { get; set; } - /// - /// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance - /// - public virtual string DynamicRef { get; set; } + /// + public string Comment { get; set; } - /// - /// $dynamicAnchor - used to create plain name fragments that are not tied to any particular structural location for referencing purposes, which are taken into consideration for dynamic referencing. - /// - public virtual string DynamicAnchor { get; set; } + /// + public IDictionary Vocabulary { get; set; } - /// - /// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema. - /// The keyword does not directly affect the validation result - /// - public virtual IDictionary Definitions { get; set; } + /// + public string DynamicRef { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual decimal? V31ExclusiveMaximum { get; set; } + /// + public string DynamicAnchor { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual decimal? V31ExclusiveMinimum { get; set; } + /// + public IDictionary Definitions { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual bool UnEvaluatedProperties { get; set; } + /// + public decimal? V31ExclusiveMaximum { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Value MUST be a string in V2 and V3. - /// - public virtual JsonSchemaType? Type { get; set; } + /// + public decimal? V31ExclusiveMinimum { get; set; } - /// - /// Follow JSON Schema definition: https://json-schema.org/draft/2020-12/json-schema-validation - /// - public virtual string Const { get; set; } + /// + public bool UnEvaluatedProperties { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// While relying on JSON Schema's defined formats, - /// the OAS offers a few additional predefined formats. - /// - public virtual string Format { get; set; } + /// + public JsonSchemaType? Type { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// CommonMark syntax MAY be used for rich text representation. - /// - public virtual string Description { get; set; } + /// + public string Const { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual decimal? Maximum { get; set; } + /// + public string Format { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual bool? ExclusiveMaximum { get; set; } + /// + public string Description { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual decimal? Minimum { get; set; } + /// + public decimal? Maximum { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual bool? ExclusiveMinimum { get; set; } + /// + public bool? ExclusiveMaximum { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MaxLength { get; set; } + /// + public decimal? Minimum { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MinLength { get; set; } + /// + public bool? ExclusiveMinimum { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect - /// - public virtual string Pattern { get; set; } + /// + public int? MaxLength { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual decimal? MultipleOf { get; set; } + /// + public int? MinLength { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided. - /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. - /// For example, if type is string, then default can be "foo" but cannot be 1. - /// - public virtual JsonNode Default { get; set; } + /// + public string Pattern { get; set; } - /// - /// Relevant only for Schema "properties" definitions. Declares the property as "read only". - /// This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request. - /// If the property is marked as readOnly being true and is in the required list, - /// the required will take effect on the response only. - /// A property MUST NOT be marked as both readOnly and writeOnly being true. - /// Default value is false. - /// - public virtual bool ReadOnly { get; set; } + /// + public decimal? MultipleOf { get; set; } - /// - /// Relevant only for Schema "properties" definitions. Declares the property as "write only". - /// Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response. - /// If the property is marked as writeOnly being true and is in the required list, - /// the required will take effect on the request only. - /// A property MUST NOT be marked as both readOnly and writeOnly being true. - /// Default value is false. - /// - public virtual bool WriteOnly { get; set; } + /// + public JsonNode Default { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public virtual IList AllOf { get; set; } = new List(); + /// + public bool ReadOnly { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public virtual IList OneOf { get; set; } = new List(); + /// + public bool WriteOnly { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public virtual IList AnyOf { get; set; } = new List(); + /// + public IList AllOf { get; set; } = []; - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public virtual OpenApiSchema Not { get; set; } + /// + public IList OneOf { get; set; } = []; - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual ISet Required { get; set; } = new HashSet(); + /// + public IList AnyOf { get; set; } = []; - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object - /// and not a standard JSON Schema. items MUST be present if the type is array. - /// - public virtual OpenApiSchema Items { get; set; } + /// + public IOpenApiSchema Not { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MaxItems { get; set; } + /// + public ISet Required { get; set; } = new HashSet(); - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MinItems { get; set; } + /// + public IOpenApiSchema Items { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual bool? UniqueItems { get; set; } + /// + public int? MaxItems { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced). - /// - public virtual IDictionary Properties { get; set; } = new Dictionary(); + /// + public int? MinItems { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// PatternProperty definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced) - /// Each property name of this object SHOULD be a valid regular expression according to the ECMA 262 r - /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST - /// be a valid Schema Object not a standard JSON Schema. - /// - public virtual IDictionary PatternProperties { get; set; } = new Dictionary(); + /// + public bool? UniqueItems { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MaxProperties { get; set; } + /// + public IDictionary Properties { get; set; } = new Dictionary(StringComparer.Ordinal); - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual int? MinProperties { get; set; } + /// + public IDictionary PatternProperties { get; set; } = new Dictionary(StringComparer.Ordinal); - /// - /// Indicates if the schema can contain properties other than those defined by the properties map. - /// - public virtual bool AdditionalPropertiesAllowed { get; set; } = true; + /// + public int? MaxProperties { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// Value can be boolean or object. Inline or referenced schema - /// MUST be of a Schema Object and not a standard JSON Schema. - /// - public virtual OpenApiSchema AdditionalProperties { get; set; } + /// + public int? MinProperties { get; set; } - /// - /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate - /// between other schemas which may satisfy the payload description. - /// - public virtual OpenApiDiscriminator Discriminator { get; set; } + /// + public bool AdditionalPropertiesAllowed { get; set; } = true; - /// - /// A free-form property to include an example of an instance for this schema. - /// To represent examples that cannot be naturally represented in JSON or YAML, - /// a string value can be used to contain the example with escaping where necessary. - /// - public virtual JsonNode Example { get; set; } + /// + public IOpenApiSchema AdditionalProperties { get; set; } - /// - /// A free-form property to include examples of an instance for this schema. - /// To represent examples that cannot be naturally represented in JSON or YAML, - /// a list of values can be used to contain the examples with escaping where necessary. - /// - public virtual IList Examples { get; set; } + /// + public OpenApiDiscriminator Discriminator { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual IList Enum { get; set; } = new List(); + /// + public JsonNode Example { get; set; } - /// - /// Allows sending a null value for the defined schema. Default value is false. - /// - public virtual bool Nullable { get; set; } + /// + public IList Examples { get; set; } - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - public virtual bool UnevaluatedProperties { get; set;} + /// + public IList Enum { get; set; } = new List(); - /// - /// Additional external documentation for this schema. - /// - public virtual OpenApiExternalDocs ExternalDocs { get; set; } + /// + public bool Nullable { get; set; } - /// - /// Specifies that a schema is deprecated and SHOULD be transitioned out of usage. - /// Default value is false. - /// - public virtual bool Deprecated { get; set; } + /// + public bool UnevaluatedProperties { get; set;} - /// - /// This MAY be used only on properties schemas. It has no effect on root schemas. - /// Adds additional metadata to describe the XML representation of this property. - /// - public virtual OpenApiXml Xml { get; set; } + /// + public OpenApiExternalDocs ExternalDocs { get; set; } - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public bool Deprecated { get; set; } - /// - /// This object stores any unrecognized keywords found in the schema. - /// - public virtual IDictionary UnrecognizedKeywords { get; set; } = new Dictionary(); + /// + public OpenApiXml Xml { get; set; } - /// - /// Indicates object is a placeholder reference to an actual object and does not contain valid data. - /// - public virtual bool UnresolvedReference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); - /// - /// Reference object. - /// - public virtual OpenApiReference Reference { get; set; } + /// + public IDictionary UnrecognizedKeywords { get; set; } = new Dictionary(); /// public IDictionary Annotations { get; set; } @@ -335,9 +183,10 @@ public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiRe public OpenApiSchema() { } /// - /// Initializes a copy of object + /// Initializes a copy of object /// - public OpenApiSchema(OpenApiSchema schema) + /// The schema object to copy from. + public OpenApiSchema(IOpenApiSchema schema) { Title = schema?.Title ?? Title; Id = schema?.Id ?? Id; @@ -347,7 +196,7 @@ public OpenApiSchema(OpenApiSchema schema) Vocabulary = schema?.Vocabulary != null ? new Dictionary(schema.Vocabulary) : null; DynamicAnchor = schema?.DynamicAnchor ?? DynamicAnchor; DynamicRef = schema?.DynamicRef ?? DynamicRef; - Definitions = schema?.Definitions != null ? new Dictionary(schema.Definitions) : null; + Definitions = schema?.Definitions != null ? new Dictionary(schema.Definitions) : null; UnevaluatedProperties = schema?.UnevaluatedProperties ?? UnevaluatedProperties; V31ExclusiveMaximum = schema?.V31ExclusiveMaximum ?? V31ExclusiveMaximum; V31ExclusiveMinimum = schema?.V31ExclusiveMinimum ?? V31ExclusiveMinimum; @@ -365,21 +214,21 @@ public OpenApiSchema(OpenApiSchema schema) Default = schema?.Default != null ? JsonNodeCloneHelper.Clone(schema?.Default) : null; ReadOnly = schema?.ReadOnly ?? ReadOnly; WriteOnly = schema?.WriteOnly ?? WriteOnly; - AllOf = schema?.AllOf != null ? new List(schema.AllOf) : null; - OneOf = schema?.OneOf != null ? new List(schema.OneOf) : null; - AnyOf = schema?.AnyOf != null ? new List(schema.AnyOf) : null; - Not = schema?.Not != null ? new(schema?.Not) : null; + AllOf = schema?.AllOf != null ? new List(schema.AllOf) : null; + OneOf = schema?.OneOf != null ? new List(schema.OneOf) : null; + AnyOf = schema?.AnyOf != null ? new List(schema.AnyOf) : null; + Not = schema?.Not != null ? new OpenApiSchema(schema?.Not) : null; Required = schema?.Required != null ? new HashSet(schema.Required) : null; - Items = schema?.Items != null ? new(schema?.Items) : null; + Items = schema?.Items != null ? new OpenApiSchema(schema?.Items) : null; MaxItems = schema?.MaxItems ?? MaxItems; MinItems = schema?.MinItems ?? MinItems; UniqueItems = schema?.UniqueItems ?? UniqueItems; - Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; - PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; + Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; + PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; MaxProperties = schema?.MaxProperties ?? MaxProperties; MinProperties = schema?.MinProperties ?? MinProperties; AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; - AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; + AdditionalProperties = schema?.AdditionalProperties != null ? new OpenApiSchema(schema?.AdditionalProperties) : null; Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; Example = schema?.Example != null ? JsonNodeCloneHelper.Clone(schema?.Example) : null; Examples = schema?.Examples != null ? new List(schema.Examples) : null; @@ -389,24 +238,18 @@ public OpenApiSchema(OpenApiSchema schema) Deprecated = schema?.Deprecated ?? Deprecated; Xml = schema?.Xml != null ? new(schema?.Xml) : null; Extensions = schema?.Extensions != null ? new Dictionary(schema.Extensions) : null; - UnresolvedReference = schema?.UnresolvedReference ?? UnresolvedReference; - Reference = schema?.Reference != null ? new(schema?.Reference) : null; Annotations = schema?.Annotations != null ? new Dictionary(schema?.Annotations) : null; UnrecognizedKeywords = schema?.UnrecognizedKeywords != null ? new Dictionary(schema?.UnrecognizedKeywords) : null; } - /// - /// Serialize to Open Api v3.1 - /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + /// + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } - /// - /// Serialize to Open Api v3.0 - /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + /// + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } @@ -551,9 +394,8 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteEndObject(); } -/// - - public virtual void SerializeAsV2(IOpenApiWriter writer) + /// + public void SerializeAsV2(IOpenApiWriter writer) { SerializeAsV2(writer: writer, parentRequiredProperties: new HashSet(), propertyName: null); } @@ -654,7 +496,7 @@ private void WriteFormatProperty(IOpenApiWriter writer) /// The open api writer. /// The list of required properties in parent schema. /// The property name that will be serialized. - internal virtual void SerializeAsV2( + private void SerializeAsV2( IOpenApiWriter writer, ISet parentRequiredProperties, string propertyName) @@ -745,7 +587,12 @@ internal virtual void SerializeAsV2( // properties writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, key, s) => - s.SerializeAsV2(w, Required, key)); + { + if (s is OpenApiSchema oais) + oais.SerializeAsV2(w, Required, key); + else + s.SerializeAsV2(w); + }); // additionalProperties if (AdditionalPropertiesAllowed) diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index d7205f37c..9b8c1be28 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -10,7 +10,7 @@ namespace Microsoft.OpenApi.Models.References; /// The interface type for the model. public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V where V : IOpenApiSerializable { - internal T _target; + private T _target; /// public T Target { @@ -72,7 +72,7 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc /// public abstract V CopyReferenceAsTargetElementWithOverrides(V source); /// - public void SerializeAsV3(IOpenApiWriter writer) + public virtual void SerializeAsV3(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { @@ -85,7 +85,7 @@ public void SerializeAsV3(IOpenApiWriter writer) } /// - public void SerializeAsV31(IOpenApiWriter writer) + public virtual void SerializeAsV31(IOpenApiWriter writer) { if (!writer.GetSettings().ShouldInlineReference(Reference)) { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index dfbee5ce7..bca77ff29 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -64,7 +64,7 @@ public string Description public bool AllowEmptyValue { get => Target?.AllowEmptyValue ?? default; } /// - public OpenApiSchema Schema { get => Target?.Schema; } + public IOpenApiSchema Schema { get => Target?.Schema; } /// public ParameterStyle? Style { get => Target?.Style; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 82c73afda..0f5137cf3 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -68,7 +68,7 @@ public string Description public bool AllowReserved { get => Target?.AllowReserved ?? default; } /// - public OpenApiSchema Schema { get => Target?.Schema; } + public IOpenApiSchema Schema { get => Target?.Schema; } /// public IDictionary Examples { get => Target?.Examples; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 731f9c1af..d31ba1950 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; using System; using System.Collections.Generic; @@ -12,79 +13,8 @@ namespace Microsoft.OpenApi.Models.References /// /// Schema reference object /// - public class OpenApiSchemaReference : OpenApiSchema, IOpenApiReferenceHolder + public class OpenApiSchemaReference : BaseOpenApiReferenceHolder, IOpenApiSchema { -#nullable enable - private OpenApiSchema? _target; - private readonly OpenApiReference _reference; - private string? _description; - private JsonNode? _default; - private JsonNode? _example; - private IList? _examples; - private bool? _nullable; - private IDictionary? _properties; - private string? _title; - private string? _schema; - private string? _comment; - private string? _id; - private string? _dynamicRef; - private string? _dynamicAnchor; - private IDictionary? _vocabulary; - private IDictionary? _definitions; - private decimal? _v31ExclusiveMaximum; - private decimal? _v31ExclusiveMinimum; - private bool? _unEvaluatedProperties; - private JsonSchemaType? _type; - private string? _const; - private string? _format; - private decimal? _maximum; - private bool? _exclusiveMaximum; - private decimal? _minimum; - private bool? _exclusiveMinimum; - private int? _maxLength; - private int? _minLength; - private string? _pattern; - private decimal? _multipleOf; - private bool? _readOnly; - private bool? _writeOnly; - private IList? _allOf; - private IList? _oneOf; - private IList? _anyOf; - private OpenApiSchema? _not; - private ISet? _required; - private OpenApiSchema _items; - private int? _maxItems; - private int? _minItems; - private bool? _uniqueItems; - private IDictionary? _patternProperties; - private int? _maxProperties; - private int? _minProperties; - private bool? _additionalPropertiesAllowed; - private OpenApiSchema? _additionalProperties; - private OpenApiDiscriminator? _discriminator; - private OpenApiExternalDocs? _externalDocs; - private bool? _deprecated; - private OpenApiXml? _xml; - private IDictionary? _extensions; - private bool? _unevaluatedProperties; - private IList? _enum; - - /// - /// Gets the target schema. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiSchema? Target -#nullable restore - { - get - { - _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); - return _target; - } - } - /// /// Constructor initializing the reference object. /// @@ -95,214 +25,173 @@ public OpenApiSchema? Target /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Schema, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - _reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Schema, - ExternalResource = externalResource - }; - - Reference = _reference; } - internal OpenApiSchemaReference(OpenApiSchema target, string referenceId) + internal OpenApiSchemaReference(OpenApiSchema target, string referenceId):base(target, referenceId, ReferenceType.Schema) { - _target = target; + } - _reference = new OpenApiReference() + /// + public string Description + { + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set { - Id = referenceId, - Type = ReferenceType.Schema, - }; + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override string Title { get => string.IsNullOrEmpty(_title) ? Target?.Title : _title; set => _title = value; } + public string Title { get => Target?.Title; } /// - public override string Schema { get => string.IsNullOrEmpty(_schema) ? Target?.Schema : _schema; set => _schema = value; } + public string Schema { get => Target?.Schema; } /// - public override string Id { get => string.IsNullOrEmpty(_id) ? Target?.Id : _id; set => _id = value; } + public string Id { get => Target?.Id; } /// - public override string Comment { get => string.IsNullOrEmpty(_comment) ? Target?.Comment : _comment; set => _comment = value; } + public string Comment { get => Target?.Comment; } /// - public override IDictionary Vocabulary { get => _vocabulary is not null ? _vocabulary : Target?.Vocabulary; set => _vocabulary = value; } + public IDictionary Vocabulary { get => Target?.Vocabulary; } /// - public override string DynamicRef { get => string.IsNullOrEmpty(_dynamicRef) ? Target?.DynamicRef : _dynamicRef; set => _dynamicRef = value; } + public string DynamicRef { get => Target?.DynamicRef; } /// - public override string DynamicAnchor { get => string.IsNullOrEmpty(_dynamicAnchor) ? Target?.DynamicAnchor : _dynamicAnchor; set => _dynamicAnchor = value; } + public string DynamicAnchor { get => Target?.DynamicAnchor; } /// - public override IDictionary Definitions { get => _definitions is not null ? _definitions : Target?.Definitions; set => _definitions = value; } + public IDictionary Definitions { get => Target?.Definitions; } /// - public override decimal? V31ExclusiveMaximum { get => _v31ExclusiveMaximum is not null ? _v31ExclusiveMaximum.Value : Target?.V31ExclusiveMaximum; set => _v31ExclusiveMaximum = value; } + public decimal? V31ExclusiveMaximum { get => Target?.V31ExclusiveMaximum; } /// - public override decimal? V31ExclusiveMinimum { get => _v31ExclusiveMinimum is not null ? _v31ExclusiveMinimum.Value : Target?.V31ExclusiveMinimum; set => _v31ExclusiveMinimum = value; } + public decimal? V31ExclusiveMinimum { get => Target?.V31ExclusiveMinimum; } /// - public override bool UnEvaluatedProperties { get => _unEvaluatedProperties is not null ? _unEvaluatedProperties.Value : Target?.UnEvaluatedProperties ?? false; set => _unEvaluatedProperties = value; } + public bool UnEvaluatedProperties { get => Target?.UnEvaluatedProperties ?? false; } /// - public override JsonSchemaType? Type { get => _type is not null ? _type.Value : Target?.Type; set => _type = value; } + public JsonSchemaType? Type { get => Target?.Type; } /// - public override string Const { get => string.IsNullOrEmpty(_const) ? Target?.Const : _const; set => _const = value; } + public string Const { get => Target?.Const; } /// - public override string Format { get => string.IsNullOrEmpty(_format) ? Target?.Format : _format; set => _format = value; } + public string Format { get => Target?.Format; } /// - public override string Description - { - get => string.IsNullOrEmpty(_description) ? Target?.Description : _description; - set => _description = value; - } + public decimal? Maximum { get => Target?.Maximum; } + /// + public bool? ExclusiveMaximum { get => Target?.ExclusiveMaximum; } /// - public override decimal? Maximum { get => _maximum is not null ? _maximum : Target?.Maximum; set => _maximum = value; } + public decimal? Minimum { get => Target?.Minimum; } /// - public override bool? ExclusiveMaximum { get => _exclusiveMaximum is not null ? _exclusiveMaximum : Target?.ExclusiveMaximum; set => _exclusiveMaximum = value; } + public bool? ExclusiveMinimum { get => Target?.ExclusiveMinimum; } /// - public override decimal? Minimum { get => _minimum is not null ? _minimum : Target?.Minimum; set => _minimum = value; } + public int? MaxLength { get => Target?.MaxLength; } /// - public override bool? ExclusiveMinimum { get => _exclusiveMinimum is not null ? _exclusiveMinimum : Target?.ExclusiveMinimum; set => _exclusiveMinimum = value; } + public int? MinLength { get => Target?.MinLength; } /// - public override int? MaxLength { get => _maxLength is not null ? _maxLength : Target?.MaxLength; set => _maxLength = value; } + public string Pattern { get => Target?.Pattern; } /// - public override int? MinLength { get => _minLength is not null ? _minLength : Target?.MinLength; set => _minLength = value; } + public decimal? MultipleOf { get => Target?.MultipleOf; } /// - public override string Pattern { get => string.IsNullOrEmpty(_pattern) ? Target?.Pattern : _pattern; set => _pattern = value; } + public JsonNode Default { get => Target?.Default; } /// - public override decimal? MultipleOf { get => _multipleOf is not null ? _multipleOf : Target?.MultipleOf; set => _multipleOf = value; } + public bool ReadOnly { get => Target?.ReadOnly ?? false; } /// - public override JsonNode Default { get => _default is not null ? _default : Target?.Default; set => _default = value; } + public bool WriteOnly { get => Target?.WriteOnly ?? false; } /// - public override bool ReadOnly { get => _readOnly is not null ? _readOnly.Value : Target?.ReadOnly ?? false; set => _readOnly = value; } + public IList AllOf { get => Target?.AllOf; } /// - public override bool WriteOnly { get => _writeOnly is not null ? _writeOnly.Value : Target?.WriteOnly ?? false; set => _writeOnly = value; } + public IList OneOf { get => Target?.OneOf; } /// - public override IList AllOf { get => _allOf is not null ? _allOf : Target?.AllOf; set => _allOf = value; } + public IList AnyOf { get => Target?.AnyOf; } /// - public override IList OneOf { get => _oneOf is not null ? _oneOf : Target?.OneOf; set => _oneOf = value; } + public IOpenApiSchema Not { get => Target?.Not; } /// - public override IList AnyOf { get => _anyOf is not null ? _anyOf : Target?.AnyOf; set => _anyOf = value; } + public ISet Required { get => Target?.Required; } /// - public override OpenApiSchema Not { get => _not is not null ? _not : Target?.Not; set => _not = value; } + public IOpenApiSchema Items { get => Target?.Items; } /// - public override ISet Required { get => _required is not null ? _required : Target?.Required; set => _required = value; } + public int? MaxItems { get => Target?.MaxItems; } /// - public override OpenApiSchema Items { get => _items is not null ? _items : Target?.Items; set => _items = value; } + public int? MinItems { get => Target?.MinItems; } /// - public override int? MaxItems { get => _maxItems is not null ? _maxItems : Target?.MaxItems; set => _maxItems = value; } + public bool? UniqueItems { get => Target?.UniqueItems; } /// - public override int? MinItems { get => _minItems is not null ? _minItems : Target?.MinItems; set => _minItems = value; } + public IDictionary Properties { get => Target?.Properties; } /// - public override bool? UniqueItems { get => _uniqueItems is not null ? _uniqueItems : Target?.UniqueItems; set => _uniqueItems = value; } + public IDictionary PatternProperties { get => Target?.PatternProperties; } /// - public override IDictionary Properties { get => _properties is not null ? _properties : Target?.Properties; set => _properties = value; } + public int? MaxProperties { get => Target?.MaxProperties; } /// - public override IDictionary PatternProperties { get => _patternProperties is not null ? _patternProperties : Target?.PatternProperties; set => _patternProperties = value; } + public int? MinProperties { get => Target?.MinProperties; } /// - public override int? MaxProperties { get => _maxProperties is not null ? _maxProperties : Target?.MaxProperties; set => _maxProperties = value; } + public bool AdditionalPropertiesAllowed { get => Target?.AdditionalPropertiesAllowed ?? true; } /// - public override int? MinProperties { get => _minProperties is not null ? _minProperties : Target?.MinProperties; set => _minProperties = value; } + public IOpenApiSchema AdditionalProperties { get => Target?.AdditionalProperties; } /// - public override bool AdditionalPropertiesAllowed { get => _additionalPropertiesAllowed is not null ? _additionalPropertiesAllowed.Value : Target?.AdditionalPropertiesAllowed ?? true; set => _additionalPropertiesAllowed = value; } + public OpenApiDiscriminator Discriminator { get => Target?.Discriminator; } /// - public override OpenApiSchema AdditionalProperties { get => _additionalProperties is not null ? _additionalProperties : Target?.AdditionalProperties; set => _additionalProperties = value; } + public JsonNode Example { get => Target?.Example; } /// - public override OpenApiDiscriminator Discriminator { get => _discriminator is not null ? _discriminator : Target?.Discriminator; set => _discriminator = value; } + public IList Examples { get => Target?.Examples; } /// - public override JsonNode Example { get => _example is not null ? _example : Target?.Example; set => _example = value; } + public IList Enum { get => Target?.Enum; } /// - public override IList Examples { get => _examples is not null ? _examples : Target?.Examples; set => _examples = value; } + public bool Nullable { get => Target?.Nullable ?? false; } /// - public override IList Enum { get => _enum is not null ? _enum : Target?.Enum; set => _enum = value; } + public bool UnevaluatedProperties { get => Target?.UnevaluatedProperties ?? false; } /// - public override bool Nullable { get => _nullable is not null ? _nullable.Value : Target?.Nullable ?? false; set => _nullable = value; } + public OpenApiExternalDocs ExternalDocs { get => Target?.ExternalDocs; } /// - public override bool UnevaluatedProperties { get => _unevaluatedProperties is not null ? _unevaluatedProperties.Value : Target?.UnevaluatedProperties ?? false; set => _unevaluatedProperties = value; } + public bool Deprecated { get => Target?.Deprecated ?? false; } /// - public override OpenApiExternalDocs ExternalDocs { get => _externalDocs is not null ? _externalDocs : Target?.ExternalDocs; set => _externalDocs = value; } + public OpenApiXml Xml { get => Target?.Xml; } /// - public override bool Deprecated { get => _deprecated is not null ? _deprecated.Value : Target?.Deprecated ?? false; set => _deprecated = value; } + public IDictionary Extensions { get => Target?.Extensions; } + /// - public override OpenApiXml Xml { get => _xml is not null ? _xml : Target?.Xml; set => _xml = value; } + public IDictionary UnrecognizedKeywords { get => Target?.UnrecognizedKeywords; } + /// - public override IDictionary Extensions { get => _extensions is not null ? _extensions : Target?.Extensions; set => _extensions = value; } + public IDictionary Annotations { get => Target?.Annotations; } /// public override void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV31(writer); - return; - } - // If Loop is detected then just Serialize as a reference. - else if (!writer.GetSettings().LoopDetector.PushLoop(this)) - { - writer.GetSettings().LoopDetector.SaveLoop(this); - _reference.SerializeAsV31(writer); - return; - } - - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - writer.GetSettings().LoopDetector.PopLoop(); + SerializeAsWithoutLoops(writer, (w, element) => (element is IOpenApiSchema s ? CopyReferenceAsTargetElementWithOverrides(s) : element).SerializeAsV3(w)); } /// public override void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV3(writer); - return; - } - // If Loop is detected then just Serialize as a reference. - else if (!writer.GetSettings().LoopDetector.PushLoop(this)) - { - writer.GetSettings().LoopDetector.SaveLoop(this); - _reference.SerializeAsV3(writer); - return; - } - - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - writer.GetSettings().LoopDetector.PopLoop(); + SerializeAsWithoutLoops(writer, (w, element) => element.SerializeAsV3(w)); } - /// - internal override void SerializeAsV2( - IOpenApiWriter writer, - ISet parentRequiredProperties, - string propertyName) + public override void SerializeAsV2(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV2(writer); - } - else - { - base.SerializeAsV2(writer, parentRequiredProperties, propertyName); - } + SerializeAsWithoutLoops(writer, (w, element) => element.SerializeAsV2(w)); } - - /// - public override void SerializeAsV2(IOpenApiWriter writer) + private void SerializeAsWithoutLoops(IOpenApiWriter writer, Action action) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV2(writer); + action(writer, Reference); + } + // If Loop is detected then just Serialize as a reference. + else if (!writer.GetSettings().LoopDetector.PushLoop(this)) + { + writer.GetSettings().LoopDetector.SaveLoop(this); + action(writer, Reference); } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); + SerializeInternal(writer, (w, element) => action(w, element)); + writer.GetSettings().LoopDetector.PopLoop(); } - } + } /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) + public override IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(IOpenApiSchema source) { - Utils.CheckArgumentNull(writer); - action(writer, Target); + return source is OpenApiSchema ? new OpenApiSchema(this) : source; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs index 92dd24138..16456c400 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs @@ -4,6 +4,7 @@ using System; using System.Text.Json.Nodes; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -15,7 +16,7 @@ internal class AnyFieldMapParameter public AnyFieldMapParameter( Func propertyGetter, Action propertySetter, - Func SchemaGetter = null) + Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -35,6 +36,6 @@ public AnyFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs index 4d365125b..52397aed9 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Text.Json.Nodes; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -17,7 +18,7 @@ public AnyMapFieldMapParameter( Func> propertyMapGetter, Func propertyGetter, Action propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyMapGetter = propertyMapGetter; this.PropertyGetter = propertyGetter; @@ -43,6 +44,6 @@ public AnyMapFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index bc2333e46..cd31ef678 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -95,12 +95,15 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) { - return p.Schema ??= new(); + return p.Schema switch { + OpenApiSchema schema => schema, + _ => (OpenApiSchema)(p.Schema = new OpenApiSchema()), + }; } public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) @@ -113,7 +116,7 @@ public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocu property.ParseField(header, _headerFixedFields, _headerPatternFields, hostDocument); } - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { header.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 140ad9f3d..7aa6f2bd5 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -9,6 +9,7 @@ using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Models.Interfaces; +using System; namespace Microsoft.OpenApi.Reader.V2 { @@ -147,18 +148,20 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List k.Name, - v => + v => { - var schema = v.Schema; - schema.Description = v.Description; - schema.Extensions = v.Extensions; - return schema; + var schema = new OpenApiSchema(v.Schema) + { + Description = v.Description, + Extensions = v.Extensions + }; + return (IOpenApiSchema)schema; }), - Required = new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name)) + Required = new HashSet(formParameters.Where(static p => p.Required).Select(static p => p.Name), StringComparer.Ordinal) } }; @@ -173,8 +176,8 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List mediaType) }; - foreach (var value in formBody.Content.Values.Where(static x => x.Schema is not null && x.Schema.Properties.Any() && x.Schema.Type == null)) - value.Schema.Type = JsonSchemaType.Object; + foreach (var value in formBody.Content.Values.Where(static x => x.Schema is not null && x.Schema.Properties.Any() && x.Schema.Type == null).Select(static x => x.Schema).OfType()) + value.Type = JsonSchemaType.Object; return formBody; } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 2153d37d2..00d6dbb9c 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -147,7 +147,10 @@ private static void LoadParameterExamplesExtension(OpenApiParameter parameter, P private static OpenApiSchema GetOrCreateSchema(OpenApiParameter p) { - return p.Schema ??= new(); + return p.Schema switch { + OpenApiSchema schema => schema, + _ => (OpenApiSchema)(p.Schema = new OpenApiSchema()), + }; } private static void ProcessIn(OpenApiParameter o, ParseNode n, OpenApiDocument hostDocument) @@ -208,7 +211,7 @@ public static IOpenApiParameter LoadParameter(ParseNode node, bool loadRequestBo ParseMap(mapNode, parameter, _parameterFixedFields, _parameterPatternFields, doc: hostDocument); - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { parameter.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index d730c8227..1bc851852 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -74,7 +74,7 @@ private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, P ?? context.GetFromTempStorage>(TempStorageKeys.GlobalProduces) ?? context.DefaultContentType ?? new List { "application/octet-stream" }; - var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); + var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); var examples = context.GetFromTempStorage>(TempStorageKeys.Examples, response) ?? new Dictionary(); @@ -171,7 +171,7 @@ private static void LoadExample(OpenApiResponse response, string mediaType, Pars { mediaTypeObject = new() { - Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) + Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) }; response.Content.Add(mediaType, mediaTypeObject); } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 78453f9d2..1c379d008 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -7,6 +7,8 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; +using Microsoft.OpenApi.Models.Interfaces; +using System; namespace Microsoft.OpenApi.Reader.V2 { @@ -153,10 +155,10 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new PatternFieldMap { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("schema"); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index bad6d04b8..23828348f 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -3,8 +3,10 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; +using System; using System.Collections.Generic; using System.Globalization; @@ -171,10 +173,10 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 87ecc8f00..a78ca14e1 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -3,8 +3,10 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -236,10 +238,10 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 6fbcbcc4a..490c7cff8 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -89,9 +89,9 @@ private void AddSchemaToComponents(OpenApiSchema schema, string referenceId = nu { EnsureComponentsExist(); EnsureSchemasExist(); - if (!Components.Schemas.ContainsKey(referenceId ?? schema.Reference.Id)) + if (!Components.Schemas.ContainsKey(referenceId)) { - Components.Schemas.Add(referenceId ?? schema.Reference.Id, schema); + Components.Schemas.Add(referenceId, schema); } } @@ -179,17 +179,13 @@ private void AddSecuritySchemeToComponents(OpenApiSecurityScheme securityScheme, } /// - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { // This is needed to handle schemas used in Responses in components if (schema is OpenApiSchemaReference openApiSchemaReference) { AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id); } - else if (schema.Reference != null) - { - AddSchemaToComponents(schema); - } base.Visit(schema); } @@ -200,7 +196,7 @@ private void EnsureComponentsExist() private void EnsureSchemasExist() { - _target.Components.Schemas ??= new Dictionary(); + _target.Components.Schemas ??= new Dictionary(); } private void EnsureParametersExist() diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index b2eb9eab1..2b79864d8 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -230,9 +230,9 @@ public virtual void Visit(OpenApiExternalDocs externalDocs) } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiSchema schema) + public virtual void Visit(IOpenApiSchema schema) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 41d7561ab..8d634834a 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -19,7 +19,7 @@ namespace Microsoft.OpenApi.Services public class OpenApiWalker { private readonly OpenApiVisitorBase _visitor; - private readonly Stack _schemaLoop = new(); + private readonly Stack _schemaLoop = new(); private readonly Stack _pathItemLoop = new(); /// @@ -864,11 +864,11 @@ internal void Walk(OpenApiEncoding encoding) } /// - /// Visits and child objects + /// Visits and child objects /// - internal void Walk(OpenApiSchema schema, bool isComponent = false) + internal void Walk(IOpenApiSchema schema, bool isComponent = false) { - if (schema == null || ProcessAsReference(schema, isComponent)) + if (schema == null || schema is IOpenApiReferenceHolder holder && ProcessAsReference(holder, isComponent)) { return; } @@ -1012,9 +1012,9 @@ internal void Walk(IList examples) } /// - /// Visits a list of and child objects + /// Visits a list of and child objects /// - internal void Walk(IList schemas) + internal void Walk(IList schemas) { if (schemas == null) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 0e1251d2e..a8669fce0 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -108,7 +108,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(IOpenApiParameter parameter) => Validate(parameter); /// - public override void Visit(OpenApiSchema schema) => Validate(schema); + public override void Visit(IOpenApiSchema schema) => Validate(schema); /// public override void Visit(OpenApiServer server) => Validate(server); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs index 1d38af4ce..03661401c 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiNonDefaultRules.cs @@ -47,7 +47,7 @@ public static class OpenApiNonDefaultRules /// /// Validate the data matches with the given data type. /// - public static ValidationRule SchemaMismatchedDataType => + public static ValidationRule SchemaMismatchedDataType => new(nameof(SchemaMismatchedDataType), (context, schema) => { @@ -91,7 +91,7 @@ private static void ValidateMismatchedDataType(IValidationContext context, string ruleName, JsonNode example, IDictionary examples, - OpenApiSchema schema) + IOpenApiSchema schema) { // example context.Enter("example"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index 054c79c6b..b954c96b6 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules @@ -16,14 +18,14 @@ public static class OpenApiSchemaRules /// /// Validates Schema Discriminator /// - public static ValidationRule ValidateSchemaDiscriminator => + public static ValidationRule ValidateSchemaDiscriminator => new(nameof(ValidateSchemaDiscriminator), (context, schema) => { // discriminator context.Enter("discriminator"); - if (schema.Reference != null && schema.Discriminator != null) + if (schema is not null && schema.Discriminator != null) { var discriminatorName = schema.Discriminator?.PropertyName; @@ -31,7 +33,7 @@ public static class OpenApiSchemaRules { context.CreateError(nameof(ValidateSchemaDiscriminator), string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, - schema.Reference.Id, discriminatorName)); + schema is OpenApiSchemaReference { Reference: not null} schemaReference ? schemaReference.Reference.Id : string.Empty, discriminatorName)); } } @@ -44,7 +46,7 @@ public static class OpenApiSchemaRules /// The parent schema. /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate /// between other schemas which may satisfy the payload description. - public static bool ValidateChildSchemaAgainstDiscriminator(OpenApiSchema schema, string discriminatorName) + public static bool ValidateChildSchemaAgainstDiscriminator(IOpenApiSchema schema, string discriminatorName) { if (!schema.Required?.Contains(discriminatorName) ?? false) { @@ -77,7 +79,7 @@ public static bool ValidateChildSchemaAgainstDiscriminator(OpenApiSchema schema, /// between other schemas which may satisfy the payload description. /// The child schema. /// - public static bool TraverseSchemaElements(string discriminatorName, IList childSchema) + public static bool TraverseSchemaElements(string discriminatorName, IList childSchema) { foreach (var childItem in childSchema) { diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index 61b9d3a0c..62ab79406 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -5,6 +5,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Validations.Rules { @@ -44,7 +45,7 @@ public static void ValidateDataTypeMismatch( IValidationContext context, string ruleName, JsonNode value, - OpenApiSchema schema) + IOpenApiSchema schema) { if (schema == null) { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index abf7232d1..f868dfa07 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -122,10 +122,10 @@ private static OpenApiDocument GetSampleOpenApiDocument() "application/json", new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -149,20 +149,20 @@ private static OpenApiDocument GetSampleOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { { "TestSchema", new OpenApiSchema { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { { "averageAudioDegradation", new OpenApiSchema { - AnyOf = new List + AnyOf = new List { - new() { Type = JsonSchemaType.Number }, - new() { Type = JsonSchemaType.String } + new OpenApiSchema() { Type = JsonSchemaType.Number }, + new OpenApiSchema() { Type = JsonSchemaType.String } }, Format = "float", Nullable = true @@ -171,10 +171,10 @@ private static OpenApiDocument GetSampleOpenApiDocument() { "defaultPrice", new OpenApiSchema { - OneOf = new List + OneOf = new List { - new() { Type = JsonSchemaType.Number, Format = "double" }, - new() { Type = JsonSchemaType.String } + new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "double" }, + new OpenApiSchema() { Type = JsonSchemaType.String } } } } diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index ca4416ae6..a3494ba13 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -129,7 +129,7 @@ public void CreateFilteredDocumentUsingPredicateFromRequestUrl() Name = "id", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index 0d25c7704..b5289c1ef 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -87,7 +87,7 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -106,7 +106,7 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array } @@ -127,7 +127,7 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -152,7 +152,7 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -171,7 +171,7 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array } @@ -191,7 +191,7 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -219,25 +219,17 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Title = "Collection of user", Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { { "value", new OpenApiSchema { Type = JsonSchemaType.Array, - Items = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "microsoft.graph.user" - } - } } } } @@ -273,14 +265,6 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "microsoft.graph.user" - } - } } } } @@ -325,7 +309,7 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Query, Required = true, Description = "Select properties to be returned", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array } @@ -344,14 +328,6 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "microsoft.graph.message" - } - } } } } @@ -380,7 +356,7 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Required = true, Description = "key: id of administrativeUnit", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -399,11 +375,11 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { - AnyOf = new List + AnyOf = new List { - new() + new OpenApiSchema() { Type = JsonSchemaType.String } @@ -463,25 +439,17 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Title = "Collection of hostSecurityProfile", Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { { "value", new OpenApiSchema { Type = JsonSchemaType.Array, - Items = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "microsoft.graph.networkInterface" - } - } } } } @@ -513,7 +481,7 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of call", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -561,7 +529,7 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of group", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -578,7 +546,7 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of event", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -602,13 +570,17 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { - Type = JsonSchemaType.Array, - Reference = new() + Properties = new Dictionary { - Type = ReferenceType.Schema, - Id = "microsoft.graph.event" + { + "value", + new OpenApiSchema + { + Type = JsonSchemaType.Array, + } + } } } } @@ -643,14 +615,14 @@ public static OpenApiDocument CreateOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { { "microsoft.graph.networkInterface", new OpenApiSchema { Title = "networkInterface", Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { { "description", new OpenApiSchema @@ -726,6 +698,11 @@ public static OpenApiDocument CreateOpenApiDocument() document.Paths[communicationsCallsKeepAlivePath].Operations[OperationType.Post].Tags!.Add(new OpenApiTagReference("communications.Actions", document)); document.Paths[eventsDeltaPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("groups.Functions", document)); document.Paths[refPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("applications.directoryObject", document)); + ((OpenApiSchema)document.Paths[usersPath].Operations[OperationType.Get].Responses!["200"].Content[applicationJsonMediaType].Schema!.Properties["value"]).Items = new OpenApiSchemaReference("microsoft.graph.user", document); + document.Paths[usersByIdPath].Operations[OperationType.Get].Responses!["200"].Content[applicationJsonMediaType].Schema = new OpenApiSchemaReference("microsoft.graph.user", document); + document.Paths[messagesByIdPath].Operations[OperationType.Get].Responses!["200"].Content[applicationJsonMediaType].Schema = new OpenApiSchemaReference("microsoft.graph.message", document); + ((OpenApiSchema)document.Paths[securityProfilesPath].Operations[OperationType.Get].Responses!["200"].Content[applicationJsonMediaType].Schema!.Properties["value"]).Items = new OpenApiSchemaReference("microsoft.graph.networkInterface", document); + ((OpenApiSchema)document.Paths[eventsDeltaPath].Operations[OperationType.Get].Responses!["200"].Content[applicationJsonMediaType].Schema!.Properties["value"]).Items = new OpenApiSchemaReference("microsoft.graph.event", document); return document; } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 8440e8df4..98cc4ed78 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -37,7 +37,7 @@ public async Task LoadParameterReference() In = ParameterLocation.Query, Description = "number of items to skip", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -92,41 +92,37 @@ public async Task LoadResponseAndSchemaReference() var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "multipleReferences.v2.yaml")); var reference = new OpenApiResponseReference("GeneralError", result.Document); - // Assert - Assert.Equivalent( - new OpenApiResponse + var expected = new OpenApiResponse { Description = "General Error", Content = { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchemaReference(new OpenApiSchema() { Description = "Sample description", Required = new HashSet {"name" }, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String } }, - - Reference = new() - { - Type = ReferenceType.Schema, - Id = "SampleObject2", - HostDocument = result.Document - } - } + }, "SampleObject2") } } - }, reference - ); + }; + + ((OpenApiSchemaReference)expected.Content["application/json"].Schema).Reference.HostDocument = result.Document; + var actual = reference.Target; + + // Assert + Assert.Equivalent(expected, actual); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index 5993d4e2c..136c46892 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -10,6 +10,7 @@ using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Xunit; @@ -73,12 +74,12 @@ public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) { Schemas = { - ["sampleSchema"] = new() + ["sampleSchema"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["sampleProperty"] = new() + ["sampleProperty"] = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = (decimal)100.54, @@ -106,7 +107,7 @@ public async Task ShouldParseProducesInAnyOrder() var okSchema = new OpenApiSchema { - Properties = new Dictionary + Properties = new Dictionary { { "id", new OpenApiSchema { @@ -119,7 +120,7 @@ public async Task ShouldParseProducesInAnyOrder() var errorSchema = new OpenApiSchema { - Properties = new Dictionary + Properties = new Dictionary { { "code", new OpenApiSchema { @@ -142,7 +143,7 @@ public async Task ShouldParseProducesInAnyOrder() var okMediaType = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchemaReference("Item", result.Document) @@ -276,7 +277,7 @@ public async Task ShouldAssignSchemaToAllResponses() var responses = result.Document.Paths["/items"].Operations[OperationType.Get].Responses; foreach (var response in responses) { - var targetSchema = response.Key == "200" ? successSchema : errorSchema; + var targetSchema = response.Key == "200" ? (IOpenApiSchema)successSchema : errorSchema; var json = response.Value.Content["application/json"]; Assert.NotNull(json); @@ -294,9 +295,11 @@ public async Task ShouldAllowComponentsThatJustContainAReference() // Act var actual = (await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "ComponentRootReference.json"))).Document; var schema1 = actual.Components.Schemas["AllPets"]; - Assert.False(schema1.UnresolvedReference); - var schema2 = actual.ResolveReferenceTo(schema1.Reference); - if (schema2.UnresolvedReference && schema1.Reference.Id == schema2.Reference.Id) + var schema1Reference = Assert.IsType(schema1); + Assert.False(schema1Reference.UnresolvedReference); + var schema2 = actual.ResolveReferenceTo(schema1Reference.Reference); + Assert.IsType(schema2); + if (string.IsNullOrEmpty(schema1Reference.Reference.Id) || schema1Reference.UnresolvedReference) { // detected a cycle - this code gets triggered Assert.Fail("A cycle should not be detected"); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index cc15d8427..1b1187a42 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -34,7 +34,7 @@ public void ParseHeaderWithDefaultShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float", @@ -63,7 +63,7 @@ public void ParseHeaderWithEnumShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float", diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index ce7382b65..13339332a 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -39,7 +39,7 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -72,7 +72,7 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -86,7 +86,7 @@ public class OpenApiOperationTests { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } @@ -216,10 +216,10 @@ public void ParseOperationWithResponseExamplesShouldSucceed() { ["application/json"] = new OpenApiMediaType() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" @@ -234,10 +234,10 @@ public void ParseOperationWithResponseExamplesShouldSucceed() }, ["application/xml"] = new OpenApiMediaType() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 1b6300faf..aa11d5137 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -57,7 +57,7 @@ public void ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -86,10 +86,10 @@ public void ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -121,7 +121,7 @@ public void ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -150,7 +150,7 @@ public void ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -204,7 +204,7 @@ public void ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -233,7 +233,7 @@ public void ParseParameterWithDefaultShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float", @@ -260,7 +260,7 @@ public void ParseParameterWithEnumShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float", diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index a86d84bdd..412a74dde 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -27,10 +27,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet to use", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -53,7 +53,7 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -65,17 +65,17 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String @@ -89,17 +89,17 @@ public class OpenApiPathItemTests }, ["multipart/form-data"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String @@ -148,7 +148,7 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -159,7 +159,7 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "Name of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -171,22 +171,22 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String }, - ["skill"] = new() + ["skill"] = new OpenApiSchema() { Description = "Updated skill of the pet", Type = JsonSchemaType.String @@ -200,22 +200,22 @@ public class OpenApiPathItemTests }, ["multipart/form-data"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String }, - ["skill"] = new() + ["skill"] = new OpenApiSchema() { Description = "Updated skill of the pet", Type = JsonSchemaType.String @@ -249,11 +249,8 @@ public class OpenApiPathItemTests public void ParseBasicPathItemWithFormDataShouldSucceed() { // Arrange - MapNode node; - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicPathItemWithFormData.yaml"))) - { - node = TestHelper.CreateYamlMapNode(stream); - } + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicPathItemWithFormData.yaml")); + var node = TestHelper.CreateYamlMapNode(stream); // Act var pathItem = OpenApiV2Deserializer.LoadPathItem(node, new()); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index 1b36921d7..781b272e1 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -13,6 +13,7 @@ using FluentAssertions.Equivalency; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Readers.Tests.V2Tests { @@ -108,7 +109,7 @@ public void PropertiesReferenceShouldWork() var targetSchema = new OpenApiSchema() { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { ["prop1"] = new OpenApiSchema() { @@ -121,7 +122,7 @@ public void PropertiesReferenceShouldWork() var referenceSchema = new OpenApiSchema() { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { ["propA"] = new OpenApiSchemaReference(referenceId, workingDocument), } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index cda7e35c3..9c391ceb2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -38,7 +38,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() { Schemas = { - ["petSchema"] = new() + ["petSchema"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -46,42 +46,42 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPetSchema"] = new() + ["newPetSchema"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -115,10 +115,10 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -130,7 +130,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -146,7 +146,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = petSchema @@ -154,7 +154,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() }, ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = petSchema @@ -212,9 +212,9 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["petSchema"] = new() + ["petSchema"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -222,42 +222,42 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPetSchema"] = new() + ["newPetSchema"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -289,10 +289,10 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -304,7 +304,7 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -419,7 +419,7 @@ public async Task ParseDocumentWithPatternPropertiesInSchemaWorks() var expectedSchema = new OpenApiSchema { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { ["prop1"] = new OpenApiSchema { @@ -434,7 +434,7 @@ public async Task ParseDocumentWithPatternPropertiesInSchemaWorks() Type = JsonSchemaType.String } }, - PatternProperties = new Dictionary + PatternProperties = new Dictionary { ["^x-.*$"] = new OpenApiSchema { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index abcaa9df6..50c506533 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -9,6 +9,7 @@ using FluentAssertions; using FluentAssertions.Equivalency; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Writers; @@ -42,7 +43,7 @@ public async Task ParseBasicV31SchemaShouldSucceed() Schema = "https://json-schema.org/draft/2020-12/schema", Description = "A representation of a person, company, organization, or place", Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { ["fruits"] = new OpenApiSchema { @@ -57,7 +58,7 @@ public async Task ParseBasicV31SchemaShouldSucceed() Type = JsonSchemaType.Array } }, - Definitions = new Dictionary + Definitions = new Dictionary { ["veggie"] = new OpenApiSchema { @@ -67,7 +68,7 @@ public async Task ParseBasicV31SchemaShouldSucceed() "veggieName", "veggieLike" }, - Properties = new Dictionary + Properties = new Dictionary { ["veggieName"] = new OpenApiSchema { @@ -165,9 +166,9 @@ public async Task ParseV31SchemaShouldSucceed() var expectedSchema = new OpenApiSchema { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { - ["one"] = new() + ["one"] = new OpenApiSchema() { Description = "type array", Type = JsonSchemaType.Integer | JsonSchemaType.String @@ -189,29 +190,29 @@ public async Task ParseAdvancedV31SchemaShouldSucceed() var expectedSchema = new OpenApiSchema { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { - ["one"] = new() + ["one"] = new OpenApiSchema() { Description = "type array", Type = JsonSchemaType.Integer | JsonSchemaType.String }, - ["two"] = new() + ["two"] = new OpenApiSchema() { Description = "type 'null'", Type = JsonSchemaType.Null }, - ["three"] = new() + ["three"] = new OpenApiSchema() { Description = "type array including 'null'", Type = JsonSchemaType.String | JsonSchemaType.Null }, - ["four"] = new() + ["four"] = new OpenApiSchema() { Description = "array with no items", Type = JsonSchemaType.Array }, - ["five"] = new() + ["five"] = new OpenApiSchema() { Description = "singular example", Type = JsonSchemaType.String, @@ -220,37 +221,37 @@ public async Task ParseAdvancedV31SchemaShouldSucceed() "exampleValue" } }, - ["six"] = new() + ["six"] = new OpenApiSchema() { Description = "exclusiveMinimum true", V31ExclusiveMinimum = 10 }, - ["seven"] = new() + ["seven"] = new OpenApiSchema() { Description = "exclusiveMinimum false", Minimum = 10 }, - ["eight"] = new() + ["eight"] = new OpenApiSchema() { Description = "exclusiveMaximum true", V31ExclusiveMaximum = 20 }, - ["nine"] = new() + ["nine"] = new OpenApiSchema() { Description = "exclusiveMaximum false", Maximum = 20 }, - ["ten"] = new() + ["ten"] = new OpenApiSchema() { Description = "nullable string", Type = JsonSchemaType.String | JsonSchemaType.Null }, - ["eleven"] = new() + ["eleven"] = new OpenApiSchema() { Description = "x-nullable string", Type = JsonSchemaType.String | JsonSchemaType.Null }, - ["twelve"] = new() + ["twelve"] = new OpenApiSchema() { Description = "file/binary" } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 4476d23a8..5aabe43d3 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -94,7 +94,7 @@ public async Task ParseCallbackWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } @@ -144,7 +144,7 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } @@ -180,7 +180,7 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -215,7 +215,7 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 1b8f26c64..d5ccec6cc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -32,7 +32,7 @@ public OpenApiDocumentTests() OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); } - private static async Task CloneAsync(T element) where T : IOpenApiSerializable + private static async Task CloneAsync(T element) where T : class, IOpenApiSerializable { using var stream = new MemoryStream(); var streamWriter = new FormattingStreamWriter(stream, CultureInfo.InvariantCulture); @@ -205,9 +205,9 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new() + ["pet1"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -215,48 +215,48 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPet"] = new() + ["newPet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["errorModel"] = new() + ["errorModel"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -264,14 +264,14 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() "code", "message" }, - Properties = new Dictionary + Properties = new Dictionary { - ["code"] = new() + ["code"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" }, - ["message"] = new() + ["message"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -331,10 +331,10 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -346,7 +346,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -362,7 +362,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = petSchema @@ -370,7 +370,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() }, ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = petSchema @@ -474,7 +474,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -534,7 +534,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -591,9 +591,9 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new() + ["pet1"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -601,48 +601,48 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPet"] = new() + ["newPet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["errorModel"] = new() + ["errorModel"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -650,14 +650,14 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() "code", "message" }, - Properties = new Dictionary + Properties = new Dictionary { - ["code"] = new() + ["code"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" }, - ["message"] = new() + ["message"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -681,31 +681,20 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() }; // Create a clone of the schema to avoid modifying things in components. - var petSchema = await CloneAsync(components.Schemas["pet1"]); - petSchema.Reference = new() - { - Id = "pet1", - Type = ReferenceType.Schema, - HostDocument = actual.Document - }; - - var newPetSchema = await CloneAsync(components.Schemas["newPet"]); + var petSchemaSource = Assert.IsType(components.Schemas["pet1"]); + var petSchema = await CloneAsync(petSchemaSource); + var castPetSchema = Assert.IsType(petSchema); + var petSchemaReference = new OpenApiSchemaReference(castPetSchema, "pet1"); - newPetSchema.Reference = new() - { - Id = "newPet", - Type = ReferenceType.Schema, - HostDocument = actual.Document - }; + var newPetSchemaSource = Assert.IsType(components.Schemas["newPet"]); + var newPetSchema = await CloneAsync(newPetSchemaSource); + var castNewPetSchema = Assert.IsType(newPetSchema); + var newPetSchemaReference = new OpenApiSchemaReference(castNewPetSchema, "newPet"); - var errorModelSchema = await CloneAsync(components.Schemas["errorModel"]); - - errorModelSchema.Reference = new() - { - Id = "errorModel", - Type = ReferenceType.Schema, - HostDocument = actual.Document - }; + var errorModelSchemaSource = Assert.IsType(components.Schemas["errorModel"]); + var errorModelSchema = await CloneAsync(errorModelSchemaSource); + var castErrorModelSchema = Assert.IsType(errorModelSchema); + var errorModelSchemaReference = new OpenApiSchemaReference(castErrorModelSchema, "errorModel"); var tagReference1 = new OpenApiTagReference("tagName1", null); @@ -778,10 +767,10 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -793,7 +782,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -809,18 +798,18 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = petSchema + Items = petSchemaReference } }, ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = petSchema + Items = petSchemaReference } } } @@ -832,7 +821,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } }, @@ -843,7 +832,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } } @@ -866,7 +855,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = newPetSchema + Schema = newPetSchemaReference } } }, @@ -879,7 +868,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = petSchema + Schema = petSchemaReference }, } }, @@ -890,7 +879,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } }, @@ -901,7 +890,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } } @@ -938,7 +927,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -954,11 +943,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = petSchema + Schema = petSchemaReference }, ["application/xml"] = new OpenApiMediaType { - Schema = petSchema + Schema = petSchemaReference } } }, @@ -969,7 +958,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } }, @@ -980,7 +969,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } } @@ -998,7 +987,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -1018,7 +1007,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } }, @@ -1029,7 +1018,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["text/html"] = new OpenApiMediaType { - Schema = errorModelSchema + Schema = errorModelSchemaReference } } } @@ -1069,8 +1058,12 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() tagReference1.Reference.HostDocument = expected; tagReference2.Reference.HostDocument = expected; + petSchemaReference.Reference.HostDocument = expected; + newPetSchemaReference.Reference.HostDocument = expected; + errorModelSchemaReference.Reference.HostDocument = expected; actual.Document.Should().BeEquivalentTo(expected, options => options + .IgnoringCyclicReferences() .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference.HostDocument) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Target) @@ -1127,7 +1120,7 @@ public async Task HeaderParameterShouldAllowExample() Style = ParameterStyle.Simple, Explode = true, Example = "99391c7e-ad88-49ec-a2ad-99ddcb1f7721", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, Format = "uuid" @@ -1160,7 +1153,7 @@ public async Task HeaderParameterShouldAllowExample() } } }, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, Format = "uuid" @@ -1231,7 +1224,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() In = ParameterLocation.Query, Description = "Limit the number of pets returned", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32", diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs index c103db5d8..bee674bfc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs @@ -52,7 +52,7 @@ public async Task ParseAdvancedEncodingShouldSucceed() new OpenApiHeader() { Description = "The number of allowed requests in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index e10c78a25..2905266fc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -35,7 +35,7 @@ public async Task ParseMediaTypeWithExampleShouldSucceed() new OpenApiMediaType { Example = 5, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" @@ -66,7 +66,7 @@ public async Task ParseMediaTypeWithExamplesShouldSucceed() Value = 7.5 } }, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs index 22167e0ee..3d629a23b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs @@ -56,7 +56,7 @@ public async Task ParseOperationWithParameterWithNoLocationShouldSucceed() Name = "username", Description = "The user name for login", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -67,7 +67,7 @@ public async Task ParseOperationWithParameterWithNoLocationShouldSucceed() Description = "The password for login in clear text", In = ParameterLocation.Query, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 17411a859..2ee63165c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -41,7 +41,7 @@ public async Task ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -62,10 +62,10 @@ public async Task ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -87,10 +87,10 @@ public async Task ParseQueryParameterWithObjectTypeShouldSucceed() { In = ParameterLocation.Query, Name = "freeForm", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -118,7 +118,7 @@ public async Task ParseQueryParameterWithObjectTypeAndContentShouldSucceed() { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = @@ -128,11 +128,11 @@ public async Task ParseQueryParameterWithObjectTypeAndContentShouldSucceed() }, Properties = { - ["lat"] = new() + ["lat"] = new OpenApiSchema() { Type = JsonSchemaType.Number }, - ["long"] = new() + ["long"] = new OpenApiSchema() { Type = JsonSchemaType.Number } @@ -159,10 +159,10 @@ public async Task ParseHeaderParameterShouldSucceed() Required = true, Style = ParameterStyle.Simple, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64", @@ -185,7 +185,7 @@ public async Task ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -209,7 +209,7 @@ public async Task ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -233,7 +233,7 @@ public async Task ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -255,7 +255,7 @@ public async Task ParseParameterWithExampleShouldSucceed() Description = "username to fetch", Required = true, Example = (float)5.0, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" @@ -288,7 +288,7 @@ public async Task ParseParameterWithExamplesShouldSucceed() Value = (float) 7.5 } }, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "float" @@ -308,7 +308,7 @@ public void ParseParameterWithReferenceWorks() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchema diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 8d94822ef..2fd230a19 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -165,7 +165,7 @@ public void ParseDictionarySchemaShouldSucceed() new OpenApiSchema { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -199,12 +199,12 @@ public void ParseBasicSchemaWithExampleShouldSucceed() Type = JsonSchemaType.Object, Properties = { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -245,18 +245,18 @@ public async Task ParseBasicSchemaWithReferenceShouldSucceed() { Schemas = { - ["ErrorModel"] = new() + ["ErrorModel"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["code"] = new() + ["code"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Minimum = 100, Maximum = 600 }, - ["message"] = new() + ["message"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -267,7 +267,7 @@ public async Task ParseBasicSchemaWithReferenceShouldSucceed() "code" } }, - ["ExtendedErrorModel"] = new() + ["ExtendedErrorModel"] = new OpenApiSchema() { AllOf = { @@ -278,7 +278,7 @@ public async Task ParseBasicSchemaWithReferenceShouldSucceed() Required = {"rootCause"}, Properties = { - ["rootCause"] = new() + ["rootCause"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -302,7 +302,7 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() { Schemas = { - ["Pet"] = new() + ["Pet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Discriminator = new() @@ -311,11 +311,11 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() }, Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["petType"] = new() + ["petType"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -326,7 +326,7 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() "petType" } }, - ["Cat"] = new() + ["Cat"] = new OpenApiSchema() { Description = "A representation of a cat", AllOf = @@ -338,7 +338,7 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() Required = {"huntingSkill"}, Properties = { - ["huntingSkill"] = new() + ["huntingSkill"] = new OpenApiSchema() { Type = JsonSchemaType.String, Description = "The measured skill for hunting", @@ -354,7 +354,7 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() } } }, - ["Dog"] = new() + ["Dog"] = new OpenApiSchema() { Description = "A representation of a dog", AllOf = @@ -366,7 +366,7 @@ public async Task ParseAdvancedSchemaWithReferenceShouldSucceed() Required = {"packSize"}, Properties = { - ["packSize"] = new() + ["packSize"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index c84788ba8..5600610de 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -34,7 +34,7 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } @@ -74,7 +74,7 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 45448aa60..45c3dc1fc 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -16,17 +16,17 @@ public class OpenApiComponentsTests { public static OpenApiComponents AdvancedComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Integer }, - ["property3"] = new() + ["property3"] = new OpenApiSchema() { Type = JsonSchemaType.String, MaxLength = 15 @@ -65,24 +65,24 @@ public class OpenApiComponentsTests public static OpenApiComponents AdvancedComponentsWithReference = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Integer }, ["property3"] = new OpenApiSchemaReference("schema2", null) } }, - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -132,22 +132,22 @@ public class OpenApiComponentsTests public static OpenApiComponents BrokenComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { Type = JsonSchemaType.String }, ["schema2"] = null, ["schema3"] = null, - ["schema4"] = new() + ["schema4"] = new OpenApiSchema() { Type = JsonSchemaType.String, - AllOf = new List + AllOf = new List { null, null, - new() + new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -163,12 +163,12 @@ public class OpenApiComponentsTests Schemas = { ["schema1"] = new OpenApiSchemaReference("schema2", null), - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -181,23 +181,23 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String } } }, - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -216,11 +216,11 @@ public class OpenApiComponentsTests public static OpenApiComponents ComponentsWithPathItem = new OpenApiComponents { - Schemas = new Dictionary() + Schemas = new Dictionary() { ["schema1"] = new OpenApiSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { ["property2"] = new OpenApiSchema() { @@ -230,9 +230,9 @@ public class OpenApiComponentsTests } }, - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { ["property2"] = new OpenApiSchema() { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 5c905f238..3716a0b32 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -34,12 +34,12 @@ public OpenApiDocumentTests() Schemas = { ["schema1"] = new OpenApiSchemaReference("schema2", null), - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String, Annotations = new Dictionary { { "key1", "value" } } @@ -53,30 +53,25 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String, Annotations = new Dictionary { { "key1", "value" } } } }, Annotations = new Dictionary { { "key1", "value" } }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" - } }, - ["schema2"] = new() + ["schema2"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -90,13 +85,8 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new() + ["schema1"] = new OpenApiSchema() { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" - } } } }; @@ -133,9 +123,9 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponentsWithReference = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new() + ["pet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -143,48 +133,48 @@ public OpenApiDocumentTests() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPet"] = new() + ["newPet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["errorModel"] = new() + ["errorModel"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -192,14 +182,14 @@ public OpenApiDocumentTests() "code", "message" }, - Properties = new Dictionary + Properties = new Dictionary { - ["code"] = new() + ["code"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" }, - ["message"] = new() + ["message"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -208,12 +198,12 @@ public OpenApiDocumentTests() } }; - public static OpenApiSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"]; + public static OpenApiSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"] as OpenApiSchema; - public static OpenApiSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"]; + public static OpenApiSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"] as OpenApiSchema; public static OpenApiSchema ErrorModelSchemaWithReference = - AdvancedComponentsWithReference.Schemas["errorModel"]; + AdvancedComponentsWithReference.Schemas["errorModel"] as OpenApiSchema; public static readonly OpenApiDocument AdvancedDocumentWithReference = new OpenApiDocument { @@ -261,10 +251,10 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -276,7 +266,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -292,7 +282,7 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchemaWithReference @@ -300,7 +290,7 @@ public OpenApiDocumentTests() }, ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchemaWithReference @@ -404,7 +394,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -464,7 +454,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -510,9 +500,9 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponents = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new() + ["pet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -520,48 +510,48 @@ public OpenApiDocumentTests() "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["newPet"] = new() + ["newPet"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet { "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, } }, - ["errorModel"] = new() + ["errorModel"] = new OpenApiSchema() { Type = JsonSchemaType.Object, Required = new HashSet @@ -569,14 +559,14 @@ public OpenApiDocumentTests() "code", "message" }, - Properties = new Dictionary + Properties = new Dictionary { - ["code"] = new() + ["code"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" }, - ["message"] = new() + ["message"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -585,11 +575,11 @@ public OpenApiDocumentTests() } }; - public static readonly OpenApiSchema PetSchema = AdvancedComponents.Schemas["pet"]; + public static readonly OpenApiSchema PetSchema = AdvancedComponents.Schemas["pet"] as OpenApiSchema; - public static readonly OpenApiSchema NewPetSchema = AdvancedComponents.Schemas["newPet"]; + public static readonly OpenApiSchema NewPetSchema = AdvancedComponents.Schemas["newPet"] as OpenApiSchema; - public static readonly OpenApiSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"]; + public static readonly OpenApiSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"] as OpenApiSchema; public OpenApiDocument AdvancedDocument = new OpenApiDocument { @@ -637,10 +627,10 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -652,7 +642,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -668,7 +658,7 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchema @@ -676,7 +666,7 @@ public OpenApiDocumentTests() }, ["application/xml"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchema @@ -780,7 +770,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -840,7 +830,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -923,7 +913,7 @@ public OpenApiDocumentTests() }, Components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { ["Pet"] = new OpenApiSchema() { @@ -931,18 +921,18 @@ public OpenApiDocumentTests() { "id", "name" }, - Properties = new Dictionary + Properties = new Dictionary { - ["id"] = new() + ["id"] = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" }, - ["name"] = new() + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String }, - ["tag"] = new() + ["tag"] = new OpenApiSchema() { Type = JsonSchemaType.String }, @@ -984,7 +974,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The first operand", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Extensions = new Dictionary @@ -1003,7 +993,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The second operand", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Extensions = new Dictionary @@ -1026,7 +1016,7 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchema @@ -1096,10 +1086,10 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -1111,7 +1101,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -1127,7 +1117,7 @@ public OpenApiDocumentTests() { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchema @@ -1135,7 +1125,7 @@ public OpenApiDocumentTests() }, ["application/xml"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = PetSchema @@ -1239,7 +1229,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -1299,7 +1289,7 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" @@ -1561,14 +1551,6 @@ public async Task SerializeDocumentWithReferenceButNoComponents() { ["application/json"] = new OpenApiMediaType { - Schema = new() - { - Reference = new() - { - Id = "test", - Type = ReferenceType.Schema - } - } } } } @@ -1578,6 +1560,7 @@ public async Task SerializeDocumentWithReferenceButNoComponents() } } }; + document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema = new OpenApiSchemaReference("test", document); // Act var actual = await document.SerializeAsync(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json); @@ -1738,7 +1721,7 @@ public async Task SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollec new OpenApiParameter { In = ParameterLocation.Query, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -1806,10 +1789,10 @@ public async Task SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { Name = "id", In = ParameterLocation.Query, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -1825,7 +1808,7 @@ public async Task SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { ["text/plain"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index e368c587b..f6d4343cb 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -18,7 +18,7 @@ public class OpenApiHeaderTests public static OpenApiHeader AdvancedHeader = new() { Description = "sampleHeader", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" @@ -30,7 +30,7 @@ public class OpenApiHeaderTests public static OpenApiHeader ReferencedHeader = new() { Description = "sampleHeader", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int32" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index df6b069ed..499477616 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -47,7 +47,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -64,7 +64,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -79,7 +79,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -135,7 +135,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -152,7 +152,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -167,7 +167,7 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Number, Minimum = 5, @@ -213,7 +213,7 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -225,16 +225,16 @@ public class OpenApiOperationTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String @@ -248,16 +248,16 @@ public class OpenApiOperationTests }, ["multipart/form-data"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Properties = { - ["name"] = new() + ["name"] = new OpenApiSchema() { Description = "Updated name of the pet", Type = JsonSchemaType.String }, - ["status"] = new() + ["status"] = new OpenApiSchema() { Description = "Updated status of the pet", Type = JsonSchemaType.String diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index edec7bbd8..944920fab 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; using VerifyXunit; @@ -40,14 +41,14 @@ public class OpenApiParameterTests Deprecated = false, Style = ParameterStyle.Simple, Explode = true, - Schema = new() + Schema = new OpenApiSchema() { Title = "title2", Description = "description2", - OneOf = new List + OneOf = new List { - new() { Type = JsonSchemaType.Number, Format = "double" }, - new() { Type = JsonSchemaType.String } + new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "double" }, + new OpenApiSchema() { Type = JsonSchemaType.String } } }, Examples = @@ -67,10 +68,10 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = false, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Enum = { @@ -88,10 +89,10 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Enum = [ @@ -106,7 +107,7 @@ public class OpenApiParameterTests { Name = "id", In = ParameterLocation.Query, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, AdditionalProperties = new OpenApiSchema @@ -116,35 +117,6 @@ public class OpenApiParameterTests } }; - public static OpenApiParameter AdvancedHeaderParameterWithSchemaReference = new OpenApiParameter - { - Name = "name1", - In = ParameterLocation.Header, - Description = "description1", - Required = true, - Deprecated = false, - - Style = ParameterStyle.Simple, - Explode = true, - Schema = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schemaObject1" - }, - UnresolvedReference = true - }, - Examples = - { - ["test"] = new OpenApiExample() - { - Summary = "summary3", - Description = "description3" - } - } - }; - public static OpenApiParameter AdvancedHeaderParameterWithSchemaTypeObject = new() { Name = "name1", @@ -155,7 +127,7 @@ public class OpenApiParameterTests Style = ParameterStyle.Simple, Explode = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index f391ef4d8..31d876b11 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -23,7 +23,7 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -40,7 +40,7 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index f0991a1cb..374d43772 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -29,7 +29,7 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchemaReference("customType", null) @@ -46,7 +46,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -54,7 +54,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -68,7 +68,7 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchemaReference("customType", null) @@ -85,7 +85,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -93,7 +93,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -109,7 +109,7 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchemaReference("customType", null) @@ -121,7 +121,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -129,7 +129,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -145,7 +145,7 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Array, Items = new OpenApiSchemaReference("customType", null) @@ -157,7 +157,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -165,7 +165,7 @@ public class OpenApiResponseTests ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -173,13 +173,6 @@ public class OpenApiResponseTests } }; - private readonly ITestOutputHelper _output; - - public OpenApiResponseTests(ITestOutputHelper output) - { - _output = output; - } - [Theory] [InlineData(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Json)] [InlineData(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json)] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index 5edd1c0d0..ffb10aa38 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -12,6 +12,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; using VerifyXunit; @@ -45,38 +46,38 @@ public class OpenApiSchemaTests public static readonly OpenApiSchema AdvancedSchemaObject = new() { Title = "title1", - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Integer }, - ["property3"] = new() + ["property3"] = new OpenApiSchema() { Type = JsonSchemaType.String, MaxLength = 15 } }, }, - ["property4"] = new() + ["property4"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property5"] = new() + ["property5"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property6"] = new() + ["property6"] = new OpenApiSchema() { Type = JsonSchemaType.Boolean } } }, - ["property7"] = new() + ["property7"] = new OpenApiSchema() { Type = JsonSchemaType.String, MinLength = 2 @@ -94,40 +95,40 @@ public class OpenApiSchemaTests public static readonly OpenApiSchema AdvancedSchemaWithAllOf = new() { Title = "title1", - AllOf = new List + AllOf = new List { - new() + new OpenApiSchema() { Title = "title2", - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.Integer }, - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.String, MaxLength = 15 } }, }, - new() + new OpenApiSchema() { Title = "title3", - Properties = new Dictionary + Properties = new Dictionary { - ["property3"] = new() + ["property3"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property4"] = new() + ["property4"] = new OpenApiSchema() { Type = JsonSchemaType.Boolean } } }, - ["property5"] = new() + ["property5"] = new OpenApiSchema() { Type = JsonSchemaType.String, MinLength = 2 @@ -164,18 +165,18 @@ public class OpenApiSchemaTests { Title = "title1", Required = new HashSet { "property1" }, - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Required = new HashSet { "property3" }, - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Integer }, - ["property3"] = new() + ["property3"] = new OpenApiSchema() { Type = JsonSchemaType.String, MaxLength = 15, @@ -184,21 +185,21 @@ public class OpenApiSchemaTests }, ReadOnly = true, }, - ["property4"] = new() + ["property4"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property5"] = new() + ["property5"] = new OpenApiSchema() { - Properties = new Dictionary + Properties = new Dictionary { - ["property6"] = new() + ["property6"] = new OpenApiSchema() { Type = JsonSchemaType.Boolean } } }, - ["property7"] = new() + ["property7"] = new OpenApiSchema() { Type = JsonSchemaType.String, MinLength = 2 @@ -423,14 +424,14 @@ public async Task SerializeAsV2ShouldSetFormatPropertyInParentSchemaIfPresentInC // Arrange var schema = new OpenApiSchema { - OneOf = new List + OneOf = new List { - new() + new OpenApiSchema() { Type = JsonSchemaType.Number, Format = "decimal" }, - new() { Type = JsonSchemaType.String }, + new OpenApiSchema() { Type = JsonSchemaType.String }, } }; @@ -634,7 +635,7 @@ internal class SchemaVisitor : OpenApiVisitorBase { public List Titles = new(); - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { Titles.Add(schema.Title); } diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs index 4f8e24f6e..ef9bea785 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs @@ -109,13 +109,15 @@ public void RequestBodyReferenceResolutionWorks() // Assert var localContent = _localRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(localContent); - Assert.Equal("UserSchema", localContent.Schema.Reference.Id); + var localContentSchema = Assert.IsType(localContent.Schema); + Assert.Equal("UserSchema", localContentSchema.Reference.Id); Assert.Equal("User request body", _localRequestBodyReference.Description); Assert.Equal("application/json", _localRequestBodyReference.Content.First().Key); var externalContent = _externalRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(externalContent); - Assert.Equal("UserSchema", externalContent.Schema.Reference.Id); + var externalContentSchema = Assert.IsType(externalContent.Schema); + Assert.Equal("UserSchema", externalContentSchema.Reference.Id); Assert.Equal("External Reference: User request body", _externalRequestBodyReference.Description); Assert.Equal("User creation request body", _openApiDoc_2.Components.RequestBodies.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs index 196759540..785ea5e55 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs @@ -92,12 +92,14 @@ public void ResponseReferenceResolutionWorks() // Assert var localContent = _localResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", localContent.Key); - Assert.Equal("Pong", localContent.Value.Schema.Reference.Id); + var localContentSchema = Assert.IsType(localContent.Value.Schema); + Assert.Equal("Pong", localContentSchema.Reference.Id); Assert.Equal("OK response", _localResponseReference.Description); var externalContent = _externalResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", externalContent.Key); - Assert.Equal("Pong", externalContent.Value.Schema.Reference.Id); + var externalContentSchema = Assert.IsType(externalContent.Value.Schema); + Assert.Equal("Pong", externalContentSchema.Reference.Id); Assert.Equal("External reference: OK response", _externalResponseReference.Description); Assert.Equal("OK", _openApiDoc_2.Components.Responses.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index e5c9f7bb1..9d505dbce 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -360,7 +360,7 @@ namespace Microsoft.OpenApi.Models.Interfaces System.Collections.Generic.IDictionary Examples { get; } bool Explode { get; } bool Required { get; } - Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } public interface IOpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement @@ -383,7 +383,7 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.ParameterLocation? In { get; } string Name { get; } bool Required { get; } - Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } public interface IOpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement @@ -405,6 +405,60 @@ namespace Microsoft.OpenApi.Models.Interfaces System.Collections.Generic.IDictionary Headers { get; } System.Collections.Generic.IDictionary Links { get; } } + public interface IOpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; } + bool AdditionalPropertiesAllowed { get; } + System.Collections.Generic.IList AllOf { get; } + System.Collections.Generic.IDictionary Annotations { get; } + System.Collections.Generic.IList AnyOf { get; } + string Comment { get; } + string Const { get; } + System.Text.Json.Nodes.JsonNode Default { get; } + System.Collections.Generic.IDictionary Definitions { get; } + bool Deprecated { get; } + Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; } + string DynamicAnchor { get; } + string DynamicRef { get; } + System.Collections.Generic.IList Enum { get; } + System.Text.Json.Nodes.JsonNode Example { get; } + System.Collections.Generic.IList Examples { get; } + bool? ExclusiveMaximum { get; } + bool? ExclusiveMinimum { get; } + Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } + string Format { get; } + string Id { get; } + Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Items { get; } + int? MaxItems { get; } + int? MaxLength { get; } + int? MaxProperties { get; } + decimal? Maximum { get; } + int? MinItems { get; } + int? MinLength { get; } + int? MinProperties { get; } + decimal? Minimum { get; } + decimal? MultipleOf { get; } + Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } + bool Nullable { get; } + System.Collections.Generic.IList OneOf { get; } + string Pattern { get; } + System.Collections.Generic.IDictionary PatternProperties { get; } + System.Collections.Generic.IDictionary Properties { get; } + bool ReadOnly { get; } + System.Collections.Generic.ISet Required { get; } + string Schema { get; } + string Title { get; } + Microsoft.OpenApi.Models.JsonSchemaType? Type { get; } + bool UnEvaluatedProperties { get; } + bool UnevaluatedProperties { get; } + bool? UniqueItems { get; } + System.Collections.Generic.IDictionary UnrecognizedKeywords { get; } + decimal? V31ExclusiveMaximum { get; } + decimal? V31ExclusiveMinimum { get; } + System.Collections.Generic.IDictionary Vocabulary { get; } + bool WriteOnly { get; } + Microsoft.OpenApi.Models.OpenApiXml Xml { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -447,7 +501,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? PathItems { get; set; } public System.Collections.Generic.IDictionary? RequestBodies { get; set; } public System.Collections.Generic.IDictionary? Responses { get; set; } - public System.Collections.Generic.IDictionary? Schemas { get; set; } + public System.Collections.Generic.IDictionary? Schemas { get; set; } public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -732,7 +786,7 @@ namespace Microsoft.OpenApi.Models public bool Explode { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public bool Required { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; set; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -789,7 +843,7 @@ namespace Microsoft.OpenApi.Models public System.Text.Json.Nodes.JsonNode? Example { get; set; } public System.Collections.Generic.IDictionary? Examples { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema? Schema { get; set; } + public virtual Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema? Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -859,7 +913,7 @@ namespace Microsoft.OpenApi.Models public Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } public string Name { get; set; } public bool Required { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; set; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -936,68 +990,66 @@ namespace Microsoft.OpenApi.Models public OpenApiResponses() { } public OpenApiResponses(Microsoft.OpenApi.Models.OpenApiResponses openApiResponses) { } } - public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { public OpenApiSchema() { } - public OpenApiSchema(Microsoft.OpenApi.Models.OpenApiSchema schema) { } + public OpenApiSchema(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; set; } + public bool AdditionalPropertiesAllowed { get; set; } + public System.Collections.Generic.IList AllOf { get; set; } public System.Collections.Generic.IDictionary Annotations { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } - public virtual bool AdditionalPropertiesAllowed { get; set; } - public virtual System.Collections.Generic.IList AllOf { get; set; } - public virtual System.Collections.Generic.IList AnyOf { get; set; } - public virtual string Comment { get; set; } - public virtual string Const { get; set; } - public virtual System.Text.Json.Nodes.JsonNode Default { get; set; } - public virtual System.Collections.Generic.IDictionary Definitions { get; set; } - public virtual bool Deprecated { get; set; } - public virtual string Description { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } - public virtual string DynamicAnchor { get; set; } - public virtual string DynamicRef { get; set; } - public virtual System.Collections.Generic.IList Enum { get; set; } - public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } - public virtual System.Collections.Generic.IList Examples { get; set; } - public virtual bool? ExclusiveMaximum { get; set; } - public virtual bool? ExclusiveMinimum { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public virtual string Format { get; set; } - public virtual string Id { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } - public virtual int? MaxItems { get; set; } - public virtual int? MaxLength { get; set; } - public virtual int? MaxProperties { get; set; } - public virtual decimal? Maximum { get; set; } - public virtual int? MinItems { get; set; } - public virtual int? MinLength { get; set; } - public virtual int? MinProperties { get; set; } - public virtual decimal? Minimum { get; set; } - public virtual decimal? MultipleOf { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } - public virtual bool Nullable { get; set; } - public virtual System.Collections.Generic.IList OneOf { get; set; } - public virtual string Pattern { get; set; } - public virtual System.Collections.Generic.IDictionary PatternProperties { get; set; } - public virtual System.Collections.Generic.IDictionary Properties { get; set; } - public virtual bool ReadOnly { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public virtual System.Collections.Generic.ISet Required { get; set; } - public virtual string Schema { get; set; } - public virtual string Title { get; set; } - public virtual Microsoft.OpenApi.Models.JsonSchemaType? Type { get; set; } - public virtual bool UnEvaluatedProperties { get; set; } - public virtual bool UnevaluatedProperties { get; set; } - public virtual bool? UniqueItems { get; set; } - public virtual System.Collections.Generic.IDictionary UnrecognizedKeywords { get; set; } - public virtual bool UnresolvedReference { get; set; } - public virtual decimal? V31ExclusiveMaximum { get; set; } - public virtual decimal? V31ExclusiveMinimum { get; set; } - public virtual System.Collections.Generic.IDictionary Vocabulary { get; set; } - public virtual bool WriteOnly { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public System.Collections.Generic.IList AnyOf { get; set; } + public string Comment { get; set; } + public string Const { get; set; } + public System.Text.Json.Nodes.JsonNode Default { get; set; } + public System.Collections.Generic.IDictionary Definitions { get; set; } + public bool Deprecated { get; set; } + public string Description { get; set; } + public Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } + public string DynamicAnchor { get; set; } + public string DynamicRef { get; set; } + public System.Collections.Generic.IList Enum { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; set; } + public System.Collections.Generic.IList Examples { get; set; } + public bool? ExclusiveMaximum { get; set; } + public bool? ExclusiveMinimum { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public string Format { get; set; } + public string Id { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Items { get; set; } + public int? MaxItems { get; set; } + public int? MaxLength { get; set; } + public int? MaxProperties { get; set; } + public decimal? Maximum { get; set; } + public int? MinItems { get; set; } + public int? MinLength { get; set; } + public int? MinProperties { get; set; } + public decimal? Minimum { get; set; } + public decimal? MultipleOf { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; set; } + public bool Nullable { get; set; } + public System.Collections.Generic.IList OneOf { get; set; } + public string Pattern { get; set; } + public System.Collections.Generic.IDictionary PatternProperties { get; set; } + public System.Collections.Generic.IDictionary Properties { get; set; } + public bool ReadOnly { get; set; } + public System.Collections.Generic.ISet Required { get; set; } + public string Schema { get; set; } + public string Title { get; set; } + public Microsoft.OpenApi.Models.JsonSchemaType? Type { get; set; } + public bool UnEvaluatedProperties { get; set; } + public bool UnevaluatedProperties { get; set; } + public bool? UniqueItems { get; set; } + public System.Collections.Generic.IDictionary UnrecognizedKeywords { get; set; } + public decimal? V31ExclusiveMaximum { get; set; } + public decimal? V31ExclusiveMinimum { get; set; } + public System.Collections.Generic.IDictionary Vocabulary { get; set; } + public bool WriteOnly { get; set; } + public Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1181,8 +1233,8 @@ namespace Microsoft.OpenApi.Models.References public bool UnresolvedReference { get; set; } public abstract V CopyReferenceAsTargetElementWithOverrides(V source); public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { @@ -1219,7 +1271,7 @@ namespace Microsoft.OpenApi.Models.References public bool Explode { get; } public System.Collections.Generic.IDictionary Extensions { get; } public bool Required { get; } - public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } } @@ -1253,7 +1305,7 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.ParameterLocation? In { get; } public string Name { get; } public bool Required { get; } - public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } } @@ -1291,61 +1343,63 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IDictionary Links { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse source) { } } - public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiSchema? Target { get; } - public override Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } - public override bool AdditionalPropertiesAllowed { get; set; } - public override System.Collections.Generic.IList AllOf { get; set; } - public override System.Collections.Generic.IList AnyOf { get; set; } - public override string Comment { get; set; } - public override string Const { get; set; } - public override System.Text.Json.Nodes.JsonNode Default { get; set; } - public override System.Collections.Generic.IDictionary Definitions { get; set; } - public override bool Deprecated { get; set; } - public override string Description { get; set; } - public override Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } - public override string DynamicAnchor { get; set; } - public override string DynamicRef { get; set; } - public override System.Collections.Generic.IList Enum { get; set; } - public override System.Text.Json.Nodes.JsonNode Example { get; set; } - public override System.Collections.Generic.IList Examples { get; set; } - public override bool? ExclusiveMaximum { get; set; } - public override bool? ExclusiveMinimum { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public override string Format { get; set; } - public override string Id { get; set; } - public override Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } - public override int? MaxItems { get; set; } - public override int? MaxLength { get; set; } - public override int? MaxProperties { get; set; } - public override decimal? Maximum { get; set; } - public override int? MinItems { get; set; } - public override int? MinLength { get; set; } - public override int? MinProperties { get; set; } - public override decimal? Minimum { get; set; } - public override decimal? MultipleOf { get; set; } - public override Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } - public override bool Nullable { get; set; } - public override System.Collections.Generic.IList OneOf { get; set; } - public override string Pattern { get; set; } - public override System.Collections.Generic.IDictionary PatternProperties { get; set; } - public override System.Collections.Generic.IDictionary Properties { get; set; } - public override bool ReadOnly { get; set; } - public override System.Collections.Generic.ISet Required { get; set; } - public override string Schema { get; set; } - public override string Title { get; set; } - public override Microsoft.OpenApi.Models.JsonSchemaType? Type { get; set; } - public override bool UnEvaluatedProperties { get; set; } - public override bool UnevaluatedProperties { get; set; } - public override bool? UniqueItems { get; set; } - public override decimal? V31ExclusiveMaximum { get; set; } - public override decimal? V31ExclusiveMinimum { get; set; } - public override System.Collections.Generic.IDictionary Vocabulary { get; set; } - public override bool WriteOnly { get; set; } - public override Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; } + public bool AdditionalPropertiesAllowed { get; } + public System.Collections.Generic.IList AllOf { get; } + public System.Collections.Generic.IDictionary Annotations { get; } + public System.Collections.Generic.IList AnyOf { get; } + public string Comment { get; } + public string Const { get; } + public System.Text.Json.Nodes.JsonNode Default { get; } + public System.Collections.Generic.IDictionary Definitions { get; } + public bool Deprecated { get; } + public string Description { get; set; } + public Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; } + public string DynamicAnchor { get; } + public string DynamicRef { get; } + public System.Collections.Generic.IList Enum { get; } + public System.Text.Json.Nodes.JsonNode Example { get; } + public System.Collections.Generic.IList Examples { get; } + public bool? ExclusiveMaximum { get; } + public bool? ExclusiveMinimum { get; } + public System.Collections.Generic.IDictionary Extensions { get; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } + public string Format { get; } + public string Id { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Items { get; } + public int? MaxItems { get; } + public int? MaxLength { get; } + public int? MaxProperties { get; } + public decimal? Maximum { get; } + public int? MinItems { get; } + public int? MinLength { get; } + public int? MinProperties { get; } + public decimal? Minimum { get; } + public decimal? MultipleOf { get; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } + public bool Nullable { get; } + public System.Collections.Generic.IList OneOf { get; } + public string Pattern { get; } + public System.Collections.Generic.IDictionary PatternProperties { get; } + public System.Collections.Generic.IDictionary Properties { get; } + public bool ReadOnly { get; } + public System.Collections.Generic.ISet Required { get; } + public string Schema { get; } + public string Title { get; } + public Microsoft.OpenApi.Models.JsonSchemaType? Type { get; } + public bool UnEvaluatedProperties { get; } + public bool UnevaluatedProperties { get; } + public bool? UniqueItems { get; } + public System.Collections.Generic.IDictionary UnrecognizedKeywords { get; } + public decimal? V31ExclusiveMaximum { get; } + public decimal? V31ExclusiveMinimum { get; } + public System.Collections.Generic.IDictionary Vocabulary { get; } + public bool WriteOnly { get; } + public Microsoft.OpenApi.Models.OpenApiXml Xml { get; } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema source) { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1567,6 +1621,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1579,7 +1634,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } @@ -1666,6 +1720,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1678,7 +1733,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } @@ -1784,7 +1838,7 @@ namespace Microsoft.OpenApi.Validations.Rules public static Microsoft.OpenApi.Validations.ValidationRule HeaderMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule MediaTypeMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule ParameterMismatchedDataType { get; } - public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } + public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiOAuthFlowRules @@ -1823,9 +1877,9 @@ namespace Microsoft.OpenApi.Validations.Rules [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiSchemaRules { - public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } - public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IList childSchema) { } - public static bool ValidateChildSchemaAgainstDiscriminator(Microsoft.OpenApi.Models.OpenApiSchema schema, string discriminatorName) { } + public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } + public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IList childSchema) { } + public static bool ValidateChildSchemaAgainstDiscriminator(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema, string discriminatorName) { } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiServerRules diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index 96afcb301..05b4bb62c 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -20,7 +20,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { Example = 55, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, } @@ -47,10 +47,10 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Integer, } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 13328046e..721445e23 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -71,7 +71,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() In = ParameterLocation.Path, Required = true, Example = 55, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, } @@ -99,10 +99,10 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Integer, } @@ -159,7 +159,7 @@ public void PathParameterNotInThePathShouldReturnAnError() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, } @@ -194,7 +194,7 @@ public void PathParameterInThePathShouldBeOk() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaType.String, } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index de9d58443..ea9a9660a 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -6,6 +6,8 @@ using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Validations; using Xunit; @@ -21,17 +23,12 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() var sharedSchema = new OpenApiSchema { Type = JsonSchemaType.String, - Reference = new() - { - Id = "test" - }, - UnresolvedReference = false }; var document = new OpenApiDocument(); document.Components = new() { - Schemas = new Dictionary() + Schemas = new Dictionary() { ["test"] = sharedSchema } @@ -53,7 +50,7 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() { ["application/json"] = new() { - Schema = sharedSchema + Schema = new OpenApiSchemaReference(sharedSchema, "test") } } } @@ -66,8 +63,8 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() // Act var rules = new Dictionary>() { - { typeof(OpenApiSchema), - new List() { new AlwaysFailRule() } + { typeof(IOpenApiSchema), + new List() { new AlwaysFailRule() } } }; @@ -75,7 +72,7 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() // Assert - Assert.True(errors.Count() == 1); + Assert.Single(errors); } [Fact] @@ -86,14 +83,10 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() var sharedSchema = new OpenApiSchema { Type = JsonSchemaType.String, - Reference = new() - { - Id = "test" - }, - UnresolvedReference = true }; var document = new OpenApiDocument(); + document.AddComponent("test", sharedSchema); document.Paths = new() { @@ -111,7 +104,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() { ["application/json"] = new() { - Schema = sharedSchema + Schema = new OpenApiSchemaReference(sharedSchema, "test") } } } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index 9edd57c1e..d8820defc 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -7,6 +7,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations.Rules; @@ -89,7 +90,7 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() }).Node }, Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Integer } @@ -111,39 +112,38 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() { // Arrange - IEnumerable warnings; var schema = new OpenApiSchema { Type = JsonSchemaType.Object, Properties = { - ["property1"] = new() + ["property1"] = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.Integer, Format = "int64" } }, - ["property2"] = new() + ["property2"] = new OpenApiSchema() { Type = JsonSchemaType.Array, - Items = new() + Items = new OpenApiSchema() { Type = JsonSchemaType.Object, - AdditionalProperties = new() + AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Boolean } } }, - ["property3"] = new() + ["property3"] = new OpenApiSchema() { Type = JsonSchemaType.String, Format = "password" }, - ["property4"] = new() + ["property4"] = new OpenApiSchema() { Type = JsonSchemaType.String } @@ -173,22 +173,18 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() // Act var defaultRuleSet = ValidationRuleSet.GetDefaultRuleSet(); - defaultRuleSet.Add(typeof(OpenApiSchema), OpenApiNonDefaultRules.SchemaMismatchedDataType); + defaultRuleSet.Add(typeof(IOpenApiSchema), OpenApiNonDefaultRules.SchemaMismatchedDataType); var validator = new OpenApiValidator(defaultRuleSet); var walker = new OpenApiWalker(validator); - walker.Walk(schema); - - warnings = validator.Warnings; - bool result = !warnings.Any(); + walker.Walk((IOpenApiSchema)schema); // Assert - Assert.False(result); + Assert.NotEmpty(validator.Warnings); } [Fact] public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator() { - IEnumerable errors; var components = new OpenApiComponents { Schemas = { @@ -198,7 +194,6 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD { Type = JsonSchemaType.Object, Discriminator = new() { PropertyName = "property1" }, - Reference = new() { Id = "schema1" } } } } @@ -208,17 +203,14 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD var walker = new OpenApiWalker(validator); walker.Walk(components); - errors = validator.Errors; - var result = !errors.Any(); - // Assert - Assert.False(result); + Assert.NotEmpty(validator.Errors); Assert.Equivalent(new List { new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateSchemaDiscriminator),"#/schemas/schema1/discriminator", string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, - "schema1", "property1")) - }, errors); + string.Empty, "property1")) + }, validator.Errors); } [Fact] @@ -238,9 +230,9 @@ public void ValidateOneOfSchemaPropertyNameContainsPropertySpecifiedInTheDiscrim { PropertyName = "type" }, - OneOf = new List + OneOf = new List { - new() + new OpenApiSchema() { Properties = { @@ -252,14 +244,8 @@ public void ValidateOneOfSchemaPropertyNameContainsPropertySpecifiedInTheDiscrim } } }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Person" - } } }, - Reference = new() { Id = "Person" } } } } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index fbe0abf14..a11d64599 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -43,7 +43,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiComponents)); visitor.Visit(default(OpenApiExternalDocs)); - visitor.Visit(default(OpenApiSchema)); + visitor.Visit(default(IOpenApiSchema)); visitor.Visit(default(IDictionary)); visitor.Visit(default(IOpenApiLink)); visitor.Visit(default(IOpenApiCallback)); @@ -232,7 +232,7 @@ public override void Visit(OpenApiExternalDocs externalDocs) base.Visit(externalDocs); } - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { EncodeCall(); base.Visit(schema); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index c4ed91658..fa5b901dc 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -121,9 +121,9 @@ public void WalkDOMWithCycles() var loopySchema = new OpenApiSchema { Type = JsonSchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { - ["name"] = new() { Type = JsonSchemaType.String } + ["name"] = new OpenApiSchema() { Type = JsonSchemaType.String } } }; @@ -133,7 +133,7 @@ public void WalkDOMWithCycles() { Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { ["loopy"] = loopySchema } @@ -161,22 +161,16 @@ public void WalkDOMWithCycles() [Fact] public void LocateReferences() { - var baseSchema = new OpenApiSchemaReference("base", null); + var baseSchema = new OpenApiSchema(); var derivedSchema = new OpenApiSchema { - AnyOf = new List { baseSchema }, - Reference = new() - { - Id = "derived", - Type = ReferenceType.Schema - }, - UnresolvedReference = false + AnyOf = new List { new OpenApiSchemaReference(baseSchema, "base") }, }; var testHeader = new OpenApiHeader() { - Schema = derivedSchema, + Schema = new OpenApiSchemaReference(derivedSchema, "derived"), }; var testHeaderReference = new OpenApiHeaderReference(testHeader, "test-header"); @@ -198,7 +192,7 @@ public void LocateReferences() { ["application/json"] = new() { - Schema = derivedSchema + Schema = new OpenApiSchemaReference(derivedSchema, "derived") } }, Headers = @@ -213,7 +207,7 @@ public void LocateReferences() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { ["derived"] = derivedSchema, ["base"] = baseSchema, @@ -305,7 +299,7 @@ public override void Visit(OpenApiMediaType mediaType) Locations.Add(this.PathString); } - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { Locations.Add(this.PathString); } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index 14e017fe9..38a9b2d8d 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Services; using Xunit; @@ -15,6 +16,11 @@ public class OpenApiWorkspaceTests [Fact] public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { + var testSchema = new OpenApiSchema() + { + Type = JsonSchemaType.String, + Description = "The referenced one" + }; var doc = new OpenApiDocument() { Paths = new OpenApiPaths() @@ -33,14 +39,7 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { ["application/json"] = new OpenApiMediaType() { - Schema = new() - { - Reference = new() - { - Id = "test", - Type = ReferenceType.Schema - } - } + Schema = new OpenApiSchemaReference(testSchema, "test") } } } @@ -56,11 +55,7 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() Components = new OpenApiComponents() { Schemas = { - ["test"] = new() - { - Type = JsonSchemaType.String, - Description = "The referenced one" - } + ["test"] = testSchema } } }; @@ -76,7 +71,8 @@ public void OpenApiWorkspacesCanResolveExternalReferences() var workspace = new OpenApiWorkspace(); var externalDoc = CreateCommonDocument(); - workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]); + var castSchema = Assert.IsType(externalDoc.Components.Schemas["test"]); + workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", castSchema); var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test"); @@ -135,7 +131,7 @@ private static OpenApiDocument CreateCommonDocument() { Schemas = { - ["test"] = new() + ["test"] = new OpenApiSchema() { Type = JsonSchemaType.String, Description = "The referenced one" diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index f10dba764..403922622 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -8,6 +8,7 @@ using System.IO; using System.Threading.Tasks; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; using Xunit; @@ -441,12 +442,6 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() var thingSchema = new OpenApiSchema { Type = JsonSchemaType.Object, - UnresolvedReference = false, - Reference = new() - { - Id = "thing", - Type = ReferenceType.Schema - } }; var doc = new OpenApiDocument() @@ -470,7 +465,7 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() Content = { ["application/json"] = new() { - Schema = thingSchema + Schema = new OpenApiSchemaReference(thingSchema, "thing") } } } From 41759a1cb587d38392f730dfce74e974c76189c6 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Jan 2025 16:55:45 -0500 Subject: [PATCH 043/103] fix: missing doc comment for annotations Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs index 5495ab307..c0c78b765 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs @@ -299,6 +299,9 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable /// public IDictionary UnrecognizedKeywords { get; } - /// + /// + /// Any annotation to attach to the schema to be used by the application. + /// Annotations are NOT (de)serialized with the schema and can be used for custom properties. + /// public IDictionary Annotations { get; } } From 4dfc9b8c533d454cefa3d576adb4d3d422747d16 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Jan 2025 17:03:57 -0500 Subject: [PATCH 044/103] fix: removes virtual modifier in MediaType Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiMediaType.cs | 2 +- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index d350c3251..6ae08b06a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -22,7 +22,7 @@ public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible /// /// The schema defining the type used for the request body. /// - public virtual IOpenApiSchema? Schema { get; set; } + public IOpenApiSchema? Schema { get; set; } /// /// Example of the media type. diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 9d505dbce..11020cee0 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -843,7 +843,7 @@ namespace Microsoft.OpenApi.Models public System.Text.Json.Nodes.JsonNode? Example { get; set; } public System.Collections.Generic.IDictionary? Examples { get; set; } public System.Collections.Generic.IDictionary? Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema? Schema { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema? Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From 21253f6d5e01500bd569e5b7f9d9b80c227b6088 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Jan 2025 17:08:29 -0500 Subject: [PATCH 045/103] chore: reduce fluent assertion usage Signed-off-by: Vincent Biret --- .../V3Tests/OpenApiDocumentTests.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index d5ccec6cc..32c27b3b1 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1390,12 +1390,8 @@ public async Task ParseDocumentWithEmptyPathsSucceeds() public async Task ParseDocumentWithExampleReferencesPasses() { // Act & Assert: Ensure no NullReferenceException is thrown - Func act = async () => - { - await OpenApiDocument.LoadAsync(System.IO.Path.Combine(SampleFolderPath, "docWithExampleReferences.yaml")); - }; - - await act.Should().NotThrowAsync(); + var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExampleReferences.yaml")); + Assert.Empty(result.Diagnostic.Errors); } } } From 1bd2624dcb6751c9f31ecec422d5ec9852370397 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 09:00:45 -0500 Subject: [PATCH 046/103] fix: draft security scheme reference proxy design pattern Signed-off-by: Vincent Biret --- .../Interfaces/IOpenApiSecurityScheme.cs | 50 +++++++ .../Models/OpenApiComponents.cs | 8 +- .../Models/OpenApiDocument.cs | 2 +- .../Models/OpenApiSecurityRequirement.cs | 33 +++-- .../Models/OpenApiSecurityScheme.cs | 85 ++++-------- .../OpenApiSecuritySchemeReference.cs | 124 ++++-------------- .../OpenApiSecurityRequirementDeserializer.cs | 20 +-- .../V2/OpenApiSecuritySchemeDeserializer.cs | 3 +- .../OpenApiSecurityRequirementDeserializer.cs | 10 +- .../V3/OpenApiSecuritySchemeDeserializer.cs | 3 +- .../OpenApiSecurityRequirementDeserializer.cs | 6 +- .../V31/OpenApiSecuritySchemeDeserializer.cs | 3 +- .../Services/CopyReferences.cs | 6 +- .../Services/OpenApiVisitorBase.cs | 4 +- .../Services/OpenApiWalker.cs | 4 +- .../Validations/OpenApiValidator.cs | 2 +- .../Models/OpenApiComponentsTests.cs | 6 +- .../Models/OpenApiSecurityRequirementTests.cs | 2 +- .../Models/OpenApiSecuritySchemeTests.cs | 2 +- ...orks_produceTerseOutput=False.verified.txt | 5 - ...Works_produceTerseOutput=True.verified.txt | 1 - ...orks_produceTerseOutput=False.verified.txt | 5 - ...Works_produceTerseOutput=True.verified.txt | 1 - .../OpenApiSecuritySchemeReferenceTests.cs | 24 ++-- .../Visitors/InheritanceTests.cs | 4 +- .../Walkers/WalkerLocationTests.cs | 2 +- 26 files changed, 174 insertions(+), 241 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs new file mode 100644 index 000000000..620ad185c --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the security scheme object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +{ + /// + /// REQUIRED. The type of the security scheme. Valid values are "apiKey", "http", "oauth2", "openIdConnect". + /// + public SecuritySchemeType? Type { get; } + + /// + /// REQUIRED. The name of the header, query or cookie parameter to be used. + /// + public string Name { get; } + + /// + /// REQUIRED. The location of the API key. Valid values are "query", "header" or "cookie". + /// + public ParameterLocation? In { get; } + + /// + /// REQUIRED. The name of the HTTP Authorization scheme to be used + /// in the Authorization header as defined in RFC7235. + /// + public string Scheme { get; } + + /// + /// A hint to the client to identify how the bearer token is formatted. + /// Bearer tokens are usually generated by an authorization server, + /// so this information is primarily for documentation purposes. + /// + public string BearerFormat { get; } + + /// + /// REQUIRED. An object containing configuration information for the flow types supported. + /// + public OpenApiOAuthFlows Flows { get; } + + /// + /// REQUIRED. OpenId Connect URL to discover OAuth2 configuration values. + /// + public Uri OpenIdConnectUrl { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 6b735087e..250254212 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -50,10 +50,10 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible public IDictionary? Headers { get; set; } = new Dictionary(); /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary? SecuritySchemes { get; set; } = - new Dictionary(); + public IDictionary? SecuritySchemes { get; set; } = + new Dictionary(); /// /// An object to hold reusable Objects. @@ -91,7 +91,7 @@ public OpenApiComponents(OpenApiComponents? components) Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; RequestBodies = components?.RequestBodies != null ? new Dictionary(components.RequestBodies) : null; Headers = components?.Headers != null ? new Dictionary(components.Headers) : null; - SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; + SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null; Links = components?.Links != null ? new Dictionary(components.Links) : null; Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null; PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index eaf436793..72fb875ef 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -624,7 +624,7 @@ public bool AddComponent(string id, T componentToRegister) Components.Headers.Add(id, openApiHeader); break; case OpenApiSecurityScheme openApiSecurityScheme: - Components.SecuritySchemes ??= new Dictionary(); + Components.SecuritySchemes ??= new Dictionary(); Components.SecuritySchemes.Add(id, openApiSecurityScheme); break; default: diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index 428d0649e..930698af0 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -16,7 +18,7 @@ namespace Microsoft.OpenApi.Models /// then the value is a list of scope names required for the execution. /// For other security scheme types, the array MUST be empty. /// - public class OpenApiSecurityRequirement : Dictionary>, + public class OpenApiSecurityRequirement : Dictionary>, IOpenApiSerializable { /// @@ -59,7 +61,7 @@ private void SerializeInternal(IOpenApiWriter writer, Action - private class OpenApiSecuritySchemeReferenceEqualityComparer : IEqualityComparer + private sealed class OpenApiSecuritySchemeReferenceEqualityComparer : IEqualityComparer { /// /// Determines whether the specified objects are equal. /// - public bool Equals(OpenApiSecurityScheme x, OpenApiSecurityScheme y) + public bool Equals(IOpenApiSecurityScheme x, IOpenApiSecurityScheme y) { if (x == null && y == null) { @@ -140,20 +142,23 @@ public bool Equals(OpenApiSecurityScheme x, OpenApiSecurityScheme y) return false; } - if (x.Reference == null || y.Reference == null) - { - return false; - } - - return x.Reference.Id == y.Reference.Id; + return GetHashCode(x) == GetHashCode(y); } /// /// Returns a hash code for the specified object. /// - public int GetHashCode(OpenApiSecurityScheme obj) + public int GetHashCode(IOpenApiSecurityScheme obj) { - return obj?.Reference?.Id == null ? 0 : obj.Reference.Id.GetHashCode(); + if (obj is null) + { + return 0; + } + else if (obj is OpenApiSecuritySchemeReference reference) + { + return string.IsNullOrEmpty(reference?.Reference?.Id) ? 0 : reference.Reference.Id.GetHashCode(); + } + return obj.GetHashCode(); } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs index d9227be25..3d9e0e636 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -12,65 +13,34 @@ namespace Microsoft.OpenApi.Models /// /// Security Scheme Object. /// - public class OpenApiSecurityScheme : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiSecurityScheme : IOpenApiExtensible, IOpenApiReferenceable, IOpenApiSecurityScheme { - /// - /// REQUIRED. The type of the security scheme. Valid values are "apiKey", "http", "oauth2", "openIdConnect". - /// - public virtual SecuritySchemeType? Type { get; set; } - - /// - /// A short description for security scheme. CommonMark syntax MAY be used for rich text representation. - /// - public virtual string Description { get; set; } - - /// - /// REQUIRED. The name of the header, query or cookie parameter to be used. - /// - public virtual string Name { get; set; } + /// + public SecuritySchemeType? Type { get; set; } - /// - /// REQUIRED. The location of the API key. Valid values are "query", "header" or "cookie". - /// - public virtual ParameterLocation? In { get; set; } + /// + public string Description { get; set; } - /// - /// REQUIRED. The name of the HTTP Authorization scheme to be used - /// in the Authorization header as defined in RFC7235. - /// - public virtual string Scheme { get; set; } + /// + public string Name { get; set; } - /// - /// A hint to the client to identify how the bearer token is formatted. - /// Bearer tokens are usually generated by an authorization server, - /// so this information is primarily for documentation purposes. - /// - public virtual string BearerFormat { get; set; } + /// + public ParameterLocation? In { get; set; } - /// - /// REQUIRED. An object containing configuration information for the flow types supported. - /// - public virtual OpenApiOAuthFlows Flows { get; set; } + /// + public string Scheme { get; set; } - /// - /// REQUIRED. OpenId Connect URL to discover OAuth2 configuration values. - /// - public virtual Uri OpenIdConnectUrl { get; set; } + /// + public string BearerFormat { get; set; } - /// - /// Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + /// + public OpenApiOAuthFlows Flows { get; set; } - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public bool UnresolvedReference { get; set; } + /// + public Uri OpenIdConnectUrl { get; set; } - /// - /// Reference object. - /// - public OpenApiReference Reference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -78,10 +48,11 @@ public class OpenApiSecurityScheme : IOpenApiReferenceable, IOpenApiExtensible public OpenApiSecurityScheme() { } /// - /// Initializes a copy of object + /// Initializes a copy of object /// - public OpenApiSecurityScheme(OpenApiSecurityScheme securityScheme) + public OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme) { + Utils.CheckArgumentNull(securityScheme); Type = securityScheme?.Type; Description = securityScheme?.Description ?? Description; Name = securityScheme?.Name ?? Name; @@ -91,14 +62,12 @@ public OpenApiSecurityScheme(OpenApiSecurityScheme securityScheme) Flows = securityScheme?.Flows != null ? new(securityScheme?.Flows) : null; OpenIdConnectUrl = securityScheme?.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null; Extensions = securityScheme?.Extensions != null ? new Dictionary(securityScheme.Extensions) : null; - UnresolvedReference = securityScheme?.UnresolvedReference ?? UnresolvedReference; - Reference = securityScheme?.Reference != null ? new(securityScheme?.Reference) : null; } /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } @@ -106,12 +75,12 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { Utils.CheckArgumentNull(writer); @@ -161,7 +130,7 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio /// /// Serialize to Open Api v2.0 /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index c1dafa80f..a05070472 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -4,147 +4,69 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Models.References { /// /// Security Scheme Object Reference. /// - public class OpenApiSecuritySchemeReference : OpenApiSecurityScheme, IOpenApiReferenceHolder + public class OpenApiSecuritySchemeReference : BaseOpenApiReferenceHolder, IOpenApiSecurityScheme { - internal OpenApiSecurityScheme _target; - private readonly OpenApiReference _reference; - private string _description; - - /// - /// Gets the target security scheme. - /// - /// - /// If the reference is not resolved, this will return null. - /// - public OpenApiSecurityScheme Target - { - get - { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); - OpenApiSecurityScheme resolved = new OpenApiSecurityScheme(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; - } - } - /// /// Constructor initializing the reference object. /// /// The reference Id. /// The host OpenAPI document. /// The externally referenced file. - public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.SecurityScheme, externalResource) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - _reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.SecurityScheme, - ExternalResource = externalResource - }; - - Reference = _reference; } - - internal OpenApiSecuritySchemeReference(string referenceId, OpenApiSecurityScheme target) + internal OpenApiSecuritySchemeReference(OpenApiSecurityScheme target, string referenceId):base(target, referenceId, ReferenceType.SecurityScheme) { - _target = target; - - _reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.SecurityScheme, - }; } /// - public override string Description + public string Description { - get => string.IsNullOrEmpty(_description) ? Target.Description : _description; - set => _description = value; + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; + set + { + if (Reference is not null) + { + Reference.Description = value; + } + } } /// - public override string Name { get => Target.Name; set => Target.Name = value; } - - /// - public override ParameterLocation? In { get => Target.In; set => Target.In = value; } + public string Name { get => Target?.Name; } /// - public override string Scheme { get => Target.Scheme; set => Target.Scheme = value; } + public ParameterLocation? In { get => Target?.In; } /// - public override string BearerFormat { get => Target.BearerFormat; set => Target.BearerFormat = value; } + public string Scheme { get => Target?.Scheme; } /// - public override OpenApiOAuthFlows Flows { get => Target.Flows; set => Target.Flows = value; } + public string BearerFormat { get => Target?.BearerFormat; } /// - public override Uri OpenIdConnectUrl { get => Target.OpenIdConnectUrl; set => Target.OpenIdConnectUrl = value; } + public OpenApiOAuthFlows Flows { get => Target?.Flows; } /// - public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + public Uri OpenIdConnectUrl { get => Target?.OpenIdConnectUrl; } /// - public override SecuritySchemeType? Type { get => Target.Type; set => Target.Type = value; } - - /// - public override void SerializeAsV3(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV3(writer); - return; - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - } - } - - /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV31(writer); - return; - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - } - } + public IDictionary Extensions { get => Target?.Extensions; } /// - public override void SerializeAsV2(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(_reference)) - { - _reference.SerializeAsV2(writer); - return; - } - else - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); - } - } + public SecuritySchemeType? Type { get => Target?.Type; } /// - private void SerializeInternal(IOpenApiWriter writer, - Action action) + public override IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides(IOpenApiSecurityScheme source) { - Utils.CheckArgumentNull(writer);; - action(writer, Target); + return source is OpenApiSecurityScheme ? new OpenApiSecurityScheme(this) : source; } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs index 4dfdbba16..b3183dcce 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs @@ -2,6 +2,8 @@ // Licensed under the MIT license. using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V2 @@ -21,7 +23,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, foreach (var property in mapNode) { var scheme = LoadSecuritySchemeByReference( - mapNode.Context, + hostDocument, property.Name); var scopes = property.Value.CreateSimpleList((n2, p) => n2.GetScalarValue(), hostDocument); @@ -41,21 +43,11 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static OpenApiSecurityScheme LoadSecuritySchemeByReference( - ParsingContext context, + private static IOpenApiSecurityScheme LoadSecuritySchemeByReference( + OpenApiDocument openApiDocument, string schemeName) { - var securitySchemeObject = new OpenApiSecurityScheme - { - UnresolvedReference = true, - Reference = new() - { - Id = schemeName, - Type = ReferenceType.SecurityScheme - } - }; - - return securitySchemeObject; + return new OpenApiSecuritySchemeReference(schemeName, openApiDocument); } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs index 43151c15a..e3bf63ff7 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs @@ -4,6 +4,7 @@ using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V2 @@ -80,7 +81,7 @@ internal static partial class OpenApiV2Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) { // Reset the local variables every time this method is called. // TODO: Change _flow to a tempStorage variable to make the deserializer thread-safe. diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs index 73610713c..7702d4bd6 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -21,7 +22,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, foreach (var property in mapNode) { - var scheme = LoadSecuritySchemeByReference(mapNode.Context, property.Name); + var scheme = LoadSecuritySchemeByReference(hostDocument, property.Name); var scopes = property.Value.CreateSimpleList((value, p) => value.GetScalarValue(), hostDocument); @@ -39,12 +40,11 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static OpenApiSecurityScheme LoadSecuritySchemeByReference( - ParsingContext context, + private static IOpenApiSecurityScheme LoadSecuritySchemeByReference( + OpenApiDocument openApiDocument, string schemeName) { - var securitySchemeObject = new OpenApiSecuritySchemeReference(schemeName, hostDocument: null); - return securitySchemeObject; + return new OpenApiSecuritySchemeReference(schemeName, openApiDocument); } } } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs index 18c4eae28..1a0ccd5c4 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs @@ -4,6 +4,7 @@ using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -72,7 +73,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("securityScheme"); var pointer = mapNode.GetReferencePointer(); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs index b204c83d4..4026793b3 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -39,10 +40,9 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static OpenApiSecurityScheme LoadSecuritySchemeByReference(string schemeName, OpenApiDocument hostDocument) + private static IOpenApiSecurityScheme LoadSecuritySchemeByReference(string schemeName, OpenApiDocument hostDocument) { - var securitySchemeObject = new OpenApiSecuritySchemeReference(schemeName, hostDocument); - return securitySchemeObject; + return new OpenApiSecuritySchemeReference(schemeName, hostDocument); } } } diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs index b56352c22..004fd0551 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs @@ -4,6 +4,7 @@ using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -82,7 +83,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) + public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("securityScheme"); diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 490c7cff8..980aafb56 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -172,9 +172,9 @@ private void AddSecuritySchemeToComponents(OpenApiSecurityScheme securityScheme, { EnsureComponentsExist(); EnsureSecuritySchemesExist(); - if (!Components.SecuritySchemes.ContainsKey(referenceId ?? securityScheme.Reference.Id)) + if (!Components.SecuritySchemes.ContainsKey(referenceId)) { - Components.SecuritySchemes.Add(referenceId ?? securityScheme.Reference.Id, securityScheme); + Components.SecuritySchemes.Add(referenceId, securityScheme); } } @@ -236,7 +236,7 @@ private void EnsureLinksExist() private void EnsureSecuritySchemesExist() { - _target.Components.SecuritySchemes ??= new Dictionary(); + _target.Components.SecuritySchemes ??= new Dictionary(); } private void EnsurePathItemsExist() { diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 2b79864d8..254528b41 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -293,9 +293,9 @@ public virtual void Visit(OpenApiSecurityRequirement securityRequirement) } /// - /// Visits + /// Visits /// - public virtual void Visit(OpenApiSecurityScheme securityScheme) + public virtual void Visit(IOpenApiSecurityScheme securityScheme) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 8d634834a..ae4430067 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -1146,9 +1146,9 @@ internal void Walk(OpenApiSecurityRequirement securityRequirement) } /// - /// Visits and child objects + /// Visits and child objects /// - internal void Walk(OpenApiSecurityScheme securityScheme, bool isComponent = false) + internal void Walk(IOpenApiSecurityScheme securityScheme, bool isComponent = false) { if (securityScheme == null) { diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index a8669fce0..784f06172 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -135,7 +135,7 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiServerVariable serverVariable) => Validate(serverVariable); /// - public override void Visit(OpenApiSecurityScheme securityScheme) => Validate(securityScheme); + public override void Visit(IOpenApiSecurityScheme securityScheme) => Validate(securityScheme); /// public override void Visit(OpenApiSecurityRequirement securityRequirement) => Validate(securityRequirement); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 45c3dc1fc..4a60524ca 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -34,9 +34,9 @@ public class OpenApiComponentsTests } } }, - SecuritySchemes = new Dictionary + SecuritySchemes = new Dictionary { - ["securityScheme1"] = new() + ["securityScheme1"] = new OpenApiSecurityScheme() { Description = "description1", Type = SecuritySchemeType.OAuth2, @@ -53,7 +53,7 @@ public class OpenApiComponentsTests } } }, - ["securityScheme2"] = new() + ["securityScheme2"] = new OpenApiSecurityScheme() { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index af0343f57..e52d44afd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -56,7 +56,7 @@ public class OpenApiSecurityRequirementTests "scope3", }, [ - new() + new OpenApiSecurityScheme() { // This security scheme is unreferenced, so this key value pair cannot be serialized. Name = "brokenUnreferencedScheme" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index 9c59ca4bd..780b2116a 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -104,7 +104,7 @@ public class OpenApiSecuritySchemeTests OpenIdConnectUrl = new("https://example.com/openIdConnect") }; - public static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference = new(target: ReferencedSecurityScheme, referenceId: "sampleSecurityScheme"); + public static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference = new(ReferencedSecurityScheme, "sampleSecurityScheme"); public static OpenApiSecurityScheme ReferencedSecurityScheme = new() { Description = "description1", diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 073ce3d7b..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "apiKey", - "name": "X-API-Key", - "in": "header" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index 6d0080a96..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"type":"apiKey","name":"X-API-Key","in":"header"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt deleted file mode 100644 index 073ce3d7b..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "apiKey", - "name": "X-API-Key", - "in": "header" -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt deleted file mode 100644 index 6d0080a96..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"type":"apiKey","name":"X-API-Key","in":"header"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs index d13d63c9a..56b7e6d07 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs @@ -57,37 +57,41 @@ public void SecuritySchemeResolutionWorks() } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeSecuritySchemeReferenceAsV3JsonWorks(bool produceTerseOutput) + [InlineData(true, false)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(false, true)] + public async Task SerializeSecuritySchemeReferenceAsV3JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _openApiSecuritySchemeReference.SerializeAsV3(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeSecuritySchemeReferenceAsV31JsonWorks(bool produceTerseOutput) + [InlineData(true, false)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(false, true)] + public async Task SerializeSecuritySchemeReferenceAsV31JsonWorks(bool produceTerseOutput, bool inlineLocalReferences) { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = inlineLocalReferences }); // Act _openApiSecuritySchemeReference.SerializeAsV31(writer); await writer.FlushAsync(); // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); + await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput, inlineLocalReferences); } } } diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index a11d64599..581f2998a 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -51,7 +51,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IOpenApiHeader)); visitor.Visit(default(OpenApiOAuthFlow)); visitor.Visit(default(OpenApiSecurityRequirement)); - visitor.Visit(default(OpenApiSecurityScheme)); + visitor.Visit(default(IOpenApiSecurityScheme)); visitor.Visit(default(IOpenApiExample)); visitor.Visit(default(IList)); visitor.Visit(default(IList)); @@ -280,7 +280,7 @@ public override void Visit(OpenApiSecurityRequirement securityRequirement) base.Visit(securityRequirement); } - public override void Visit(OpenApiSecurityScheme securityScheme) + public override void Visit(IOpenApiSecurityScheme securityScheme) { EncodeCall(); base.Visit(securityScheme); diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index fa5b901dc..663328b78 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -216,7 +216,7 @@ public void LocateReferences() { ["test-header"] = testHeader }, - SecuritySchemes = new Dictionary + SecuritySchemes = new Dictionary { ["test-secScheme"] = new OpenApiSecuritySchemeReference("reference-to-scheme", null, null) } From ea68427110e5f789019b46885ea45f8f6b975c53 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 09:48:09 -0500 Subject: [PATCH 047/103] fix: build passes Signed-off-by: Vincent Biret --- .../TryLoadReferenceV2Tests.cs | 4 ++-- .../V3Tests/OpenApiDocumentTests.cs | 24 +++++-------------- .../V3Tests/OpenApiOperationTests.cs | 3 +-- .../Models/OpenApiComponentsTests.cs | 16 +++---------- .../Models/OpenApiSecurityRequirementTests.cs | 20 ---------------- 5 files changed, 12 insertions(+), 55 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 98cc4ed78..9d1400de6 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -56,13 +56,13 @@ public async Task LoadSecuritySchemeReference() var reference = new OpenApiSecuritySchemeReference("api_key_sample", result.Document); // Assert - reference.Should().BeEquivalentTo( + Assert.Equivalent( new OpenApiSecurityScheme { Type = SecuritySchemeType.ApiKey, Name = "api_key", In = ParameterLocation.Header - }, options => options.Excluding(x => x.Reference) + }, reference ); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 32c27b3b1..d8f58db38 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -664,7 +664,7 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }, }, - SecuritySchemes = new Dictionary + SecuritySchemes = new Dictionary { ["securitySchemeName1"] = new OpenApiSecurityScheme { @@ -700,21 +700,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() var tagReference2 = new OpenApiTagReference("tagName2", null); - var securityScheme1 = await CloneSecuritySchemeAsync(components.SecuritySchemes["securitySchemeName1"]); + var securityScheme1Cast = Assert.IsType(components.SecuritySchemes["securitySchemeName1"]); + var securityScheme1 = await CloneSecuritySchemeAsync(securityScheme1Cast); - securityScheme1.Reference = new OpenApiReference - { - Id = "securitySchemeName1", - Type = ReferenceType.SecurityScheme - }; - - var securityScheme2 = await CloneSecuritySchemeAsync(components.SecuritySchemes["securitySchemeName2"]); - - securityScheme2.Reference = new OpenApiReference - { - Id = "securitySchemeName2", - Type = ReferenceType.SecurityScheme - }; + var securityScheme2Cast = Assert.IsType(components.SecuritySchemes["securitySchemeName2"]); + var securityScheme2 = await CloneSecuritySchemeAsync(securityScheme2Cast); var expected = new OpenApiDocument { @@ -1098,8 +1088,7 @@ public async Task GlobalSecurityRequirementShouldReferenceSecurityScheme() var securityRequirement = result.Document.SecurityRequirements[0]; - securityRequirement.Keys.First().Should().BeEquivalentTo(result.Document.Components.SecuritySchemes.First().Value, - options => options.Excluding(x => x.Reference)); + Assert.Equivalent(result.Document.Components.SecuritySchemes.First().Value, securityRequirement.Keys.First()); } [Fact] @@ -1176,7 +1165,6 @@ public async Task ParseDocumentWithReferencedSecuritySchemeWorks() var securityScheme = result.Document.Components.SecuritySchemes["OAuth2"]; // Assert - Assert.False(securityScheme.UnresolvedReference); Assert.NotNull(securityScheme.Flows); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs index 3d629a23b..1dd24a128 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs @@ -27,8 +27,7 @@ public async Task OperationWithSecurityRequirementShouldReferenceSecurityScheme( var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "securedOperation.yaml")); var securityScheme = result.Document.Paths["/"].Operations[OperationType.Get].Security[0].Keys.First(); - securityScheme.Should().BeEquivalentTo(result.Document.Components.SecuritySchemes.First().Value, - options => options.Excluding(x => x.Reference)); + Assert.Equivalent(result.Document.Components.SecuritySchemes.First().Value, securityScheme); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 4a60524ca..379dc0c4f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -89,9 +89,9 @@ public class OpenApiComponentsTests } }, }, - SecuritySchemes = new Dictionary + SecuritySchemes = new Dictionary { - ["securityScheme1"] = new() + ["securityScheme1"] = new OpenApiSecurityScheme() { Description = "description1", Type = SecuritySchemeType.OAuth2, @@ -107,23 +107,13 @@ public class OpenApiComponentsTests AuthorizationUrl = new("https://example.com/api/oauth") } }, - Reference = new() - { - Type = ReferenceType.SecurityScheme, - Id = "securityScheme1" - } }, - ["securityScheme2"] = new() + ["securityScheme2"] = new OpenApiSecurityScheme() { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, Scheme = OpenApiConstants.Bearer, OpenIdConnectUrl = new("https://example.com/openIdConnect"), - Reference = new() - { - Type = ReferenceType.SecurityScheme, - Id = "securityScheme2" - } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index e52d44afd..23328f2f1 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -223,22 +223,12 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() Type = SecuritySchemeType.ApiKey, Name = "apiKeyName1", In = ParameterLocation.Header, - Reference = new() - { - Id = "securityScheme1", - Type = ReferenceType.SecurityScheme - } }; var securityScheme2 = new OpenApiSecurityScheme { Type = SecuritySchemeType.OpenIdConnect, OpenIdConnectUrl = new("http://example.com"), - Reference = new() - { - Id = "securityScheme2", - Type = ReferenceType.SecurityScheme - } }; var securityScheme1Duplicate = new OpenApiSecurityScheme @@ -246,11 +236,6 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() Type = SecuritySchemeType.ApiKey, Name = "apiKeyName1", In = ParameterLocation.Header, - Reference = new() - { - Id = "securityScheme1", - Type = ReferenceType.SecurityScheme - } }; var securityScheme1WithDifferentProperties = new OpenApiSecurityScheme @@ -258,11 +243,6 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() Type = SecuritySchemeType.ApiKey, Name = "apiKeyName2", In = ParameterLocation.Query, - Reference = new() - { - Id = "securityScheme1", - Type = ReferenceType.SecurityScheme - } }; // Act From 4aad962e821956e5c54347e0fc33aec15b465d65 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 09:50:52 -0500 Subject: [PATCH 048/103] chore: updates public api export Signed-off-by: Vincent Biret --- .../PublicApi/PublicApi.approved.txt | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 11020cee0..c8f16289a 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -459,6 +459,16 @@ namespace Microsoft.OpenApi.Models.Interfaces bool WriteOnly { get; } Microsoft.OpenApi.Models.OpenApiXml Xml { get; } } + public interface IOpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + { + string BearerFormat { get; } + Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; } + Microsoft.OpenApi.Models.ParameterLocation? In { get; } + string Name { get; } + System.Uri OpenIdConnectUrl { get; } + string Scheme { get; } + Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; } + } public interface IOpenApiSummarizedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement { string Summary { get; set; } @@ -502,7 +512,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary? RequestBodies { get; set; } public System.Collections.Generic.IDictionary? Responses { get; set; } public System.Collections.Generic.IDictionary? Schemas { get; set; } - public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } + public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1051,31 +1061,29 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSecurityRequirement() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme { public OpenApiSecurityScheme() { } - public OpenApiSecurityScheme(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public bool UnresolvedReference { get; set; } - public virtual string BearerFormat { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; set; } - public virtual Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } - public virtual string Name { get; set; } - public virtual System.Uri OpenIdConnectUrl { get; set; } - public virtual string Scheme { get; set; } - public virtual Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiSecurityScheme(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme securityScheme) { } + public string BearerFormat { get; set; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; set; } + public Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } + public string Name { get; set; } + public System.Uri OpenIdConnectUrl { get; set; } + public string Scheme { get; set; } + public Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiServer : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1404,22 +1412,19 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiSecurityScheme Target { get; } - public override string BearerFormat { get; set; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; set; } - public override Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } - public override string Name { get; set; } - public override System.Uri OpenIdConnectUrl { get; set; } - public override string Scheme { get; set; } - public override Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; set; } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public string BearerFormat { get; } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; } + public Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; } + public Microsoft.OpenApi.Models.ParameterLocation? In { get; } + public string Name { get; } + public System.Uri OpenIdConnectUrl { get; } + public string Scheme { get; } + public Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme source) { } } public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1622,6 +1627,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } + public virtual void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme securityScheme) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1635,7 +1641,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } - public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServerVariable serverVariable) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } @@ -1721,6 +1726,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } + public override void Visit(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme securityScheme) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiContact contact) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { } @@ -1734,7 +1740,6 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiPaths paths) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } - public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiServerVariable serverVariable) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } From 9b392a6589036910058ffb9a60298defb140e2ac Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 09:52:52 -0500 Subject: [PATCH 049/103] chore: updates test files for security scheme references Signed-off-by: Vincent Biret --- ...erseOutput=False_inlineLocalReferences=False.verified.txt | 3 +++ ...TerseOutput=False_inlineLocalReferences=True.verified.txt | 5 +++++ ...TerseOutput=True_inlineLocalReferences=False.verified.txt | 1 + ...eTerseOutput=True_inlineLocalReferences=True.verified.txt | 1 + ...erseOutput=False_inlineLocalReferences=False.verified.txt | 3 +++ ...TerseOutput=False_inlineLocalReferences=True.verified.txt | 5 +++++ ...TerseOutput=True_inlineLocalReferences=False.verified.txt | 1 + ...eTerseOutput=True_inlineLocalReferences=True.verified.txt | 1 + 8 files changed, 20 insertions(+) create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt create mode 100644 test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..a73e7078d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "mySecurityScheme" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..073ce3d7b --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -0,0 +1,5 @@ +{ + "type": "apiKey", + "name": "X-API-Key", + "in": "header" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..5c70082e7 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"mySecurityScheme"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..6d0080a96 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV31JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"type":"apiKey","name":"X-API-Key","in":"header"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..a73e7078d --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=False.verified.txt @@ -0,0 +1,3 @@ +{ + "$ref": "mySecurityScheme" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..073ce3d7b --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=False_inlineLocalReferences=True.verified.txt @@ -0,0 +1,5 @@ +{ + "type": "apiKey", + "name": "X-API-Key", + "in": "header" +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt new file mode 100644 index 000000000..5c70082e7 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=False.verified.txt @@ -0,0 +1 @@ +{"$ref":"mySecurityScheme"} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt new file mode 100644 index 000000000..6d0080a96 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.SerializeSecuritySchemeReferenceAsV3JsonWorks_produceTerseOutput=True_inlineLocalReferences=True.verified.txt @@ -0,0 +1 @@ +{"type":"apiKey","name":"X-API-Key","in":"header"} \ No newline at end of file From 3c7c894bcc180123090dcb46e3821329a3c4f816 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:10:07 -0500 Subject: [PATCH 050/103] chore: updates public api export Signed-off-by: Vincent Biret --- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index c8f16289a..98029f874 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1061,7 +1061,7 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSecurityRequirement() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From 837f00081a1e52200b90adeac6e2aff32c92d296 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:10:21 -0500 Subject: [PATCH 051/103] fix: fixes invalid OAI document for unit tests Signed-off-by: Vincent Biret --- ...entTests.ParseDocumentWith31PropertiesWorks.verified.txt | 6 +++++- .../Samples/OpenApiDocument/documentWith31Properties.yaml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.ParseDocumentWith31PropertiesWorks.verified.txt b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.ParseDocumentWith31PropertiesWorks.verified.txt index 3392a4bb8..fa7dd54e4 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.ParseDocumentWith31PropertiesWorks.verified.txt +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.ParseDocumentWith31PropertiesWorks.verified.txt @@ -5,7 +5,6 @@ info: description: A sample API demonstrating OpenAPI 3.1 features license: name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html identifier: Apache-2.0 version: 2.0.0 summary: Sample OpenAPI 3.1 API with the latest features @@ -93,6 +92,11 @@ components: - 'null' - object description: Dynamic attributes for the pet + securitySchemes: + api_key: + type: apiKey + name: api_key + in: header security: - api_key: [ ] webhooks: diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/documentWith31Properties.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/documentWith31Properties.yaml index 35e5ccf80..e3d1b6cf5 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/documentWith31Properties.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/documentWith31Properties.yaml @@ -7,7 +7,6 @@ info: license: name: Apache 2.0 identifier: Apache-2.0 # SPDX license identifier, a new 3.1 feature to define an API's SPDX license expression - url: https://www.apache.org/licenses/LICENSE-2.0.html # JSON Schema 2020-12 feature jsonSchemaDialect: "https://json-schema.org/draft/2020-12/schema" @@ -89,6 +88,11 @@ paths: - name $dynamicAnchor: "addressDef" components: + securitySchemes: + api_key: + type: apiKey + name: api_key + in: header schemas: Pet: $id: 'https://example.com/schemas/pet.json' From d2e4111198a435547bacfe62a5626e4d78114f8d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:10:51 -0500 Subject: [PATCH 052/103] fix: failing unit tests for security scheme references in security requirements Signed-off-by: Vincent Biret --- .../Models/OpenApiSecurityRequirement.cs | 76 ++++++------------- .../References/BaseOpenApiReferenceHolder.cs | 2 +- .../OpenApiSecurityRequirementDeserializer.cs | 2 +- .../OpenApiSecurityRequirementDeserializer.cs | 2 +- .../OpenApiSecurityRequirementDeserializer.cs | 2 +- .../V3Tests/OpenApiDocumentTests.cs | 8 +- .../Models/OpenApiOperationTests.cs | 4 +- .../Models/OpenApiSecurityRequirementTests.cs | 28 +++---- 8 files changed, 45 insertions(+), 79 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index 930698af0..2ea4f13b9 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -18,7 +19,7 @@ namespace Microsoft.OpenApi.Models /// then the value is a list of scope names required for the execution. /// For other security scheme types, the array MUST be empty. /// - public class OpenApiSecurityRequirement : Dictionary>, + public class OpenApiSecurityRequirement : Dictionary>, IOpenApiSerializable { /// @@ -36,7 +37,7 @@ public OpenApiSecurityRequirement() /// public void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + SerializeInternal(writer, (w, s) => w.WritePropertyName(s.Reference.ReferenceV3)); } /// @@ -44,32 +45,34 @@ public void SerializeAsV31(IOpenApiWriter writer) /// public void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, (w, s) => w.WritePropertyName(s.Reference.ReferenceV3)); } /// /// Serialize /// - private void SerializeInternal(IOpenApiWriter writer, Action callback) + private void SerializeInternal(IOpenApiWriter writer, Action callback) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); + + // Reaching this point means the reference to a specific OpenApiSecurityScheme fails. + // We are not able to serialize this SecurityScheme/Scopes key value pair since we do not know what + // string to output. + var validPairs = this.Where(static p => p.Key?.Target is not null).ToArray(); + + if (validPairs.Length == 0) + { + return; + } writer.WriteStartObject(); - foreach (var securitySchemeAndScopesValuePair in this) + foreach (var securitySchemeAndScopesValuePair in validPairs) { var securityScheme = securitySchemeAndScopesValuePair.Key; var scopes = securitySchemeAndScopesValuePair.Value; - if (securityScheme is not OpenApiSecuritySchemeReference schemeReference || schemeReference.Reference is null) - { - // Reaching this point means the reference to a specific OpenApiSecurityScheme fails. - // We are not able to serialize this SecurityScheme/Scopes key value pair since we do not know what - // string to output. - continue; - } - - writer.WritePropertyName(schemeReference.Reference.ReferenceV3); + callback(writer, securityScheme); writer.WriteStartArray(); @@ -89,48 +92,19 @@ private void SerializeInternal(IOpenApiWriter writer, Action public void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; - - writer.WriteStartObject(); - - foreach (var securitySchemeAndScopesValuePair in this) - { - var securityScheme = securitySchemeAndScopesValuePair.Key; - var scopes = securitySchemeAndScopesValuePair.Value; - - if (securityScheme is not OpenApiSecuritySchemeReference schemeReference || schemeReference.Reference is null) - { - // Reaching this point means the reference to a specific OpenApiSecurityScheme fails. - // We are not able to serialize this SecurityScheme/Scopes key value pair since we do not know what - // string to output. - continue; - } - - securityScheme.SerializeAsV2(writer); - - writer.WriteStartArray(); - - foreach (var scope in scopes) - { - writer.WriteValue(scope); - } - - writer.WriteEndArray(); - } - - writer.WriteEndObject(); + SerializeInternal(writer, (w, s) => s.SerializeAsV2(w)); } /// /// Comparer for OpenApiSecurityScheme that only considers the Id in the Reference /// (i.e. the string that will actually be displayed in the written document) /// - private sealed class OpenApiSecuritySchemeReferenceEqualityComparer : IEqualityComparer + private sealed class OpenApiSecuritySchemeReferenceEqualityComparer : IEqualityComparer { /// /// Determines whether the specified objects are equal. /// - public bool Equals(IOpenApiSecurityScheme x, IOpenApiSecurityScheme y) + public bool Equals(OpenApiSecuritySchemeReference x, OpenApiSecuritySchemeReference y) { if (x == null && y == null) { @@ -148,17 +122,13 @@ public bool Equals(IOpenApiSecurityScheme x, IOpenApiSecurityScheme y) /// /// Returns a hash code for the specified object. /// - public int GetHashCode(IOpenApiSecurityScheme obj) + public int GetHashCode(OpenApiSecuritySchemeReference obj) { if (obj is null) { return 0; } - else if (obj is OpenApiSecuritySchemeReference reference) - { - return string.IsNullOrEmpty(reference?.Reference?.Id) ? 0 : reference.Reference.Id.GetHashCode(); - } - return obj.GetHashCode(); + return string.IsNullOrEmpty(obj?.Reference?.Id) ? 0 : obj.Reference.Id.GetHashCode(); } } } diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 9b8c1be28..56d694d0a 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -16,7 +16,7 @@ public T Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(Reference); + _target ??= Reference.HostDocument?.ResolveReferenceTo(Reference); return _target; } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs index b3183dcce..7b47ff6c5 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs @@ -43,7 +43,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static IOpenApiSecurityScheme LoadSecuritySchemeByReference( + private static OpenApiSecuritySchemeReference LoadSecuritySchemeByReference( OpenApiDocument openApiDocument, string schemeName) { diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs index 7702d4bd6..030f2ef34 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs @@ -40,7 +40,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static IOpenApiSecurityScheme LoadSecuritySchemeByReference( + private static OpenApiSecuritySchemeReference LoadSecuritySchemeByReference( OpenApiDocument openApiDocument, string schemeName) { diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs index 4026793b3..cddb97699 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs @@ -40,7 +40,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, return securityRequirement; } - private static IOpenApiSecurityScheme LoadSecuritySchemeByReference(string schemeName, OpenApiDocument hostDocument) + private static OpenApiSecuritySchemeReference LoadSecuritySchemeByReference(string schemeName, OpenApiDocument hostDocument) { return new OpenApiSecuritySchemeReference(schemeName, hostDocument); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index d8f58db38..c59aec6fb 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -889,8 +889,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { new OpenApiSecurityRequirement { - [securityScheme1] = new List(), - [securityScheme2] = new List + [new OpenApiSecuritySchemeReference(securityScheme1, "securitySchemeName1")] = new List(), + [new OpenApiSecuritySchemeReference(securityScheme2, "securitySchemeName2")] = new List { "scope1", "scope2" @@ -1035,8 +1035,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { new OpenApiSecurityRequirement { - [securityScheme1] = new List(), - [securityScheme2] = new List + [new OpenApiSecuritySchemeReference(securityScheme1, "securitySchemeName1")] = new List(), + [new OpenApiSecuritySchemeReference(securityScheme2, "securitySchemeName2")] = new List { "scope1", "scope2", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 499477616..138888d71 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -181,8 +181,8 @@ public class OpenApiOperationTests { new() { - [new OpenApiSecuritySchemeReference("securitySchemeId1", hostDocument: null)] = new List(), - [new OpenApiSecuritySchemeReference("securitySchemeId2", hostDocument: null)] = new List + [new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "securitySchemeId1")] = new List(), + [new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "securitySchemeId2")] = new List { "scopeName1", "scopeName2" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 23328f2f1..19900f215 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -25,7 +25,7 @@ public class OpenApiSecurityRequirementTests new() { [ - new OpenApiSecuritySchemeReference("scheme1", hostDocument: null) + new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme1") ] = new List { "scope1", @@ -33,14 +33,14 @@ public class OpenApiSecurityRequirementTests "scope3", }, [ - new OpenApiSecuritySchemeReference("scheme2", hostDocument: null) + new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme2") ] = new List { "scope4", "scope5", }, [ - new OpenApiSecuritySchemeReference("scheme3", hostDocument: null) + new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme3") ] = new List() }; @@ -48,7 +48,7 @@ public class OpenApiSecurityRequirementTests new() { [ - new OpenApiSecuritySchemeReference("scheme1", hostDocument: null) + new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme1") ] = new List { "scope1", @@ -56,18 +56,14 @@ public class OpenApiSecurityRequirementTests "scope3", }, [ - new OpenApiSecurityScheme() - { - // This security scheme is unreferenced, so this key value pair cannot be serialized. - Name = "brokenUnreferencedScheme" - } + new OpenApiSecuritySchemeReference("brokenUnreferencedScheme", hostDocument: null) ] = new List { "scope4", "scope5", }, [ - new OpenApiSecuritySchemeReference("scheme3", hostDocument: null) + new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme3") ] = new List() }; @@ -246,13 +242,13 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() }; // Act - securityRequirement.Add(securityScheme1, new List()); - securityRequirement.Add(securityScheme2, new List { "scope1", "scope2" }); + securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1, "securityScheme1"), new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme2, "securityScheme2"), new List { "scope1", "scope2" }); var addSecurityScheme1Duplicate = () => - securityRequirement.Add(securityScheme1Duplicate, new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1Duplicate, "securityScheme1"), new List()); var addSecurityScheme1WithDifferentProperties = () => - securityRequirement.Add(securityScheme1WithDifferentProperties, new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1WithDifferentProperties, "securityScheme1"), new List()); // Assert // Only the first two should be added successfully since the latter two are duplicates of securityScheme1. @@ -267,8 +263,8 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() { // This should work with any security scheme object // as long as Reference.Id os securityScheme1 - [securityScheme1WithDifferentProperties] = new List(), - [securityScheme2] = new List { "scope1", "scope2" }, + [new OpenApiSecuritySchemeReference(securityScheme1WithDifferentProperties, "securityScheme1")] = new List(), + [new OpenApiSecuritySchemeReference(securityScheme2, "securityScheme2")] = new List { "scope1", "scope2" }, }); } } From 1c6fd8e8ff38d0259af7fbd9903f361ecfb19225 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:23:35 -0500 Subject: [PATCH 053/103] fix: an empty security requirement should not result in an object during serialization Signed-off-by: Vincent Biret --- .../Models/OpenApiSecurityRequirementTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 19900f215..741f1a7c3 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -71,7 +71,7 @@ public class OpenApiSecurityRequirementTests public async Task SerializeBasicSecurityRequirementAsV3JsonWorks() { // Arrange - var expected = @"{ }"; + var expected = string.Empty; // Act var actual = await BasicSecurityRequirement.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); From f0cd02c61a4f74730b44b1401c17502bb5ca004e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:24:08 -0500 Subject: [PATCH 054/103] Revert "fix: an empty security requirement should not result in an object during serialization" This reverts commit 1c6fd8e8ff38d0259af7fbd9903f361ecfb19225. --- .../Models/OpenApiSecurityRequirementTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 741f1a7c3..19900f215 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -71,7 +71,7 @@ public class OpenApiSecurityRequirementTests public async Task SerializeBasicSecurityRequirementAsV3JsonWorks() { // Arrange - var expected = string.Empty; + var expected = @"{ }"; // Act var actual = await BasicSecurityRequirement.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); From 42bd3960d799af3d522ba122ce713a7d418c98ba Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:25:33 -0500 Subject: [PATCH 055/103] fix: empty security requirements are actually valid. to negate the document ones Signed-off-by: Vincent Biret --- .../Models/OpenApiSecurityRequirement.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index 2ea4f13b9..193d648df 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -55,19 +55,13 @@ private void SerializeInternal(IOpenApiWriter writer, Action p.Key?.Target is not null).ToArray(); - - if (validPairs.Length == 0) - { - return; - } - - writer.WriteStartObject(); - foreach (var securitySchemeAndScopesValuePair in validPairs) + foreach (var securitySchemeAndScopesValuePair in this.Where(static p => p.Key?.Target is not null)) { var securityScheme = securitySchemeAndScopesValuePair.Key; var scopes = securitySchemeAndScopesValuePair.Value; From b17a552e3d4ac3bef4fcb0d68aa5ded3604324cc Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 13:43:55 -0500 Subject: [PATCH 056/103] chore: code linting Signed-off-by: Vincent Biret --- .../Reader/V2/OpenApiSecuritySchemeDeserializer.cs | 2 +- .../Reader/V3/OpenApiSecuritySchemeDeserializer.cs | 2 +- .../Reader/V31/OpenApiSecuritySchemeDeserializer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs index e3bf63ff7..0b49b5e9d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs @@ -78,7 +78,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs index 1a0ccd5c4..cd696ddfb 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs @@ -70,7 +70,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs index 004fd0551..5a2667cda 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs @@ -80,7 +80,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) From 8ff367b4f1669820932642d9b469e645a64111ec Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 14:09:40 -0500 Subject: [PATCH 057/103] chore: adds missing string comparison Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.Workbench/MainModel.cs | 4 ++-- .../Expressions/RuntimeExpression.cs | 12 ++++++------ .../Expressions/SourceExpression.cs | 9 +++++---- .../Extensions/OpenApiExtensibleExtensions.cs | 3 ++- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiReference.cs | 4 ++-- .../Reader/V2/OpenApiContactDeserializer.cs | 2 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V2/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V2/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V2/OpenApiLicenseDeserializer.cs | 2 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 7 ++++--- .../Reader/V2/OpenApiParameterDeserializer.cs | 2 +- .../Reader/V2/OpenApiPathsDeserializer.cs | 5 +++-- .../Reader/V2/OpenApiResponseDeserializer.cs | 2 +- .../Reader/V2/OpenApiTagDeserializer.cs | 3 ++- .../Reader/V2/OpenApiV2Deserializer.cs | 3 ++- .../Reader/V2/OpenApiV2VersionService.cs | 4 ++-- .../Reader/V2/OpenApiXmlDeserializer.cs | 2 +- .../Reader/V3/OpenApiCallbackDeserializer.cs | 5 +++-- .../Reader/V3/OpenApiComponentsDeserializer.cs | 3 ++- .../Reader/V3/OpenApiContactDeserializer.cs | 2 +- .../Reader/V3/OpenApiDocumentDeserializer.cs | 3 ++- .../Reader/V3/OpenApiEncodingDeserializer.cs | 3 ++- .../Reader/V3/OpenApiExampleDeserializer.cs | 3 ++- .../Reader/V3/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V3/OpenApiHeaderDeserializer.cs | 3 ++- .../Reader/V3/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V3/OpenApiLicenseDeserializer.cs | 2 +- .../Reader/V3/OpenApiLinkDeserializer.cs | 3 ++- .../Reader/V3/OpenApiMediaTypeDeserializer.cs | 3 ++- .../Reader/V3/OpenApiOAuthFlowDeserializer.cs | 2 +- .../Reader/V3/OpenApiOAuthFlowsDeserializer.cs | 3 ++- .../Reader/V3/OpenApiOperationDeserializer.cs | 3 ++- .../Reader/V3/OpenApiParameterDeserializer.cs | 3 ++- .../Reader/V3/OpenApiPathItemDeserializer.cs | 3 ++- .../Reader/V3/OpenApiPathsDeserializer.cs | 5 +++-- .../Reader/V3/OpenApiRequestBodyDeserializer.cs | 3 ++- .../Reader/V3/OpenApiResponseDeserializer.cs | 3 ++- .../Reader/V3/OpenApiServerDeserializer.cs | 3 ++- .../Reader/V3/OpenApiServerVariableDeserializer.cs | 3 ++- .../Reader/V3/OpenApiTagDeserializer.cs | 3 ++- .../Reader/V3/OpenApiV3Deserializer.cs | 5 +++-- .../Reader/V3/OpenApiV3VersionService.cs | 6 +++--- .../Reader/V3/OpenApiXmlDeserializer.cs | 2 +- .../Reader/V31/OpenApiContactDeserializer.cs | 2 +- .../Reader/V31/OpenApiDiscriminatorDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiDocumentDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiEncodingDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiExampleDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V31/OpenApiHeaderDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V31/OpenApiLicenseDeserializer.cs | 2 +- .../Reader/V31/OpenApiLinkDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiMediaTypeDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiOAuthFlowDeserializer.cs | 2 +- .../Reader/V31/OpenApiOAuthFlowsDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiOperationDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiParameterDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiPathItemDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiPathsDeserializer.cs | 7 ++++--- .../Reader/V31/OpenApiRequestBodyDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiResponseDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiResponsesDeserializer.cs | 5 +++-- .../Reader/V31/OpenApiServerDeserializer.cs | 3 ++- .../Reader/V31/OpenApiServerVariableDeserializer.cs | 3 ++- .../Reader/V31/OpenApiTagDeserializer.cs | 3 ++- .../Reader/V31/OpenApiV31Deserializer.cs | 5 +++-- .../Reader/V31/OpenApiV31VersionService.cs | 4 ++-- .../Reader/V31/OpenApiXmlDeserializer.cs | 2 +- src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs | 4 ++-- src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs | 3 ++- .../Writers/SpecialCharacterStringExtensions.cs | 4 ++-- .../Walkers/WalkerLocationTests.cs | 3 ++- 75 files changed, 160 insertions(+), 114 deletions(-) diff --git a/src/Microsoft.OpenApi.Workbench/MainModel.cs b/src/Microsoft.OpenApi.Workbench/MainModel.cs index 7eee12251..34a44c026 100644 --- a/src/Microsoft.OpenApi.Workbench/MainModel.cs +++ b/src/Microsoft.OpenApi.Workbench/MainModel.cs @@ -219,7 +219,7 @@ internal async Task ParseDocumentAsync() { if (!string.IsNullOrWhiteSpace(_inputFile)) { - stream = _inputFile.StartsWith("http") ? await _httpClient.GetStreamAsync(_inputFile) + stream = _inputFile.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? await _httpClient.GetStreamAsync(_inputFile) : new FileStream(_inputFile, FileMode.Open); } else @@ -241,7 +241,7 @@ internal async Task ParseDocumentAsync() }; if (ResolveExternal && !string.IsNullOrWhiteSpace(_inputFile)) { - settings.BaseUrl = _inputFile.StartsWith("http") ? new(_inputFile) + settings.BaseUrl = _inputFile.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? new(_inputFile) : new("file://" + Path.GetDirectoryName(_inputFile) + "/"); } diff --git a/src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs b/src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs index 25792257e..69aecfd37 100644 --- a/src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs +++ b/src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs @@ -31,31 +31,31 @@ public static RuntimeExpression Build(string expression) { Utils.CheckArgumentNullOrEmpty(expression); - if (!expression.StartsWith(Prefix)) + if (!expression.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase)) { return new CompositeExpression(expression); } // $url - if (expression == UrlExpression.Url) + if (expression.Equals(UrlExpression.Url, StringComparison.Ordinal)) { return new UrlExpression(); } // $method - if (expression == MethodExpression.Method) + if (expression.Equals(MethodExpression.Method, StringComparison.Ordinal)) { return new MethodExpression(); } // $statusCode - if (expression == StatusCodeExpression.StatusCode) + if (expression.Equals(StatusCodeExpression.StatusCode, StringComparison.Ordinal)) { return new StatusCodeExpression(); } // $request. - if (expression.StartsWith(RequestExpression.Request)) + if (expression.StartsWith(RequestExpression.Request, StringComparison.Ordinal)) { var subString = expression.Substring(RequestExpression.Request.Length); var source = SourceExpression.Build(subString); @@ -63,7 +63,7 @@ public static RuntimeExpression Build(string expression) } // $response. - if (expression.StartsWith(ResponseExpression.Response)) + if (expression.StartsWith(ResponseExpression.Response, StringComparison.Ordinal)) { var subString = expression.Substring(ResponseExpression.Response.Length); var source = SourceExpression.Build(subString); diff --git a/src/Microsoft.OpenApi/Expressions/SourceExpression.cs b/src/Microsoft.OpenApi/Expressions/SourceExpression.cs index 8504a1e89..76a22f97d 100644 --- a/src/Microsoft.OpenApi/Expressions/SourceExpression.cs +++ b/src/Microsoft.OpenApi/Expressions/SourceExpression.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Properties; @@ -37,19 +38,19 @@ protected SourceExpression(string value) var expressions = expression.Split('.'); if (expressions.Length == 2) { - if (expression.StartsWith(HeaderExpression.Header)) + if (expression.StartsWith(HeaderExpression.Header, StringComparison.Ordinal)) { // header. return new HeaderExpression(expressions[1]); } - if (expression.StartsWith(QueryExpression.Query)) + if (expression.StartsWith(QueryExpression.Query, StringComparison.Ordinal)) { // query. return new QueryExpression(expressions[1]); } - if (expression.StartsWith(PathExpression.Path)) + if (expression.StartsWith(PathExpression.Path, StringComparison.Ordinal)) { // path. return new PathExpression(expressions[1]); @@ -57,7 +58,7 @@ protected SourceExpression(string value) } // body - if (expression.StartsWith(BodyExpression.Body)) + if (expression.StartsWith(BodyExpression.Body, StringComparison.Ordinal)) { var subString = expression.Substring(BodyExpression.Body.Length); if (string.IsNullOrEmpty(subString)) diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiExtensibleExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiExtensibleExtensions.cs index d6522ead3..c8c3b2a48 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiExtensibleExtensions.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiExtensibleExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -26,7 +27,7 @@ public static void AddExtension(this T element, string name, IOpenApiExtensio Utils.CheckArgumentNull(element); Utils.CheckArgumentNullOrEmpty(name); - if (!name.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix)) + if (!name.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase)) { throw new OpenApiException(string.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name)); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 32afbdf90..85b6c3ba6 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -389,7 +389,7 @@ private static void WriteHostInfoV2(IOpenApiWriter writer, IList? else { var relativeUrl = firstServerUrl.OriginalString; - if (relativeUrl.StartsWith("//")) + if (relativeUrl.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { var pathPosition = relativeUrl.IndexOf('/', 3); writer.WriteProperty(OpenApiConstants.Host, relativeUrl.Substring(0, pathPosition)); diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index 191f884ea..507401cd4 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -95,7 +95,7 @@ public string ReferenceV3 { return Id; } - if (Id.StartsWith("http")) + if (Id.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { return Id; } @@ -238,7 +238,7 @@ private string GetExternalReferenceV3() return ExternalResource + "#" + Id; } - if (Id.StartsWith("http")) + if (Id.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { return Id; } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs index d225899cc..95a992f32 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index a09d2eab9..a2a393a62 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -111,7 +111,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _openApiPatternFields = new() { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static void MakeServers(IList servers, ParsingContext context, RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs index 6fc438542..1a1bf4322 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs @@ -30,7 +30,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _externalDocsPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs index 74c3ac917..552674670 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _infoPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs index 8eae690ed..2ae656293 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs @@ -28,7 +28,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 140ad9f3d..491e52638 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -9,6 +9,7 @@ using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Models.Interfaces; +using System; namespace Microsoft.OpenApi.Reader.V2 { @@ -80,7 +81,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static readonly FixedFieldMap _responsesFixedFields = new(); @@ -88,8 +89,8 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _responsesPatternFields = new() { - {s => !s.StartsWith("x-"), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 2153d37d2..37b7699d4 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -106,7 +106,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-") && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs index a048316d5..400a8523b 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -17,8 +18,8 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { - {s => s.StartsWith("/"), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index d730c8227..3abfb6296 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -42,7 +42,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-") && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs index 23614029a..cd6197250 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -31,7 +32,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs index 0e90a4633..83505670d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; @@ -98,7 +99,7 @@ private static (string, string) GetReferenceIdAndExternalResource(string pointer { var refSegments = pointer.Split('/'); var refId = refSegments.Last(); - var isExternalResource = !refSegments.First().StartsWith("#"); + var isExternalResource = !refSegments.First().StartsWith("#", StringComparison.OrdinalIgnoreCase); string externalResource = isExternalResource ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" : null; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs index c9e58b519..c4186bb25 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs @@ -161,7 +161,7 @@ public OpenApiReference ConvertToOpenApiReference(string reference, ReferenceTyp } else if (segments.Length == 2) { - if (reference.StartsWith("#")) + if (reference.StartsWith("#", StringComparison.OrdinalIgnoreCase)) { // "$ref": "#/definitions/Pet" try @@ -178,7 +178,7 @@ public OpenApiReference ConvertToOpenApiReference(string reference, ReferenceTyp // Where fragments point into a non-OpenAPI document, the id will be the complete fragment identifier var id = segments[1]; // $ref: externalSource.yaml#/Pet - if (id.StartsWith("/definitions/")) + if (id.StartsWith("/definitions/", StringComparison.Ordinal)) { var localSegments = id.Split('/'); var referencedType = GetReferenceTypeV2FromName(localSegments[1]); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs index 21c9be0fe..a487e95f3 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs @@ -51,7 +51,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _xmlPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs index adab9ccab..1b4afb8c7 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -21,8 +22,8 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _callbackPatternFields = new() { - {s => !s.StartsWith("x-"), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs index a5e3d082b..a4d7163b7 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -29,7 +30,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _componentsPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs index cc5058b52..1c0b4ffeb 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs index 842b75bf0..e2102233d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -33,7 +34,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _openApiPatternFields = new PatternFieldMap { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiDocument LoadOpenApi(RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs index 2345436dd..3ea3e9f17 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -47,7 +48,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _encodingPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiEncoding LoadEncoding(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs index 344565884..aa6bb52ff 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -38,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _examplePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs index a3f20bad0..bcdc5c62a 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs @@ -31,7 +31,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _externalDocsPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs index 8553c1b70..8983dde7d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -68,7 +69,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs index dbe3a554c..9fffc6bcd 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV3Deserializer public static readonly PatternFieldMap InfoPatternFields = new() { - {s => s.StartsWith("x-"), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs index d836c6e0f..32148892b 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs @@ -28,7 +28,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; internal static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs index 9744ea256..24012daab 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -42,7 +43,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _linkPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs index b30dc88e0..349b3911f 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -38,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _mediaTypePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _mediaTypeAnyFields = new() diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs index 1a7f40c15..1bd6b7338 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _oAuthFlowPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlow LoadOAuthFlow(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs index e4e003f9c..92e61c920 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -25,7 +26,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _oAuthFlowsPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlows LoadOAuthFlows(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs index 1ebb57880..8ad8d79b8 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -72,7 +73,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs index c8660d899..5c70bdbe6 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -88,7 +89,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _parameterAnyFields = new() diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs index 4d5815794..379ec106b 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -40,7 +41,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs index e28a9d569..34aca2185 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -17,8 +18,8 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { - {s => s.StartsWith("/"), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs index 783f2869e..e2652aac8 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -35,7 +36,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _requestBodyPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs index a85ed5fe1..3ed29cea4 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -38,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs index 52ee335c0..dbaf69d65 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -31,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _serverPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServer LoadServer(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs index 9436e62fe..b9cbbeb3f 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -33,7 +34,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _serverVariablePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServerVariable LoadServerVariable(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs index e6efafae7..dc297041f 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -31,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs index cad424c50..67a9b0495 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; @@ -148,7 +149,7 @@ private static RuntimeExpressionAnyWrapper LoadRuntimeExpressionAnyWrapper(Parse { var value = node.GetScalarValue(); - if (value != null && value.StartsWith("$")) + if (value != null && value.StartsWith("$", StringComparison.OrdinalIgnoreCase)) { return new() { @@ -190,7 +191,7 @@ private static (string, string) GetReferenceIdAndExternalResource(string pointer { var refSegments = pointer.Split('/'); var refId = refSegments.Last(); - var isExternalResource = !refSegments.First().StartsWith("#"); + var isExternalResource = !refSegments.First().StartsWith("#", StringComparison.OrdinalIgnoreCase); string externalResource = isExternalResource ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" : null; diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index 372a8b26f..ffb7431fc 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -102,7 +102,7 @@ public OpenApiReference ConvertToOpenApiReference( } else if (segments.Length == 2) { - if (reference.StartsWith("#")) + if (reference.StartsWith("#", StringComparison.OrdinalIgnoreCase)) { // "$ref": "#/components/schemas/Pet" try @@ -119,7 +119,7 @@ public OpenApiReference ConvertToOpenApiReference( var openApiReference = new OpenApiReference(); // $ref: externalSource.yaml#/Pet - if (id.StartsWith("/components/")) + if (id.StartsWith("/components/", StringComparison.Ordinal)) { var localSegments = segments[1].Split('/'); localSegments[2].TryGetEnumFromDisplayName(out var referencedType); @@ -136,7 +136,7 @@ public OpenApiReference ConvertToOpenApiReference( } id = localSegments[3]; } - else if (id.StartsWith("/paths/")) + else if (id.StartsWith("/paths/", StringComparison.Ordinal)) { var localSegments = segments[1].Split(_pathSeparator, StringSplitOptions.RemoveEmptyEntries); if (localSegments.Length == 2) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs index 51b66d348..c7ed6bed0 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs @@ -41,7 +41,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _xmlPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs index 801eb2de9..bf3955f8b 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs index 90e904f60..280eec500 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -30,7 +31,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _discriminatorPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiDiscriminator LoadDiscriminator(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs index 0d1e08479..66f86c9a2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -31,7 +32,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _openApiPatternFields = new() { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiDocument LoadOpenApi(RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs index 51a5b4ef6..f2129e389 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -51,7 +52,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _encodingPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiEncoding LoadEncoding(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs index f6511d8b9..7fc518bb1 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -44,7 +45,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _examplePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs index 56dd2bc77..354f717ee 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs @@ -33,7 +33,7 @@ internal static partial class OpenApiV31Deserializer new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs index 43a4f3292..e15f21da7 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -82,7 +83,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs index d3aed5511..039815f0c 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs @@ -59,7 +59,7 @@ internal static partial class OpenApiV31Deserializer public static readonly PatternFieldMap InfoPatternFields = new() { - {s => s.StartsWith("x-"), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs index 303f2f65a..fd944e1f2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; internal static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs index 3924a41c7..0ac3d97ae 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -49,7 +50,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _linkPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs index a9024f9ed..e79416bb2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Reader.ParseNodes; @@ -43,7 +44,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _mediaTypePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _mediaTypeAnyFields = new AnyFieldMap diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs index 5b18caecf..17d373d02 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs @@ -38,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _oAuthFlowPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlow LoadOAuthFlow(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs index b20b96775..5a7ca00aa 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -22,7 +23,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _oAuthFlowsPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlows LoadOAuthFlows(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs index 2d6c831e3..7478bf41f 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; @@ -90,7 +91,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs index cf5f5b294..a6c05ae4d 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -106,7 +107,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _parameterAnyFields = new AnyFieldMap diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs index ecaf88bf2..b8edec12a 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -42,7 +43,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs index c72394bf2..d277b526c 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -14,8 +15,8 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { - {s => s.StartsWith("/"), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs index db6792a5f..d4ca9bf7a 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -38,7 +39,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _requestBodyPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs index a71fd5369..6d9bb5882 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs @@ -1,4 +1,5 @@ -using Microsoft.OpenApi.Extensions; +using System; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -43,7 +44,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs index 228a0045e..a53e204e8 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -17,8 +18,8 @@ internal static partial class OpenApiV31Deserializer public static readonly PatternFieldMap ResponsesPatternFields = new() { - {s => !s.StartsWith("x-"), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiResponses LoadResponses(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs index 2ae8ac340..85c0cc8d1 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -37,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _serverPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServer LoadServer(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs index 0c6e8b756..9183d74ff 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -39,7 +40,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _serverVariablePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServerVariable LoadServerVariable(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs index f1b0065cc..a091ebcf2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -37,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index 7c3441eed..92e7770df 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Linq; using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; @@ -113,7 +114,7 @@ private static RuntimeExpressionAnyWrapper LoadRuntimeExpressionAnyWrapper(Parse { var value = node.GetScalarValue(); - if (value != null && value.StartsWith("$")) + if (value != null && value.StartsWith("$", StringComparison.OrdinalIgnoreCase)) { return new RuntimeExpressionAnyWrapper { @@ -160,7 +161,7 @@ private static (string, string) GetReferenceIdAndExternalResource(string pointer var refSegments = pointer.Split('/'); string refId = !pointer.Contains('#') ? pointer : refSegments.Last(); - var isExternalResource = !refSegments.First().StartsWith("#"); + var isExternalResource = !refSegments.First().StartsWith("#", StringComparison.OrdinalIgnoreCase); string externalResource = null; if (isExternalResource && pointer.Contains('#')) { diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs index f564c37ab..bfaa82051 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs @@ -105,7 +105,7 @@ public OpenApiReference ConvertToOpenApiReference( } else if (segments.Length == 2) { - if (reference.StartsWith("#")) + if (reference.StartsWith("#", StringComparison.OrdinalIgnoreCase)) { // "$ref": "#/components/schemas/Pet" try @@ -121,7 +121,7 @@ public OpenApiReference ConvertToOpenApiReference( // Where fragments point into a non-OpenAPI document, the id will be the complete fragment identifier string id = segments[1]; // $ref: externalSource.yaml#/Pet - if (id.StartsWith("/components/")) + if (id.StartsWith("/components/", StringComparison.Ordinal)) { var localSegments = segments[1].Split('/'); localSegments[2].TryGetEnumFromDisplayName(out var referencedType); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs index 13870f341..de14a9f16 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs @@ -51,7 +51,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _xmlPatternFields = new PatternFieldMap { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs index 1d306edfb..8a61772dd 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs @@ -41,7 +41,7 @@ public class OpenApiUrlTreeNode /// /// Flag indicating whether a node segment is a path parameter. /// - public bool IsParameter => Segment.StartsWith("{"); + public bool IsParameter => Segment.StartsWith("{", StringComparison.OrdinalIgnoreCase); /// /// The subdirectory of a relative path. @@ -144,7 +144,7 @@ public OpenApiUrlTreeNode Attach(string path, Utils.CheckArgumentNullOrEmpty(path); Utils.CheckArgumentNull(pathItem); - if (path.StartsWith(RootPathSegment)) + if (path.StartsWith(RootPathSegment, StringComparison.OrdinalIgnoreCase)) { // Remove leading slash path = path.Substring(1); diff --git a/src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs b/src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs index 7f525d642..aaa160548 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.IO; namespace Microsoft.OpenApi.Writers @@ -189,7 +190,7 @@ public override void WriteValue(string value) WriteChompingIndicator(value); // Write indentation indicator when it starts with spaces - if (value.StartsWith(" ")) + if (value.StartsWith(" ", StringComparison.OrdinalIgnoreCase)) { Writer.Write(IndentationString.Length); } diff --git a/src/Microsoft.OpenApi/Writers/SpecialCharacterStringExtensions.cs b/src/Microsoft.OpenApi/Writers/SpecialCharacterStringExtensions.cs index 708aa7237..22388b076 100644 --- a/src/Microsoft.OpenApi/Writers/SpecialCharacterStringExtensions.cs +++ b/src/Microsoft.OpenApi/Writers/SpecialCharacterStringExtensions.cs @@ -148,7 +148,7 @@ internal static string GetYamlCompatibleString(this string input) // wrap the string in single quote. // http://www.yaml.org/spec/1.2/spec.html#style/flow/plain if (_yamlPlainStringForbiddenCombinations.Any(fc => input.Contains(fc)) || - _yamlIndicators.Any(i => input.StartsWith(i)) || + _yamlIndicators.Any(i => input.StartsWith(i, StringComparison.Ordinal)) || _yamlPlainStringForbiddenTerminals.Any(i => input.EndsWith(i)) || input.Trim() != input) { @@ -199,7 +199,7 @@ internal static string GetJsonCompatibleString(this string value) internal static bool IsHexadecimalNotation(string input) { - return input.StartsWith("0x") && int.TryParse(input.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _); + return input.StartsWith("0x", StringComparison.Ordinal) && int.TryParse(input.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _); } } } diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index c4ed91658..0baab7290 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Interfaces; @@ -239,7 +240,7 @@ public void LocateReferences() "referenceAt: #/components/schemas/derived/anyOf/0", "referenceAt: #/components/securitySchemes/test-secScheme", "referenceAt: #/components/headers/test-header/schema" - }, locator.Locations.Where(l => l.StartsWith("referenceAt:"))); + }, locator.Locations.Where(l => l.StartsWith("referenceAt:", StringComparison.OrdinalIgnoreCase))); } } From df91f8d7a32f561c08af2eccf85b434de91f0700 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 14:11:15 -0500 Subject: [PATCH 058/103] chore: use constant for extension mechanism Signed-off-by: Vincent Biret --- .../Reader/V2/OpenApiContactDeserializer.cs | 2 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V2/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V2/OpenApiLicenseDeserializer.cs | 2 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 6 +++--- .../Reader/V2/OpenApiParameterDeserializer.cs | 2 +- .../Reader/V2/OpenApiPathItemDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs | 2 +- .../Reader/V2/OpenApiResponseDeserializer.cs | 2 +- .../Reader/V2/OpenApiSchemaDeserializer.cs | 2 +- .../Reader/V2/OpenApiSecuritySchemeDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs | 2 +- .../Reader/V3/OpenApiCallbackDeserializer.cs | 4 ++-- .../Reader/V3/OpenApiComponentsDeserializer.cs | 2 +- .../Reader/V3/OpenApiContactDeserializer.cs | 2 +- .../Reader/V3/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V3/OpenApiEncodingDeserializer.cs | 2 +- .../Reader/V3/OpenApiExampleDeserializer.cs | 2 +- .../Reader/V3/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V3/OpenApiHeaderDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V3/OpenApiLicenseDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs | 2 +- .../Reader/V3/OpenApiMediaTypeDeserializer.cs | 2 +- .../Reader/V3/OpenApiOAuthFlowDeserializer.cs | 2 +- .../Reader/V3/OpenApiOAuthFlowsDeserializer.cs | 2 +- .../Reader/V3/OpenApiOperationDeserializer.cs | 2 +- .../Reader/V3/OpenApiParameterDeserializer.cs | 2 +- .../Reader/V3/OpenApiPathItemDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs | 2 +- .../Reader/V3/OpenApiRequestBodyDeserializer.cs | 2 +- .../Reader/V3/OpenApiResponseDeserializer.cs | 2 +- .../Reader/V3/OpenApiResponsesDeserializer.cs | 4 ++-- .../Reader/V3/OpenApiSchemaDeserializer.cs | 2 +- .../Reader/V3/OpenApiSecuritySchemeDeserializer.cs | 2 +- .../Reader/V3/OpenApiServerDeserializer.cs | 2 +- .../Reader/V3/OpenApiServerVariableDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs | 2 +- .../Reader/V31/OpenApiCallbackDeserializer.cs | 4 ++-- .../Reader/V31/OpenApiComponentsDeserializer.cs | 2 +- .../Reader/V31/OpenApiContactDeserializer.cs | 2 +- .../Reader/V31/OpenApiDiscriminatorDeserializer.cs | 2 +- .../Reader/V31/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V31/OpenApiEncodingDeserializer.cs | 2 +- .../Reader/V31/OpenApiExampleDeserializer.cs | 2 +- .../Reader/V31/OpenApiExternalDocsDeserializer.cs | 2 +- .../Reader/V31/OpenApiHeaderDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs | 2 +- .../Reader/V31/OpenApiLicenseDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs | 2 +- .../Reader/V31/OpenApiMediaTypeDeserializer.cs | 2 +- .../Reader/V31/OpenApiOAuthFlowDeserializer.cs | 2 +- .../Reader/V31/OpenApiOAuthFlowsDeserializer.cs | 2 +- .../Reader/V31/OpenApiOperationDeserializer.cs | 2 +- .../Reader/V31/OpenApiParameterDeserializer.cs | 2 +- .../Reader/V31/OpenApiPathItemDeserializer.cs | 2 +- .../Reader/V31/OpenApiPathsDeserializer.cs | 2 +- .../Reader/V31/OpenApiRequestBodyDeserializer.cs | 2 +- .../Reader/V31/OpenApiResponseDeserializer.cs | 2 +- .../Reader/V31/OpenApiResponsesDeserializer.cs | 4 ++-- .../Reader/V31/OpenApiSchemaDeserializer.cs | 2 +- .../Reader/V31/OpenApiSecuritySchemeDeserializer.cs | 2 +- .../Reader/V31/OpenApiServerDeserializer.cs | 2 +- .../Reader/V31/OpenApiServerVariableDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs | 2 +- .../Validations/Rules/OpenApiExtensionRules.cs | 3 ++- 71 files changed, 78 insertions(+), 77 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs index 95a992f32..00bfc2d74 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiContactDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index a2a393a62..0aa2b8093 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -111,7 +111,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _openApiPatternFields = new() { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static void MakeServers(IList servers, ParsingContext context, RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs index 1a1bf4322..312313585 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiExternalDocsDeserializer.cs @@ -30,7 +30,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _externalDocsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index bc2333e46..cc96bce59 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -95,7 +95,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs index 552674670..0d33e896c 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiInfoDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _infoPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs index 2ae656293..d4a95de89 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiLicenseDeserializer.cs @@ -28,7 +28,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 491e52638..0198a252f 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -81,7 +81,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static readonly FixedFieldMap _responsesFixedFields = new(); @@ -89,8 +89,8 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _responsesPatternFields = new() { - {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 37b7699d4..993597e39 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -106,7 +106,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs index 84f79cc16..b1e0da7a8 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathItemDeserializer.cs @@ -34,7 +34,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}, }; public static OpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs index 400a8523b..30d1df8a9 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiPathsDeserializer.cs @@ -19,7 +19,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index 3abfb6296..4a6461ebb 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -42,7 +42,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase) && !s.Equals(OpenApiConstants.ExamplesExtension, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 78453f9d2..500dba707 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -153,7 +153,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new PatternFieldMap { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs index 43151c15a..5b1c66457 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs @@ -77,7 +77,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs index cd6197250..809dccacd 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiTagDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs index a487e95f3..38acf840d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiXmlDeserializer.cs @@ -51,7 +51,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _xmlPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs index 1b4afb8c7..4ec9bfa3a 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiCallbackDeserializer.cs @@ -22,8 +22,8 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _callbackPatternFields = new() { - {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs index a4d7163b7..76cfc96d7 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs @@ -30,7 +30,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _componentsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs index 1c0b4ffeb..7eab275c8 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiContactDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs index e2102233d..c07d28d46 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs @@ -34,7 +34,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _openApiPatternFields = new PatternFieldMap { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiDocument LoadOpenApi(RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs index 3ea3e9f17..2d324745d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiEncodingDeserializer.cs @@ -48,7 +48,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _encodingPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiEncoding LoadEncoding(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs index aa6bb52ff..5ec2665a0 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiExampleDeserializer.cs @@ -39,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _examplePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs index bcdc5c62a..0d8c25b05 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiExternalDocsDeserializer.cs @@ -31,7 +31,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _externalDocsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs index 8983dde7d..94350d429 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiHeaderDeserializer.cs @@ -69,7 +69,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs index 9fffc6bcd..48979439d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiInfoDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV3Deserializer public static readonly PatternFieldMap InfoPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs index 32148892b..4ecdce151 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiLicenseDeserializer.cs @@ -28,7 +28,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; internal static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs index 24012daab..f85fb0328 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiLinkDeserializer.cs @@ -43,7 +43,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _linkPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs index 349b3911f..6fd96b38d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiMediaTypeDeserializer.cs @@ -39,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _mediaTypePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _mediaTypeAnyFields = new() diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs index 1bd6b7338..d60cf0aa5 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _oAuthFlowPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlow LoadOAuthFlow(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs index 92e61c920..892ec4701 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOAuthFlowsDeserializer.cs @@ -26,7 +26,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _oAuthFlowsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlows LoadOAuthFlows(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs index 8ad8d79b8..e9712da98 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs @@ -73,7 +73,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs index 5c70bdbe6..7d2c5074b 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiParameterDeserializer.cs @@ -89,7 +89,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _parameterAnyFields = new() diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs index 379ec106b..baaf5babc 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathItemDeserializer.cs @@ -41,7 +41,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs index 34aca2185..ef27f5d94 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiPathsDeserializer.cs @@ -19,7 +19,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs index e2652aac8..ac007d813 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiRequestBodyDeserializer.cs @@ -36,7 +36,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _requestBodyPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs index 3ed29cea4..8e10c2e79 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponseDeserializer.cs @@ -39,7 +39,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs index 6d03fe86b..379811dda 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiResponsesDeserializer.cs @@ -18,8 +18,8 @@ internal static partial class OpenApiV3Deserializer public static readonly PatternFieldMap ResponsesPatternFields = new() { - {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiResponses LoadResponses(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index bad6d04b8..2cd3cc371 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -171,7 +171,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs index 18c4eae28..40a891c04 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs @@ -69,7 +69,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs index dbaf69d65..4e4411625 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _serverPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServer LoadServer(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs index b9cbbeb3f..3579a40b7 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs @@ -34,7 +34,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _serverVariablePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServerVariable LoadServerVariable(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs index dc297041f..d67d54d7c 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiTagDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs index c7ed6bed0..43245338d 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiXmlDeserializer.cs @@ -41,7 +41,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _xmlPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs index 49407e339..ac1a43998 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiCallbackDeserializer.cs @@ -20,8 +20,8 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _callbackPatternFields = new() { - {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs index c9dccde5d..2520692cd 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs @@ -31,7 +31,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _componentsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs index bf3955f8b..be487e434 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiContactDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _contactPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiContact LoadContact(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs index 280eec500..0302149f6 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs @@ -31,7 +31,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _discriminatorPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiDiscriminator LoadDiscriminator(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs index 66f86c9a2..4f3a05fcc 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs @@ -32,7 +32,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _openApiPatternFields = new() { // We have no semantics to verify X- nodes, therefore treat them as just values. - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiDocument LoadOpenApi(RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs index f2129e389..d571a42d0 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiEncodingDeserializer.cs @@ -52,7 +52,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _encodingPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiEncoding LoadEncoding(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs index 7fc518bb1..49f7c3fd0 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiExampleDeserializer.cs @@ -45,7 +45,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _examplePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiExample LoadExample(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs index 354f717ee..a5b06efff 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiExternalDocsDeserializer.cs @@ -33,7 +33,7 @@ internal static partial class OpenApiV31Deserializer new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiExternalDocs LoadExternalDocs(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs index e15f21da7..2c23c70a4 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiHeaderDeserializer.cs @@ -83,7 +83,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs index 039815f0c..86597b421 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiInfoDeserializer.cs @@ -59,7 +59,7 @@ internal static partial class OpenApiV31Deserializer public static readonly PatternFieldMap InfoPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, k, n, _) => o.AddExtension(k,LoadExtension(k, n))} }; public static OpenApiInfo LoadInfo(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs index fd944e1f2..7ef705095 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiLicenseDeserializer.cs @@ -35,7 +35,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _licensePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; internal static OpenApiLicense LoadLicense(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs index 0ac3d97ae..9fdea6e29 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiLinkDeserializer.cs @@ -50,7 +50,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _linkPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; public static IOpenApiLink LoadLink(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs index e79416bb2..2a46b4412 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiMediaTypeDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _mediaTypePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _mediaTypeAnyFields = new AnyFieldMap diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs index 17d373d02..3efc3ef5a 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowDeserializer.cs @@ -38,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _oAuthFlowPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlow LoadOAuthFlow(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs index 5a7ca00aa..d472748f8 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOAuthFlowsDeserializer.cs @@ -23,7 +23,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _oAuthFlowsPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiOAuthFlows LoadOAuthFlows(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs index 7478bf41f..cb44bb438 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs @@ -91,7 +91,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _operationPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}, }; internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs index a6c05ae4d..35e1308cb 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiParameterDeserializer.cs @@ -107,7 +107,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _parameterPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; private static readonly AnyFieldMap _parameterAnyFields = new AnyFieldMap diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs index b8edec12a..391a34bf6 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathItemDeserializer.cs @@ -43,7 +43,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _pathItemPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiPathItem LoadPathItem(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs index d277b526c..6e97b41ac 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiPathsDeserializer.cs @@ -16,7 +16,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _pathsPatternFields = new() { {s => s.StartsWith("/", StringComparison.OrdinalIgnoreCase), (o, k, n, t) => o.Add(k, LoadPathItem(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiPaths LoadPaths(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs index d4ca9bf7a..fe786aa44 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiRequestBodyDeserializer.cs @@ -39,7 +39,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _requestBodyPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiRequestBody LoadRequestBody(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs index 6d9bb5882..6d910761c 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponseDeserializer.cs @@ -44,7 +44,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _responsePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static IOpenApiResponse LoadResponse(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs index a53e204e8..50aad0d9a 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiResponsesDeserializer.cs @@ -18,8 +18,8 @@ internal static partial class OpenApiV31Deserializer public static readonly PatternFieldMap ResponsesPatternFields = new() { - {s => !s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.Add(p, LoadResponse(n, t))}, + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiResponses LoadResponses(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 87ecc8f00..f32fa8aeb 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -236,7 +236,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs index b56352c22..9dcec433d 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs @@ -79,7 +79,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs index 85c0cc8d1..b51a16f5d 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerDeserializer.cs @@ -38,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _serverPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServer LoadServer(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs index 9183d74ff..a3aaa141a 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs @@ -40,7 +40,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _serverVariablePatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiServerVariable LoadServerVariable(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs index a091ebcf2..aea4c9c43 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiTagDeserializer.cs @@ -38,7 +38,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _tagPatternFields = new() { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiTag LoadTag(ParseNode n, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs index de14a9f16..0f821e9d2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiXmlDeserializer.cs @@ -51,7 +51,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _xmlPatternFields = new PatternFieldMap { - {s => s.StartsWith("x-", StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiXml LoadXml(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs index 3509d797f..545f68f85 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules @@ -22,7 +23,7 @@ public static class OpenApiExtensibleRules (context, item) => { context.Enter("extensions"); - foreach (var extensible in item.Extensions.Keys.Where(static x => !x.StartsWith("x-", StringComparison.OrdinalIgnoreCase))) + foreach (var extensible in item.Extensions.Keys.Where(static x => !x.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase))) { context.CreateError(nameof(ExtensionNameMustStartWithXDash), string.Format(SRResource.Validation_ExtensionNameMustBeginWithXDash, extensible, context.PathString)); From 3cb80af7c53a557d0b6d14518c84441e271e3385 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 14:12:56 -0500 Subject: [PATCH 059/103] chore: adds missing string comparison in anticipation for conflicts Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs | 3 ++- .../Reader/V2/OpenApiSecuritySchemeDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs | 3 ++- .../Reader/V3/OpenApiSecuritySchemeDeserializer.cs | 2 +- src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs | 3 ++- .../Reader/V31/OpenApiSecuritySchemeDeserializer.cs | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index cc96bce59..71ad8f8d5 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -95,7 +95,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _headerPatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 500dba707..d159633d3 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Models.References; +using System; namespace Microsoft.OpenApi.Reader.V2 { @@ -153,7 +154,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new PatternFieldMap { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs index 5b1c66457..56b7bb88c 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecuritySchemeDeserializer.cs @@ -77,7 +77,7 @@ internal static partial class OpenApiV2Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index 2cd3cc371..88adbd198 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -5,6 +5,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; +using System; using System.Collections.Generic; using System.Globalization; @@ -171,7 +172,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs index 40a891c04..5037e4227 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecuritySchemeDeserializer.cs @@ -69,7 +69,7 @@ internal static partial class OpenApiV3Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index f32fa8aeb..005e00fea 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -5,6 +5,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -236,7 +237,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _openApiSchemaPatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs index 9dcec433d..900268702 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs @@ -79,7 +79,7 @@ internal static partial class OpenApiV31Deserializer private static readonly PatternFieldMap _securitySchemePatternFields = new() { - {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} + {s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument) From 46e08d4b53e756db5d717337488c9bb787ec8ee7 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 14:51:19 -0500 Subject: [PATCH 060/103] fix: tag reference proxy design pattern implementation Signed-off-by: Vincent Biret --- .../Interfaces/IOpenApiDescribedElement.cs | 12 +++ .../Models/Interfaces/IOpenApiTag.cs | 20 +++++ src/Microsoft.OpenApi/Models/OpenApiTag.cs | 45 ++++------ .../References/BaseOpenApiReferenceHolder.cs | 7 +- .../Models/References/OpenApiTagReference.cs | 86 +++---------------- .../Models/OpenApiTagTests.cs | 3 +- .../References/OpenApiTagReferenceTest.cs | 1 - .../PublicApi/PublicApi.approved.txt | 49 ++++++----- 8 files changed, 95 insertions(+), 128 deletions(-) create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs index ca035cc51..3deee3d3c 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiDescribedElement.cs @@ -13,3 +13,15 @@ public interface IOpenApiDescribedElement : IOpenApiElement /// public string Description { get; set; } } + +/// +/// Describes an element that has a description. +/// +public interface IOpenApiReadOnlyDescribedElement : IOpenApiElement +{ + /// + /// Long description for the example. + /// CommonMark syntax MAY be used for rich text representation. + /// + public string Description { get; } +} diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs new file mode 100644 index 000000000..c4f7d1e95 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs @@ -0,0 +1,20 @@ +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Models.Interfaces; + +/// +/// Defines the base properties for the path item object. +/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. +/// +public interface IOpenApiTag : IOpenApiSerializable, IOpenApiReadOnlyExtensible, IOpenApiReadOnlyDescribedElement +{ + /// + /// The name of the tag. + /// + public string Name { get; } + + /// + /// Additional external documentation for this tag. + /// + public OpenApiExternalDocs ExternalDocs { get; } +} diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs index 057cf6d49..c30d7b819 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -11,32 +12,19 @@ namespace Microsoft.OpenApi.Models /// /// Tag Object. /// - public class OpenApiTag : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiTag : IOpenApiExtensible, IOpenApiReferenceable, IOpenApiTag, IOpenApiDescribedElement { - /// - /// The name of the tag. - /// - public virtual string Name { get; set; } + /// + public string Name { get; set; } - /// - /// A short description for the tag. - /// - public virtual string Description { get; set; } + /// + public string Description { get; set; } - /// - /// Additional external documentation for this tag. - /// - public virtual OpenApiExternalDocs ExternalDocs { get; set; } + /// + public OpenApiExternalDocs ExternalDocs { get; set; } - /// - /// This object MAY be extended with Specification Extensions. - /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); - - /// - /// Indicates if object is populated with data or is just a reference to the data - /// - public bool UnresolvedReference { get; set; } + /// + public IDictionary Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -44,21 +32,20 @@ public class OpenApiTag : IOpenApiReferenceable, IOpenApiExtensible public OpenApiTag() { } /// - /// Initializes a copy of an object + /// Initializes a copy of an object /// - public OpenApiTag(OpenApiTag tag) + public OpenApiTag(IOpenApiTag tag) { Name = tag?.Name ?? Name; Description = tag?.Description ?? Description; ExternalDocs = tag?.ExternalDocs != null ? new(tag.ExternalDocs) : null; Extensions = tag?.Extensions != null ? new Dictionary(tag.Extensions) : null; - UnresolvedReference = tag?.UnresolvedReference ?? UnresolvedReference; } /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public void SerializeAsV31(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); @@ -67,13 +54,13 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV3(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { writer.WriteStartObject(); @@ -96,7 +83,7 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio /// /// Serialize to Open Api v2.0 /// - public virtual void SerializeAsV2(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { writer.WriteStartObject(); diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 56d694d0a..0b500945b 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -10,9 +10,12 @@ namespace Microsoft.OpenApi.Models.References; /// The interface type for the model. public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V where V : IOpenApiSerializable { - private T _target; + /// + /// The resolved target object. + /// + protected T _target; /// - public T Target + public virtual T Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index 09afa3655..b70717403 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -5,26 +5,19 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Models.References { /// /// Tag Object Reference /// - public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceHolder + public class OpenApiTagReference : BaseOpenApiReferenceHolder, IOpenApiTag { - internal OpenApiTag _target; - - /// - /// Reference. - /// - public OpenApiReference Reference { get; set; } - /// /// Resolved target of the reference. /// - public OpenApiTag Target + public override OpenApiTag Target { get { @@ -38,85 +31,32 @@ public OpenApiTag Target /// /// The reference Id. /// The host OpenAPI document. - public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument) + public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument):base(referenceId, hostDocument, ReferenceType.Tag) { - Utils.CheckArgumentNullOrEmpty(referenceId); - - Reference = new OpenApiReference() - { - Id = referenceId, - HostDocument = hostDocument, - Type = ReferenceType.Tag - }; } - /// - /// Copy Constructor - /// - /// The source to copy information from. - public OpenApiTagReference(OpenApiTagReference source):base() + internal OpenApiTagReference(OpenApiTag target, string referenceId):base(target, referenceId, ReferenceType.Tag) { - Reference = source?.Reference != null ? new(source.Reference) : null; - _target = source?._target; } - private const string ReferenceErrorMessage = "Setting the value from the reference is not supported, use the target property instead."; /// - public override string Description { get => Target.Description; set => throw new InvalidOperationException(ReferenceErrorMessage); } - - /// - public override OpenApiExternalDocs ExternalDocs { get => Target.ExternalDocs; set => throw new InvalidOperationException(ReferenceErrorMessage); } - - /// - public override IDictionary Extensions { get => Target.Extensions; set => throw new InvalidOperationException(ReferenceErrorMessage); } - - /// - public override string Name { get => Target.Name; set => throw new InvalidOperationException(ReferenceErrorMessage); } - - /// - public override void SerializeAsV3(IOpenApiWriter writer) + public string Description { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV3(writer); - } - else - { - SerializeInternal(writer); - } + get => string.IsNullOrEmpty(Reference?.Description) ? Target?.Description : Reference.Description; } /// - public override void SerializeAsV31(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV31(writer); - } - else - { - SerializeInternal(writer); - } - } + public OpenApiExternalDocs ExternalDocs { get => Target?.ExternalDocs; } /// - public override void SerializeAsV2(IOpenApiWriter writer) - { - if (!writer.GetSettings().ShouldInlineReference(Reference)) - { - Reference.SerializeAsV2(writer); - } - else - { - SerializeInternal(writer); - } - } + public IDictionary Extensions { get => Target?.Extensions; } /// - private void SerializeInternal(IOpenApiWriter writer) + public string Name { get => Target?.Name; } + /// + public override IOpenApiTag CopyReferenceAsTargetElementWithOverrides(IOpenApiTag source) { - Utils.CheckArgumentNull(writer); - writer.WriteValue(Name); + return source is OpenApiTag ? new OpenApiTag(this) : source; } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs index 508779adf..c987592d4 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; using VerifyXunit; @@ -30,7 +31,7 @@ public class OpenApiTagTests } }; - public static OpenApiTag ReferencedTag = new OpenApiTagReference("pet", null); + public static IOpenApiTag ReferencedTag = new OpenApiTagReference(AdvancedTag, "pet"); [Theory] [InlineData(true)] diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs index 9d409c24b..250f8ee53 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs @@ -74,7 +74,6 @@ public void TagReferenceResolutionWorks() // Assert Assert.Equal("user", _openApiTagReference.Name); Assert.Equal("Operations about users.", _openApiTagReference.Description); - Assert.Throws(() => _openApiTagReference.Description = "New Description"); } [Theory] diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 98029f874..54da760d1 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -392,6 +392,10 @@ namespace Microsoft.OpenApi.Models.Interfaces System.Collections.Generic.IList Parameters { get; } System.Collections.Generic.IList Servers { get; } } + public interface IOpenApiReadOnlyDescribedElement : Microsoft.OpenApi.Interfaces.IOpenApiElement + { + string Description { get; } + } public interface IOpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { System.Collections.Generic.IDictionary Content { get; } @@ -473,6 +477,11 @@ namespace Microsoft.OpenApi.Models.Interfaces { string Summary { get; set; } } + public interface IOpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement + { + Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } + string Name { get; } + } } namespace Microsoft.OpenApi.Models { @@ -1109,18 +1118,17 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag { public OpenApiTag() { } - public OpenApiTag(Microsoft.OpenApi.Models.OpenApiTag tag) { } - public bool UnresolvedReference { get; set; } - public virtual string Description { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public virtual string Name { get; set; } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public OpenApiTag(Microsoft.OpenApi.Models.Interfaces.IOpenApiTag tag) { } + public string Description { get; set; } + public System.Collections.Generic.IDictionary Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public string Name { get; set; } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiXml : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1234,10 +1242,11 @@ namespace Microsoft.OpenApi.Models.References where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V where V : Microsoft.OpenApi.Interfaces.IOpenApiSerializable { + protected T _target; protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public T Target { get; } + public virtual T Target { get; } public bool UnresolvedReference { get; set; } public abstract V CopyReferenceAsTargetElementWithOverrides(V source); public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1426,19 +1435,15 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme source) { } } - public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTagReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag { - public OpenApiTagReference(Microsoft.OpenApi.Models.References.OpenApiTagReference source) { } public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public Microsoft.OpenApi.Models.OpenApiTag Target { get; } - public override string Description { get; set; } - public override System.Collections.Generic.IDictionary Extensions { get; set; } - public override Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public override string Name { get; set; } - public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public string Description { get; } + public System.Collections.Generic.IDictionary Extensions { get; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } + public string Name { get; } + public override Microsoft.OpenApi.Models.OpenApiTag Target { get; } + public override Microsoft.OpenApi.Models.Interfaces.IOpenApiTag CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiTag source) { } } } namespace Microsoft.OpenApi.Reader From e147e72b119a28c2afacb8bb98c6c9f34cb4f893 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 14:51:40 -0500 Subject: [PATCH 061/103] chore: removes unused test files Signed-off-by: Vincent Biret --- ...renceWorksAsync_produceTerseOutput=False.verified.txt | 9 --------- ...erenceWorksAsync_produceTerseOutput=True.verified.txt | 1 - ...renceWorksAsync_produceTerseOutput=False.verified.txt | 9 --------- ...erenceWorksAsync_produceTerseOutput=True.verified.txt | 1 - 4 files changed, 20 deletions(-) delete mode 100644 test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt delete mode 100644 test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index 2afa516e0..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "pet", - "description": "Pets operations", - "externalDocs": { - "description": "Find more info here", - "url": "https://example.com" - }, - "x-tag-extension": null -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index f0a901938..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt deleted file mode 100644 index 2afa516e0..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=False.verified.txt +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "pet", - "description": "Pets operations", - "externalDocs": { - "description": "Find more info here", - "url": "https://example.com" - }, - "x-tag-extension": null -} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt deleted file mode 100644 index f0a901938..000000000 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync_produceTerseOutput=True.verified.txt +++ /dev/null @@ -1 +0,0 @@ -{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null} \ No newline at end of file From e3c80a3ca660bc955f787c80cb40c1a29833e725 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 15:04:59 -0500 Subject: [PATCH 062/103] chore: cleans up temporary interface structure for references migration Signed-off-by: Vincent Biret --- .../Interfaces/IOpenApiReferenceHolder.cs | 17 ++++------------- .../References/BaseOpenApiReferenceHolder.cs | 3 +-- .../Reader/ParseNodes/MapNode.cs | 1 - .../OpenApiWorkspaceStreamTests.cs | 1 - .../PublicApi/PublicApi.approved.txt | 14 +++++--------- 5 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs index 74a38e04a..c244263f6 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs @@ -8,22 +8,14 @@ namespace Microsoft.OpenApi.Interfaces /// /// A generic interface for OpenApiReferenceable objects that have a target. /// - /// Type of the target being referenced - public interface IOpenApiReferenceHolder : IOpenApiReferenceHolder where T : IOpenApiReferenceable + /// The type of the target being referenced + /// The type of the interface implemented by both the target and the reference type + public interface IOpenApiReferenceHolder : IOpenApiReferenceHolder where T : IOpenApiReferenceable, V { /// /// Gets the resolved target object. /// T Target { get; } - } - /// - /// A generic interface for OpenApiReferenceable objects that have a target. - /// - /// The type of the target being referenced - /// The type of the interface implemented by both the target and the reference type - public interface IOpenApiReferenceHolder : IOpenApiReferenceHolder where T : IOpenApiReferenceable, V - { - //TODO merge this interface with the previous once all implementations are updated /// /// Copy the reference as a target element with overrides. /// @@ -37,8 +29,7 @@ public interface IOpenApiReferenceHolder : IOpenApiSerializable /// /// Indicates if object is populated with data or is just a reference to the data /// - bool UnresolvedReference { get; set; } - //TODO the UnresolvedReference property setter should be removed and a default implementation that checks whether the target is null for the getter should be provided instead + bool UnresolvedReference { get; } /// /// Reference object. diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 0b500945b..4a5da8025 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -31,7 +31,6 @@ protected BaseOpenApiReferenceHolder(BaseOpenApiReferenceHolder source) { Utils.CheckArgumentNull(source); Reference = source.Reference != null ? new(source.Reference) : null; - UnresolvedReference = source.UnresolvedReference; //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } @@ -69,7 +68,7 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc }; } /// - public bool UnresolvedReference { get; set; } + public bool UnresolvedReference { get => Reference is null || Target is null; } /// public OpenApiReference Reference { get; set; } /// diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs index d8740857b..b71593dca 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs @@ -124,7 +124,6 @@ public T GetReferencedObject(ReferenceType referenceType, string referenceId, { return new() { - UnresolvedReference = true, Reference = Context.VersionService.ConvertToOpenApiReference(referenceId, referenceType, summary, description) }; } diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs index 2b079ffb8..68ecbe33e 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs @@ -30,7 +30,6 @@ public async Task LoadingDocumentWithResolveAllReferencesShouldLoadDocumentIntoW BaseUrl = new("file://c:\\") }; - // Todo: this should be ReadAsync var stream = new MemoryStream(); var doc = """ openapi: 3.0.0 diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 54da760d1..caf7ade09 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -225,16 +225,12 @@ namespace Microsoft.OpenApi.Interfaces public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - bool UnresolvedReference { get; set; } + bool UnresolvedReference { get; } } - public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable - where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable - { - T Target { get; } - } - public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V { + T Target { get; } V CopyReferenceAsTargetElementWithOverrides(V source); } public interface IOpenApiReferenceable : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { } @@ -1238,7 +1234,7 @@ namespace Microsoft.OpenApi.Models } namespace Microsoft.OpenApi.Models.References { - public abstract class BaseOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public abstract class BaseOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V where V : Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -1247,7 +1243,7 @@ namespace Microsoft.OpenApi.Models.References protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public virtual T Target { get; } - public bool UnresolvedReference { get; set; } + public bool UnresolvedReference { get; } public abstract V CopyReferenceAsTargetElementWithOverrides(V source); public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From e4c14a451d9d50bcae0cf9b74162033cb2954a72 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 15:35:08 -0500 Subject: [PATCH 063/103] fix: adds generic shallow copy method to avoid inadvertent conversions of references to schemas Signed-off-by: Vincent Biret --- .../Interfaces/IShallowCopyable.cs | 12 ++ .../Models/Interfaces/IOpenApiSchema.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 2 +- .../Models/OpenApiMediaType.cs | 2 +- .../Models/OpenApiParameter.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 113 ++++++++++-------- .../References/OpenApiSchemaReference.cs | 7 ++ .../Reader/V2/OpenApiOperationDeserializer.cs | 11 +- .../V31Tests/OpenApiSchemaTests.cs | 10 +- .../Models/OpenApiSchemaTests.cs | 12 +- .../PublicApi/PublicApi.approved.txt | 13 +- 11 files changed, 107 insertions(+), 79 deletions(-) create mode 100644 src/Microsoft.OpenApi/Interfaces/IShallowCopyable.cs diff --git a/src/Microsoft.OpenApi/Interfaces/IShallowCopyable.cs b/src/Microsoft.OpenApi/Interfaces/IShallowCopyable.cs new file mode 100644 index 000000000..c1327bf0f --- /dev/null +++ b/src/Microsoft.OpenApi/Interfaces/IShallowCopyable.cs @@ -0,0 +1,12 @@ +namespace Microsoft.OpenApi.Interfaces; +/// +/// Interface for shallow copyable objects. +/// +/// The type of the resulting object +public interface IShallowCopyable +{ + /// + /// Create a shallow copy of the current instance. + /// + T CreateShallowCopy(); +} diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs index c0c78b765..b548e300d 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the schema object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index d1240bbd0..1e4e62874 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -72,7 +72,7 @@ public OpenApiHeader(IOpenApiHeader header) Style = header?.Style ?? Style; Explode = header?.Explode ?? Explode; AllowReserved = header?.AllowReserved ?? AllowReserved; - Schema = header?.Schema != null ? new OpenApiSchema(header.Schema) : null; + Schema = header?.Schema?.CreateShallowCopy(); Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 6ae08b06a..64917f95d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -59,7 +59,7 @@ public OpenApiMediaType() { } /// public OpenApiMediaType(OpenApiMediaType? mediaType) { - Schema = mediaType?.Schema != null ? new OpenApiSchema(mediaType.Schema) : null; + Schema = mediaType?.Schema?.CreateShallowCopy(); Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; Encoding = mediaType?.Encoding != null ? new Dictionary(mediaType.Encoding) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 27c443a5b..af233c2a3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -90,7 +90,7 @@ public OpenApiParameter(IOpenApiParameter parameter) Style = parameter.Style ?? Style; Explode = parameter.Explode; AllowReserved = parameter.AllowReserved; - Schema = parameter.Schema != null ? new OpenApiSchema(parameter.Schema) : null; + Schema = parameter.Schema.CreateShallowCopy(); Examples = parameter.Examples != null ? new Dictionary(parameter.Examples) : null; Example = parameter.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; Content = parameter.Content != null ? new Dictionary(parameter.Content) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index aae5723e8..482ee6b3c 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -186,60 +186,61 @@ public OpenApiSchema() { } /// Initializes a copy of object /// /// The schema object to copy from. - public OpenApiSchema(IOpenApiSchema schema) + internal OpenApiSchema(IOpenApiSchema schema) { - Title = schema?.Title ?? Title; - Id = schema?.Id ?? Id; - Const = schema?.Const ?? Const; - Schema = schema?.Schema ?? Schema; - Comment = schema?.Comment ?? Comment; - Vocabulary = schema?.Vocabulary != null ? new Dictionary(schema.Vocabulary) : null; - DynamicAnchor = schema?.DynamicAnchor ?? DynamicAnchor; - DynamicRef = schema?.DynamicRef ?? DynamicRef; - Definitions = schema?.Definitions != null ? new Dictionary(schema.Definitions) : null; - UnevaluatedProperties = schema?.UnevaluatedProperties ?? UnevaluatedProperties; - V31ExclusiveMaximum = schema?.V31ExclusiveMaximum ?? V31ExclusiveMaximum; - V31ExclusiveMinimum = schema?.V31ExclusiveMinimum ?? V31ExclusiveMinimum; - Type = schema?.Type ?? Type; - Format = schema?.Format ?? Format; - Description = schema?.Description ?? Description; - Maximum = schema?.Maximum ?? Maximum; - ExclusiveMaximum = schema?.ExclusiveMaximum ?? ExclusiveMaximum; - Minimum = schema?.Minimum ?? Minimum; - ExclusiveMinimum = schema?.ExclusiveMinimum ?? ExclusiveMinimum; - MaxLength = schema?.MaxLength ?? MaxLength; - MinLength = schema?.MinLength ?? MinLength; - Pattern = schema?.Pattern ?? Pattern; - MultipleOf = schema?.MultipleOf ?? MultipleOf; - Default = schema?.Default != null ? JsonNodeCloneHelper.Clone(schema?.Default) : null; - ReadOnly = schema?.ReadOnly ?? ReadOnly; - WriteOnly = schema?.WriteOnly ?? WriteOnly; - AllOf = schema?.AllOf != null ? new List(schema.AllOf) : null; - OneOf = schema?.OneOf != null ? new List(schema.OneOf) : null; - AnyOf = schema?.AnyOf != null ? new List(schema.AnyOf) : null; - Not = schema?.Not != null ? new OpenApiSchema(schema?.Not) : null; - Required = schema?.Required != null ? new HashSet(schema.Required) : null; - Items = schema?.Items != null ? new OpenApiSchema(schema?.Items) : null; - MaxItems = schema?.MaxItems ?? MaxItems; - MinItems = schema?.MinItems ?? MinItems; - UniqueItems = schema?.UniqueItems ?? UniqueItems; - Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; - PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; - MaxProperties = schema?.MaxProperties ?? MaxProperties; - MinProperties = schema?.MinProperties ?? MinProperties; - AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; - AdditionalProperties = schema?.AdditionalProperties != null ? new OpenApiSchema(schema?.AdditionalProperties) : null; - Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; - Example = schema?.Example != null ? JsonNodeCloneHelper.Clone(schema?.Example) : null; - Examples = schema?.Examples != null ? new List(schema.Examples) : null; - Enum = schema?.Enum != null ? new List(schema.Enum) : null; - Nullable = schema?.Nullable ?? Nullable; - ExternalDocs = schema?.ExternalDocs != null ? new(schema?.ExternalDocs) : null; - Deprecated = schema?.Deprecated ?? Deprecated; - Xml = schema?.Xml != null ? new(schema?.Xml) : null; - Extensions = schema?.Extensions != null ? new Dictionary(schema.Extensions) : null; - Annotations = schema?.Annotations != null ? new Dictionary(schema?.Annotations) : null; - UnrecognizedKeywords = schema?.UnrecognizedKeywords != null ? new Dictionary(schema?.UnrecognizedKeywords) : null; + Utils.CheckArgumentNull(schema); + Title = schema.Title ?? Title; + Id = schema.Id ?? Id; + Const = schema.Const ?? Const; + Schema = schema.Schema ?? Schema; + Comment = schema.Comment ?? Comment; + Vocabulary = schema.Vocabulary != null ? new Dictionary(schema.Vocabulary) : null; + DynamicAnchor = schema.DynamicAnchor ?? DynamicAnchor; + DynamicRef = schema.DynamicRef ?? DynamicRef; + Definitions = schema.Definitions != null ? new Dictionary(schema.Definitions) : null; + UnevaluatedProperties = schema.UnevaluatedProperties; + V31ExclusiveMaximum = schema.V31ExclusiveMaximum ?? V31ExclusiveMaximum; + V31ExclusiveMinimum = schema.V31ExclusiveMinimum ?? V31ExclusiveMinimum; + Type = schema.Type ?? Type; + Format = schema.Format ?? Format; + Description = schema.Description ?? Description; + Maximum = schema.Maximum ?? Maximum; + ExclusiveMaximum = schema.ExclusiveMaximum ?? ExclusiveMaximum; + Minimum = schema.Minimum ?? Minimum; + ExclusiveMinimum = schema.ExclusiveMinimum ?? ExclusiveMinimum; + MaxLength = schema.MaxLength ?? MaxLength; + MinLength = schema.MinLength ?? MinLength; + Pattern = schema.Pattern ?? Pattern; + MultipleOf = schema.MultipleOf ?? MultipleOf; + Default = schema.Default != null ? JsonNodeCloneHelper.Clone(schema.Default) : null; + ReadOnly = schema.ReadOnly; + WriteOnly = schema.WriteOnly; + AllOf = schema.AllOf != null ? new List(schema.AllOf) : null; + OneOf = schema.OneOf != null ? new List(schema.OneOf) : null; + AnyOf = schema.AnyOf != null ? new List(schema.AnyOf) : null; + Not = schema.Not?.CreateShallowCopy(); + Required = schema.Required != null ? new HashSet(schema.Required) : null; + Items = schema.Items?.CreateShallowCopy(); + MaxItems = schema.MaxItems ?? MaxItems; + MinItems = schema.MinItems ?? MinItems; + UniqueItems = schema.UniqueItems ?? UniqueItems; + Properties = schema.Properties != null ? new Dictionary(schema.Properties) : null; + PatternProperties = schema.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; + MaxProperties = schema.MaxProperties ?? MaxProperties; + MinProperties = schema.MinProperties ?? MinProperties; + AdditionalPropertiesAllowed = schema.AdditionalPropertiesAllowed; + AdditionalProperties = schema.AdditionalProperties?.CreateShallowCopy(); + Discriminator = schema.Discriminator != null ? new(schema.Discriminator) : null; + Example = schema.Example != null ? JsonNodeCloneHelper.Clone(schema.Example) : null; + Examples = schema.Examples != null ? new List(schema.Examples) : null; + Enum = schema.Enum != null ? new List(schema.Enum) : null; + Nullable = schema.Nullable; + ExternalDocs = schema.ExternalDocs != null ? new(schema.ExternalDocs) : null; + Deprecated = schema.Deprecated; + Xml = schema.Xml != null ? new(schema.Xml) : null; + Extensions = schema.Extensions != null ? new Dictionary(schema.Extensions) : null; + Annotations = schema.Annotations != null ? new Dictionary(schema.Annotations) : null; + UnrecognizedKeywords = schema.UnrecognizedKeywords != null ? new Dictionary(schema.UnrecognizedKeywords) : null; } /// @@ -736,5 +737,11 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter } } } + + /// + public IOpenApiSchema CreateShallowCopy() + { + return new OpenApiSchema(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index d31ba1950..56fedc7f9 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -193,5 +193,12 @@ public override IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(IOpenAp { return source is OpenApiSchema ? new OpenApiSchema(this) : source; } + /// + public IOpenApiSchema CreateShallowCopy() + { + return _target is null ? + new OpenApiSchemaReference(Reference.Id, Reference?.HostDocument, Reference?.ExternalResource) : + new OpenApiSchemaReference(_target, Reference.Id); + } } } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 7aa6f2bd5..726af76bb 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -154,12 +154,13 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List k.Name, v => { - var schema = new OpenApiSchema(v.Schema) + var schema = v.Schema.CreateShallowCopy(); + schema.Description = v.Description; + if (schema is OpenApiSchema openApiSchema) { - Description = v.Description, - Extensions = v.Extensions - }; - return (IOpenApiSchema)schema; + openApiSchema.Extensions = v.Extensions; + } + return schema; }), Required = new HashSet(formParameters.Where(static p => p.Required).Select(static p => p.Name), StringComparer.Ordinal) } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index 50c506533..555b71c54 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -140,13 +140,11 @@ public void TestSchemaCopyConstructorWithTypeArrayWorks() }; // Act - var schemaWithArrayCopy = new OpenApiSchema(schemaWithTypeArray); + var schemaWithArrayCopy = schemaWithTypeArray.CreateShallowCopy() as OpenApiSchema; schemaWithArrayCopy.Type = JsonSchemaType.String; - var simpleSchemaCopy = new OpenApiSchema(simpleSchema) - { - Type = JsonSchemaType.String | JsonSchemaType.Null - }; + var simpleSchemaCopy = simpleSchema.CreateShallowCopy() as OpenApiSchema; + simpleSchemaCopy.Type = JsonSchemaType.String | JsonSchemaType.Null; // Assert Assert.NotEqual(schemaWithTypeArray.Type, schemaWithArrayCopy.Type); @@ -294,7 +292,7 @@ public void CloningSchemaWithExamplesAndEnumsShouldSucceed() Enum = [1, 2, 3] }; - var clone = new OpenApiSchema(schema); + var clone = schema.CreateShallowCopy() as OpenApiSchema; clone.Examples.Add(4); clone.Enum.Add(4); clone.Default = 6; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index ffb10aa38..c035b04ce 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -471,10 +471,8 @@ public void OpenApiSchemaCopyConstructorSucceeds() Format = "date" }; - var actualSchema = new OpenApiSchema(baseSchema) - { - Nullable = true - }; + var actualSchema = baseSchema.CreateShallowCopy() as OpenApiSchema; + actualSchema.Nullable = true; Assert.Equal(JsonSchemaType.String, actualSchema.Type); Assert.Equal("date", actualSchema.Format); @@ -493,7 +491,7 @@ public void OpenApiSchemaCopyConstructorWithAnnotationsSucceeds() } }; - var actualSchema = new OpenApiSchema(baseSchema); + var actualSchema = baseSchema.CreateShallowCopy(); Assert.Equal(baseSchema.Annotations["key1"], actualSchema.Annotations["key1"]); @@ -531,7 +529,7 @@ public void CloningSchemaExamplesWorks(JsonNode example) }; // Act && Assert - var schemaCopy = new OpenApiSchema(schema); + var schemaCopy = schema.CreateShallowCopy(); // Act && Assert schema.Example.Should().BeEquivalentTo(schemaCopy.Example, options => options @@ -552,7 +550,7 @@ public void CloningSchemaExtensionsWorks() }; // Act && Assert - var schemaCopy = new OpenApiSchema(schema); + var schemaCopy = schema.CreateShallowCopy() as OpenApiSchema; Assert.Single(schemaCopy.Extensions); // Act && Assert diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index caf7ade09..ad48d1694 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -240,6 +240,10 @@ namespace Microsoft.OpenApi.Interfaces void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer); void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer); } + public interface IShallowCopyable + { + T CreateShallowCopy(); + } public interface IStreamLoader { System.Threading.Tasks.Task LoadAsync(System.Uri uri); @@ -405,7 +409,7 @@ namespace Microsoft.OpenApi.Models.Interfaces System.Collections.Generic.IDictionary Headers { get; } System.Collections.Generic.IDictionary Links { get; } } - public interface IOpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; } bool AdditionalPropertiesAllowed { get; } @@ -1005,10 +1009,9 @@ namespace Microsoft.OpenApi.Models public OpenApiResponses() { } public OpenApiResponses(Microsoft.OpenApi.Models.OpenApiResponses openApiResponses) { } } - public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema + public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { public OpenApiSchema() { } - public OpenApiSchema(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema schema) { } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; set; } public bool AdditionalPropertiesAllowed { get; set; } public System.Collections.Generic.IList AllOf { get; set; } @@ -1062,6 +1065,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary Vocabulary { get; set; } public bool WriteOnly { get; set; } public Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1356,7 +1360,7 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IDictionary Links { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse source) { } } - public class OpenApiSchemaReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; } @@ -1413,6 +1417,7 @@ namespace Microsoft.OpenApi.Models.References public bool WriteOnly { get; } public Microsoft.OpenApi.Models.OpenApiXml Xml { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From d87375dc8d463fb348938acb1ed048b5a5dde166 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 08:24:05 -0500 Subject: [PATCH 064/103] fix: last reference to copy constructor Signed-off-by: Vincent Biret --- .../Models/OpenApiRequestBody.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 029a6d407..0cb7d3eda 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -123,19 +124,27 @@ public IEnumerable ConvertToFormDataParameters(IOpenApiWriter foreach (var property in Content.First().Value.Schema.Properties) { - var paramSchema = new OpenApiSchema(property.Value); + var paramSchema = property.Value.CreateShallowCopy(); if ((paramSchema.Type & JsonSchemaType.String) == JsonSchemaType.String && ("binary".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase) || "base64".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase))) { - paramSchema.Type = "file".ToJsonSchemaType(); - paramSchema.Format = null; + var updatedSchema = paramSchema switch { + OpenApiSchema s => s, // we already have a copy + // we have a copy of a reference but don't want to mutate the source schema + // TODO might need recursive resolution of references here + OpenApiSchemaReference r => (OpenApiSchema)r.Target.CreateShallowCopy(), + _ => throw new InvalidOperationException("Unexpected schema type") + }; + updatedSchema.Type = "file".ToJsonSchemaType(); + updatedSchema.Format = null; + paramSchema = updatedSchema; } yield return new OpenApiFormDataParameter() { - Description = property.Value.Description, + Description = paramSchema.Description, Name = property.Key, - Schema = property.Value, + Schema = paramSchema, Examples = Content.Values.FirstOrDefault()?.Examples, Required = Content.First().Value.Schema.Required?.Contains(property.Key) ?? false }; From 4ea87efad0edde89f2e29c0c495a33a4467ba939 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 08:33:40 -0500 Subject: [PATCH 065/103] fix: shallow copy for callback Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiCallback.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiCallback.cs | 8 +++++++- .../References/OpenApiCallbackReference.cs | 16 ++++++++-------- .../Models/References/OpenApiSchemaReference.cs | 2 +- .../PublicApi/PublicApi.approved.txt | 10 +++++----- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs index e4e948c1b..a8a818d33 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiCallback.cs @@ -9,7 +9,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the callback object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiCallback : IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiCallback : IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// A Path Item Object used to define a callback request and expected responses. diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs index 7f06ca277..cd74bfd75 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs @@ -33,7 +33,7 @@ public OpenApiCallback() { } /// /// Initializes a copy of an object /// - public OpenApiCallback(IOpenApiCallback callback) + internal OpenApiCallback(IOpenApiCallback callback) { PathItems = callback?.PathItems != null ? new(callback?.PathItems) : null; Extensions = callback?.Extensions != null ? new Dictionary(callback.Extensions) : null; @@ -98,5 +98,11 @@ public void SerializeAsV2(IOpenApiWriter writer) { // Callback object does not exist in V2. } + + /// + public IOpenApiCallback CreateShallowCopy() + { + return new OpenApiCallback(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index afa22d4e2..ec660f18a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -29,14 +29,6 @@ public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument { } - /// - /// Copy constructor - /// - /// The callback reference to copy - public OpenApiCallbackReference(OpenApiCallbackReference callback):base(callback) - { - } - internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):base(target, referenceId, ReferenceType.Callback) { } @@ -59,5 +51,13 @@ public override void SerializeAsV2(IOpenApiWriter writer) // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); } + + /// + public IOpenApiCallback CreateShallowCopy() + { + return _target is null ? + new OpenApiCallbackReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : + new OpenApiCallbackReference(_target, Reference.Id); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 56fedc7f9..7bfbe038b 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -197,7 +197,7 @@ public override IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(IOpenAp public IOpenApiSchema CreateShallowCopy() { return _target is null ? - new OpenApiSchemaReference(Reference.Id, Reference?.HostDocument, Reference?.ExternalResource) : + new OpenApiSchemaReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : new OpenApiSchemaReference(_target, Reference.Id); } } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index ad48d1694..821f0e652 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -337,7 +337,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions } namespace Microsoft.OpenApi.Models.Interfaces { - public interface IOpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public interface IOpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable { System.Collections.Generic.Dictionary PathItems { get; } } @@ -496,13 +496,13 @@ namespace Microsoft.OpenApi.Models Object = 32, Array = 64, } - public class OpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback + public class OpenApiCallback : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { public OpenApiCallback() { } - public OpenApiCallback(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback callback) { } public System.Collections.Generic.IDictionary Extensions { get; set; } public System.Collections.Generic.Dictionary PathItems { get; set; } public void AddPathItem(Microsoft.OpenApi.Expressions.RuntimeExpression expression, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1253,13 +1253,13 @@ namespace Microsoft.OpenApi.Models.References public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback + public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { - public OpenApiCallbackReference(Microsoft.OpenApi.Models.References.OpenApiCallbackReference callback) { } public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public System.Collections.Generic.IDictionary Extensions { get; } public System.Collections.Generic.Dictionary PathItems { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement From 9bc30443ab95fd05b0b328c13b7e36e911628dda Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 08:35:54 -0500 Subject: [PATCH 066/103] fix: shallow copy for example Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiExample.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiExample.cs | 8 +++++++- .../Models/References/OpenApiExampleReference.cs | 16 ++++++++-------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs index bc7639c04..ece8b48ad 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiExample.cs @@ -7,7 +7,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the example object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiExample : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiExample : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// Embedded literal example. The value field and externalValue field are mutually diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index be543c525..bdfd42f4e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -39,7 +39,7 @@ public OpenApiExample() { } /// Initializes a copy of object /// /// The object - public OpenApiExample(IOpenApiExample example) + internal OpenApiExample(IOpenApiExample example) { Utils.CheckArgumentNull(example); Summary = example.Summary ?? Summary; @@ -90,5 +90,11 @@ public void SerializeAsV2(IOpenApiWriter writer) { SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); } + + /// + public IOpenApiExample CreateShallowCopy() + { + return new OpenApiExample(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 9a1c5ae16..79e994fcf 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -29,14 +29,6 @@ public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, { } - /// - /// Copy constructor - /// - /// The reference to copy. - public OpenApiExampleReference(OpenApiExampleReference example):base(example) - { - } - internal OpenApiExampleReference(OpenApiExample target, string referenceId):base(target, referenceId, ReferenceType.Example) { } @@ -88,5 +80,13 @@ public override void SerializeAsV2(IOpenApiWriter writer) // examples components are not supported in OAS 2.0 Reference.SerializeAsV2(writer); } + + /// + public IOpenApiExample CreateShallowCopy() + { + return _target is null ? + new OpenApiExampleReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : + new OpenApiExampleReference(_target, Reference.Id); + } } } From ce93aa7a23280b1fb60b9bc4e5ca4a070414fb0c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 09:10:22 -0500 Subject: [PATCH 067/103] fix: aligns reference copy constructors Signed-off-by: Vincent Biret --- .../Models/References/OpenApiCallbackReference.cs | 12 +++++++++--- .../Models/References/OpenApiExampleReference.cs | 11 ++++++++--- .../Models/References/OpenApiLinkReference.cs | 2 +- .../Models/References/OpenApiParameterReference.cs | 2 +- .../Models/References/OpenApiSchemaReference.cs | 11 ++++++++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index ec660f18a..c9884877e 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -27,6 +27,14 @@ public class OpenApiCallbackReference : BaseOpenApiReferenceHolder public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Callback, externalResource) { + } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiCallbackReference(OpenApiCallbackReference callback):base(callback) + { + } internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):base(target, referenceId, ReferenceType.Callback) @@ -55,9 +63,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) /// public IOpenApiCallback CreateShallowCopy() { - return _target is null ? - new OpenApiCallbackReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : - new OpenApiCallbackReference(_target, Reference.Id); + return new OpenApiCallbackReference(this); } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 79e994fcf..41c2109cb 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -28,6 +28,13 @@ public class OpenApiExampleReference : BaseOpenApiReferenceHolder + /// Copy constructor + /// + /// The example reference to copy + private OpenApiExampleReference(OpenApiExampleReference example):base(example) + { + } internal OpenApiExampleReference(OpenApiExample target, string referenceId):base(target, referenceId, ReferenceType.Example) { @@ -84,9 +91,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) /// public IOpenApiExample CreateShallowCopy() { - return _target is null ? - new OpenApiExampleReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : - new OpenApiExampleReference(_target, Reference.Id); + return new OpenApiExampleReference(this); } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index f177bee2c..0e27323ed 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -31,7 +31,7 @@ public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, st /// Copy constructor. /// /// The reference to copy - public OpenApiLinkReference(OpenApiLinkReference reference):base(reference) + private OpenApiLinkReference(OpenApiLinkReference reference):base(reference) { } internal OpenApiLinkReference(OpenApiLink target, string referenceId):base(target, referenceId, ReferenceType.Link) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 0f5137cf3..9af469917 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -31,7 +31,7 @@ public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocumen /// Copy constructor /// /// The parameter reference to copy - public OpenApiParameterReference(OpenApiParameterReference parameter):base(parameter) + private OpenApiParameterReference(OpenApiParameterReference parameter):base(parameter) { } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 7bfbe038b..8fbeadd50 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -28,6 +28,13 @@ public class OpenApiSchemaReference : BaseOpenApiReferenceHolder + /// Copy constructor + /// + /// The schema reference to copy + private OpenApiSchemaReference(OpenApiSchemaReference schema):base(schema) + { + } internal OpenApiSchemaReference(OpenApiSchema target, string referenceId):base(target, referenceId, ReferenceType.Schema) { @@ -196,9 +203,7 @@ public override IOpenApiSchema CopyReferenceAsTargetElementWithOverrides(IOpenAp /// public IOpenApiSchema CreateShallowCopy() { - return _target is null ? - new OpenApiSchemaReference(Reference.Id, Reference.HostDocument, Reference.ExternalResource) : - new OpenApiSchemaReference(_target, Reference.Id); + return new OpenApiSchemaReference(this); } } } From 2a42c36eb7d83c0b83f8263b7989f84c5ddf911d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 09:10:43 -0500 Subject: [PATCH 068/103] fix: switches header to shallow copy Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiHeader.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 8 ++++++- .../References/OpenApiHeaderReference.cs | 9 ++++++-- .../PublicApi/PublicApi.approved.txt | 22 +++++++++---------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs index 9caca85f6..35b6cdfe9 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs @@ -9,7 +9,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the headers object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// Determines whether this header is mandatory. diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 1e4e62874..3e6bd1944 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -63,7 +63,7 @@ public OpenApiHeader() { } /// /// Initializes a copy of an object /// - public OpenApiHeader(IOpenApiHeader header) + internal OpenApiHeader(IOpenApiHeader header) { Description = header?.Description ?? Description; Required = header?.Required ?? Required; @@ -187,5 +187,11 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteEndObject(); } + + /// + public IOpenApiHeader CreateShallowCopy() + { + return new OpenApiHeader(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index bca77ff29..c62aa9f00 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -6,7 +6,6 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models.Interfaces; -using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models.References { @@ -33,7 +32,7 @@ public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument, /// Copy constructor /// /// The object to copy - public OpenApiHeaderReference(OpenApiHeaderReference header):base(header) + private OpenApiHeaderReference(OpenApiHeaderReference header):base(header) { } @@ -92,5 +91,11 @@ public override IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(IOpenAp { return source is OpenApiHeader ? new OpenApiHeader(this) : source; } + + /// + public IOpenApiHeader CreateShallowCopy() + { + return new OpenApiHeaderReference(this); + } } } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 821f0e652..e98f53322 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -345,12 +345,12 @@ namespace Microsoft.OpenApi.Models.Interfaces { string Description { get; set; } } - public interface IOpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public interface IOpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { string ExternalValue { get; } System.Text.Json.Nodes.JsonNode Value { get; } } - public interface IOpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { bool AllowEmptyValue { get; } bool AllowReserved { get; } @@ -757,15 +757,15 @@ namespace Microsoft.OpenApi.Models public string Pointer { get; set; } public override string ToString() { } } - public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public class OpenApiExample : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiExample() { } - public OpenApiExample(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample example) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public string ExternalValue { get; set; } public string Summary { get; set; } public System.Text.Json.Nodes.JsonNode Value { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -791,10 +791,9 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader + public class OpenApiHeader : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { public OpenApiHeader() { } - public OpenApiHeader(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader header) { } public bool AllowEmptyValue { get; set; } public bool AllowReserved { get; set; } public System.Collections.Generic.IDictionary Content { get; set; } @@ -807,6 +806,7 @@ namespace Microsoft.OpenApi.Models public bool Required { get; set; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; set; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1262,9 +1262,8 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { - public OpenApiExampleReference(Microsoft.OpenApi.Models.References.OpenApiExampleReference example) { } public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } @@ -1272,11 +1271,11 @@ namespace Microsoft.OpenApi.Models.References public string Summary { get; set; } public System.Text.Json.Nodes.JsonNode Value { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiExample source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiExample CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiHeaderReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader + public class OpenApiHeaderReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { - public OpenApiHeaderReference(Microsoft.OpenApi.Models.References.OpenApiHeaderReference header) { } public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public bool AllowEmptyValue { get; } public bool AllowReserved { get; } @@ -1291,10 +1290,10 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CreateShallowCopy() { } } public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { - public OpenApiLinkReference(Microsoft.OpenApi.Models.References.OpenApiLinkReference reference) { } public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } @@ -1308,7 +1307,6 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { - public OpenApiParameterReference(Microsoft.OpenApi.Models.References.OpenApiParameterReference parameter) { } public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public bool AllowEmptyValue { get; } public bool AllowReserved { get; } From 9af6f30719c7e0718798df98096f1679f74c20e7 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 09:27:41 -0500 Subject: [PATCH 069/103] fix: shallow copy for parameter link path item and request body Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiLink.cs | 2 +- .../Models/Interfaces/IOpenApiParameter.cs | 2 +- .../Models/Interfaces/IOpenApiPathItem.cs | 2 +- .../Models/Interfaces/IOpenApiRequestBody.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiLink.cs | 8 +++- .../Models/OpenApiOperation.cs | 31 +++++++-------- .../Models/OpenApiParameter.cs | 8 +++- .../Models/OpenApiPathItem.cs | 8 +++- .../Models/OpenApiRequestBody.cs | 8 +++- .../Models/References/OpenApiLinkReference.cs | 6 +++ .../References/OpenApiParameterReference.cs | 6 +++ .../References/OpenApiPathItemReference.cs | 15 ++++++++ .../References/OpenApiRequestBodyReference.cs | 14 +++++++ src/Microsoft.OpenApi/Utils.cs | 9 +++++ .../PublicApi/PublicApi.approved.txt | 38 ++++++++++--------- 15 files changed, 119 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs index 854c945f8..66e8b5e3b 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs @@ -7,7 +7,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the link object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiLink : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiLink : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// A relative or absolute reference to an OAS operation. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs index ff6c2994f..465078e43 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the parameter object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// REQUIRED. The name of the parameter. Parameter names are case sensitive. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs index 41b8ab0e6..bbc316a14 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the path item object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiPathItem : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiPathItem : IOpenApiDescribedElement, IOpenApiSummarizedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// Gets the definition of operations on this path. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs index f014d2b4d..84afff156 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the request body object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiRequestBody : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiRequestBody : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// Determines if the request body is required in the request. Defaults to false. diff --git a/src/Microsoft.OpenApi/Models/OpenApiLink.cs b/src/Microsoft.OpenApi/Models/OpenApiLink.cs index fec27dd67..09883b4a2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiLink.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiLink.cs @@ -43,7 +43,7 @@ public OpenApiLink() { } /// /// Initializes a copy of an object /// - public OpenApiLink(IOpenApiLink link) + internal OpenApiLink(IOpenApiLink link) { Utils.CheckArgumentNull(link); OperationRef = link.OperationRef ?? OperationRef; @@ -102,5 +102,11 @@ public void SerializeAsV2(IOpenApiWriter writer) { // Link object does not exist in V2. } + + /// + public IOpenApiLink CreateShallowCopy() + { + return new OpenApiLink(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index a3ded96eb..1009c76b7 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -120,22 +120,23 @@ public OpenApiOperation() { } /// /// Initializes a copy of an object /// - public OpenApiOperation(OpenApiOperation? operation) + public OpenApiOperation(OpenApiOperation operation) { - Tags = operation?.Tags != null ? new List(operation.Tags) : null; - Summary = operation?.Summary ?? Summary; - Description = operation?.Description ?? Description; - ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; - OperationId = operation?.OperationId ?? OperationId; - Parameters = operation?.Parameters != null ? new List(operation.Parameters) : null; - RequestBody = operation?.RequestBody != null ? new OpenApiRequestBody(operation?.RequestBody) : null; - Responses = operation?.Responses != null ? new(operation?.Responses) : null; - Callbacks = operation?.Callbacks != null ? new Dictionary(operation.Callbacks) : null; - Deprecated = operation?.Deprecated ?? Deprecated; - Security = operation?.Security != null ? new List(operation.Security) : null; - Servers = operation?.Servers != null ? new List(operation.Servers) : null; - Extensions = operation?.Extensions != null ? new Dictionary(operation.Extensions) : null; - Annotations = operation?.Annotations != null ? new Dictionary(operation.Annotations) : null; + Utils.CheckArgumentNull(operation); + Tags = operation.Tags != null ? new List(operation.Tags) : null; + Summary = operation.Summary ?? Summary; + Description = operation.Description ?? Description; + ExternalDocs = operation.ExternalDocs != null ? new(operation.ExternalDocs) : null; + OperationId = operation.OperationId ?? OperationId; + Parameters = operation.Parameters != null ? new List(operation.Parameters) : null; + RequestBody = operation.RequestBody?.CreateShallowCopy(); + Responses = operation.Responses != null ? new(operation.Responses) : null; + Callbacks = operation.Callbacks != null ? new Dictionary(operation.Callbacks) : null; + Deprecated = operation.Deprecated; + Security = operation.Security != null ? new List(operation.Security) : null; + Servers = operation.Servers != null ? new List(operation.Servers) : null; + Extensions = operation.Extensions != null ? new Dictionary(operation.Extensions) : null; + Annotations = operation.Annotations != null ? new Dictionary(operation.Annotations) : null; } /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index af233c2a3..0f1d7c03a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -80,7 +80,7 @@ public OpenApiParameter() { } /// /// Initializes a clone instance of object /// - public OpenApiParameter(IOpenApiParameter parameter) + internal OpenApiParameter(IOpenApiParameter parameter) { Utils.CheckArgumentNull(parameter); Name = parameter.Name ?? Name; @@ -302,6 +302,12 @@ public void SerializeAsV2(IOpenApiWriter writer) _ => (ParameterStyle?)ParameterStyle.Simple, }; } + + /// + public IOpenApiParameter CreateShallowCopy() + { + return new OpenApiParameter(this); + } } /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs index 4aa4dedb1..88ea160bf 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs @@ -52,7 +52,7 @@ public OpenApiPathItem() { } /// /// Initializes a clone of an object /// - public OpenApiPathItem(IOpenApiPathItem pathItem) + internal OpenApiPathItem(IOpenApiPathItem pathItem) { Utils.CheckArgumentNull(pathItem); Summary = pathItem?.Summary ?? Summary; @@ -151,5 +151,11 @@ internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersio writer.WriteEndObject(); } + + /// + public IOpenApiPathItem CreateShallowCopy() + { + return new OpenApiPathItem(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 0cb7d3eda..5ec43a961 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -38,7 +38,7 @@ public OpenApiRequestBody() { } /// /// Initializes a copy instance of an object /// - public OpenApiRequestBody(IOpenApiRequestBody requestBody) + internal OpenApiRequestBody(IOpenApiRequestBody requestBody) { Utils.CheckArgumentNull(requestBody); Description = requestBody?.Description ?? Description; @@ -150,5 +150,11 @@ public IEnumerable ConvertToFormDataParameters(IOpenApiWriter }; } } + + /// + public IOpenApiRequestBody CreateShallowCopy() + { + return new OpenApiRequestBody(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index 0e27323ed..c658f32fc 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -80,5 +80,11 @@ public override IOpenApiLink CopyReferenceAsTargetElementWithOverrides(IOpenApiL { return source is OpenApiLink ? new OpenApiLink(this) : source; } + + /// + public IOpenApiLink CreateShallowCopy() + { + return new OpenApiLinkReference(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 9af469917..957c7b350 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -96,5 +96,11 @@ public override IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpe { return source is OpenApiParameter ? new OpenApiParameter(this) : source; } + + /// + public IOpenApiParameter CreateShallowCopy() + { + return new OpenApiParameterReference(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index f36bca3fd..8ee78384b 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -28,6 +28,15 @@ public OpenApiPathItemReference(string referenceId, OpenApiDocument hostDocument { } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiPathItemReference(OpenApiPathItemReference pathItem):base(pathItem) + { + + } + internal OpenApiPathItemReference(OpenApiPathItem target, string referenceId):base(target, referenceId, ReferenceType.PathItem) { } @@ -76,6 +85,12 @@ public override IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(IOpen return source is OpenApiPathItem ? new OpenApiPathItem(this) : source; } + /// + public IOpenApiPathItem CreateShallowCopy() + { + return new OpenApiPathItemReference(this); + } + /// public override void SerializeAsV2(IOpenApiWriter writer) { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index d698dd092..dc6ca082c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -27,6 +27,14 @@ public class OpenApiRequestBodyReference : BaseOpenApiReferenceHolder public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.RequestBody, externalResource) { + } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiRequestBodyReference(OpenApiRequestBodyReference openApiRequestBodyReference):base(openApiRequestBodyReference) + { + } internal OpenApiRequestBodyReference(OpenApiRequestBody target, string referenceId):base(target, referenceId, ReferenceType.RequestBody) { @@ -89,5 +97,11 @@ public IEnumerable ConvertToFormDataParameters(IOpenApiWriter return Content.First().Value.Schema.Properties.Select(x => new OpenApiParameterReference(x.Key, Reference.HostDocument)); } + + /// + public IOpenApiRequestBody CreateShallowCopy() + { + return new OpenApiRequestBodyReference(this); + } } } diff --git a/src/Microsoft.OpenApi/Utils.cs b/src/Microsoft.OpenApi/Utils.cs index b025af8e7..094361bb9 100644 --- a/src/Microsoft.OpenApi/Utils.cs +++ b/src/Microsoft.OpenApi/Utils.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.OpenApi @@ -19,7 +20,11 @@ internal static class Utils /// The input parameter name. /// The input value. internal static T CheckArgumentNull( +#if NET5_0_OR_GREATER + [NotNull] T value, +#else T value, +#endif [CallerArgumentExpression(nameof(value))] string parameterName = "") { return value ?? throw new ArgumentNullException(parameterName, $"Value cannot be null: {parameterName}"); @@ -32,7 +37,11 @@ internal static T CheckArgumentNull( /// The input parameter name. /// The input value. internal static string CheckArgumentNullOrEmpty( +#if NET5_0_OR_GREATER + [NotNull] string value, +#else string value, +#endif [CallerArgumentExpression(nameof(value))] string parameterName = "") { return string.IsNullOrWhiteSpace(value) ? throw new ArgumentNullException(parameterName, $"Value cannot be null or empty: {parameterName}") : value; diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index e98f53322..e8adb9657 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -363,7 +363,7 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } - public interface IOpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { string OperationId { get; } string OperationRef { get; } @@ -371,7 +371,7 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } Microsoft.OpenApi.Models.OpenApiServer Server { get; } } - public interface IOpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { bool AllowEmptyValue { get; } bool AllowReserved { get; } @@ -386,7 +386,7 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } Microsoft.OpenApi.Models.ParameterStyle? Style { get; } } - public interface IOpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public interface IOpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { System.Collections.Generic.IDictionary Operations { get; } System.Collections.Generic.IList Parameters { get; } @@ -396,7 +396,7 @@ namespace Microsoft.OpenApi.Models.Interfaces { string Description { get; } } - public interface IOpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { System.Collections.Generic.IDictionary Content { get; } bool Required { get; } @@ -839,10 +839,9 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink + public class OpenApiLink : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { public OpenApiLink() { } - public OpenApiLink(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink link) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public string OperationId { get; set; } @@ -850,6 +849,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IDictionary Parameters { get; set; } public Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; set; } public Microsoft.OpenApi.Models.OpenApiServer Server { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -897,7 +897,7 @@ namespace Microsoft.OpenApi.Models { public const bool DeprecatedDefault = false; public OpenApiOperation() { } - public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation? operation) { } + public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation operation) { } public System.Collections.Generic.IDictionary? Annotations { get; set; } public System.Collections.Generic.IDictionary? Callbacks { get; set; } public bool Deprecated { get; set; } @@ -916,10 +916,9 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter + public class OpenApiParameter : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { public OpenApiParameter() { } - public OpenApiParameter(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter parameter) { } public bool AllowEmptyValue { get; set; } public bool AllowReserved { get; set; } public System.Collections.Generic.IDictionary Content { get; set; } @@ -934,14 +933,14 @@ namespace Microsoft.OpenApi.Models public bool Required { get; set; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; set; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiPathItem() { } - public OpenApiPathItem(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem pathItem) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public System.Collections.Generic.IDictionary Operations { get; set; } @@ -949,6 +948,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IList Servers { get; set; } public string Summary { get; set; } public void AddOperation(Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operation) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -977,16 +977,16 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody + public class OpenApiRequestBody : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody { public OpenApiRequestBody() { } - public OpenApiRequestBody(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody requestBody) { } public System.Collections.Generic.IDictionary Content { get; set; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public bool Required { get; set; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1292,7 +1292,7 @@ namespace Microsoft.OpenApi.Models.References public override Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader source) { } public Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader CreateShallowCopy() { } } - public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink + public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string Description { get; set; } @@ -1303,9 +1303,10 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper RequestBody { get; } public Microsoft.OpenApi.Models.OpenApiServer Server { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiLink source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiLink CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter + public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public bool AllowEmptyValue { get; } @@ -1323,8 +1324,9 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Schema { get; } public Microsoft.OpenApi.Models.ParameterStyle? Style { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter CreateShallowCopy() { } } - public class OpenApiPathItemReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement + public class OpenApiPathItemReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string Description { get; set; } @@ -1334,9 +1336,10 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IList Servers { get; } public string Summary { get; set; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody + public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody { public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public System.Collections.Generic.IDictionary Content { get; } @@ -1346,6 +1349,7 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiResponseReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse From 7ac149c70d69c357aa0dc0d8e29e975a886226f9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 09:39:30 -0500 Subject: [PATCH 070/103] fix: tag, response, and security scheme shallow copy Signed-off-by: Vincent Biret --- .../Models/Interfaces/IOpenApiResponse.cs | 2 +- .../Interfaces/IOpenApiSecurityScheme.cs | 2 +- .../Models/Interfaces/IOpenApiTag.cs | 2 +- .../Models/OpenApiResponse.cs | 18 ++++++++----- .../Models/OpenApiSecurityScheme.cs | 8 +++++- src/Microsoft.OpenApi/Models/OpenApiTag.cs | 17 ++++++++---- .../References/OpenApiResponseReference.cs | 14 ++++++++++ .../OpenApiSecuritySchemeReference.cs | 14 ++++++++++ .../Models/References/OpenApiTagReference.cs | 14 ++++++++++ .../PublicApi/PublicApi.approved.txt | 27 ++++++++++--------- 10 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs index 5a1f33e7a..3df66eec0 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs @@ -7,7 +7,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the response object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiResponse : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiResponse : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// Maps a header name to its definition. diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs index 620ad185c..9580a3dad 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs @@ -8,7 +8,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the security scheme object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible +public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible, IShallowCopyable { /// /// REQUIRED. The type of the security scheme. Valid values are "apiKey", "http", "oauth2", "openIdConnect". diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs index c4f7d1e95..c2a6d8523 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiTag.cs @@ -6,7 +6,7 @@ namespace Microsoft.OpenApi.Models.Interfaces; /// Defines the base properties for the path item object. /// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking. /// -public interface IOpenApiTag : IOpenApiSerializable, IOpenApiReadOnlyExtensible, IOpenApiReadOnlyDescribedElement +public interface IOpenApiTag : IOpenApiSerializable, IOpenApiReadOnlyExtensible, IOpenApiReadOnlyDescribedElement, IShallowCopyable { /// /// The name of the tag. diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index cf2a54cfb..0ec6cbb84 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -38,14 +38,14 @@ public OpenApiResponse() { } /// /// Initializes a copy of object /// - public OpenApiResponse(IOpenApiResponse response) + internal OpenApiResponse(IOpenApiResponse response) { Utils.CheckArgumentNull(response); - Description = response?.Description ?? Description; - Headers = response?.Headers != null ? new Dictionary(response.Headers) : null; - Content = response?.Content != null ? new Dictionary(response.Content) : null; - Links = response?.Links != null ? new Dictionary(response.Links) : null; - Extensions = response?.Extensions != null ? new Dictionary(response.Extensions) : null; + Description = response.Description ?? Description; + Headers = response.Headers != null ? new Dictionary(response.Headers) : null; + Content = response.Content != null ? new Dictionary(response.Content) : null; + Links = response.Links != null ? new Dictionary(response.Links) : null; + Extensions = response.Extensions != null ? new Dictionary(response.Extensions) : null; } /// @@ -164,5 +164,11 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteEndObject(); } + + /// + public IOpenApiResponse CreateShallowCopy() + { + return new OpenApiResponse(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs index 3d9e0e636..06a4dd4e1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs @@ -50,7 +50,7 @@ public OpenApiSecurityScheme() { } /// /// Initializes a copy of object /// - public OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme) + internal OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme) { Utils.CheckArgumentNull(securityScheme); Type = securityScheme?.Type; @@ -229,5 +229,11 @@ private static void WriteOAuthFlowForV2(IOpenApiWriter writer, string flowValue, // scopes writer.WriteOptionalMap(OpenApiConstants.Scopes, flow.Scopes, (w, s) => w.WriteValue(s)); } + + /// + public IOpenApiSecurityScheme CreateShallowCopy() + { + return new OpenApiSecurityScheme(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs index c30d7b819..91e3aac68 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs @@ -34,12 +34,13 @@ public OpenApiTag() { } /// /// Initializes a copy of an object /// - public OpenApiTag(IOpenApiTag tag) + internal OpenApiTag(IOpenApiTag tag) { - Name = tag?.Name ?? Name; - Description = tag?.Description ?? Description; - ExternalDocs = tag?.ExternalDocs != null ? new(tag.ExternalDocs) : null; - Extensions = tag?.Extensions != null ? new Dictionary(tag.Extensions) : null; + Utils.CheckArgumentNull(tag); + Name = tag.Name ?? Name; + Description = tag.Description ?? Description; + ExternalDocs = tag.ExternalDocs != null ? new(tag.ExternalDocs) : null; + Extensions = tag.Extensions != null ? new Dictionary(tag.Extensions) : null; } /// @@ -101,5 +102,11 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteEndObject(); } + + /// + public IOpenApiTag CreateShallowCopy() + { + return new OpenApiTag(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index ef6b68fff..c4ddf59d7 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -25,6 +25,14 @@ public class OpenApiResponseReference : BaseOpenApiReferenceHolder public OpenApiResponseReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Response, externalResource) { + } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiResponseReference(OpenApiResponseReference openApiResponseReference):base(openApiResponseReference) + { + } internal OpenApiResponseReference(OpenApiResponse target, string referenceId):base(target, referenceId, ReferenceType.Response) @@ -61,5 +69,11 @@ public override IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(IOpen { return source is OpenApiResponse ? new OpenApiResponse(this) : source; } + + /// + public IOpenApiResponse CreateShallowCopy() + { + return new OpenApiResponseReference(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index a05070472..dd379c808 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -21,6 +21,14 @@ public class OpenApiSecuritySchemeReference : BaseOpenApiReferenceHolderThe externally referenced file. public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.SecurityScheme, externalResource) { + } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiSecuritySchemeReference(OpenApiSecuritySchemeReference openApiSecuritySchemeReference):base(openApiSecuritySchemeReference) + { + } internal OpenApiSecuritySchemeReference(OpenApiSecurityScheme target, string referenceId):base(target, referenceId, ReferenceType.SecurityScheme) { @@ -68,5 +76,11 @@ public override IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides { return source is OpenApiSecurityScheme ? new OpenApiSecurityScheme(this) : source; } + + /// + public IOpenApiSecurityScheme CreateShallowCopy() + { + return new OpenApiSecuritySchemeReference(this); + } } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index b70717403..70ca44dbc 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -33,6 +33,14 @@ public override OpenApiTag Target /// The host OpenAPI document. public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument):base(referenceId, hostDocument, ReferenceType.Tag) { + } + /// + /// Copy constructor + /// + /// The reference to copy + private OpenApiTagReference(OpenApiTagReference openApiTagReference):base(openApiTagReference) + { + } internal OpenApiTagReference(OpenApiTag target, string referenceId):base(target, referenceId, ReferenceType.Tag) @@ -58,5 +66,11 @@ public override IOpenApiTag CopyReferenceAsTargetElementWithOverrides(IOpenApiTa { return source is OpenApiTag ? new OpenApiTag(this) : source; } + + /// + public IOpenApiTag CreateShallowCopy() + { + return new OpenApiTagReference(this); + } } } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index e8adb9657..69956d663 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -403,7 +403,7 @@ namespace Microsoft.OpenApi.Models.Interfaces Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter ConvertToBodyParameter(Microsoft.OpenApi.Writers.IOpenApiWriter writer); System.Collections.Generic.IEnumerable ConvertToFormDataParameters(Microsoft.OpenApi.Writers.IOpenApiWriter writer); } - public interface IOpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { System.Collections.Generic.IDictionary Content { get; } System.Collections.Generic.IDictionary Headers { get; } @@ -463,7 +463,7 @@ namespace Microsoft.OpenApi.Models.Interfaces bool WriteOnly { get; } Microsoft.OpenApi.Models.OpenApiXml Xml { get; } } - public interface IOpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement + public interface IOpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement { string BearerFormat { get; } Microsoft.OpenApi.Models.OpenApiOAuthFlows Flows { get; } @@ -477,7 +477,7 @@ namespace Microsoft.OpenApi.Models.Interfaces { string Summary { get; set; } } - public interface IOpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement + public interface IOpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement { Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } string Name { get; } @@ -991,15 +991,15 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse + public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse { public OpenApiResponse() { } - public OpenApiResponse(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse response) { } public System.Collections.Generic.IDictionary Content { get; set; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public System.Collections.Generic.IDictionary Headers { get; set; } public System.Collections.Generic.IDictionary Links { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1077,10 +1077,9 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme + public class OpenApiSecurityScheme : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme { public OpenApiSecurityScheme() { } - public OpenApiSecurityScheme(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme securityScheme) { } public string BearerFormat { get; set; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1090,6 +1089,7 @@ namespace Microsoft.OpenApi.Models public System.Uri OpenIdConnectUrl { get; set; } public string Scheme { get; set; } public Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1118,14 +1118,14 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag + public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag { public OpenApiTag() { } - public OpenApiTag(Microsoft.OpenApi.Models.Interfaces.IOpenApiTag tag) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } public string Name { get; set; } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiTag CreateShallowCopy() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1352,7 +1352,7 @@ namespace Microsoft.OpenApi.Models.References public Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody CreateShallowCopy() { } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponseReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse + public class OpenApiResponseReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse { public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public System.Collections.Generic.IDictionary Content { get; } @@ -1361,6 +1361,7 @@ namespace Microsoft.OpenApi.Models.References public System.Collections.Generic.IDictionary Headers { get; } public System.Collections.Generic.IDictionary Links { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse CreateShallowCopy() { } } public class OpenApiSchemaReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { @@ -1424,7 +1425,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme + public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } public string BearerFormat { get; } @@ -1437,8 +1438,9 @@ namespace Microsoft.OpenApi.Models.References public string Scheme { get; } public Microsoft.OpenApi.Models.SecuritySchemeType? Type { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme CreateShallowCopy() { } } - public class OpenApiTagReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag + public class OpenApiTagReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag { public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { } public string Description { get; } @@ -1447,6 +1449,7 @@ namespace Microsoft.OpenApi.Models.References public string Name { get; } public override Microsoft.OpenApi.Models.OpenApiTag Target { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiTag CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiTag source) { } + public Microsoft.OpenApi.Models.Interfaces.IOpenApiTag CreateShallowCopy() { } } } namespace Microsoft.OpenApi.Reader From 227d99d23557fab82fcb7eb7d6e8fa34b486719d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 09:48:50 -0500 Subject: [PATCH 071/103] fix: missing defensive programming in copy constructors fix: removes extraneuous null prop op in copy constructor Signed-off-by: Vincent Biret --- .../Models/OpenApiCallback.cs | 1 + src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 25 ++++++++++--------- .../Models/OpenApiPathItem.cs | 12 ++++----- .../Models/OpenApiRequestBody.cs | 8 +++--- .../Models/OpenApiSecurityScheme.cs | 18 ++++++------- 5 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs index cd74bfd75..96f5c5cf4 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs @@ -35,6 +35,7 @@ public OpenApiCallback() { } /// internal OpenApiCallback(IOpenApiCallback callback) { + Utils.CheckArgumentNull(callback); PathItems = callback?.PathItems != null ? new(callback?.PathItems) : null; Extensions = callback?.Extensions != null ? new Dictionary(callback.Extensions) : null; } diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 3e6bd1944..dd7a0ec84 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -65,18 +65,19 @@ public OpenApiHeader() { } /// internal OpenApiHeader(IOpenApiHeader header) { - Description = header?.Description ?? Description; - Required = header?.Required ?? Required; - Deprecated = header?.Deprecated ?? Deprecated; - AllowEmptyValue = header?.AllowEmptyValue ?? AllowEmptyValue; - Style = header?.Style ?? Style; - Explode = header?.Explode ?? Explode; - AllowReserved = header?.AllowReserved ?? AllowReserved; - Schema = header?.Schema?.CreateShallowCopy(); - Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; - Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; - Content = header?.Content != null ? new Dictionary(header.Content) : null; - Extensions = header?.Extensions != null ? new Dictionary(header.Extensions) : null; + Utils.CheckArgumentNull(header); + Description = header.Description ?? Description; + Required = header.Required; + Deprecated = header.Deprecated; + AllowEmptyValue = header.AllowEmptyValue; + Style = header.Style ?? Style; + Explode = header.Explode; + AllowReserved = header.AllowReserved; + Schema = header.Schema.CreateShallowCopy(); + Example = header.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; + Examples = header.Examples != null ? new Dictionary(header.Examples) : null; + Content = header.Content != null ? new Dictionary(header.Content) : null; + Extensions = header.Extensions != null ? new Dictionary(header.Extensions) : null; } /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs index 88ea160bf..f3baa5743 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs @@ -55,12 +55,12 @@ public OpenApiPathItem() { } internal OpenApiPathItem(IOpenApiPathItem pathItem) { Utils.CheckArgumentNull(pathItem); - Summary = pathItem?.Summary ?? Summary; - Description = pathItem?.Description ?? Description; - Operations = pathItem?.Operations != null ? new Dictionary(pathItem.Operations) : null; - Servers = pathItem?.Servers != null ? new List(pathItem.Servers) : null; - Parameters = pathItem?.Parameters != null ? new List(pathItem.Parameters) : null; - Extensions = pathItem?.Extensions != null ? new Dictionary(pathItem.Extensions) : null; + Summary = pathItem.Summary ?? Summary; + Description = pathItem.Description ?? Description; + Operations = pathItem.Operations != null ? new Dictionary(pathItem.Operations) : null; + Servers = pathItem.Servers != null ? new List(pathItem.Servers) : null; + Parameters = pathItem.Parameters != null ? new List(pathItem.Parameters) : null; + Extensions = pathItem.Extensions != null ? new Dictionary(pathItem.Extensions) : null; } /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 5ec43a961..95f86dba3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -41,10 +41,10 @@ public OpenApiRequestBody() { } internal OpenApiRequestBody(IOpenApiRequestBody requestBody) { Utils.CheckArgumentNull(requestBody); - Description = requestBody?.Description ?? Description; - Required = requestBody?.Required ?? Required; - Content = requestBody?.Content != null ? new Dictionary(requestBody.Content) : null; - Extensions = requestBody?.Extensions != null ? new Dictionary(requestBody.Extensions) : null; + Description = requestBody.Description ?? Description; + Required = requestBody.Required; + Content = requestBody.Content != null ? new Dictionary(requestBody.Content) : null; + Extensions = requestBody.Extensions != null ? new Dictionary(requestBody.Extensions) : null; } /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs index 06a4dd4e1..dddbbffec 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs @@ -53,15 +53,15 @@ public OpenApiSecurityScheme() { } internal OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme) { Utils.CheckArgumentNull(securityScheme); - Type = securityScheme?.Type; - Description = securityScheme?.Description ?? Description; - Name = securityScheme?.Name ?? Name; - In = securityScheme?.In; - Scheme = securityScheme?.Scheme ?? Scheme; - BearerFormat = securityScheme?.BearerFormat ?? BearerFormat; - Flows = securityScheme?.Flows != null ? new(securityScheme?.Flows) : null; - OpenIdConnectUrl = securityScheme?.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null; - Extensions = securityScheme?.Extensions != null ? new Dictionary(securityScheme.Extensions) : null; + Type = securityScheme.Type; + Description = securityScheme.Description ?? Description; + Name = securityScheme.Name ?? Name; + In = securityScheme.In; + Scheme = securityScheme.Scheme ?? Scheme; + BearerFormat = securityScheme.BearerFormat ?? BearerFormat; + Flows = securityScheme.Flows != null ? new(securityScheme.Flows) : null; + OpenIdConnectUrl = securityScheme.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null; + Extensions = securityScheme.Extensions != null ? new Dictionary(securityScheme.Extensions) : null; } /// From 019eb99fc26f323f7a5bc79609954d237b1c0bfc Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 14:06:18 -0500 Subject: [PATCH 072/103] fix: missing null prop operator on parameter reference Signed-off-by: Vincent Biret --- .../Models/References/OpenApiParameterReference.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 957c7b350..59929ea14 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -40,7 +40,7 @@ internal OpenApiParameterReference(OpenApiParameter target, string referenceId): } /// - public string Name { get => Target.Name; } + public string Name { get => Target?.Name; } /// public string Description @@ -86,10 +86,10 @@ public string Description public bool Explode { get => Target?.Explode ?? default; } /// - public IDictionary Content { get => Target.Content; } + public IDictionary Content { get => Target?.Content; } /// - public IDictionary Extensions { get => Target.Extensions; } + public IDictionary Extensions { get => Target?.Extensions; } /// public override IOpenApiParameter CopyReferenceAsTargetElementWithOverrides(IOpenApiParameter source) From 14750dcabe29805479c3fed10152dee1ac4111af Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Jan 2025 15:08:46 -0500 Subject: [PATCH 073/103] fix: allow registration of component references --- .../Models/OpenApiDocument.cs | 20 +++++++++--------- .../Services/OpenApiWorkspace.cs | 21 ++++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 72fb875ef..9b3e9a5b1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -587,43 +587,43 @@ public bool AddComponent(string id, T componentToRegister) Components ??= new(); switch (componentToRegister) { - case OpenApiSchema openApiSchema: + case IOpenApiSchema openApiSchema: Components.Schemas ??= new Dictionary(); Components.Schemas.Add(id, openApiSchema); break; - case OpenApiParameter openApiParameter: + case IOpenApiParameter openApiParameter: Components.Parameters ??= new Dictionary(); Components.Parameters.Add(id, openApiParameter); break; - case OpenApiResponse openApiResponse: + case IOpenApiResponse openApiResponse: Components.Responses ??= new Dictionary(); Components.Responses.Add(id, openApiResponse); break; - case OpenApiRequestBody openApiRequestBody: + case IOpenApiRequestBody openApiRequestBody: Components.RequestBodies ??= new Dictionary(); Components.RequestBodies.Add(id, openApiRequestBody); break; - case OpenApiLink openApiLink: + case IOpenApiLink openApiLink: Components.Links ??= new Dictionary(); Components.Links.Add(id, openApiLink); break; - case OpenApiCallback openApiCallback: + case IOpenApiCallback openApiCallback: Components.Callbacks ??= new Dictionary(); Components.Callbacks.Add(id, openApiCallback); break; - case OpenApiPathItem openApiPathItem: + case IOpenApiPathItem openApiPathItem: Components.PathItems ??= new Dictionary(); Components.PathItems.Add(id, openApiPathItem); break; - case OpenApiExample openApiExample: + case IOpenApiExample openApiExample: Components.Examples ??= new Dictionary(); Components.Examples.Add(id, openApiExample); break; - case OpenApiHeader openApiHeader: + case IOpenApiHeader openApiHeader: Components.Headers ??= new Dictionary(); Components.Headers.Add(id, openApiHeader); break; - case OpenApiSecurityScheme openApiSecurityScheme: + case IOpenApiSecurityScheme openApiSecurityScheme: Components.SecuritySchemes ??= new Dictionary(); Components.SecuritySchemes.Add(id, openApiSecurityScheme); break; diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index f92e6f322..ec368a6c0 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -7,6 +7,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Services { @@ -165,16 +166,16 @@ public bool RegisterComponentForDocument(OpenApiDocument openApiDocument, T c var location = componentToRegister switch { - OpenApiSchema => baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiParameter => baseUri + ReferenceType.Parameter.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiResponse => baseUri + ReferenceType.Response.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiRequestBody => baseUri + ReferenceType.RequestBody.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiLink => baseUri + ReferenceType.Link.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiCallback => baseUri + ReferenceType.Callback.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiPathItem => baseUri + ReferenceType.PathItem.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiExample => baseUri + ReferenceType.Example.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiHeader => baseUri + ReferenceType.Header.GetDisplayName() + ComponentSegmentSeparator + id, - OpenApiSecurityScheme => baseUri + ReferenceType.SecurityScheme.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiSchema => baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiParameter => baseUri + ReferenceType.Parameter.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiResponse => baseUri + ReferenceType.Response.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiRequestBody => baseUri + ReferenceType.RequestBody.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiLink => baseUri + ReferenceType.Link.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiCallback => baseUri + ReferenceType.Callback.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiPathItem => baseUri + ReferenceType.PathItem.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiExample => baseUri + ReferenceType.Example.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiHeader => baseUri + ReferenceType.Header.GetDisplayName() + ComponentSegmentSeparator + id, + IOpenApiSecurityScheme => baseUri + ReferenceType.SecurityScheme.GetDisplayName() + ComponentSegmentSeparator + id, _ => throw new ArgumentException($"Invalid component type {componentToRegister.GetType().Name}"), }; From ac05342befbe51944cf3a1c966d564077e8e28ea Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 14:24:29 -0500 Subject: [PATCH 074/103] fix: a bug where 3.0 downcast of type null would not work --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 49 ++++++++++++------- ...sync_produceTerseOutput=False.verified.txt | 2 +- ...Async_produceTerseOutput=True.verified.txt | 2 +- ...sync_produceTerseOutput=False.verified.txt | 2 +- ...Async_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiSchemaTests.cs | 10 ++-- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index aae5723e8..14ab1001b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; @@ -355,12 +357,6 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version // default writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d)); - // nullable - if (version is OpenApiSpecVersion.OpenApi3_0) - { - writer.WriteProperty(OpenApiConstants.Nullable, Nullable, false); - } - // discriminator writer.WriteOptionalObject(OpenApiConstants.Discriminator, Discriminator, callback); @@ -635,20 +631,33 @@ private void SerializeAsV2( private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version) { + // check whether nullable is true for upcasting purposes + var isNullable = Nullable || + Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && + nullExtRawValue is OpenApiAny openApiAny && + openApiAny.Node is JsonNode jsonNode && + jsonNode.GetValueKind() is JsonValueKind.True; if (type is null) { - return; - } - if (!HasMultipleTypes(type.Value)) - { - // check whether nullable is true for upcasting purposes - if (version is OpenApiSpecVersion.OpenApi3_1 && (Nullable || Extensions.ContainsKey(OpenApiConstants.NullableExtension))) + if (version is OpenApiSpecVersion.OpenApi3_0 && isNullable) { - UpCastSchemaTypeToV31(type, writer); + writer.WriteProperty(OpenApiConstants.Nullable, true); } - else + } + else if (!HasMultipleTypes(type.Value)) + { + + switch (version) { - writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier()); + case OpenApiSpecVersion.OpenApi3_1 when isNullable: + UpCastSchemaTypeToV31(type.Value, writer); + break; + case OpenApiSpecVersion.OpenApi3_0 when isNullable: + writer.WriteProperty(OpenApiConstants.Nullable, true); + goto default; + default: + writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier()); + break; } } else @@ -663,6 +672,10 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, var list = (from JsonSchemaType flag in jsonSchemaTypeValues where type.Value.HasFlag(flag) select flag).ToList(); + if (Nullable && !list.Contains(JsonSchemaType.Null)) + { + list.Add(JsonSchemaType.Null); + } writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier())); } } @@ -680,12 +693,12 @@ private static bool HasMultipleTypes(JsonSchemaType schemaType) schemaTypeNumeric != (int)JsonSchemaType.Null; } - private void UpCastSchemaTypeToV31(JsonSchemaType? type, IOpenApiWriter writer) + private void UpCastSchemaTypeToV31(JsonSchemaType type, IOpenApiWriter writer) { // create a new array and insert the type and "null" as values - Type = type | JsonSchemaType.Null; + var temporaryType = type | JsonSchemaType.Null; var list = (from JsonSchemaType? flag in jsonSchemaTypeValues// Check if the flag is set in 'type' using a bitwise AND operation - where Type.Value.HasFlag(flag) + where temporaryType.HasFlag(flag) select flag.ToIdentifier()).ToList(); writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s)); } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt index b431f1607..852e12e71 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,9 +4,9 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, + "nullable": true, "type": "integer", "default": 15, - "nullable": true, "externalDocs": { "url": "http://example.com/externalDocs" } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt index d71a5f0a8..bfea35bdd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","default":15,"nullable":true,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt index b431f1607..852e12e71 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,9 +4,9 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, + "nullable": true, "type": "integer", "default": 15, - "nullable": true, "externalDocs": { "url": "http://example.com/externalDocs" } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt index d71a5f0a8..bfea35bdd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","default":15,"nullable":true,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index ffb10aa38..898a96627 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -242,9 +242,9 @@ public async Task SerializeAdvancedSchemaNumberAsV3JsonWorks() "maximum": 42, "minimum": 10, "exclusiveMinimum": true, + "nullable": true, "type": "integer", "default": 15, - "nullable": true, "externalDocs": { "url": "http://example.com/externalDocs" } @@ -268,6 +268,7 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks() """ { "title": "title1", + "nullable": true, "properties": { "property1": { "properties": { @@ -296,7 +297,6 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks() } } }, - "nullable": true, "externalDocs": { "url": "http://example.com/externalDocs" } @@ -320,6 +320,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() """ { "title": "title1", + "nullable": true, "allOf": [ { "title": "title2", @@ -335,6 +336,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() }, { "title": "title3", + "nullable": true, "properties": { "property3": { "properties": { @@ -347,11 +349,9 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() "minLength": 2, "type": "string" } - }, - "nullable": true + } } ], - "nullable": true, "externalDocs": { "url": "http://example.com/externalDocs" } From a5023d659b7adaedbe18853c297e78ac12e22823 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 14:31:01 -0500 Subject: [PATCH 075/103] fix: null reference check Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 14ab1001b..c6d3219af 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -633,6 +633,7 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, { // check whether nullable is true for upcasting purposes var isNullable = Nullable || + Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny openApiAny && openApiAny.Node is JsonNode jsonNode && From 121bb48a8f376e0257e4c2ced80978116efaa3a3 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 14:35:09 -0500 Subject: [PATCH 076/103] chore: formatting --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index c6d3219af..319734dc6 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -635,8 +635,7 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, var isNullable = Nullable || Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && - nullExtRawValue is OpenApiAny openApiAny && - openApiAny.Node is JsonNode jsonNode && + nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode} && jsonNode.GetValueKind() is JsonValueKind.True; if (type is null) { From 920a51a9170eb76921fd0e6529461e7681ac4c19 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 15:00:14 -0500 Subject: [PATCH 077/103] fix: 3.0 serialization when type is set to null Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 319734dc6..355172035 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -632,7 +632,8 @@ private void SerializeAsV2( private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version) { // check whether nullable is true for upcasting purposes - var isNullable = Nullable || + var isNullable = Nullable || + Type is JsonSchemaType.Null || Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode} && @@ -652,9 +653,14 @@ Extensions is not null && case OpenApiSpecVersion.OpenApi3_1 when isNullable: UpCastSchemaTypeToV31(type.Value, writer); break; - case OpenApiSpecVersion.OpenApi3_0 when isNullable: + case OpenApiSpecVersion.OpenApi3_0 when isNullable && type.Value == JsonSchemaType.Null: writer.WriteProperty(OpenApiConstants.Nullable, true); - goto default; + writer.WriteProperty(OpenApiConstants.Type, JsonSchemaType.Object.ToIdentifier()); + break; + case OpenApiSpecVersion.OpenApi3_0 when isNullable && type.Value != JsonSchemaType.Null: + writer.WriteProperty(OpenApiConstants.Nullable, true); + writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier()); + break; default: writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier()); break; From 3b3d0e6da51f7958285b8aa5be5d1eb73ec69acd Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 15:29:25 -0500 Subject: [PATCH 078/103] fix: do not emit a type array in 3.1 when unnecessary Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 355172035..0296a1d5f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -706,7 +706,14 @@ private void UpCastSchemaTypeToV31(JsonSchemaType type, IOpenApiWriter writer) var list = (from JsonSchemaType? flag in jsonSchemaTypeValues// Check if the flag is set in 'type' using a bitwise AND operation where temporaryType.HasFlag(flag) select flag.ToIdentifier()).ToList(); - writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s)); + if (list.Count > 1) + { + writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s)); + } + else + { + writer.WriteProperty(OpenApiConstants.Type, list[0]); + } } #if NET5_0_OR_GREATER From e09fb3865663b1f3b6295db357837006208760aa Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 16:15:48 -0500 Subject: [PATCH 079/103] chore: simplifies the filter now that null reference exp are not an issue anymore --- src/Microsoft.OpenApi/Models/OpenApiOperation.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 1009c76b7..16f5d6a01 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -278,12 +278,7 @@ public void SerializeAsV2(IOpenApiWriter writer) var produces = Responses .Where(static r => r.Value.Content != null) .SelectMany(static r => r.Value.Content?.Keys ?? []) - .Concat( - Responses - .Select(static r => r.Value) - .OfType() - .Where(static r => r.Reference is {HostDocument: not null}) - .SelectMany(static r => r.Content?.Keys ?? [])) + .Where(static m => !string.IsNullOrEmpty(m)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); From 081e2511b9df964ad74f7cb0e48761977e50cc45 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 08:55:20 -0500 Subject: [PATCH 080/103] fix: null flag comparison Co-authored-by: Andrew Omondi --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 0296a1d5f..c664aec3d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -633,7 +633,7 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, { // check whether nullable is true for upcasting purposes var isNullable = Nullable || - Type is JsonSchemaType.Null || + (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) || Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode} && From 306cd32cd9727e7b17a4117c84f39bb661a90e88 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 09:20:28 -0500 Subject: [PATCH 081/103] chore: code linting Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index c664aec3d..2cf729e0f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -699,11 +699,11 @@ private static bool HasMultipleTypes(JsonSchemaType schemaType) schemaTypeNumeric != (int)JsonSchemaType.Null; } - private void UpCastSchemaTypeToV31(JsonSchemaType type, IOpenApiWriter writer) + private static void UpCastSchemaTypeToV31(JsonSchemaType type, IOpenApiWriter writer) { // create a new array and insert the type and "null" as values var temporaryType = type | JsonSchemaType.Null; - var list = (from JsonSchemaType? flag in jsonSchemaTypeValues// Check if the flag is set in 'type' using a bitwise AND operation + var list = (from JsonSchemaType flag in jsonSchemaTypeValues// Check if the flag is set in 'type' using a bitwise AND operation where temporaryType.HasFlag(flag) select flag.ToIdentifier()).ToList(); if (list.Count > 1) @@ -736,7 +736,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null { - foreach (JsonSchemaType? flag in jsonSchemaTypeValues) + foreach (JsonSchemaType flag in jsonSchemaTypeValues) { // Skip if the flag is not set or if it's the Null flag if (schemaType.HasFlag(flag) && flag != JsonSchemaType.Null) From a46e8578519c85b9455e41ccbeebeb8740252ae3 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 09:32:20 -0500 Subject: [PATCH 082/103] fix: do not copy host document as it negatively impact performance --- src/Microsoft.OpenApi/Models/OpenApiReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index 507401cd4..c055dd072 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -150,7 +150,7 @@ public OpenApiReference(OpenApiReference reference) ExternalResource = reference?.ExternalResource; Type = reference?.Type; Id = reference?.Id; - HostDocument = new(reference?.HostDocument); + HostDocument = reference?.HostDocument; } /// From ea0a4154b5b18ff7a036c16384c2e865c19f84b5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 10:00:40 -0500 Subject: [PATCH 083/103] ci: adds release please configuration Signed-off-by: Vincent Biret --- .github/release-please.yml | 7 +++ .release-please-manifest.json | 3 ++ CHANGELOG.md | 7 +++ CONTRIBUTING.md | 52 +++++++++++++++++++ Directory.Build.props | 1 + release-please-config.json | 33 ++++++++++++ .../Microsoft.OpenApi.Hidi.csproj | 1 - .../Microsoft.OpenApi.Readers.csproj | 1 - .../Microsoft.OpenApi.csproj | 1 - 9 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 .github/release-please.yml create mode 100644 .release-please-manifest.json create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 release-please-config.json diff --git a/.github/release-please.yml b/.github/release-please.yml new file mode 100644 index 000000000..c821fc166 --- /dev/null +++ b/.github/release-please.yml @@ -0,0 +1,7 @@ +manifest: true +primaryBranch: main +handleGHRelease: true +branches: + - branch: support/v1 + manifest: true + handleGHRelease: true \ No newline at end of file diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 000000000..38714b6bd --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "2.0.0-preview5" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..52e80a16a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..a08924c7b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing to OpenAPI.net + +OpenAPI.net is a mono-repo containing source code for the following packages: + +## Libraries + +| Library | NuGet Release | +|----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [Microsoft.OpenAPI](./src/Microsoft.OpenAPI/README.md) | [![NuGet Version](https://img.shields.io/nuget/vpre/Microsoft.OpenAPI?label=Latest&logo=nuget)](https://www.nuget.org/packages/Microsoft.OpenAPI/) | +| [Microsoft.OpenAPI.Readers](./src/Microsoft.OpenAPI.Readers/README.md) | [![NuGet Version](https://img.shields.io/nuget/vpre/Microsoft.OpenAPI.Readers?label=Latest&logo=nuget)](https://www.nuget.org/packages/Microsoft.OpenAPI.Readers/) | +| [Microsoft.OpenAPI.Hidi](./src/Microsoft.OpenAPI.Hidi/README.md) | [![NuGet Version](https://img.shields.io/nuget/vpre/Microsoft.OpenAPI.Hidi?label=Latest&logo=nuget)](https://www.nuget.org/packages/Microsoft.OpenAPI.Hidi/) | + +OpenAPI.net is open to contributions. There are a couple of different recommended paths to get contributions into the released version of this library. + +__NOTE__ A signed a contribution license agreement is required for all contributions, and is checked automatically on new pull requests. Please read and sign [the agreement](https://cla.microsoft.com/) before starting any work for this repository. + +## File issues + +The best way to get started with a contribution is to start a dialog with the owners of this repository. Sometimes features will be under development or out of scope for this SDK and it's best to check before starting work on contribution. Discussions on bugs and potential fixes could point you to the write change to make. + +## Submit pull requests for bug fixes and features + +Feel free to submit a pull request with a linked issue against the __main__ branch. The main branch will be updated frequently. +## Commit message format + +To support our automated release process, pull requests are required to follow the [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) +format. +Each commit message consists of a __header__, an optional __body__ and an optional __footer__. The header is the first line of the commit and +MUST have a __type__ (see below for a list of types) and a __description__. An optional __scope__ can be added to the header to give extra context. + +``` +[optional scope]: + + + + +``` + +The recommended commit types used are: + +- __feat__ for feature updates (increments the _minor_ version) +- __fix__ for bug fixes (increments the _patch_ version) +- __perf__ for performance related changes e.g. optimizing an algorithm +- __refactor__ for code refactoring changes +- __test__ for test suite updates e.g. adding a test or fixing a test +- __style__ for changes that don't affect the meaning of code. e.g. formatting changes +- __docs__ for documentation updates e.g. ReadMe update or code documentation updates +- __build__ for build system changes (gradle updates, external dependency updates) +- __ci__ for CI configuration file changes e.g. updating a pipeline +- __chore__ for miscallaneous non-sdk changesin the repo e.g. removing an unused file + +Adding an exclamation mark after the commit type (`feat!`) or footer with the prefix __BREAKING CHANGE:__ will cause an increment of the _major_ version. \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 4fbb218f9..1b2409cb0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,6 +12,7 @@ https://github.com/Microsoft/OpenAPI.NET © Microsoft Corporation. All rights reserved. OpenAPI .NET + 2.0.0-preview5 diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 000000000..e6d1fb148 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,33 @@ +{ + "bootstrap-sha": "8943e2ad40babb0204dedb11ad6f9273adf9cd53", + "exclude-paths": [ + ".azure-pipelines", + ".github", + ".idea", + ".vs", + ".vscode" + ], + "release-type": "simple", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "include-component-in-tag": false, + "include-v-in-tag": true, + "draft": false, + "prerelease": true, + "versioning": "prerelease", + "prerelease-type": "preview", + "packages": { + ".": { + "package-name": "Microsoft.OpenApi", + "changelog-path": "CHANGELOG.md", + "extra-files": [ + { + "type": "xml", + "path": "Directory.Build.props", + "xpath": "//Project/PropertyGroup/Version" + } + ] + } + }, + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index 1e13eb157..b4bfa6189 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -9,7 +9,6 @@ enable hidi ./../../artifacts - 2.0.0-preview5 OpenAPI.NET CLI tool for slicing OpenAPI documents true diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj index 624fe822f..13c50aefd 100644 --- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj +++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj @@ -4,7 +4,6 @@ latest true - 2.0.0-preview5 OpenAPI.NET Readers for JSON and YAML documents true true diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj index 46cb80f08..6a402478f 100644 --- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj +++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj @@ -3,7 +3,6 @@ netstandard2.0;net8.0 Latest true - 2.0.0-preview5 .NET models with JSON and YAML writers for OpenAPI specification true true From 801b968a2b5bcc71a7643a00bb33ccc1f1b7ab3d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 10:06:34 -0500 Subject: [PATCH 084/103] ci: updates the ADO pipeline to match release please configuration Signed-off-by: Vincent Biret --- .azure-pipelines/ci-build.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index 6686bba75..968286c19 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -8,6 +8,9 @@ trigger: - main - dev - support/v1 + tags: + include: + - 'v*' pr: branches: include: @@ -194,7 +197,7 @@ extends: content: '*.nupkg' - stage: deploy - condition: and(or(contains(variables['build.sourceBranch'], 'refs/heads/main'),contains(variables['build.sourceBranch'], 'refs/heads/support/v1')), succeeded()) + condition: and(contains(variables['build.sourceBranch'], 'refs/tags/v'), succeeded()) dependsOn: build jobs: - deployment: deploy_hidi @@ -305,18 +308,10 @@ extends: condition: succeededOrFailed() inputs: gitHubConnection: 'Github-MaggieKimani1' - action: create + action: edit tagSource: userSpecifiedTag - tag: '$(artifactVersion)' - title: '$(artifactVersion)' + tag: 'v$(artifactVersion)' releaseNotesSource: inline assets: '$(Pipeline.Workspace)\**\*.exe' - changeLogType: issueBased - changeLogLabels: '[ - { "label" : "feature-work", "feature", "displayName" : "New Features", "state" : "closed" }, - { "label" : "enhancement", "V2-Enhancement", "displayName" : "Enhancements", "state" : "closed" }, - { "label" : "bug", "bug-fix", "displayName" : "Bugs", "state" : "closed" }, - { "label" : "documentation", "doc", "displayName" : "Documentation", "state" : "closed"}, - { "label" : "dependencies", "displayName" : "Package Updates", "state" : "closed" } - ]' + addChangeLog: false From 4d9c17b7287b27b9058828765722f55eb378e40a Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 14:55:47 -0500 Subject: [PATCH 085/103] fix: removes nullable property that shouldn't be part of dom --- .../Formatters/PowerShellFormatter.cs | 1 - .../Extensions/OpenApiTypeMapper.cs | 84 +++++++++---------- .../Models/Interfaces/IOpenApiSchema.cs | 5 -- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 17 ++-- .../References/OpenApiSchemaReference.cs | 2 - .../Reader/V3/OpenApiSchemaDeserializer.cs | 20 ++++- .../Validations/Rules/RuleHelpers.cs | 3 +- .../Formatters/PowerShellFormatterTests.cs | 24 +++--- .../UtilityFiles/OpenApiDocumentMock.cs | 12 +-- .../Extensions/OpenApiTypeMapperTests.cs | 50 +++++------ ...sync_produceTerseOutput=False.verified.txt | 2 +- ...Async_produceTerseOutput=True.verified.txt | 2 +- ...sync_produceTerseOutput=False.verified.txt | 2 +- ...Async_produceTerseOutput=True.verified.txt | 2 +- ...sync_produceTerseOutput=False.verified.txt | 1 + ...Async_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiSchemaTests.cs | 18 ++-- .../PublicApi/PublicApi.approved.txt | 3 - 18 files changed, 120 insertions(+), 130 deletions(-) diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index 2224f6f96..df632b78a 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -243,7 +243,6 @@ private static void CopySchema(OpenApiSchema schema, OpenApiSchema newSchema) schema.Enum ??= newSchema.Enum; schema.ReadOnly = !schema.ReadOnly ? newSchema.ReadOnly : schema.ReadOnly; schema.WriteOnly = !schema.WriteOnly ? newSchema.WriteOnly : schema.WriteOnly; - schema.Nullable = !schema.Nullable ? newSchema.Nullable : schema.Nullable; schema.Deprecated = !schema.Deprecated ? newSchema.Deprecated : schema.Deprecated; } } diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs index e47eff496..857de1d16 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs @@ -87,19 +87,19 @@ public static JsonSchemaType ToJsonSchemaType(this string identifier) [typeof(char)] = () => new() { Type = JsonSchemaType.String }, // Nullable types - [typeof(bool?)] = () => new() { Type = JsonSchemaType.Boolean, Nullable = true }, - [typeof(byte?)] = () => new() { Type = JsonSchemaType.String, Format = "byte", Nullable = true }, - [typeof(int?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true }, - [typeof(uint?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true }, - [typeof(long?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true }, - [typeof(ulong?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true }, - [typeof(float?)] = () => new() { Type = JsonSchemaType.Number, Format = "float", Nullable = true }, - [typeof(double?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true }, - [typeof(decimal?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true }, - [typeof(DateTime?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true }, - [typeof(DateTimeOffset?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true }, - [typeof(Guid?)] = () => new() { Type = JsonSchemaType.String, Format = "uuid", Nullable = true }, - [typeof(char?)] = () => new() { Type = JsonSchemaType.String, Nullable = true }, + [typeof(bool?)] = () => new() { Type = JsonSchemaType.Boolean | JsonSchemaType.Null }, + [typeof(byte?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "byte" }, + [typeof(int?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" }, + [typeof(uint?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" }, + [typeof(long?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" }, + [typeof(ulong?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" }, + [typeof(float?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" }, + [typeof(double?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" }, + [typeof(decimal?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" }, + [typeof(DateTime?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" }, + [typeof(DateTimeOffset?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" }, + [typeof(Guid?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid" }, + [typeof(char?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null }, [typeof(Uri)] = () => new() { Type = JsonSchemaType.String, Format = "uri" }, // Uri is treated as simple string [typeof(string)] = () => new() { Type = JsonSchemaType.String }, @@ -153,37 +153,37 @@ public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema throw new ArgumentNullException(nameof(schema)); } - var type = (schema.Type.ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Nullable) switch + var type = ((schema.Type.Value ^ JsonSchemaType.Null).ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Type.Value & JsonSchemaType.Null) switch { - ("boolean", null, false) => typeof(bool), + ("integer" or "number", "int32", JsonSchemaType.Null) => typeof(int?), + ("integer" or "number", "int64", JsonSchemaType.Null) => typeof(long?), + ("integer", null, JsonSchemaType.Null) => typeof(long?), + ("number", "float", JsonSchemaType.Null) => typeof(float?), + ("number", "double", JsonSchemaType.Null) => typeof(double?), + ("number", null, JsonSchemaType.Null) => typeof(double?), + ("number", "decimal", JsonSchemaType.Null) => typeof(decimal?), + ("string", "byte", JsonSchemaType.Null) => typeof(byte?), + ("string", "date-time", JsonSchemaType.Null) => typeof(DateTimeOffset?), + ("string", "uuid", JsonSchemaType.Null) => typeof(Guid?), + ("string", "char", JsonSchemaType.Null) => typeof(char?), + ("boolean", null, JsonSchemaType.Null) => typeof(bool?), + ("boolean", null, _) => typeof(bool), // integer is technically not valid with format, but we must provide some compatibility - ("integer" or "number", "int32", false) => typeof(int), - ("integer" or "number", "int64", false) => typeof(long), - ("integer", null, false) => typeof(long), - ("number", "float", false) => typeof(float), - ("number", "double", false) => typeof(double), - ("number", "decimal", false) => typeof(decimal), - ("number", null, false) => typeof(double), - ("string", "byte", false) => typeof(byte), - ("string", "date-time", false) => typeof(DateTimeOffset), - ("string", "uuid", false) => typeof(Guid), - ("string", "duration", false) => typeof(TimeSpan), - ("string", "char", false) => typeof(char), - ("string", null, false) => typeof(string), - ("object", null, false) => typeof(object), - ("string", "uri", false) => typeof(Uri), - ("integer" or "number", "int32", true) => typeof(int?), - ("integer" or "number", "int64", true) => typeof(long?), - ("integer", null, true) => typeof(long?), - ("number", "float", true) => typeof(float?), - ("number", "double", true) => typeof(double?), - ("number", null, true) => typeof(double?), - ("number", "decimal", true) => typeof(decimal?), - ("string", "byte", true) => typeof(byte?), - ("string", "date-time", true) => typeof(DateTimeOffset?), - ("string", "uuid", true) => typeof(Guid?), - ("string", "char", true) => typeof(char?), - ("boolean", null, true) => typeof(bool?), + ("integer" or "number", "int32", _) => typeof(int), + ("integer" or "number", "int64", _) => typeof(long), + ("integer", null, _) => typeof(long), + ("number", "float", _) => typeof(float), + ("number", "double", _) => typeof(double), + ("number", "decimal", _) => typeof(decimal), + ("number", null, _) => typeof(double), + ("string", "byte", _) => typeof(byte), + ("string", "date-time", _) => typeof(DateTimeOffset), + ("string", "uuid", _) => typeof(Guid), + ("string", "duration", _) => typeof(TimeSpan), + ("string", "char", _) => typeof(char), + ("string", null, _) => typeof(string), + ("object", null, _) => typeof(object), + ("string", "uri", _) => typeof(Uri), _ => typeof(string), }; diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs index b548e300d..9ff8e8389 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs @@ -267,11 +267,6 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable /// public IList Enum { get; } - /// - /// Allows sending a null value for the defined schema. Default value is false. - /// - public bool Nullable { get; } - /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index b8dfcefd4..86fbc89ed 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -155,9 +155,6 @@ public class OpenApiSchema : IOpenApiReferenceable, IOpenApiExtensible, IOpenApi /// public IList Enum { get; set; } = new List(); - /// - public bool Nullable { get; set; } - /// public bool UnevaluatedProperties { get; set;} @@ -236,7 +233,6 @@ internal OpenApiSchema(IOpenApiSchema schema) Example = schema.Example != null ? JsonNodeCloneHelper.Clone(schema.Example) : null; Examples = schema.Examples != null ? new List(schema.Examples) : null; Enum = schema.Enum != null ? new List(schema.Enum) : null; - Nullable = schema.Nullable; ExternalDocs = schema.ExternalDocs != null ? new(schema.ExternalDocs) : null; Deprecated = schema.Deprecated; Xml = schema.Xml != null ? new(schema.Xml) : null; @@ -633,8 +629,7 @@ private void SerializeAsV2( private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version) { // check whether nullable is true for upcasting purposes - var isNullable = Nullable || - (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) || + var isNullable = (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) || Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode} && @@ -679,10 +674,6 @@ Extensions is not null && var list = (from JsonSchemaType flag in jsonSchemaTypeValues where type.Value.HasFlag(flag) select flag).ToList(); - if (Nullable && !list.Contains(JsonSchemaType.Null)) - { - list.Add(JsonSchemaType.Null); - } writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier())); } } @@ -735,7 +726,9 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter ? OpenApiConstants.NullableExtension : OpenApiConstants.Nullable; - if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null + var nullable = (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null; + + if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && nullable) // checks for two values and one is null { foreach (JsonSchemaType flag in jsonSchemaTypeValues) { @@ -746,7 +739,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter writer.WriteProperty(OpenApiConstants.Type, flag.ToIdentifier()); } } - if (!Nullable) + if (!nullable || version is not OpenApiSpecVersion.OpenApi2_0) { writer.WriteProperty(nullableProp, true); } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 8fbeadd50..f0c9a9f47 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -142,8 +142,6 @@ public string Description /// public IList Enum { get => Target?.Enum; } /// - public bool Nullable { get => Target?.Nullable ?? false; } - /// public bool UnevaluatedProperties { get => Target?.UnevaluatedProperties ?? false; } /// public OpenApiExternalDocs ExternalDocs { get => Target?.ExternalDocs; } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index ff2706f00..25d68b477 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -86,7 +86,14 @@ internal static partial class OpenApiV3Deserializer }, { "type", - (o, n, _) => o.Type = n.GetScalarValue().ToJsonSchemaType() + (o, n, _) => { + var type = n.GetScalarValue().ToJsonSchemaType(); + // so we don't loose the value from nullable + if (o.Type.HasValue) + o.Type |= type; + else + o.Type = type; + } }, { "allOf", @@ -139,7 +146,16 @@ internal static partial class OpenApiV3Deserializer }, { "nullable", - (o, n, _) => o.Nullable = bool.Parse(n.GetScalarValue()) + (o, n, _) => + { + if (bool.TryParse(n.GetScalarValue(), out var parsed) && parsed) + { + if (o.Type.HasValue) + o.Type |= JsonSchemaType.Null; + else + o.Type = JsonSchemaType.Null; + } + } }, { "discriminator", diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index 62ab79406..63ca4d05e 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -57,11 +57,10 @@ public static void ValidateDataTypeMismatch( var type = schema.Type.ToIdentifier(); var format = schema.Format; - var nullable = schema.Nullable; // Before checking the type, check first if the schema allows null. // If so and the data given is also null, this is allowed for any type. - if (nullable && valueKind is JsonValueKind.Null) + if ((schema.Type.Value & JsonSchemaType.Null) is JsonSchemaType.Null && valueKind is JsonValueKind.Null) { return; } diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index f868dfa07..cad3b4548 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -58,21 +58,23 @@ public void RemoveAnyOfAndOneOfFromSchema() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var testSchema = openApiDocument.Components?.Schemas?["TestSchema"]; - var averageAudioDegradationProperty = testSchema?.Properties["averageAudioDegradation"]; - var defaultPriceProperty = testSchema?.Properties["defaultPrice"]; + Assert.NotNull(openApiDocument.Components); + Assert.NotNull(openApiDocument.Components.Schemas); + var testSchema = openApiDocument.Components.Schemas["TestSchema"]; + var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema.Properties["defaultPrice"]; // Assert Assert.NotNull(openApiDocument.Components); Assert.NotNull(openApiDocument.Components.Schemas); Assert.NotNull(testSchema); - Assert.Null(averageAudioDegradationProperty?.AnyOf); - Assert.Equal(JsonSchemaType.Number, averageAudioDegradationProperty?.Type); - Assert.Equal("float", averageAudioDegradationProperty?.Format); - Assert.True(averageAudioDegradationProperty?.Nullable); - Assert.Null(defaultPriceProperty?.OneOf); - Assert.Equal(JsonSchemaType.Number, defaultPriceProperty?.Type); - Assert.Equal("double", defaultPriceProperty?.Format); + Assert.Null(averageAudioDegradationProperty.AnyOf); + Assert.Equal(JsonSchemaType.Number, averageAudioDegradationProperty.Type); + Assert.Equal("float", averageAudioDegradationProperty.Format); + Assert.Equal(JsonSchemaType.Null, averageAudioDegradationProperty.Type & JsonSchemaType.Null); + Assert.Null(defaultPriceProperty.OneOf); + Assert.Equal(JsonSchemaType.Number, defaultPriceProperty.Type); + Assert.Equal("double", defaultPriceProperty.Format); Assert.NotNull(testSchema.AdditionalProperties); } @@ -165,7 +167,7 @@ private static OpenApiDocument GetSampleOpenApiDocument() new OpenApiSchema() { Type = JsonSchemaType.String } }, Format = "float", - Nullable = true + Type = JsonSchemaType.Number | JsonSchemaType.Null | JsonSchemaType.String } }, { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index b5289c1ef..3f81c71a3 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -377,14 +377,7 @@ public static OpenApiDocument CreateOpenApiDocument() { Schema = new OpenApiSchema() { - AnyOf = new List - { - new OpenApiSchema() - { - Type = JsonSchemaType.String - } - }, - Nullable = true + Type = JsonSchemaType.String | JsonSchemaType.Null } } } @@ -627,9 +620,8 @@ public static OpenApiDocument CreateOpenApiDocument() { "description", new OpenApiSchema { - Type = JsonSchemaType.String, + Type = JsonSchemaType.String | JsonSchemaType.Null, Description = "Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.).", - Nullable = true } } } diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs index c41bd6e98..dead3b27c 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs @@ -15,45 +15,45 @@ public class OpenApiTypeMapperTests { new object[] { typeof(int), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" } }, new object[] { typeof(decimal), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" } }, - new object[] { typeof(decimal?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true } }, - new object[] { typeof(bool?), new OpenApiSchema { Type = JsonSchemaType.Boolean, Nullable = true } }, + new object[] { typeof(decimal?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" } }, + new object[] { typeof(bool?), new OpenApiSchema { Type = JsonSchemaType.Boolean | JsonSchemaType.Null } }, new object[] { typeof(Guid), new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid" } }, - new object[] { typeof(Guid?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid", Nullable = true } }, + new object[] { typeof(Guid?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid" } }, new object[] { typeof(uint), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" } }, new object[] { typeof(long), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" } }, - new object[] { typeof(long?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true } }, + new object[] { typeof(long?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" } }, new object[] { typeof(ulong), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" } }, new object[] { typeof(string), new OpenApiSchema { Type = JsonSchemaType.String } }, new object[] { typeof(double), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" } }, - new object[] { typeof(float?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "float", Nullable = true } }, - new object[] { typeof(byte?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "byte", Nullable = true } }, - new object[] { typeof(int?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true } }, - new object[] { typeof(uint?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true } }, - new object[] { typeof(DateTimeOffset?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time", Nullable = true } }, - new object[] { typeof(double?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true } }, - new object[] { typeof(char?), new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true } }, + new object[] { typeof(float?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" } }, + new object[] { typeof(byte?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "byte" } }, + new object[] { typeof(int?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" } }, + new object[] { typeof(uint?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" } }, + new object[] { typeof(DateTimeOffset?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" } }, + new object[] { typeof(double?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" } }, + new object[] { typeof(char?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null } }, new object[] { typeof(DateTimeOffset), new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time" } } }; public static IEnumerable OpenApiDataTypes => new List { - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = false}, typeof(int) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true}, typeof(int?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = false}, typeof(long) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true}, typeof(long?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" }, typeof(int) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32"}, typeof(int?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" }, typeof(long) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64"}, typeof(long?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "decimal"}, typeof(decimal) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null, Nullable = false}, typeof(long) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null, Nullable = true}, typeof(long?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null, Nullable = false}, typeof(double) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null, Nullable = true}, typeof(double?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "decimal", Nullable = true}, typeof(decimal?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true}, typeof(double?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time", Nullable = true}, typeof(DateTimeOffset?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "char", Nullable = true}, typeof(char?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid", Nullable = true}, typeof(Guid?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null }, typeof(long) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = null}, typeof(long?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null }, typeof(double) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = null}, typeof(double?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "decimal"}, typeof(decimal?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double"}, typeof(double?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time"}, typeof(DateTimeOffset?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "char"}, typeof(char?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid"}, typeof(Guid?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.String }, typeof(string) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" }, typeof(double) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "float", Nullable = true }, typeof(float?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" }, typeof(float?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time" }, typeof(DateTimeOffset) } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt index 852e12e71..aac504993 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,8 +4,8 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, - "nullable": true, "type": "integer", + "nullable": true, "default": 15, "externalDocs": { "url": "http://example.com/externalDocs" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt index bfea35bdd..3ed4ce5c8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","nullable":true,"default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt index 852e12e71..aac504993 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,8 +4,8 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, - "nullable": true, "type": "integer", + "nullable": true, "default": 15, "externalDocs": { "url": "http://example.com/externalDocs" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt index bfea35bdd..3ed4ce5c8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","nullable":true,"default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt index e9543ede7..4e4e0200b 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -1,4 +1,5 @@ { + "type": "object", "title": "title1", "required": [ "property1" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt index 9ea88dee8..864b97656 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"type":"object","title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index bc3a78a7c..3e6ed2f2e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -33,9 +33,8 @@ public class OpenApiSchemaTests ExclusiveMinimum = true, Minimum = 10, Default = 15, - Type = JsonSchemaType.Integer, + Type = JsonSchemaType.Integer | JsonSchemaType.Null, - Nullable = true, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -85,7 +84,7 @@ public class OpenApiSchemaTests }, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -134,10 +133,10 @@ public class OpenApiSchemaTests MinLength = 2 } }, - Nullable = true + Type = JsonSchemaType.Object | JsonSchemaType.Null, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -152,9 +151,8 @@ public class OpenApiSchemaTests ExclusiveMinimum = true, Minimum = 10, Default = 15, - Type = JsonSchemaType.Integer, + Type = JsonSchemaType.Integer | JsonSchemaType.Null, - Nullable = true, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -208,7 +206,7 @@ public class OpenApiSchemaTests ReadOnly = true, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -472,11 +470,11 @@ public void OpenApiSchemaCopyConstructorSucceeds() }; var actualSchema = baseSchema.CreateShallowCopy() as OpenApiSchema; - actualSchema.Nullable = true; + actualSchema.Type |= JsonSchemaType.Null; Assert.Equal(JsonSchemaType.String, actualSchema.Type); Assert.Equal("date", actualSchema.Format); - Assert.True(actualSchema.Nullable); + Assert.Equal(JsonSchemaType.Null, actualSchema.Type & JsonSchemaType.Null); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 69956d663..343b8731c 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -443,7 +443,6 @@ namespace Microsoft.OpenApi.Models.Interfaces decimal? Minimum { get; } decimal? MultipleOf { get; } Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } - bool Nullable { get; } System.Collections.Generic.IList OneOf { get; } string Pattern { get; } System.Collections.Generic.IDictionary PatternProperties { get; } @@ -1046,7 +1045,6 @@ namespace Microsoft.OpenApi.Models public decimal? Minimum { get; set; } public decimal? MultipleOf { get; set; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; set; } - public bool Nullable { get; set; } public System.Collections.Generic.IList OneOf { get; set; } public string Pattern { get; set; } public System.Collections.Generic.IDictionary PatternProperties { get; set; } @@ -1400,7 +1398,6 @@ namespace Microsoft.OpenApi.Models.References public decimal? Minimum { get; } public decimal? MultipleOf { get; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } - public bool Nullable { get; } public System.Collections.Generic.IList OneOf { get; } public string Pattern { get; } public System.Collections.Generic.IDictionary PatternProperties { get; } From 2f171a3476ea0f3227ecdcb724f1d1af5406ec0e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 3 Feb 2025 15:34:07 -0500 Subject: [PATCH 086/103] fix: multiple unit test failures Signed-off-by: Vincent Biret --- .../Extensions/OpenApiTypeMapper.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 9 ++------ .../Formatters/PowerShellFormatterTests.cs | 5 ++--- ...sync_produceTerseOutput=False.verified.txt | 1 + ...Async_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiSchemaTests.cs | 21 ++++++++----------- 6 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs index 857de1d16..eea41be49 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs @@ -153,7 +153,7 @@ public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema throw new ArgumentNullException(nameof(schema)); } - var type = ((schema.Type.Value ^ JsonSchemaType.Null).ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Type.Value & JsonSchemaType.Null) switch + var type = ((schema.Type & ~JsonSchemaType.Null).ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Type & JsonSchemaType.Null) switch { ("integer" or "number", "int32", JsonSchemaType.Null) => typeof(int?), ("integer" or "number", "int64", JsonSchemaType.Null) => typeof(long?), diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 86fbc89ed..e69340641 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -726,9 +726,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter ? OpenApiConstants.NullableExtension : OpenApiConstants.Nullable; - var nullable = (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null; - - if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && nullable) // checks for two values and one is null + if (!HasMultipleTypes(schemaType & ~JsonSchemaType.Null) && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null { foreach (JsonSchemaType flag in jsonSchemaTypeValues) { @@ -739,10 +737,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter writer.WriteProperty(OpenApiConstants.Type, flag.ToIdentifier()); } } - if (!nullable || version is not OpenApiSpecVersion.OpenApi2_0) - { - writer.WriteProperty(nullableProp, true); - } + writer.WriteProperty(nullableProp, true); } else if (!HasMultipleTypes(schemaType)) { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index cad3b4548..da6d8c61e 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -69,7 +69,7 @@ public void RemoveAnyOfAndOneOfFromSchema() Assert.NotNull(openApiDocument.Components.Schemas); Assert.NotNull(testSchema); Assert.Null(averageAudioDegradationProperty.AnyOf); - Assert.Equal(JsonSchemaType.Number, averageAudioDegradationProperty.Type); + Assert.Equal(JsonSchemaType.Number | JsonSchemaType.Null, averageAudioDegradationProperty.Type); Assert.Equal("float", averageAudioDegradationProperty.Format); Assert.Equal(JsonSchemaType.Null, averageAudioDegradationProperty.Type & JsonSchemaType.Null); Assert.Null(defaultPriceProperty.OneOf); @@ -163,11 +163,10 @@ private static OpenApiDocument GetSampleOpenApiDocument() { AnyOf = new List { - new OpenApiSchema() { Type = JsonSchemaType.Number }, + new OpenApiSchema() { Type = JsonSchemaType.Number | JsonSchemaType.Null }, new OpenApiSchema() { Type = JsonSchemaType.String } }, Format = "float", - Type = JsonSchemaType.Number | JsonSchemaType.Null | JsonSchemaType.String } }, { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt index 4e4e0200b..e30457226 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -1,5 +1,6 @@ { "type": "object", + "x-nullable": true, "title": "title1", "required": [ "property1" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt index 864b97656..d5d9596f0 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"type":"object","title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"type":"object","x-nullable":true,"title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index 3e6ed2f2e..951c96fe8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -240,8 +240,8 @@ public async Task SerializeAdvancedSchemaNumberAsV3JsonWorks() "maximum": 42, "minimum": 10, "exclusiveMinimum": true, - "nullable": true, "type": "integer", + "nullable": true, "default": 15, "externalDocs": { "url": "http://example.com/externalDocs" @@ -253,9 +253,7 @@ public async Task SerializeAdvancedSchemaNumberAsV3JsonWorks() var actual = await AdvancedSchemaNumber.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -266,6 +264,7 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks() """ { "title": "title1", + "type": "object", "nullable": true, "properties": { "property1": { @@ -305,9 +304,7 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks() var actual = await AdvancedSchemaObject.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -318,6 +315,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() """ { "title": "title1", + "type": "object", "nullable": true, "allOf": [ { @@ -334,6 +332,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() }, { "title": "title3", + "type": "object", "nullable": true, "properties": { "property3": { @@ -360,9 +359,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks() var actual = await AdvancedSchemaWithAllOf.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonObject.DeepEquals(JsonObject.Parse(expected), JsonObject.Parse(actual))); } [Theory] @@ -472,9 +469,9 @@ public void OpenApiSchemaCopyConstructorSucceeds() var actualSchema = baseSchema.CreateShallowCopy() as OpenApiSchema; actualSchema.Type |= JsonSchemaType.Null; - Assert.Equal(JsonSchemaType.String, actualSchema.Type); - Assert.Equal("date", actualSchema.Format); + Assert.Equal(JsonSchemaType.String, actualSchema.Type & JsonSchemaType.String); Assert.Equal(JsonSchemaType.Null, actualSchema.Type & JsonSchemaType.Null); + Assert.Equal("date", actualSchema.Format); } [Fact] From a9469522ac9413ab14bd1161342204efe892b97a Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 4 Feb 2025 16:39:35 +0100 Subject: [PATCH 087/103] Remove dependency on CurrentCulture in tests On a system configured for german language the tests weren't working because the . on the german system are written as , which results in invalid json, because the StreamWriter depends on the CurrentCulture by default. --- .../OpenApiWriterAnyExtensionsTests.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs index a26173606..2e05a70a3 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs @@ -113,7 +113,7 @@ public async Task WriteOpenApiFloatAsJsonWorksAsync(float input, bool produceTer var json = await WriteAsJsonAsync(floatValue, produceTerseOutput); // Assert - Assert.Equal(input.ToString(), json); + Assert.Equal(input.ToString(CultureInfo.InvariantCulture), json); } public static IEnumerable DoubleInputs @@ -141,7 +141,7 @@ public async Task WriteOpenApiDoubleAsJsonWorksAsync(double input, bool produceT var json = await WriteAsJsonAsync(doubleValue, produceTerseOutput); // Assert - Assert.Equal(input.ToString(), json); + Assert.Equal(input.ToString(CultureInfo.InvariantCulture), json); } public static IEnumerable StringifiedDateTimes @@ -149,7 +149,7 @@ public static IEnumerable StringifiedDateTimes get { return - from input in new [] { + from input in new[] { "2017-1-2", "1999-01-02T12:10:22", "1999-01-03", @@ -178,7 +178,7 @@ public async Task WriteOpenApiDateTimeAsJsonWorksAsync(string inputString, bool public static IEnumerable BooleanInputs { get => - from input in new [] { true, false } + from input in new[] { true, false } from shouldBeTerse in shouldProduceTerseOutputValues select new object[] { input, shouldBeTerse }; } @@ -258,7 +258,7 @@ private static async Task WriteAsJsonAsync(JsonNode any, bool produceTer // Arrange (continued) using var stream = new MemoryStream(); var writer = new OpenApiJsonWriter( - new StreamWriter(stream), + new CultureInvariantStreamWriter(stream), new() { Terse = produceTerseOutput }); writer.WriteAny(any); @@ -279,5 +279,15 @@ private static async Task WriteAsJsonAsync(JsonNode any, bool produceTer _ => value.MakeLineBreaksEnvironmentNeutral(), }; } + + private class CultureInvariantStreamWriter : StreamWriter + { + public CultureInvariantStreamWriter(Stream stream) : base(stream) + { + } + + public override IFormatProvider FormatProvider => CultureInfo.InvariantCulture; + } + } } From fda05d465ef84f2c4c755aca2252e2672ad40107 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 12:18:22 -0500 Subject: [PATCH 088/103] fix: makes reference fields immutable --- .../Models/OpenApiReference.cs | 39 +++++++++++++------ .../Reader/V3/OpenApiV3VersionService.cs | 14 ++++--- .../Services/ReferenceHostDocumentSetter.cs | 5 ++- .../TryLoadReferenceV2Tests.cs | 6 ++- .../V3Tests/OpenApiDocumentTests.cs | 12 +++--- .../PublicApi/PublicApi.approved.txt | 12 +++--- 6 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index c055dd072..ea614ae0a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -4,14 +4,28 @@ using System; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; +#if !NET5_0_OR_GREATER +namespace System.Runtime.CompilerServices { + using System.ComponentModel; + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit { + } +} +#endif + namespace Microsoft.OpenApi.Models { /// /// A simple object to allow referencing other components in the specification, internally and externally. /// - public class OpenApiReference : IOpenApiSerializable + public class OpenApiReference : IOpenApiSerializable, IOpenApiDescribedElement, IOpenApiSummarizedElement { /// /// A short summary which by default SHOULD override that of the referenced component. @@ -32,13 +46,13 @@ public class OpenApiReference : IOpenApiSerializable /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - public string ExternalResource { get; set; } + public string ExternalResource { get; init; } /// /// The element type referenced. /// /// This must be present if is not present. - public ReferenceType? Type { get; set; } + public ReferenceType? Type { get; init; } /// /// The identifier of the reusable component of one particular ReferenceType. @@ -47,7 +61,7 @@ public class OpenApiReference : IOpenApiSerializable /// If ExternalResource is not present, this is the name of the component without the reference type name. /// For example, if the reference is '#/components/schemas/componentName', the Id is 'componentName'. /// - public string Id { get; set; } + public string Id { get; init; } /// /// Gets a flag indicating whether this reference is an external reference. @@ -62,12 +76,12 @@ public class OpenApiReference : IOpenApiSerializable /// /// Gets a flag indicating whether a file is a valid OpenAPI document or a fragment /// - public bool IsFragment = false; + public bool IsFragment { get; init; } /// /// The OpenApiDocument that is hosting the OpenApiReference instance. This is used to enable dereferencing the reference. /// - public OpenApiDocument HostDocument { get; set; } + public OpenApiDocument HostDocument { get; init; } /// /// Gets the full reference string for v3.0. @@ -145,12 +159,13 @@ public OpenApiReference() { } /// public OpenApiReference(OpenApiReference reference) { - Summary = reference?.Summary; - Description = reference?.Description; - ExternalResource = reference?.ExternalResource; - Type = reference?.Type; - Id = reference?.Id; - HostDocument = reference?.HostDocument; + Utils.CheckArgumentNull(reference); + Summary = reference.Summary; + Description = reference.Description; + ExternalResource = reference.ExternalResource; + Type = reference.Type; + Id = reference.Id; + HostDocument = reference.HostDocument; } /// diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index ffb7431fc..c10bf6ddf 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -116,7 +116,7 @@ public OpenApiReference ConvertToOpenApiReference( } // Where fragments point into a non-OpenAPI document, the id will be the complete fragment identifier var id = segments[1]; - var openApiReference = new OpenApiReference(); + var isFragment = false; // $ref: externalSource.yaml#/Pet if (id.StartsWith("/components/", StringComparison.Ordinal)) @@ -152,12 +152,16 @@ public OpenApiReference ConvertToOpenApiReference( } else { - openApiReference.IsFragment = true; + isFragment = true; } - openApiReference.ExternalResource = segments[0]; - openApiReference.Type = type; - openApiReference.Id = id; + var openApiReference = new OpenApiReference + { + ExternalResource = segments[0], + Type = type, + Id = id, + IsFragment = isFragment, + }; return openApiReference; } diff --git a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs index 146c8941d..7a9685ba4 100644 --- a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs +++ b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs @@ -23,7 +23,10 @@ public override void Visit(IOpenApiReferenceHolder referenceHolder) { if (referenceHolder.Reference != null) { - referenceHolder.Reference.HostDocument = _currentDocument; + referenceHolder.Reference = new OpenApiReference(referenceHolder.Reference) + { + HostDocument = _currentDocument, + }; } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 9d1400de6..2380c07e3 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -118,7 +118,11 @@ public async Task LoadResponseAndSchemaReference() } }; - ((OpenApiSchemaReference)expected.Content["application/json"].Schema).Reference.HostDocument = result.Document; + var schemaReference = (OpenApiSchemaReference)expected.Content["application/json"].Schema; + schemaReference.Reference = new OpenApiReference(schemaReference.Reference) + { + HostDocument = result.Document, + }; var actual = reference.Target; // Assert diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index c59aec6fb..44775f27d 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1046,11 +1046,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }; - tagReference1.Reference.HostDocument = expected; - tagReference2.Reference.HostDocument = expected; - petSchemaReference.Reference.HostDocument = expected; - newPetSchemaReference.Reference.HostDocument = expected; - errorModelSchemaReference.Reference.HostDocument = expected; + tagReference1.Reference = new OpenApiReference(tagReference1.Reference) {HostDocument = expected }; + tagReference2.Reference = new OpenApiReference(tagReference2.Reference) {HostDocument = expected }; + petSchemaReference.Reference = new OpenApiReference(petSchemaReference.Reference) {HostDocument = expected }; + newPetSchemaReference.Reference = new OpenApiReference(newPetSchemaReference.Reference) {HostDocument = expected }; + errorModelSchemaReference.Reference = new OpenApiReference(errorModelSchemaReference.Reference) {HostDocument = expected }; actual.Document.Should().BeEquivalentTo(expected, options => options .IgnoringCyclicReferences() @@ -1284,7 +1284,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() var outputDoc = (await doc.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0)).MakeLineBreaksEnvironmentNeutral(); var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters[0]; var expectedParamReference = Assert.IsType(expectedParam); - expectedParamReference.Reference.HostDocument = doc; + expectedParamReference.Reference = new OpenApiReference(expectedParamReference.Reference) {HostDocument = doc}; var actualParamReference = Assert.IsType(actualParam); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 343b8731c..dfaca710b 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -957,21 +957,21 @@ namespace Microsoft.OpenApi.Models public OpenApiPaths() { } public OpenApiPaths(Microsoft.OpenApi.Models.OpenApiPaths paths) { } } - public class OpenApiReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiReference : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { - public bool IsFragment; public OpenApiReference() { } public OpenApiReference(Microsoft.OpenApi.Models.OpenApiReference reference) { } public string Description { get; set; } - public string ExternalResource { get; set; } - public Microsoft.OpenApi.Models.OpenApiDocument HostDocument { get; set; } - public string Id { get; set; } public bool IsExternal { get; } public bool IsLocal { get; } public string ReferenceV2 { get; } public string ReferenceV3 { get; } public string Summary { get; set; } - public Microsoft.OpenApi.Models.ReferenceType? Type { get; set; } + public string ExternalResource { get; init; } + public Microsoft.OpenApi.Models.OpenApiDocument HostDocument { get; init; } + public string Id { get; init; } + public bool IsFragment { get; init; } + public Microsoft.OpenApi.Models.ReferenceType? Type { get; init; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From 89881fd5fa28148969eba75fad07ac26d4fb4e3d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 12:32:27 -0500 Subject: [PATCH 089/103] fix: makes target field read only Signed-off-by: Vincent Biret --- .../References/BaseOpenApiReferenceHolder.cs | 7 ++++--- .../Models/References/OpenApiTagReference.cs | 4 ++-- .../Models/OpenApiCallbackTests.cs | 6 +++--- .../Models/OpenApiExampleTests.cs | 6 +++--- .../Models/OpenApiHeaderTests.cs | 6 +++--- .../Models/OpenApiLinkTests.cs | 6 +++--- .../Models/OpenApiParameterTests.cs | 16 ++++++++-------- .../Models/OpenApiRequestBodyTests.cs | 6 +++--- .../Models/OpenApiResponseTests.cs | 14 +++++++------- .../Models/OpenApiSecuritySchemeTests.cs | 16 ++++++++-------- .../PublicApi/PublicApi.approved.txt | 2 +- 11 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 4a5da8025..1658a4fb4 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -13,14 +13,14 @@ public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder /// /// The resolved target object. /// - protected T _target; + protected readonly T _target; /// public virtual T Target { get { - _target ??= Reference.HostDocument?.ResolveReferenceTo(Reference); - return _target; + if (_target is not null) return _target; + return Reference.HostDocument?.ResolveReferenceTo(Reference); } } /// @@ -36,6 +36,7 @@ protected BaseOpenApiReferenceHolder(BaseOpenApiReferenceHolder source) } private protected BaseOpenApiReferenceHolder(T target, string referenceId, ReferenceType referenceType) { + Utils.CheckArgumentNull(target); _target = target; Reference = new OpenApiReference() diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index 70ca44dbc..2b7d3e727 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -21,8 +21,8 @@ public override OpenApiTag Target { get { - _target ??= Reference.HostDocument?.Tags.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, Reference.Id)); - return _target; + if (_target is not null) return _target; + return Reference.HostDocument?.Tags.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, Reference.Id)); } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 5600610de..f60fa3a1a 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiCallbackTests { - public static OpenApiCallback AdvancedCallback = new() + private static OpenApiCallback AdvancedCallback => new() { PathItems = { @@ -54,9 +54,9 @@ public class OpenApiCallbackTests } }; - public static OpenApiCallbackReference CallbackProxy = new(ReferencedCallback, "simpleHook"); + private static OpenApiCallbackReference CallbackProxy => new(ReferencedCallback, "simpleHook"); - public static OpenApiCallback ReferencedCallback = new() + private static OpenApiCallback ReferencedCallback => new() { PathItems = { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs index d1e2cd8f5..438d2a2fe 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiExampleTests { - public static OpenApiExample AdvancedExample = new() + private static OpenApiExample AdvancedExample => new() { Value = new JsonObject { @@ -57,8 +57,8 @@ public class OpenApiExampleTests } }; - public static OpenApiExampleReference OpenApiExampleReference = new(ReferencedExample, "example1"); - public static OpenApiExample ReferencedExample = new() + private static OpenApiExampleReference OpenApiExampleReference => new(ReferencedExample, "example1"); + private static OpenApiExample ReferencedExample => new() { Value = new JsonObject { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index f6d4343cb..2bd3aa0c7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiHeaderTests { - public static OpenApiHeader AdvancedHeader = new() + private static OpenApiHeader AdvancedHeader => new() { Description = "sampleHeader", Schema = new OpenApiSchema() @@ -25,9 +25,9 @@ public class OpenApiHeaderTests } }; - public static OpenApiHeaderReference OpenApiHeaderReference = new(ReferencedHeader, "example1"); + private static OpenApiHeaderReference OpenApiHeaderReference => new(ReferencedHeader, "example1"); - public static OpenApiHeader ReferencedHeader = new() + private static OpenApiHeader ReferencedHeader => new() { Description = "sampleHeader", Schema = new OpenApiSchema() diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs index e97fbb6b8..c8bf27a29 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiLinkTests { - public static readonly OpenApiLink AdvancedLink = new() + private static OpenApiLink AdvancedLink => new() { OperationId = "operationId1", Parameters = @@ -42,8 +42,8 @@ public class OpenApiLinkTests } }; - public static readonly OpenApiLinkReference LinkReference = new(ReferencedLink, "example1"); - public static readonly OpenApiLink ReferencedLink = new() + private static OpenApiLinkReference LinkReference => new(ReferencedLink, "example1"); + private static OpenApiLink ReferencedLink => new() { OperationId = "operationId1", Parameters = diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index 944920fab..bfbae32a8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -19,20 +19,20 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiParameterTests { - public static OpenApiParameter BasicParameter = new() + private static OpenApiParameter BasicParameter => new() { Name = "name1", In = ParameterLocation.Path }; - public static OpenApiParameterReference OpenApiParameterReference = new(ReferencedParameter, "example1"); - public static OpenApiParameter ReferencedParameter = new() + private static OpenApiParameterReference OpenApiParameterReference => new(ReferencedParameter, "example1"); + private static OpenApiParameter ReferencedParameter => new() { Name = "name1", In = ParameterLocation.Path }; - public static OpenApiParameter AdvancedPathParameterWithSchema = new() + private static OpenApiParameter AdvancedPathParameterWithSchema => new() { Name = "name1", In = ParameterLocation.Path, @@ -61,7 +61,7 @@ public class OpenApiParameterTests } }; - public static OpenApiParameter ParameterWithFormStyleAndExplodeFalse = new() + private static OpenApiParameter ParameterWithFormStyleAndExplodeFalse => new() { Name = "name1", In = ParameterLocation.Query, @@ -82,7 +82,7 @@ public class OpenApiParameterTests } }; - public static OpenApiParameter ParameterWithFormStyleAndExplodeTrue = new() + private static OpenApiParameter ParameterWithFormStyleAndExplodeTrue => new() { Name = "name1", In = ParameterLocation.Query, @@ -103,7 +103,7 @@ public class OpenApiParameterTests } }; - public static OpenApiParameter QueryParameterWithMissingStyle = new OpenApiParameter + private static OpenApiParameter QueryParameterWithMissingStyle => new OpenApiParameter { Name = "id", In = ParameterLocation.Query, @@ -117,7 +117,7 @@ public class OpenApiParameterTests } }; - public static OpenApiParameter AdvancedHeaderParameterWithSchemaTypeObject = new() + private static OpenApiParameter AdvancedHeaderParameterWithSchemaTypeObject => new() { Name = "name1", In = ParameterLocation.Header, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index 31d876b11..5ca281dae 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiRequestBodyTests { - public static OpenApiRequestBody AdvancedRequestBody = new() + private static OpenApiRequestBody AdvancedRequestBody => new() { Description = "description", Required = true, @@ -31,8 +31,8 @@ public class OpenApiRequestBodyTests } }; - public static OpenApiRequestBodyReference OpenApiRequestBodyReference = new(ReferencedRequestBody, "example1"); - public static OpenApiRequestBody ReferencedRequestBody = new() + private static OpenApiRequestBodyReference OpenApiRequestBodyReference => new(ReferencedRequestBody, "example1"); + private static OpenApiRequestBody ReferencedRequestBody => new() { Description = "description", Required = true, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index 374d43772..1c4137d1f 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -20,9 +20,9 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiResponseTests { - public static OpenApiResponse BasicResponse = new OpenApiResponse(); + private static OpenApiResponse BasicResponse => new OpenApiResponse(); - public static OpenApiResponse AdvancedV2Response = new OpenApiResponse + private static OpenApiResponse AdvancedV2Response => new OpenApiResponse { Description = "A complex object array response", Content = @@ -61,7 +61,7 @@ public class OpenApiResponseTests }, } }; - public static OpenApiResponse AdvancedV3Response = new OpenApiResponse + private static OpenApiResponse AdvancedV3Response => new OpenApiResponse { Description = "A complex object array response", Content = @@ -101,8 +101,8 @@ public class OpenApiResponseTests } }; - public static OpenApiResponseReference V2OpenApiResponseReference = new OpenApiResponseReference(ReferencedV2Response, "example1"); - public static OpenApiResponse ReferencedV2Response = new OpenApiResponse + private static OpenApiResponseReference V2OpenApiResponseReference => new OpenApiResponseReference(ReferencedV2Response, "example1"); + private static OpenApiResponse ReferencedV2Response => new OpenApiResponse { Description = "A complex object array response", Content = @@ -136,9 +136,9 @@ public class OpenApiResponseTests }, } }; - public static OpenApiResponseReference V3OpenApiResponseReference = new OpenApiResponseReference(ReferencedV3Response, "example1"); + private static OpenApiResponseReference V3OpenApiResponseReference => new OpenApiResponseReference(ReferencedV3Response, "example1"); - public static OpenApiResponse ReferencedV3Response = new OpenApiResponse + private static OpenApiResponse ReferencedV3Response => new OpenApiResponse { Description = "A complex object array response", Content = diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index 780b2116a..991c31847 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -17,7 +17,7 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiSecuritySchemeTests { - public static OpenApiSecurityScheme ApiKeySecurityScheme = new() + private static OpenApiSecurityScheme ApiKeySecurityScheme => new() { Description = "description1", Name = "parameterName", @@ -25,14 +25,14 @@ public class OpenApiSecuritySchemeTests In = ParameterLocation.Query, }; - public static OpenApiSecurityScheme HttpBasicSecurityScheme = new() + private static OpenApiSecurityScheme HttpBasicSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.Http, Scheme = OpenApiConstants.Basic }; - public static OpenApiSecurityScheme HttpBearerSecurityScheme = new() + private static OpenApiSecurityScheme HttpBearerSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.Http, @@ -40,7 +40,7 @@ public class OpenApiSecuritySchemeTests BearerFormat = OpenApiConstants.Jwt }; - public static OpenApiSecurityScheme OAuth2SingleFlowSecurityScheme = new() + private static OpenApiSecurityScheme OAuth2SingleFlowSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.OAuth2, @@ -58,7 +58,7 @@ public class OpenApiSecuritySchemeTests } }; - public static OpenApiSecurityScheme OAuth2MultipleFlowSecurityScheme = new() + private static OpenApiSecurityScheme OAuth2MultipleFlowSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.OAuth2, @@ -96,7 +96,7 @@ public class OpenApiSecuritySchemeTests } }; - public static OpenApiSecurityScheme OpenIdConnectSecurityScheme = new() + private static OpenApiSecurityScheme OpenIdConnectSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, @@ -104,8 +104,8 @@ public class OpenApiSecuritySchemeTests OpenIdConnectUrl = new("https://example.com/openIdConnect") }; - public static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference = new(ReferencedSecurityScheme, "sampleSecurityScheme"); - public static OpenApiSecurityScheme ReferencedSecurityScheme = new() + private static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference => new(ReferencedSecurityScheme, "sampleSecurityScheme"); + private static OpenApiSecurityScheme ReferencedSecurityScheme => new() { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index dfaca710b..f8679c32d 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1240,7 +1240,7 @@ namespace Microsoft.OpenApi.Models.References where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V where V : Microsoft.OpenApi.Interfaces.IOpenApiSerializable { - protected T _target; + protected readonly T _target; protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } From 92877e08d5689b06ead8a79bfdf6442858010dae Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 12:36:42 -0500 Subject: [PATCH 090/103] docs: adds considerations for why the target is readonly Signed-off-by: Vincent Biret --- .../Models/References/BaseOpenApiReferenceHolder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 1658a4fb4..86b31fa06 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models.References; public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V where V : IOpenApiSerializable { /// - /// The resolved target object. + /// The resolved target object. This should remain readonly, otherwise mutating the reference will have side effects. /// protected readonly T _target; /// From 9cd7aaea76316b3944e8a549db9aad3a3155b51b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 12:43:16 -0500 Subject: [PATCH 091/103] fix: removes unused parameters Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs | 4 ++-- src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs | 4 +--- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs index 2f1ce2b37..353435bc8 100644 --- a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs +++ b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs @@ -77,9 +77,9 @@ public ReadResult Read(MemoryStream input, } /// - public static ReadResult Read(JsonNode jsonNode, OpenApiReaderSettings settings, string format = null) + public static ReadResult Read(JsonNode jsonNode, OpenApiReaderSettings settings) { - return _jsonReader.Read(jsonNode, settings, OpenApiConstants.Yaml); + return _jsonReader.Read(jsonNode, settings); } /// diff --git a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs index 4aad45278..bac24a51d 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs @@ -60,11 +60,9 @@ public ReadResult Read(MemoryStream input, /// /// The JsonNode input. /// The Reader settings to be used during parsing. - /// The OpenAPI format. /// public ReadResult Read(JsonNode jsonNode, - OpenApiReaderSettings settings, - string format = null) + OpenApiReaderSettings settings) { if (jsonNode is null) throw new ArgumentNullException(nameof(jsonNode)); if (settings is null) throw new ArgumentNullException(nameof(settings)); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 343b8731c..21128b6c1 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1463,7 +1463,7 @@ namespace Microsoft.OpenApi.Reader { public OpenApiJsonReader() { } public Microsoft.OpenApi.Reader.ReadResult Read(System.IO.MemoryStream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings) { } - public Microsoft.OpenApi.Reader.ReadResult Read(System.Text.Json.Nodes.JsonNode jsonNode, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings, string format = null) { } + public Microsoft.OpenApi.Reader.ReadResult Read(System.Text.Json.Nodes.JsonNode jsonNode, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings) { } public System.Threading.Tasks.Task ReadAsync(System.IO.Stream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings, System.Threading.CancellationToken cancellationToken = default) { } public T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } From a182f44bfb74ccbbb5b4bbf842693de48d60dac1 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 13:02:18 -0500 Subject: [PATCH 092/103] fix: makes reference of holder immutable Signed-off-by: Vincent Biret --- .../Interfaces/IOpenApiReferenceHolder.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiReference.cs | 14 +++++++++++++- .../References/BaseOpenApiReferenceHolder.cs | 2 +- .../Services/ReferenceHostDocumentSetter.cs | 8 +------- .../ReferenceService/TryLoadReferenceV2Tests.cs | 6 +----- .../V3Tests/OpenApiDocumentTests.cs | 12 ++++++------ .../PublicApi/PublicApi.approved.txt | 4 ++-- 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs index c244263f6..8883a90f5 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceHolder.cs @@ -34,6 +34,6 @@ public interface IOpenApiReferenceHolder : IOpenApiSerializable /// /// Reference object. /// - OpenApiReference Reference { get; set; } + OpenApiReference Reference { get; init; } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index ea614ae0a..bed22a7c3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -78,10 +78,11 @@ public class OpenApiReference : IOpenApiSerializable, IOpenApiDescribedElement, /// public bool IsFragment { get; init; } + private OpenApiDocument openApiDocument; /// /// The OpenApiDocument that is hosting the OpenApiReference instance. This is used to enable dereferencing the reference. /// - public OpenApiDocument HostDocument { get; init; } + public OpenApiDocument HostDocument { get => openApiDocument; init => openApiDocument = value; } /// /// Gets the full reference string for v3.0. @@ -291,5 +292,16 @@ private string GetReferenceTypeNameAsV2(ReferenceType type) // to indicate that the reference is not pointing to any object. }; } + + /// + /// Sets the host document after deserialization or before serialization. + /// This method is internal on purpose to avoid consumers mutating the host document. + /// + /// Host document to set if none is present + internal void EnsureHostDocumentIsSet(OpenApiDocument currentDocument) + { + Utils.CheckArgumentNull(currentDocument); + openApiDocument ??= currentDocument; + } } } diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 86b31fa06..4d1eaf4c0 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -71,7 +71,7 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc /// public bool UnresolvedReference { get => Reference is null || Target is null; } /// - public OpenApiReference Reference { get; set; } + public OpenApiReference Reference { get; init; } /// public abstract V CopyReferenceAsTargetElementWithOverrides(V source); /// diff --git a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs index 7a9685ba4..c660d21bd 100644 --- a/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs +++ b/src/Microsoft.OpenApi/Services/ReferenceHostDocumentSetter.cs @@ -21,13 +21,7 @@ public ReferenceHostDocumentSetter(OpenApiDocument currentDocument) /// public override void Visit(IOpenApiReferenceHolder referenceHolder) { - if (referenceHolder.Reference != null) - { - referenceHolder.Reference = new OpenApiReference(referenceHolder.Reference) - { - HostDocument = _currentDocument, - }; - } + referenceHolder.Reference?.EnsureHostDocumentIsSet(_currentDocument); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 2380c07e3..9208fabd8 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -118,11 +118,7 @@ public async Task LoadResponseAndSchemaReference() } }; - var schemaReference = (OpenApiSchemaReference)expected.Content["application/json"].Schema; - schemaReference.Reference = new OpenApiReference(schemaReference.Reference) - { - HostDocument = result.Document, - }; + ((OpenApiSchemaReference)expected.Content["application/json"].Schema).Reference.EnsureHostDocumentIsSet(result.Document); var actual = reference.Target; // Assert diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 44775f27d..6a5d80f0f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1046,11 +1046,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }; - tagReference1.Reference = new OpenApiReference(tagReference1.Reference) {HostDocument = expected }; - tagReference2.Reference = new OpenApiReference(tagReference2.Reference) {HostDocument = expected }; - petSchemaReference.Reference = new OpenApiReference(petSchemaReference.Reference) {HostDocument = expected }; - newPetSchemaReference.Reference = new OpenApiReference(newPetSchemaReference.Reference) {HostDocument = expected }; - errorModelSchemaReference.Reference = new OpenApiReference(errorModelSchemaReference.Reference) {HostDocument = expected }; + tagReference1.Reference.EnsureHostDocumentIsSet(expected); + tagReference2.Reference.EnsureHostDocumentIsSet(expected); + petSchemaReference.Reference.EnsureHostDocumentIsSet(expected); + newPetSchemaReference.Reference.EnsureHostDocumentIsSet(expected); + errorModelSchemaReference.Reference.EnsureHostDocumentIsSet(expected); actual.Document.Should().BeEquivalentTo(expected, options => options .IgnoringCyclicReferences() @@ -1284,7 +1284,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() var outputDoc = (await doc.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0)).MakeLineBreaksEnvironmentNeutral(); var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters[0]; var expectedParamReference = Assert.IsType(expectedParam); - expectedParamReference.Reference = new OpenApiReference(expectedParamReference.Reference) {HostDocument = doc}; + expectedParamReference.Reference.EnsureHostDocumentIsSet(doc); var actualParamReference = Assert.IsType(actualParam); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index f8679c32d..5b6c34d8e 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -224,8 +224,8 @@ namespace Microsoft.OpenApi.Interfaces } public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { - Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } bool UnresolvedReference { get; } + Microsoft.OpenApi.Models.OpenApiReference Reference { get; init; } } public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V @@ -1243,9 +1243,9 @@ namespace Microsoft.OpenApi.Models.References protected readonly T _target; protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public virtual T Target { get; } public bool UnresolvedReference { get; } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; init; } public abstract V CopyReferenceAsTargetElementWithOverrides(V source); public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } From ee6fae221b3f76045353ba8c33ff44e14318d3b9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 14:07:26 -0500 Subject: [PATCH 093/103] chore: linting Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/IsExternalInit.cs | 13 +++++++++++++ .../Models/OpenApiReference.cs | 19 +++---------------- 2 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 src/Microsoft.OpenApi/IsExternalInit.cs diff --git a/src/Microsoft.OpenApi/IsExternalInit.cs b/src/Microsoft.OpenApi/IsExternalInit.cs new file mode 100644 index 000000000..9c8e2ad1a --- /dev/null +++ b/src/Microsoft.OpenApi/IsExternalInit.cs @@ -0,0 +1,13 @@ +//TODO remove this if we ever remove the netstandard2.0 target +#if !NET5_0_OR_GREATER +namespace System.Runtime.CompilerServices { + using System.ComponentModel; + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit { + } +} +#endif diff --git a/src/Microsoft.OpenApi/Models/OpenApiReference.cs b/src/Microsoft.OpenApi/Models/OpenApiReference.cs index bed22a7c3..43d307fad 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiReference.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiReference.cs @@ -7,19 +7,6 @@ using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Writers; -#if !NET5_0_OR_GREATER -namespace System.Runtime.CompilerServices { - using System.ComponentModel; - /// - /// Reserved to be used by the compiler for tracking metadata. - /// This class should not be used by developers in source code. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - internal static class IsExternalInit { - } -} -#endif - namespace Microsoft.OpenApi.Models { /// @@ -78,11 +65,11 @@ public class OpenApiReference : IOpenApiSerializable, IOpenApiDescribedElement, /// public bool IsFragment { get; init; } - private OpenApiDocument openApiDocument; + private OpenApiDocument hostDocument; /// /// The OpenApiDocument that is hosting the OpenApiReference instance. This is used to enable dereferencing the reference. /// - public OpenApiDocument HostDocument { get => openApiDocument; init => openApiDocument = value; } + public OpenApiDocument HostDocument { get => hostDocument; init => hostDocument = value; } /// /// Gets the full reference string for v3.0. @@ -301,7 +288,7 @@ private string GetReferenceTypeNameAsV2(ReferenceType type) internal void EnsureHostDocumentIsSet(OpenApiDocument currentDocument) { Utils.CheckArgumentNull(currentDocument); - openApiDocument ??= currentDocument; + hostDocument ??= currentDocument; } } } From 317ad10fd88140e5a4640f132000cd7c3f514dd0 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 15:20:52 -0500 Subject: [PATCH 094/103] chore: code linting Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiMediaType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 64917f95d..7ba469bc6 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -88,7 +88,7 @@ public void SerializeAsV3(IOpenApiWriter writer) private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); writer.WriteStartObject(); From 754f763c2b148c04f0ba11b9c8e948557cc91b14 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 15:37:49 -0500 Subject: [PATCH 095/103] feat: makes document optional Signed-off-by: Vincent Biret --- .../Models/OpenApiDocument.cs | 7 ++ .../References/BaseOpenApiReferenceHolder.cs | 20 +--- .../References/OpenApiCallbackReference.cs | 6 +- .../References/OpenApiExampleReference.cs | 6 +- .../References/OpenApiHeaderReference.cs | 6 +- .../Models/References/OpenApiLinkReference.cs | 5 +- .../References/OpenApiParameterReference.cs | 6 +- .../References/OpenApiPathItemReference.cs | 6 +- .../References/OpenApiRequestBodyReference.cs | 5 +- .../References/OpenApiResponseReference.cs | 6 +- .../References/OpenApiSchemaReference.cs | 6 +- .../OpenApiSecuritySchemeReference.cs | 5 +- .../Models/References/OpenApiTagReference.cs | 12 +-- .../TryLoadReferenceV2Tests.cs | 16 +--- .../V3Tests/OpenApiDocumentTests.cs | 22 +++-- .../V3Tests/OpenApiParameterTests.cs | 2 +- .../Models/OpenApiCallbackTests.cs | 2 +- .../Models/OpenApiExampleTests.cs | 2 +- .../Models/OpenApiHeaderTests.cs | 2 +- .../Models/OpenApiLinkTests.cs | 2 +- .../Models/OpenApiOperationTests.cs | 95 ++++++++----------- .../Models/OpenApiParameterTests.cs | 2 +- .../Models/OpenApiRequestBodyTests.cs | 2 +- .../Models/OpenApiResponseTests.cs | 4 +- .../Models/OpenApiSecurityRequirementTests.cs | 76 ++++++++++----- .../Models/OpenApiSecuritySchemeTests.cs | 2 +- .../Models/OpenApiTagTests.cs | 2 +- .../PublicApi/PublicApi.approved.txt | 26 ++--- .../OpenApiReferenceValidationTests.cs | 4 +- .../Walkers/WalkerLocationTests.cs | 10 +- .../Workspaces/OpenApiWorkspaceTests.cs | 2 +- .../Writers/OpenApiYamlWriterTests.cs | 10 +- 32 files changed, 170 insertions(+), 209 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 0844edf1f..7820a6f8e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -26,6 +26,13 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenApiAnnotatable { + /// + /// Register components in the document to the workspace + /// + public void RegisterComponents() + { + Workspace?.RegisterComponents(this); + } /// /// Related workspace containing components that are referenced in a document /// diff --git a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs index 4d1eaf4c0..e01545c61 100644 --- a/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs +++ b/src/Microsoft.OpenApi/Models/References/BaseOpenApiReferenceHolder.cs @@ -10,16 +10,11 @@ namespace Microsoft.OpenApi.Models.References; /// The interface type for the model. public abstract class BaseOpenApiReferenceHolder : IOpenApiReferenceHolder where T : class, IOpenApiReferenceable, V where V : IOpenApiSerializable { - /// - /// The resolved target object. This should remain readonly, otherwise mutating the reference will have side effects. - /// - protected readonly T _target; /// public virtual T Target { get { - if (_target is not null) return _target; return Reference.HostDocument?.ResolveReferenceTo(Reference); } } @@ -34,17 +29,6 @@ protected BaseOpenApiReferenceHolder(BaseOpenApiReferenceHolder source) //no need to copy summary and description as if they are not overridden, they will be fetched from the target //if they are, the reference copy will handle it } - private protected BaseOpenApiReferenceHolder(T target, string referenceId, ReferenceType referenceType) - { - Utils.CheckArgumentNull(target); - _target = target; - - Reference = new OpenApiReference() - { - Id = referenceId, - Type = referenceType, - }; - } /// /// Constructor initializing the reference object. /// @@ -56,9 +40,11 @@ private protected BaseOpenApiReferenceHolder(T target, string referenceId, Refer /// 1. a absolute/relative file path, for example: ../commons/pet.json /// 2. a Url, for example: http://localhost/pet.json /// - protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDocument, ReferenceType referenceType, string externalResource = null) + protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDocument, ReferenceType referenceType, string externalResource) { Utils.CheckArgumentNullOrEmpty(referenceId); + // we're not checking for null hostDocument as it's optional and can be set via additional methods by a walker + // this way object initialization of a whole document is supported Reference = new OpenApiReference() { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index c9884877e..4c30328d4 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -25,7 +25,7 @@ public class OpenApiCallbackReference : BaseOpenApiReferenceHolder - public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Callback, externalResource) + public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Callback, externalResource) { } /// @@ -37,10 +37,6 @@ private OpenApiCallbackReference(OpenApiCallbackReference callback):base(callbac } - internal OpenApiCallbackReference(OpenApiCallback target, string referenceId):base(target, referenceId, ReferenceType.Callback) - { - } - /// public Dictionary PathItems { get => Target?.PathItems; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 41c2109cb..edfe27b61 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -25,7 +25,7 @@ public class OpenApiExampleReference : BaseOpenApiReferenceHolder - public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Example, externalResource) + public OpenApiExampleReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Example, externalResource) { } /// @@ -36,10 +36,6 @@ private OpenApiExampleReference(OpenApiExampleReference example):base(example) { } - internal OpenApiExampleReference(OpenApiExample target, string referenceId):base(target, referenceId, ReferenceType.Example) - { - } - /// public string Description { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index c62aa9f00..719cdce3a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -24,7 +24,7 @@ public class OpenApiHeaderReference : BaseOpenApiReferenceHolder - public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Header, externalResource) + public OpenApiHeaderReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Header, externalResource) { } @@ -36,10 +36,6 @@ private OpenApiHeaderReference(OpenApiHeaderReference header):base(header) { } - internal OpenApiHeaderReference(OpenApiHeader target, string referenceId):base(target, referenceId, ReferenceType.Header) - { - } - /// public string Description { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index c658f32fc..f91b5711b 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -24,7 +24,7 @@ public class OpenApiLinkReference : BaseOpenApiReferenceHolder - public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Link, externalResource) + public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Link, externalResource) { } /// @@ -34,9 +34,6 @@ public OpenApiLinkReference(string referenceId, OpenApiDocument hostDocument, st private OpenApiLinkReference(OpenApiLinkReference reference):base(reference) { } - internal OpenApiLinkReference(OpenApiLink target, string referenceId):base(target, referenceId, ReferenceType.Link) - { - } /// public string Description diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 59929ea14..d337b841e 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -23,7 +23,7 @@ public class OpenApiParameterReference : BaseOpenApiReferenceHolder - public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Parameter, externalResource) + public OpenApiParameterReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Parameter, externalResource) { } @@ -35,10 +35,6 @@ private OpenApiParameterReference(OpenApiParameterReference parameter):base(para { } - internal OpenApiParameterReference(OpenApiParameter target, string referenceId):base(target, referenceId, ReferenceType.Parameter) - { - } - /// public string Name { get => Target?.Name; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index 8ee78384b..038e1cb13 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -24,7 +24,7 @@ public class OpenApiPathItemReference : BaseOpenApiReferenceHolder - public OpenApiPathItemReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null): base(referenceId, hostDocument, ReferenceType.PathItem, externalResource) + public OpenApiPathItemReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null): base(referenceId, hostDocument, ReferenceType.PathItem, externalResource) { } @@ -37,10 +37,6 @@ private OpenApiPathItemReference(OpenApiPathItemReference pathItem):base(pathIte } - internal OpenApiPathItemReference(OpenApiPathItem target, string referenceId):base(target, referenceId, ReferenceType.PathItem) - { - } - /// public string Summary { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index dc6ca082c..966d3aad1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -25,7 +25,7 @@ public class OpenApiRequestBodyReference : BaseOpenApiReferenceHolder - public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.RequestBody, externalResource) + public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.RequestBody, externalResource) { } /// @@ -35,9 +35,6 @@ public OpenApiRequestBodyReference(string referenceId, OpenApiDocument hostDocum private OpenApiRequestBodyReference(OpenApiRequestBodyReference openApiRequestBodyReference):base(openApiRequestBodyReference) { - } - internal OpenApiRequestBodyReference(OpenApiRequestBody target, string referenceId):base(target, referenceId, ReferenceType.RequestBody) - { } /// diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index c4ddf59d7..9fbfb47a0 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -23,7 +23,7 @@ public class OpenApiResponseReference : BaseOpenApiReferenceHolder - public OpenApiResponseReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Response, externalResource) + public OpenApiResponseReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Response, externalResource) { } /// @@ -35,10 +35,6 @@ private OpenApiResponseReference(OpenApiResponseReference openApiResponseReferen } - internal OpenApiResponseReference(OpenApiResponse target, string referenceId):base(target, referenceId, ReferenceType.Response) - { - } - /// public string Description { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index f0c9a9f47..9252d6b89 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -25,7 +25,7 @@ public class OpenApiSchemaReference : BaseOpenApiReferenceHolder - public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Schema, externalResource) + public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Schema, externalResource) { } /// @@ -36,10 +36,6 @@ private OpenApiSchemaReference(OpenApiSchemaReference schema):base(schema) { } - internal OpenApiSchemaReference(OpenApiSchema target, string referenceId):base(target, referenceId, ReferenceType.Schema) - { - } - /// public string Description { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index dd379c808..75ca30573 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -19,7 +19,7 @@ public class OpenApiSecuritySchemeReference : BaseOpenApiReferenceHolderThe reference Id. /// The host OpenAPI document. /// The externally referenced file. - public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null):base(referenceId, hostDocument, ReferenceType.SecurityScheme, externalResource) + public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.SecurityScheme, externalResource) { } /// @@ -29,9 +29,6 @@ public OpenApiSecuritySchemeReference(string referenceId, OpenApiDocument hostDo private OpenApiSecuritySchemeReference(OpenApiSecuritySchemeReference openApiSecuritySchemeReference):base(openApiSecuritySchemeReference) { - } - internal OpenApiSecuritySchemeReference(OpenApiSecurityScheme target, string referenceId):base(target, referenceId, ReferenceType.SecurityScheme) - { } /// diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index 2b7d3e727..6f218fc13 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -21,7 +21,6 @@ public override OpenApiTag Target { get { - if (_target is not null) return _target; return Reference.HostDocument?.Tags.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, Reference.Id)); } } @@ -31,7 +30,12 @@ public override OpenApiTag Target /// /// The reference Id. /// The host OpenAPI document. - public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument):base(referenceId, hostDocument, ReferenceType.Tag) + /// Optional: External resource in the reference. + /// It may be: + /// 1. a absolute/relative file path, for example: ../commons/pet.json + /// 2. a Url, for example: http://localhost/pet.json + /// + public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument = null, string externalResource = null):base(referenceId, hostDocument, ReferenceType.Tag, externalResource) { } /// @@ -43,10 +47,6 @@ private OpenApiTagReference(OpenApiTagReference openApiTagReference):base(openAp } - internal OpenApiTagReference(OpenApiTag target, string referenceId):base(target, referenceId, ReferenceType.Tag) - { - } - /// public string Description { diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 9208fabd8..3edc9ac67 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -99,21 +99,7 @@ public async Task LoadResponseAndSchemaReference() { ["application/json"] = new() { - Schema = new OpenApiSchemaReference(new OpenApiSchema() - { - Description = "Sample description", - Required = new HashSet {"name" }, - Properties = { - ["name"] = new OpenApiSchema() - { - Type = JsonSchemaType.String - }, - ["tag"] = new OpenApiSchema() - { - Type = JsonSchemaType.String - } - }, - }, "SampleObject2") + Schema = new OpenApiSchemaReference("SampleObject2") } } }; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 6a5d80f0f..ccf3a9407 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -684,21 +684,21 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() var petSchemaSource = Assert.IsType(components.Schemas["pet1"]); var petSchema = await CloneAsync(petSchemaSource); var castPetSchema = Assert.IsType(petSchema); - var petSchemaReference = new OpenApiSchemaReference(castPetSchema, "pet1"); + var petSchemaReference = new OpenApiSchemaReference("pet1"); var newPetSchemaSource = Assert.IsType(components.Schemas["newPet"]); var newPetSchema = await CloneAsync(newPetSchemaSource); var castNewPetSchema = Assert.IsType(newPetSchema); - var newPetSchemaReference = new OpenApiSchemaReference(castNewPetSchema, "newPet"); + var newPetSchemaReference = new OpenApiSchemaReference("newPet"); var errorModelSchemaSource = Assert.IsType(components.Schemas["errorModel"]); var errorModelSchema = await CloneAsync(errorModelSchemaSource); var castErrorModelSchema = Assert.IsType(errorModelSchema); - var errorModelSchemaReference = new OpenApiSchemaReference(castErrorModelSchema, "errorModel"); + var errorModelSchemaReference = new OpenApiSchemaReference("errorModel"); - var tagReference1 = new OpenApiTagReference("tagName1", null); + var tagReference1 = new OpenApiTagReference("tagName1"); - var tagReference2 = new OpenApiTagReference("tagName2", null); + var tagReference2 = new OpenApiTagReference("tagName2"); var securityScheme1Cast = Assert.IsType(components.SecuritySchemes["securitySchemeName1"]); var securityScheme1 = await CloneSecuritySchemeAsync(securityScheme1Cast); @@ -889,8 +889,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { new OpenApiSecurityRequirement { - [new OpenApiSecuritySchemeReference(securityScheme1, "securitySchemeName1")] = new List(), - [new OpenApiSecuritySchemeReference(securityScheme2, "securitySchemeName2")] = new List + [new OpenApiSecuritySchemeReference("securitySchemeName1")] = new List(), + [new OpenApiSecuritySchemeReference("securitySchemeName2")] = new List { "scope1", "scope2" @@ -1035,8 +1035,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { new OpenApiSecurityRequirement { - [new OpenApiSecuritySchemeReference(securityScheme1, "securitySchemeName1")] = new List(), - [new OpenApiSecuritySchemeReference(securityScheme2, "securitySchemeName2")] = new List + [new OpenApiSecuritySchemeReference("securitySchemeName1")] = new List(), + [new OpenApiSecuritySchemeReference("securitySchemeName2")] = new List { "scope1", "scope2", @@ -1045,6 +1045,8 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } } }; + expected.RegisterComponents(); + expected.SetReferenceHostDocument(); tagReference1.Reference.EnsureHostDocumentIsSet(expected); tagReference2.Reference.EnsureHostDocumentIsSet(expected); @@ -1238,7 +1240,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() Summary = "Returns all pets", Parameters = [ - new OpenApiParameterReference(parameter, "LimitParameter"), + new OpenApiParameterReference("LimitParameter"), ], Responses = new OpenApiResponses() } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 2ee63165c..efdb87110 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -343,7 +343,7 @@ public void ParseParameterWithReferenceWorks() OperationId = "findPets", Parameters = [ - new OpenApiParameterReference (parameter, "tagsParameter"), + new OpenApiParameterReference("tagsParameter"), ], } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index f60fa3a1a..fc232fa3a 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -54,7 +54,7 @@ public class OpenApiCallbackTests } }; - private static OpenApiCallbackReference CallbackProxy => new(ReferencedCallback, "simpleHook"); + private static OpenApiCallbackReference CallbackProxy => new("simpleHook"); private static OpenApiCallback ReferencedCallback => new() { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs index 438d2a2fe..fd59b4250 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs @@ -57,7 +57,7 @@ public class OpenApiExampleTests } }; - private static OpenApiExampleReference OpenApiExampleReference => new(ReferencedExample, "example1"); + private static OpenApiExampleReference OpenApiExampleReference => new("example1"); private static OpenApiExample ReferencedExample => new() { Value = new JsonObject diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index 2bd3aa0c7..afda460f7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -25,7 +25,7 @@ public class OpenApiHeaderTests } }; - private static OpenApiHeaderReference OpenApiHeaderReference => new(ReferencedHeader, "example1"); + private static OpenApiHeaderReference OpenApiHeaderReference => new("example1"); private static OpenApiHeader ReferencedHeader => new() { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs index c8bf27a29..a6b4bc500 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs @@ -42,7 +42,7 @@ public class OpenApiLinkTests } }; - private static OpenApiLinkReference LinkReference => new(ReferencedLink, "example1"); + private static OpenApiLinkReference LinkReference => new("example1"); private static OpenApiLink ReferencedLink => new() { OperationId = "operationId1", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 138888d71..af22284b9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using System.Text.Json.Nodes; using System.Threading.Tasks; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -58,21 +59,7 @@ public class OpenApiOperationTests }, Responses = new() { - ["200"] = new OpenApiResponseReference(new OpenApiResponse() - { - Content = new Dictionary - { - ["application/json"] = new() - { - Schema = new OpenApiSchema() - { - Type = JsonSchemaType.Number, - Minimum = 5, - Maximum = 10 - } - } - } - }, "response1"), + ["200"] = new OpenApiResponseReference("response1"), ["400"] = new OpenApiResponse() { Content = new Dictionary @@ -100,7 +87,7 @@ public class OpenApiOperationTests Annotations = new Dictionary { { "key1", "value1" }, { "key2", 2 } }, }; - private static readonly OpenApiOperation _advancedOperationWithTagsAndSecurity = new() + private static OpenApiOperation _advancedOperationWithTagsAndSecurity => new() { Tags = new List { @@ -146,21 +133,7 @@ public class OpenApiOperationTests }, Responses = new() { - ["200"] = new OpenApiResponseReference(new OpenApiResponse() - { - Content = new Dictionary - { - ["application/json"] = new() - { - Schema = new OpenApiSchema() - { - Type = JsonSchemaType.Number, - Minimum = 5, - Maximum = 10 - } - } - } - }, "response1"), + ["200"] = new OpenApiResponseReference("response1"), ["400"] = new OpenApiResponse() { Content = new Dictionary @@ -181,8 +154,8 @@ public class OpenApiOperationTests { new() { - [new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "securitySchemeId1")] = new List(), - [new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "securitySchemeId2")] = new List + [new OpenApiSecuritySchemeReference("securitySchemeId1", __advancedOperationWithTagsAndSecurity_supportingDocument)] = new List(), + [new OpenApiSecuritySchemeReference("securitySchemeId2", __advancedOperationWithTagsAndSecurity_supportingDocument)] = new List { "scopeName1", "scopeName2" @@ -198,6 +171,34 @@ public class OpenApiOperationTests } } }; + private static OpenApiDocument __advancedOperationWithTagsAndSecurity_supportingDocument + { + get + { + var document = new OpenApiDocument() + { + Components = new() + { + SecuritySchemes = new Dictionary + { + ["securitySchemeId1"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.ApiKey, + Name = "apiKeyName1", + In = ParameterLocation.Header, + }, + ["securitySchemeId2"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OpenIdConnect, + OpenIdConnectUrl = new("http://example.com"), + } + } + } + }; + document.RegisterComponents(); + return document; + } + } private static readonly OpenApiOperation _operationWithFormData = new() @@ -455,9 +456,7 @@ public async Task SerializeAdvancedOperationWithTagAndSecurityAsV3JsonWorks() var actual = await _advancedOperationWithTagsAndSecurity.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -475,9 +474,7 @@ public async Task SerializeBasicOperationAsV2JsonWorks() var actual = await _basicOperation.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -554,9 +551,7 @@ public async Task SerializeOperationWithFormDataAsV3JsonWorks() var actual = await _operationWithFormData.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -610,9 +605,7 @@ public async Task SerializeOperationWithFormDataAsV2JsonWorks() var actual = await _operationWithFormData.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -679,9 +672,7 @@ public async Task SerializeOperationWithBodyAsV2JsonWorks() var actual = await _operationWithBody.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -760,9 +751,7 @@ public async Task SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() var actual = await _advancedOperationWithTagsAndSecurity.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -785,9 +774,7 @@ public async Task SerializeOperationWithNullCollectionAsV2JsonWorks() var actual = await operation.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index bfbae32a8..da0c00d44 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -25,7 +25,7 @@ public class OpenApiParameterTests In = ParameterLocation.Path }; - private static OpenApiParameterReference OpenApiParameterReference => new(ReferencedParameter, "example1"); + private static OpenApiParameterReference OpenApiParameterReference => new("example1"); private static OpenApiParameter ReferencedParameter => new() { Name = "name1", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index 5ca281dae..863ce5145 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -31,7 +31,7 @@ public class OpenApiRequestBodyTests } }; - private static OpenApiRequestBodyReference OpenApiRequestBodyReference => new(ReferencedRequestBody, "example1"); + private static OpenApiRequestBodyReference OpenApiRequestBodyReference => new("example1"); private static OpenApiRequestBody ReferencedRequestBody => new() { Description = "description", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index 1c4137d1f..7d077b540 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -101,7 +101,7 @@ public class OpenApiResponseTests } }; - private static OpenApiResponseReference V2OpenApiResponseReference => new OpenApiResponseReference(ReferencedV2Response, "example1"); + private static OpenApiResponseReference V2OpenApiResponseReference => new OpenApiResponseReference("example1"); private static OpenApiResponse ReferencedV2Response => new OpenApiResponse { Description = "A complex object array response", @@ -136,7 +136,7 @@ public class OpenApiResponseTests }, } }; - private static OpenApiResponseReference V3OpenApiResponseReference => new OpenApiResponseReference(ReferencedV3Response, "example1"); + private static OpenApiResponseReference V3OpenApiResponseReference => new OpenApiResponseReference("example1"); private static OpenApiResponse ReferencedV3Response => new OpenApiResponse { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 19900f215..cfbe0ae50 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -13,6 +13,8 @@ using VerifyXunit; using Microsoft.OpenApi.Models.References; using Xunit; +using System.Text.Json.Nodes; +using Microsoft.OpenApi.Models.Interfaces; namespace Microsoft.OpenApi.Tests.Models { @@ -25,7 +27,7 @@ public class OpenApiSecurityRequirementTests new() { [ - new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme1") + new OpenApiSecuritySchemeReference("scheme1", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List { "scope1", @@ -33,22 +35,56 @@ public class OpenApiSecurityRequirementTests "scope3", }, [ - new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme2") + new OpenApiSecuritySchemeReference("scheme2", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List { "scope4", "scope5", }, [ - new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme3") + new OpenApiSecuritySchemeReference("scheme3", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List() }; + public static OpenApiDocument SecurityRequirementWithReferencedSecurityScheme_supportingDocument + { + get + { + var document = new OpenApiDocument() + { + Components = new() + { + SecuritySchemes = new Dictionary + { + ["scheme1"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.ApiKey, + Name = "apiKeyName1", + In = ParameterLocation.Header, + }, + ["scheme2"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OpenIdConnect, + OpenIdConnectUrl = new("http://example.com"), + }, + ["scheme3"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "bearer", + BearerFormat = "JWT", + }, + } + } + }; + document.RegisterComponents(); + return document; + } + } public static OpenApiSecurityRequirement SecurityRequirementWithUnreferencedSecurityScheme = new() { [ - new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme1") + new OpenApiSecuritySchemeReference("scheme1", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List { "scope1", @@ -56,14 +92,14 @@ public class OpenApiSecurityRequirementTests "scope3", }, [ - new OpenApiSecuritySchemeReference("brokenUnreferencedScheme", hostDocument: null) + new OpenApiSecuritySchemeReference("brokenUnreferencedScheme", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List { "scope4", "scope5", }, [ - new OpenApiSecuritySchemeReference(new OpenApiSecurityScheme(), "scheme3") + new OpenApiSecuritySchemeReference("scheme3", SecurityRequirementWithReferencedSecurityScheme_supportingDocument) ] = new List() }; @@ -123,9 +159,7 @@ public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV3Js var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -152,9 +186,7 @@ public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2Js var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -177,9 +209,7 @@ public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV3 var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -203,9 +233,7 @@ public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2 await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); // Assert - actual = actual.MakeLineBreaksEnvironmentNeutral(); - expected = expected.MakeLineBreaksEnvironmentNeutral(); - Assert.Equal(expected, actual); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } [Fact] @@ -242,13 +270,13 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() }; // Act - securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1, "securityScheme1"), new List()); - securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme2, "securityScheme2"), new List { "scope1", "scope2" }); + securityRequirement.Add(new OpenApiSecuritySchemeReference("securityScheme1"), new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference("securityScheme2"), new List { "scope1", "scope2" }); var addSecurityScheme1Duplicate = () => - securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1Duplicate, "securityScheme1"), new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference("securityScheme1"), new List()); var addSecurityScheme1WithDifferentProperties = () => - securityRequirement.Add(new OpenApiSecuritySchemeReference(securityScheme1WithDifferentProperties, "securityScheme1"), new List()); + securityRequirement.Add(new OpenApiSecuritySchemeReference("securityScheme1"), new List()); // Assert // Only the first two should be added successfully since the latter two are duplicates of securityScheme1. @@ -263,8 +291,8 @@ public void SchemesShouldConsiderOnlyReferenceIdForEquality() { // This should work with any security scheme object // as long as Reference.Id os securityScheme1 - [new OpenApiSecuritySchemeReference(securityScheme1WithDifferentProperties, "securityScheme1")] = new List(), - [new OpenApiSecuritySchemeReference(securityScheme2, "securityScheme2")] = new List { "scope1", "scope2" }, + [new OpenApiSecuritySchemeReference("securityScheme1", null)] = new List(), + [new OpenApiSecuritySchemeReference("securityScheme2", null)] = new List { "scope1", "scope2" }, }); } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index 991c31847..12db6c1e8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -104,7 +104,7 @@ public class OpenApiSecuritySchemeTests OpenIdConnectUrl = new("https://example.com/openIdConnect") }; - private static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference => new(ReferencedSecurityScheme, "sampleSecurityScheme"); + private static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference => new("sampleSecurityScheme"); private static OpenApiSecurityScheme ReferencedSecurityScheme => new() { Description = "description1", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs index c987592d4..73ac0d0b7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs @@ -31,7 +31,7 @@ public class OpenApiTagTests } }; - public static IOpenApiTag ReferencedTag = new OpenApiTagReference(AdvancedTag, "pet"); + public static IOpenApiTag ReferencedTag = new OpenApiTagReference("pet"); [Theory] [InlineData(true)] diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 5b6c34d8e..a667f6ef3 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -724,6 +724,7 @@ namespace Microsoft.OpenApi.Models public Microsoft.OpenApi.Services.OpenApiWorkspace? Workspace { get; set; } public bool AddComponent(string id, T componentToRegister) { } public System.Threading.Tasks.Task GetHashCodeAsync(System.Threading.CancellationToken cancellationToken = default) { } + public void RegisterComponents() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1240,9 +1241,8 @@ namespace Microsoft.OpenApi.Models.References where T : class, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V where V : Microsoft.OpenApi.Interfaces.IOpenApiSerializable { - protected readonly T _target; protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder source) { } - protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { } + protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource) { } public virtual T Target { get; } public bool UnresolvedReference { get; } public Microsoft.OpenApi.Models.OpenApiReference Reference { get; init; } @@ -1253,7 +1253,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiCallbackReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback { - public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public System.Collections.Generic.IDictionary Extensions { get; } public System.Collections.Generic.Dictionary PathItems { get; } public override Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback CopyReferenceAsTargetElementWithOverrides(Microsoft.OpenApi.Models.Interfaces.IOpenApiCallback source) { } @@ -1262,7 +1262,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiExampleReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiExample, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { - public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } public string ExternalValue { get; } @@ -1274,7 +1274,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiHeaderReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiHeader { - public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public bool AllowEmptyValue { get; } public bool AllowReserved { get; } public System.Collections.Generic.IDictionary Content { get; } @@ -1292,7 +1292,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiLinkReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiLink { - public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } public string OperationId { get; } @@ -1306,7 +1306,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiParameterReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiParameter { - public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public bool AllowEmptyValue { get; } public bool AllowReserved { get; } public System.Collections.Generic.IDictionary Content { get; } @@ -1326,7 +1326,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiPathItemReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiPathItem, Microsoft.OpenApi.Models.Interfaces.IOpenApiSummarizedElement { - public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } public System.Collections.Generic.IDictionary Operations { get; } @@ -1339,7 +1339,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiRequestBody { - public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public System.Collections.Generic.IDictionary Content { get; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } @@ -1352,7 +1352,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiResponseReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiResponse { - public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public System.Collections.Generic.IDictionary Content { get; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } @@ -1363,7 +1363,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiSchemaReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema { - public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema AdditionalProperties { get; } public bool AdditionalPropertiesAllowed { get; } public System.Collections.Generic.IList AllOf { get; } @@ -1424,7 +1424,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiSecurityScheme { - public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public string BearerFormat { get; } public string Description { get; set; } public System.Collections.Generic.IDictionary Extensions { get; } @@ -1439,7 +1439,7 @@ namespace Microsoft.OpenApi.Models.References } public class OpenApiTagReference : Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable, Microsoft.OpenApi.Interfaces.IShallowCopyable, Microsoft.OpenApi.Models.Interfaces.IOpenApiReadOnlyDescribedElement, Microsoft.OpenApi.Models.Interfaces.IOpenApiTag { - public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { } + public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument = null, string externalResource = null) { } public string Description { get; } public System.Collections.Generic.IDictionary Extensions { get; } public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index ea9a9660a..b9a73da40 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -50,7 +50,7 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() { ["application/json"] = new() { - Schema = new OpenApiSchemaReference(sharedSchema, "test") + Schema = new OpenApiSchemaReference("test") } } } @@ -104,7 +104,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() { ["application/json"] = new() { - Schema = new OpenApiSchemaReference(sharedSchema, "test") + Schema = new OpenApiSchemaReference("test") } } } diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 44000b024..ce45186c6 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -166,14 +166,14 @@ public void LocateReferences() var derivedSchema = new OpenApiSchema { - AnyOf = new List { new OpenApiSchemaReference(baseSchema, "base") }, + AnyOf = new List { new OpenApiSchemaReference("base") }, }; var testHeader = new OpenApiHeader() { - Schema = new OpenApiSchemaReference(derivedSchema, "derived"), + Schema = new OpenApiSchemaReference("derived"), }; - var testHeaderReference = new OpenApiHeaderReference(testHeader, "test-header"); + var testHeaderReference = new OpenApiHeaderReference("test-header"); var doc = new OpenApiDocument { @@ -193,7 +193,7 @@ public void LocateReferences() { ["application/json"] = new() { - Schema = new OpenApiSchemaReference(derivedSchema, "derived") + Schema = new OpenApiSchemaReference("derived") } }, Headers = @@ -219,7 +219,7 @@ public void LocateReferences() }, SecuritySchemes = new Dictionary { - ["test-secScheme"] = new OpenApiSecuritySchemeReference("reference-to-scheme", null, null) + ["test-secScheme"] = new OpenApiSecuritySchemeReference("reference-to-scheme") } } }; diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index 38a9b2d8d..8c5478cf7 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -39,7 +39,7 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { ["application/json"] = new OpenApiMediaType() { - Schema = new OpenApiSchemaReference(testSchema, "test") + Schema = new OpenApiSchemaReference("test") } } } diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index 403922622..669f4cb13 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -463,10 +463,10 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() { Description = "OK", Content = { - ["application/json"] = new() - { - Schema = new OpenApiSchemaReference(thingSchema, "thing") - } + ["application/json"] = new() + { + Schema = new OpenApiSchemaReference("thing") + } } } } @@ -480,6 +480,8 @@ private static OpenApiDocument CreateDocWithSimpleSchemaToInline() ["thing"] = thingSchema} } }; + doc.RegisterComponents(); + doc.SetReferenceHostDocument(); return doc; } From 8ad773ef4df4f7b12106e5adb40b1c13cd848b2f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 15:42:32 -0500 Subject: [PATCH 096/103] chore: code linting Signed-off-by: Vincent Biret --- .../V3Tests/OpenApiDocumentTests.cs | 35 +++---------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index ccf3a9407..fb7524c42 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -49,23 +49,6 @@ private static async Task CloneAsync(T element) where T : class, IOpenApiS return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, new(), out var _); } - private static async Task CloneSecuritySchemeAsync(OpenApiSecurityScheme element) - { - using var stream = new MemoryStream(); - var streamWriter = new FormattingStreamWriter(stream, CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(streamWriter, new OpenApiJsonWriterSettings() - { - InlineLocalReferences = true - }); - element.SerializeAsV3(writer); - await writer.FlushAsync(); - stream.Position = 0; - - using var streamReader = new StreamReader(stream); - var result = await streamReader.ReadToEndAsync(); - return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, new(), out var _); - } - [Fact] public void ParseDocumentFromInlineStringShouldSucceed() { @@ -683,28 +666,26 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() // Create a clone of the schema to avoid modifying things in components. var petSchemaSource = Assert.IsType(components.Schemas["pet1"]); var petSchema = await CloneAsync(petSchemaSource); - var castPetSchema = Assert.IsType(petSchema); + Assert.IsType(petSchema); var petSchemaReference = new OpenApiSchemaReference("pet1"); var newPetSchemaSource = Assert.IsType(components.Schemas["newPet"]); var newPetSchema = await CloneAsync(newPetSchemaSource); - var castNewPetSchema = Assert.IsType(newPetSchema); + Assert.IsType(newPetSchema); var newPetSchemaReference = new OpenApiSchemaReference("newPet"); var errorModelSchemaSource = Assert.IsType(components.Schemas["errorModel"]); var errorModelSchema = await CloneAsync(errorModelSchemaSource); - var castErrorModelSchema = Assert.IsType(errorModelSchema); + Assert.IsType(errorModelSchema); var errorModelSchemaReference = new OpenApiSchemaReference("errorModel"); var tagReference1 = new OpenApiTagReference("tagName1"); var tagReference2 = new OpenApiTagReference("tagName2"); - var securityScheme1Cast = Assert.IsType(components.SecuritySchemes["securitySchemeName1"]); - var securityScheme1 = await CloneSecuritySchemeAsync(securityScheme1Cast); + Assert.IsType(components.SecuritySchemes["securitySchemeName1"]); - var securityScheme2Cast = Assert.IsType(components.SecuritySchemes["securitySchemeName2"]); - var securityScheme2 = await CloneSecuritySchemeAsync(securityScheme2Cast); + Assert.IsType(components.SecuritySchemes["securitySchemeName2"]); var expected = new OpenApiDocument { @@ -1048,12 +1029,6 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() expected.RegisterComponents(); expected.SetReferenceHostDocument(); - tagReference1.Reference.EnsureHostDocumentIsSet(expected); - tagReference2.Reference.EnsureHostDocumentIsSet(expected); - petSchemaReference.Reference.EnsureHostDocumentIsSet(expected); - newPetSchemaReference.Reference.EnsureHostDocumentIsSet(expected); - errorModelSchemaReference.Reference.EnsureHostDocumentIsSet(expected); - actual.Document.Should().BeEquivalentTo(expected, options => options .IgnoringCyclicReferences() .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference) From be3c552ce1f4c529ac06833b4fe817ed0fdfa5ca Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 15:48:45 -0500 Subject: [PATCH 097/103] chore: code linting Signed-off-by: Vincent Biret --- .../V3Tests/OpenApiDocumentTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index fb7524c42..e61ee8fbc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1230,8 +1230,12 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() } } }; + expected.RegisterComponents(); + expected.SetReferenceHostDocument(); - var expectedSerializedDoc = @"openapi: 3.0.4 + var expectedSerializedDoc = +""" +openapi: 3.0.4 info: title: Pet Store with Referenceable Parameter version: 1.0.0 @@ -1251,7 +1255,8 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() schema: type: integer format: int32 - default: 10"; + default: 10 +"""; using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "minifiedPetStore.yaml")); @@ -1261,7 +1266,6 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds() var outputDoc = (await doc.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0)).MakeLineBreaksEnvironmentNeutral(); var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters[0]; var expectedParamReference = Assert.IsType(expectedParam); - expectedParamReference.Reference.EnsureHostDocumentIsSet(doc); var actualParamReference = Assert.IsType(actualParam); From e0aba68aaa9ce27ad8f3fb5078792a4571d68a4e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 4 Feb 2025 15:51:06 -0500 Subject: [PATCH 098/103] chore: code linting Signed-off-by: Vincent Biret --- .../Reader/V3/OpenApiV3VersionService.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index c10bf6ddf..612c59dfb 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -183,11 +183,12 @@ public T LoadElement(ParseNode node, OpenApiDocument doc) where T : IOpenApiE /// public string GetReferenceScalarValues(MapNode mapNode, string scalarValue) { - if (mapNode.Any(static x => !"$ref".Equals(x.Name, StringComparison.OrdinalIgnoreCase))) + if (mapNode.Any(static x => !"$ref".Equals(x.Name, StringComparison.OrdinalIgnoreCase)) && + mapNode + .Where(x => x.Name.Equals(scalarValue)) + .Select(static x => x.Value) + .OfType().FirstOrDefault() is {} valueNode) { - var valueNode = mapNode.Where(x => x.Name.Equals(scalarValue)) - .Select(static x => x.Value).OfType().FirstOrDefault(); - return valueNode.GetScalarValue(); } From 4f99ad4839af56edfe626a25826bf7b89ac44344 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:24:03 +0000 Subject: [PATCH 099/103] chore(deps): bump Verify.Xunit from 28.9.0 to 28.10.1 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 28.9.0 to 28.10.1. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/compare/28.9.0...28.10.1) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj index f8f8930e2..f87992246 100644 --- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj +++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj @@ -14,7 +14,7 @@ - + From bd9f810834d71be9d1abd640d4bb56277fdf2584 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Wed, 5 Feb 2025 13:31:41 +0300 Subject: [PATCH 100/103] Support non-standard MIME type during format inference --- src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs | 6 +++++- .../V3Tests/OpenApiDocumentTests.cs | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs index 33bea8fb5..bcf1df8ea 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs @@ -279,10 +279,14 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp var mediaType = response.Content.Headers.ContentType.MediaType; var contentType = mediaType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0]; format = contentType.Split('/').LastOrDefault(); + if (!string.IsNullOrEmpty(format) && format.Contains('-')) + { + format = format.Split('-').LastOrDefault(); // for non-standard MIME types e.g. text/x-yaml used in older libs or apps + } #if NETSTANDARD2_0 stream = await response.Content.ReadAsStreamAsync(); #else - stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);; + stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false); #endif return (stream, format); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index e61ee8fbc..ea287db5e 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -26,6 +26,7 @@ namespace Microsoft.OpenApi.Readers.Tests.V3Tests public class OpenApiDocumentTests { private const string SampleFolderPath = "V3Tests/Samples/OpenApiDocument/"; + private const string codacyApi = "https://api.codacy.com/api/api-docs/swagger.yaml"; public OpenApiDocumentTests() { @@ -1362,5 +1363,13 @@ public async Task ParseDocumentWithExampleReferencesPasses() var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExampleReferences.yaml")); Assert.Empty(result.Diagnostic.Errors); } + + [Fact] + public async Task ParseDocumentWithNonStandardMIMETypePasses() + { + // Act & Assert: Ensure NotSupportedException is not thrown for non-standard MIME type: text/x-yaml + var result = await OpenApiDocument.LoadAsync(codacyApi); + Assert.NotNull(result.Document); + } } } From 3f46ebf30f36e865e8abdd77b374c6bf8cbbf64c Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Wed, 5 Feb 2025 14:10:04 +0300 Subject: [PATCH 101/103] Remove unnecessary format param; clean up extra semi-colon --- src/Microsoft.OpenApi.Hidi/OpenApiService.cs | 9 ++++----- src/Microsoft.OpenApi/Models/OpenApiOperation.cs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs index c7bf1a558..c757f4031 100644 --- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs +++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs @@ -254,7 +254,7 @@ private static async Task GetOpenApiAsync(HidiOptions options, else if (!string.IsNullOrEmpty(options.OpenApi)) { stream = await GetStreamAsync(options.OpenApi, logger, cancellationToken).ConfigureAwait(false); - var result = await ParseOpenApiAsync(options.OpenApi, format, options.InlineExternal, logger, stream, cancellationToken).ConfigureAwait(false); + var result = await ParseOpenApiAsync(options.OpenApi, options.InlineExternal, logger, stream, cancellationToken).ConfigureAwait(false); document = result.Document; } else throw new InvalidOperationException("No input file path or URL provided"); @@ -351,8 +351,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe try { using var stream = await GetStreamAsync(openApi, logger, cancellationToken).ConfigureAwait(false); - var openApiFormat = !string.IsNullOrEmpty(openApi) ? GetOpenApiFormat(openApi, logger) : OpenApiFormat.Yaml; - result = await ParseOpenApiAsync(openApi, openApiFormat.GetDisplayName(),false, logger, stream, cancellationToken).ConfigureAwait(false); + result = await ParseOpenApiAsync(openApi, false, logger, stream, cancellationToken).ConfigureAwait(false); using (logger.BeginScope("Calculating statistics")) { @@ -380,7 +379,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe return result.Diagnostic.Errors.Count == 0; } - private static async Task ParseOpenApiAsync(string openApiFile, string format, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default) + private static async Task ParseOpenApiAsync(string openApiFile, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default) { ReadResult result; var stopwatch = Stopwatch.StartNew(); @@ -396,7 +395,7 @@ private static async Task ParseOpenApiAsync(string openApiFile, stri new Uri("file://" + new FileInfo(openApiFile).DirectoryName + Path.DirectorySeparatorChar) }; - result = await OpenApiDocument.LoadAsync(stream, format, settings, cancellationToken).ConfigureAwait(false); + result = await OpenApiDocument.LoadAsync(stream, settings: settings, cancellationToken: cancellationToken).ConfigureAwait(false); logger.LogTrace("{Timestamp}ms: Completed parsing.", stopwatch.ElapsedMilliseconds); diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 16f5d6a01..3acbd05ab 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -160,7 +160,7 @@ public void SerializeAsV3(IOpenApiWriter writer) /// private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); writer.WriteStartObject(); From d5517ad05baf60e5f22f29fa3f7d743d2dfcba88 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Wed, 5 Feb 2025 14:41:00 +0300 Subject: [PATCH 102/103] Use ArgumentNullException.ThrowIfNull instead of exliplicitly throwing a new exception instance --- .../Reader/OpenApiModelFactory.cs | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs index bcf1df8ea..64f34fc68 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs @@ -39,7 +39,11 @@ public static ReadResult Load(MemoryStream stream, string format = null, OpenApiReaderSettings settings = null) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(stream); +#else if (stream is null) throw new ArgumentNullException(nameof(stream)); +#endif settings ??= new OpenApiReaderSettings(); // Get the format of the stream if not provided @@ -112,7 +116,11 @@ public static async Task LoadAsync(string url, OpenApiSpecVersion version, /// public static async Task LoadAsync(Stream input, string format = null, OpenApiReaderSettings settings = null, CancellationToken cancellationToken = default) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(input); +#else if (input is null) throw new ArgumentNullException(nameof(input)); +#endif settings ??= new OpenApiReaderSettings(); Stream preparedStream; @@ -160,7 +168,11 @@ public static async Task LoadAsync(Stream input, CancellationToken token = default) where T : IOpenApiElement { Utils.CheckArgumentNull(openApiDocument); +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(input); +#else if (input is null) throw new ArgumentNullException(nameof(input)); +#endif if (input is MemoryStream memoryStream) { return Load(memoryStream, version, format, openApiDocument, out var _, settings); @@ -185,7 +197,11 @@ public static ReadResult Parse(string input, string format = null, OpenApiReaderSettings settings = null) { - if (input is null) throw new ArgumentNullException(nameof(input)); +#if NET6_0_OR_GREATER + ArgumentException.ThrowIfNullOrEmpty(input); +#else + if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input)); +#endif format ??= InspectInputFormat(input); settings ??= new OpenApiReaderSettings(); @@ -212,7 +228,11 @@ public static T Parse(string input, string format = null, OpenApiReaderSettings settings = null) where T : IOpenApiElement { - if (input is null) throw new ArgumentNullException(nameof(input)); +#if NET6_0_OR_GREATER + ArgumentException.ThrowIfNullOrEmpty(input); +#else + if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input)); +#endif format ??= InspectInputFormat(input); settings ??= new OpenApiReaderSettings(); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(input)); @@ -325,8 +345,12 @@ private static string InspectInputFormat(string input) private static string InspectStreamFormat(Stream stream) { - if (stream == null) throw new ArgumentNullException(nameof(stream)); - +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(stream); +#else + if (stream is null) throw new ArgumentNullException(nameof(stream)); +#endif + long initialPosition = stream.Position; int firstByte = stream.ReadByte(); From 711b3d17a07c23930e9ae5ca5b2d815701e2516d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 5 Feb 2025 07:51:12 -0500 Subject: [PATCH 103/103] Update src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs --- src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs index 64f34fc68..9424f053f 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs @@ -298,11 +298,8 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp var response = await _httpClient.GetAsync(url, token).ConfigureAwait(false); var mediaType = response.Content.Headers.ContentType.MediaType; var contentType = mediaType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0]; - format = contentType.Split('/').LastOrDefault(); - if (!string.IsNullOrEmpty(format) && format.Contains('-')) - { - format = format.Split('-').LastOrDefault(); // for non-standard MIME types e.g. text/x-yaml used in older libs or apps - } + format = contentType.Split('/').Last().Split('+').Last().Split('-').Last(); + // for non-standard MIME types e.g. text/x-yaml used in older libs or apps #if NETSTANDARD2_0 stream = await response.Content.ReadAsStreamAsync(); #else