From e3c80a3ca660bc955f787c80cb40c1a29833e725 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Jan 2025 15:04:59 -0500 Subject: [PATCH 01/13] 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 02/13] 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 03/13] 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 04/13] 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 05/13] 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 06/13] 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 07/13] 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 08/13] 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 09/13] 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 10/13] 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 11/13] 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 12/13] 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 e09fb3865663b1f3b6295db357837006208760aa Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 31 Jan 2025 16:15:48 -0500 Subject: [PATCH 13/13] 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();