diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs new file mode 100644 index 000000000..fc4c1daed --- /dev/null +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceableWithTarget.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.OpenApi.Interfaces +{ + /// + /// A generic interface for OpenApiReferenceable objects that have a target. + /// + /// + public interface IOpenApiReferenceableWithTarget : IOpenApiReferenceable + { + /// + /// Gets the resolved target object. + /// + T Target { get; } + } +} diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 632aa485f..81985cb12 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -12,12 +12,20 @@ namespace Microsoft.OpenApi.Models.References /// /// Callback Object Reference: A reference to a map of possible out-of band callbacks related to the parent operation. /// - public class OpenApiCallbackReference : OpenApiCallback + public class OpenApiCallbackReference : OpenApiCallback, IOpenApiReferenceableWithTarget { +#nullable enable internal OpenApiCallback _target; private readonly OpenApiReference _reference; - private OpenApiCallback Target + /// + /// Gets the target callback. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiCallback Target +#nullable restore { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index 310ff0a8e..c36c43d9a 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -12,14 +12,20 @@ namespace Microsoft.OpenApi.Models.References /// /// Example Object Reference. /// - public class OpenApiExampleReference : OpenApiExample + public class OpenApiExampleReference : OpenApiExample, IOpenApiReferenceableWithTarget { internal OpenApiExample _target; private readonly OpenApiReference _reference; private string _summary; private string _description; - private OpenApiExample Target + /// + /// Gets the target example. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiExample Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 2ffb0c3de..e8275c23c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -12,13 +12,19 @@ namespace Microsoft.OpenApi.Models.References /// /// Header Object Reference. /// - public class OpenApiHeaderReference : OpenApiHeader + public class OpenApiHeaderReference : OpenApiHeader, IOpenApiReferenceableWithTarget { internal OpenApiHeader _target; private readonly OpenApiReference _reference; private string _description; - private OpenApiHeader Target + /// + /// Gets the target header. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiHeader Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index a3c33503e..05817ddc9 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -11,13 +11,19 @@ namespace Microsoft.OpenApi.Models.References /// /// Link Object Reference. /// - public class OpenApiLinkReference : OpenApiLink + public class OpenApiLinkReference : OpenApiLink, IOpenApiReferenceableWithTarget { internal OpenApiLink _target; private readonly OpenApiReference _reference; private string _description; - private OpenApiLink Target + /// + /// Gets the target link. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiLink Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 2c2a6c90d..9df1e7be2 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Parameter Object Reference. /// - public class OpenApiParameterReference : OpenApiParameter + public class OpenApiParameterReference : OpenApiParameter, IOpenApiReferenceableWithTarget { internal OpenApiParameter _target; private readonly OpenApiReference _reference; @@ -20,7 +20,13 @@ public class OpenApiParameterReference : OpenApiParameter private bool? _explode; private ParameterStyle? _style; - private OpenApiParameter Target + /// + /// Gets the target parameter. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiParameter Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index f757b7a07..fad8922ae 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -11,14 +11,20 @@ namespace Microsoft.OpenApi.Models.References /// /// Path Item Object Reference: to describe the operations available on a single path. /// - public class OpenApiPathItemReference : OpenApiPathItem + public class OpenApiPathItemReference : OpenApiPathItem, IOpenApiReferenceableWithTarget { internal OpenApiPathItem _target; private readonly OpenApiReference _reference; private string _description; private string _summary; - private OpenApiPathItem Target + /// + /// Gets the target path item. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiPathItem Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index 8e3a81ad8..598d70310 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -11,13 +11,19 @@ namespace Microsoft.OpenApi.Models.References /// /// Request Body Object Reference. /// - public class OpenApiRequestBodyReference : OpenApiRequestBody + public class OpenApiRequestBodyReference : OpenApiRequestBody, IOpenApiReferenceableWithTarget { internal OpenApiRequestBody _target; private readonly OpenApiReference _reference; private string _description; - private OpenApiRequestBody Target + /// + /// Gets the target request body. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiRequestBody Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index c24652504..0e4ac30ac 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -11,13 +11,19 @@ namespace Microsoft.OpenApi.Models.References /// /// Response Object Reference. /// - public class OpenApiResponseReference : OpenApiResponse + public class OpenApiResponseReference : OpenApiResponse, IOpenApiReferenceableWithTarget { internal OpenApiResponse _target; private readonly OpenApiReference _reference; private string _description; - private OpenApiResponse Target + /// + /// Gets the target response. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiResponse Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 41a1dceb5..da2f9b745 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -12,9 +12,9 @@ namespace Microsoft.OpenApi.Models.References /// /// Schema reference object /// - public class OpenApiSchemaReference : OpenApiSchema + public class OpenApiSchemaReference : OpenApiSchema, IOpenApiReferenceableWithTarget { - #nullable enable +#nullable enable private OpenApiSchema? _target; private readonly OpenApiReference _reference; private string? _description; @@ -69,8 +69,14 @@ public class OpenApiSchemaReference : OpenApiSchema private bool? _unevaluatedProperties; private IList? _enum; - private OpenApiSchema? Target - #nullable restore + /// + /// Gets the target schema. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiSchema? Target +#nullable restore { get { @@ -190,7 +196,7 @@ public override string Description /// public override bool? UniqueItems { get => _uniqueItems is not null ? _uniqueItems : Target?.UniqueItems; set => _uniqueItems = value; } /// - public override IDictionary Properties { get => _properties is not null ? _properties : Target?.Properties ; set => _properties = value; } + public override IDictionary Properties { get => _properties is not null ? _properties : Target?.Properties; set => _properties = value; } /// public override IDictionary PatternProperties { get => _patternProperties is not null ? _patternProperties : Target?.PatternProperties; set => _patternProperties = value; } /// @@ -257,7 +263,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) _reference.SerializeAsV3(writer); return; } - + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); writer.GetSettings().LoopDetector.PopLoop(); } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index faf6ae3bc..dcd5009b1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -11,13 +11,19 @@ namespace Microsoft.OpenApi.Models.References /// /// Security Scheme Object Reference. /// - public class OpenApiSecuritySchemeReference : OpenApiSecurityScheme + public class OpenApiSecuritySchemeReference : OpenApiSecurityScheme, IOpenApiReferenceableWithTarget { internal OpenApiSecurityScheme _target; private readonly OpenApiReference _reference; private string _description; - private OpenApiSecurityScheme Target + /// + /// Gets the target security scheme. + /// + /// + /// If the reference is not resolved, this will return null. + /// + public OpenApiSecurityScheme Target { get { diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index ddf7ad4e2..ae15b4085 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models.References /// /// Tag Object Reference /// - public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceable + public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceableWithTarget { internal OpenApiTag _target; diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index 73bb667b6..22f1c5ad3 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -4,183 +4,248 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; -namespace Microsoft.OpenApi.Services +namespace Microsoft.OpenApi.Services; +internal class CopyReferences(OpenApiDocument target) : OpenApiVisitorBase { - internal class CopyReferences : OpenApiVisitorBase + private readonly OpenApiDocument _target = target; + public OpenApiComponents Components = new(); + + /// + /// Visits IOpenApiReferenceable instances that are references and not in components. + /// + /// An IOpenApiReferenceable object. + public override void Visit(IOpenApiReferenceable referenceable) { - private readonly OpenApiDocument _target; - public OpenApiComponents Components = new(); - - public CopyReferences(OpenApiDocument target) + switch (referenceable) { - _target = target; + case OpenApiSchemaReference openApiSchemaReference: + AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id); + break; + case OpenApiSchema schema: + AddSchemaToComponents(schema); + break; + case OpenApiParameterReference openApiParameterReference: + AddParameterToComponents(openApiParameterReference.Target, openApiParameterReference.Reference.Id); + break; + case OpenApiParameter parameter: + AddParameterToComponents(parameter); + break; + case OpenApiResponseReference openApiResponseReference: + AddResponseToComponents(openApiResponseReference.Target, openApiResponseReference.Reference.Id); + break; + case OpenApiResponse response: + AddResponseToComponents(response); + break; + case OpenApiRequestBodyReference openApiRequestBodyReference: + AddRequestBodyToComponents(openApiRequestBodyReference.Target, openApiRequestBodyReference.Reference.Id); + break; + case OpenApiRequestBody requestBody: + AddRequestBodyToComponents(requestBody); + break; + case OpenApiExampleReference openApiExampleReference: + AddExampleToComponents(openApiExampleReference.Target, openApiExampleReference.Reference.Id); + break; + case OpenApiExample example: + AddExampleToComponents(example); + break; + case OpenApiHeaderReference openApiHeaderReference: + AddHeaderToComponents(openApiHeaderReference.Target, openApiHeaderReference.Reference.Id); + break; + case OpenApiHeader header: + AddHeaderToComponents(header); + break; + case OpenApiCallbackReference openApiCallbackReference: + AddCallbackToComponents(openApiCallbackReference.Target, openApiCallbackReference.Reference.Id); + break; + case OpenApiCallback callback: + AddCallbackToComponents(callback); + break; + case OpenApiLinkReference openApiLinkReference: + AddLinkToComponents(openApiLinkReference.Target, openApiLinkReference.Reference.Id); + break; + case OpenApiLink link: + AddLinkToComponents(link); + break; + case OpenApiSecuritySchemeReference openApiSecuritySchemeReference: + AddSecuritySchemeToComponents(openApiSecuritySchemeReference.Target, openApiSecuritySchemeReference.Reference.Id); + break; + case OpenApiSecurityScheme securityScheme: + AddSecuritySchemeToComponents(securityScheme); + break; + case OpenApiPathItemReference openApiPathItemReference: + AddPathItemToComponents(openApiPathItemReference.Target, openApiPathItemReference.Reference.Id); + break; + case OpenApiPathItem pathItem: + AddPathItemToComponents(pathItem); + break; + default: + break; } - /// - /// Visits IOpenApiReferenceable instances that are references and not in components. - /// - /// An IOpenApiReferenceable object. - public override void Visit(IOpenApiReferenceable referenceable) + base.Visit(referenceable); + } + + private void AddSchemaToComponents(OpenApiSchema schema, string referenceId = null) + { + EnsureComponentsExist(); + EnsureSchemasExist(); + if (!Components.Schemas.ContainsKey(referenceId ?? schema.Reference.Id)) { - switch (referenceable) - { - case OpenApiSchema schema: - EnsureComponentsExist(); - EnsureSchemasExist(); - if (!Components.Schemas.ContainsKey(schema.Reference.Id)) - { - Components.Schemas.Add(schema.Reference.Id, schema); - } - break; - - case OpenApiParameter parameter: - EnsureComponentsExist(); - EnsureParametersExist(); - if (!Components.Parameters.ContainsKey(parameter.Reference.Id)) - { - Components.Parameters.Add(parameter.Reference.Id, parameter); - } - break; - - case OpenApiResponse response: - EnsureComponentsExist(); - EnsureResponsesExist(); - if (!Components.Responses.ContainsKey(response.Reference.Id)) - { - Components.Responses.Add(response.Reference.Id, response); - } - break; - - case OpenApiRequestBody requestBody: - EnsureComponentsExist(); - EnsureResponsesExist(); - EnsureRequestBodiesExist(); - if (!Components.RequestBodies.ContainsKey(requestBody.Reference.Id)) - { - Components.RequestBodies.Add(requestBody.Reference.Id, requestBody); - } - break; - - case OpenApiExample example: - EnsureComponentsExist(); - EnsureExamplesExist(); - if (!Components.Examples.ContainsKey(example.Reference.Id)) - { - Components.Examples.Add(example.Reference.Id, example); - } - break; - - case OpenApiHeader header: - EnsureComponentsExist(); - EnsureHeadersExist(); - if (!Components.Headers.ContainsKey(header.Reference.Id)) - { - Components.Headers.Add(header.Reference.Id, header); - } - break; - - case OpenApiCallback callback: - EnsureComponentsExist(); - EnsureCallbacksExist(); - if (!Components.Callbacks.ContainsKey(callback.Reference.Id)) - { - Components.Callbacks.Add(callback.Reference.Id, callback); - } - break; - - case OpenApiLink link: - EnsureComponentsExist(); - EnsureLinksExist(); - if (!Components.Links.ContainsKey(link.Reference.Id)) - { - Components.Links.Add(link.Reference.Id, link); - } - break; - - case OpenApiSecurityScheme securityScheme: - EnsureComponentsExist(); - EnsureSecuritySchemesExist(); - if (!Components.SecuritySchemes.ContainsKey(securityScheme.Reference.Id)) - { - Components.SecuritySchemes.Add(securityScheme.Reference.Id, securityScheme); - } - break; - - default: - break; - } - - base.Visit(referenceable); + Components.Schemas.Add(referenceId ?? schema.Reference.Id, schema); } + } - /// - /// Visits - /// - /// The OpenApiSchema to be visited. - public override void Visit(OpenApiSchema schema) + private void AddParameterToComponents(OpenApiParameter parameter, string referenceId = null) + { + EnsureComponentsExist(); + EnsureParametersExist(); + if (!Components.Parameters.ContainsKey(referenceId ?? parameter.Reference.Id)) { - // This is needed to handle schemas used in Responses in components - if (schema.Reference != null) - { - EnsureComponentsExist(); - EnsureSchemasExist(); - if (!Components.Schemas.ContainsKey(schema.Reference.Id)) - { - Components.Schemas.Add(schema.Reference.Id, schema); - } - } - base.Visit(schema); + Components.Parameters.Add(referenceId ?? parameter.Reference.Id, parameter); } + } - private void EnsureComponentsExist() + private void AddResponseToComponents(OpenApiResponse response, string referenceId = null) + { + EnsureComponentsExist(); + EnsureResponsesExist(); + if (!Components.Responses.ContainsKey(referenceId ?? response.Reference.Id)) { - _target.Components ??= new(); + Components.Responses.Add(referenceId ?? response.Reference.Id, response); } - - private void EnsureSchemasExist() + } + private void AddRequestBodyToComponents(OpenApiRequestBody requestBody, string referenceId = null) + { + EnsureComponentsExist(); + EnsureRequestBodiesExist(); + if (!Components.RequestBodies.ContainsKey(referenceId ?? requestBody.Reference.Id)) { - _target.Components.Schemas ??= new Dictionary(); + Components.RequestBodies.Add(referenceId ?? requestBody.Reference.Id, requestBody); } - - private void EnsureParametersExist() + } + private void AddLinkToComponents(OpenApiLink link, string referenceId = null) + { + EnsureComponentsExist(); + EnsureLinksExist(); + if (!Components.Links.ContainsKey(referenceId ?? link.Reference.Id)) { - _target.Components.Parameters ??= new Dictionary(); + Components.Links.Add(referenceId ?? link.Reference.Id, link); } - - private void EnsureResponsesExist() + } + private void AddCallbackToComponents(OpenApiCallback callback, string referenceId = null) + { + EnsureComponentsExist(); + EnsureCallbacksExist(); + if (!Components.Callbacks.ContainsKey(referenceId ?? callback.Reference.Id)) { - _target.Components.Responses ??= new Dictionary(); + Components.Callbacks.Add(referenceId ?? callback.Reference.Id, callback); } - - private void EnsureRequestBodiesExist() + } + private void AddHeaderToComponents(OpenApiHeader header, string referenceId = null) + { + EnsureComponentsExist(); + EnsureHeadersExist(); + if (!Components.Headers.ContainsKey(referenceId ?? header.Reference.Id)) { - _target.Components.RequestBodies ??= new Dictionary(); + Components.Headers.Add(referenceId ?? header.Reference.Id, header); } - - private void EnsureExamplesExist() + } + private void AddExampleToComponents(OpenApiExample example, string referenceId = null) + { + EnsureComponentsExist(); + EnsureExamplesExist(); + if (!Components.Examples.ContainsKey(referenceId ?? example.Reference.Id)) { - _target.Components.Examples ??= new Dictionary(); + Components.Examples.Add(referenceId ?? example.Reference.Id, example); } - - private void EnsureHeadersExist() + } + private void AddPathItemToComponents(OpenApiPathItem pathItem, string referenceId = null) + { + EnsureComponentsExist(); + EnsurePathItemsExist(); + if (!Components.PathItems.ContainsKey(referenceId ?? pathItem.Reference.Id)) { - _target.Components.Headers ??= new Dictionary(); + Components.PathItems.Add(referenceId ?? pathItem.Reference.Id, pathItem); } - - private void EnsureCallbacksExist() + } + private void AddSecuritySchemeToComponents(OpenApiSecurityScheme securityScheme, string referenceId = null) + { + EnsureComponentsExist(); + EnsureSecuritySchemesExist(); + if (!Components.SecuritySchemes.ContainsKey(referenceId ?? securityScheme.Reference.Id)) { - _target.Components.Callbacks ??= new Dictionary(); + Components.SecuritySchemes.Add(referenceId ?? securityScheme.Reference.Id, securityScheme); } + } - private void EnsureLinksExist() + /// + public override void Visit(OpenApiSchema schema) + { + // This is needed to handle schemas used in Responses in components + if (schema is OpenApiSchemaReference openApiSchemaReference) { - _target.Components.Links ??= new Dictionary(); + AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id); } - - private void EnsureSecuritySchemesExist() + else if (schema.Reference != null) { - _target.Components.SecuritySchemes ??= new Dictionary(); + AddSchemaToComponents(schema); } + base.Visit(schema); + } + + private void EnsureComponentsExist() + { + _target.Components ??= new(); + } + + private void EnsureSchemasExist() + { + _target.Components.Schemas ??= new Dictionary(); + } + + private void EnsureParametersExist() + { + _target.Components.Parameters ??= new Dictionary(); + } + + private void EnsureResponsesExist() + { + _target.Components.Responses ??= new Dictionary(); + } + + private void EnsureRequestBodiesExist() + { + _target.Components.RequestBodies ??= new Dictionary(); + } + + private void EnsureExamplesExist() + { + _target.Components.Examples ??= new Dictionary(); + } + + private void EnsureHeadersExist() + { + _target.Components.Headers ??= new Dictionary(); + } + + private void EnsureCallbacksExist() + { + _target.Components.Callbacks ??= new Dictionary(); + } + + private void EnsureLinksExist() + { + _target.Components.Links ??= new Dictionary(); + } + + private void EnsureSecuritySchemesExist() + { + _target.Components.SecuritySchemes ??= new Dictionary(); + } + private void EnsurePathItemsExist() + { + _target.Components.PathItems ??= new Dictionary(); } } diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterSettings.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterSettings.cs index 3ff128ae6..e6364affa 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterSettings.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterSettings.cs @@ -24,10 +24,5 @@ internal bool ShouldInlineReference(OpenApiReference reference) return (reference.IsLocal && InlineLocalReferences) || (reference.IsExternal && InlineExternalReferences); } - - internal bool ShouldInlineReference() - { - return InlineLocalReferences || InlineExternalReferences; - } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs index 70eca5e9e..d7fef6396 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.OpenApi.Tests.Models.References public class OpenApiHeaderReferenceTests { // OpenApi doc with external $ref - private const string OpenApi= @" + private const string OpenApi = @" openapi: 3.0.0 info: title: Sample API @@ -149,7 +149,7 @@ public async Task SerializeHeaderReferenceAsV2JsonWorksAsync(bool produceTerseOu { // Arrange var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true}); + var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true }); // Act _localHeaderReference.SerializeAsV2(writer); @@ -158,5 +158,34 @@ public async Task SerializeHeaderReferenceAsV2JsonWorksAsync(bool produceTerseOu // Assert await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); } + + [Fact] + public void OpenApiHeaderTargetShouldResolveReference() + { + var doc = new OpenApiDocument + { + Components = new OpenApiComponents + { + Headers = new System.Collections.Generic.Dictionary + { + { "header1", new OpenApiHeader + { + Description = "test header", + Schema = new OpenApiSchema + { + Type = JsonSchemaType.String + } + } + } + } + } + }; + + doc.Workspace.RegisterComponents(doc); + + var headerReference = new OpenApiHeaderReference("header1", doc); + Assert.Equal("test header", headerReference.Description); + Assert.Equal(JsonSchemaType.String, headerReference.Schema.Type); + } } } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index fe5ad5bad..887fb3db8 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -223,6 +223,10 @@ namespace Microsoft.OpenApi.Interfaces Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } bool UnresolvedReference { get; set; } } + public interface IOpenApiReferenceableWithTarget : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + { + T Target { get; } + } public interface IOpenApiSerializable : Microsoft.OpenApi.Interfaces.IOpenApiElement { void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer); @@ -1096,17 +1100,19 @@ namespace Microsoft.OpenApi.Models } namespace Microsoft.OpenApi.Models.References { - public class OpenApiCallbackReference : Microsoft.OpenApi.Models.OpenApiCallback + public class OpenApiCallbackReference : Microsoft.OpenApi.Models.OpenApiCallback, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiCallbackReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiCallback Target { get; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override System.Collections.Generic.Dictionary PathItems { get; set; } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiExampleReference : Microsoft.OpenApi.Models.OpenApiExample + public class OpenApiExampleReference : Microsoft.OpenApi.Models.OpenApiExample, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiExampleReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiExample Target { get; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override string ExternalValue { get; set; } @@ -1115,9 +1121,10 @@ 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 OpenApiHeaderReference : Microsoft.OpenApi.Models.OpenApiHeader + public class OpenApiHeaderReference : Microsoft.OpenApi.Models.OpenApiHeader, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiHeaderReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiHeader Target { get; } public override bool AllowEmptyValue { get; set; } public override bool AllowReserved { get; set; } public override System.Collections.Generic.IDictionary Content { get; set; } @@ -1134,9 +1141,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink + public class OpenApiLinkReference : Microsoft.OpenApi.Models.OpenApiLink, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiLinkReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiLink Target { get; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override string OperationId { get; set; } @@ -1147,9 +1155,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter + public class OpenApiParameterReference : Microsoft.OpenApi.Models.OpenApiParameter, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiParameterReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiParameter Target { get; } public override bool AllowEmptyValue { get; set; } public override bool AllowReserved { get; set; } public override System.Collections.Generic.IDictionary Content { get; set; } @@ -1168,9 +1177,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem + public class OpenApiPathItemReference : Microsoft.OpenApi.Models.OpenApiPathItem, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiPathItemReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiPathItem Target { get; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override System.Collections.Generic.IDictionary Operations { get; set; } @@ -1179,9 +1189,10 @@ namespace Microsoft.OpenApi.Models.References public override string Summary { get; set; } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody + public class OpenApiRequestBodyReference : Microsoft.OpenApi.Models.OpenApiRequestBody, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiRequestBodyReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiRequestBody Target { get; } public override System.Collections.Generic.IDictionary Content { get; set; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1189,9 +1200,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse + public class OpenApiResponseReference : Microsoft.OpenApi.Models.OpenApiResponse, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiResponseReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiResponse Target { get; } public override System.Collections.Generic.IDictionary Content { get; set; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1201,9 +1213,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiSchema? Target { get; } public override Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } public override bool AdditionalPropertiesAllowed { get; set; } public override System.Collections.Generic.IList AllOf { get; set; } @@ -1259,9 +1272,10 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme + public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public Microsoft.OpenApi.Models.OpenApiSecurityScheme Target { get; } public override string BearerFormat { get; set; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1275,7 +1289,7 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiReferenceableWithTarget, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiTagReference(Microsoft.OpenApi.Models.References.OpenApiTagReference source) { } public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { }