Skip to content

Commit

Permalink
fix: components schema copy
Browse files Browse the repository at this point in the history
  • Loading branch information
baywet committed Jan 8, 2025
1 parent 66e4101 commit 88daad5
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 158 deletions.
16 changes: 11 additions & 5 deletions src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.Models.References
/// </summary>
public class OpenApiSchemaReference : OpenApiSchema
{
#nullable enable
#nullable enable
private OpenApiSchema? _target;
private readonly OpenApiReference _reference;
private string? _description;
Expand Down Expand Up @@ -69,8 +69,14 @@ public class OpenApiSchemaReference : OpenApiSchema
private bool? _unevaluatedProperties;
private IList<JsonNode>? _enum;

private OpenApiSchema? Target
#nullable restore
/// <summary>
/// Gets the target schema.
/// </summary>
/// <remarks>
/// If the reference is not resolved, this will return null.
/// </remarks>
public OpenApiSchema? Target
#nullable restore
{
get
{
Expand Down Expand Up @@ -190,7 +196,7 @@ public override string Description
/// <inheritdoc/>
public override bool? UniqueItems { get => _uniqueItems is not null ? _uniqueItems : Target?.UniqueItems; set => _uniqueItems = value; }
/// <inheritdoc/>
public override IDictionary<string, OpenApiSchema> Properties { get => _properties is not null ? _properties : Target?.Properties ; set => _properties = value; }
public override IDictionary<string, OpenApiSchema> Properties { get => _properties is not null ? _properties : Target?.Properties; set => _properties = value; }
/// <inheritdoc/>
public override IDictionary<string, OpenApiSchema> PatternProperties { get => _patternProperties is not null ? _patternProperties : Target?.PatternProperties; set => _patternProperties = value; }
/// <inheritdoc/>
Expand Down Expand Up @@ -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<OpenApiSchema>();
}
Expand Down
304 changes: 151 additions & 153 deletions src/Microsoft.OpenApi/Services/CopyReferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,183 +4,181 @@
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();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note

Field 'Components' can be 'readonly'.

/// <summary>
/// Visits IOpenApiReferenceable instances that are references and not in components.
/// </summary>
/// <param name="referenceable"> An IOpenApiReferenceable object.</param>
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 OpenApiParameter parameter:
EnsureComponentsExist();
EnsureParametersExist();
if (!Components.Parameters.ContainsKey(parameter.Reference.Id))
{
Components.Parameters.Add(parameter.Reference.Id, parameter);
}
break;

/// <summary>
/// Visits IOpenApiReferenceable instances that are references and not in components.
/// </summary>
/// <param name="referenceable"> An IOpenApiReferenceable object.</param>
public override void Visit(IOpenApiReferenceable referenceable)
{
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);
}
case OpenApiResponse response:
EnsureComponentsExist();
EnsureResponsesExist();
if (!Components.Responses.ContainsKey(response.Reference.Id))
{
Components.Responses.Add(response.Reference.Id, response);
}
break;

/// <summary>
/// Visits <see cref="OpenApiSchema"/>
/// </summary>
/// <param name="schema">The OpenApiSchema to be visited.</param>
public override void Visit(OpenApiSchema schema)
{
// This is needed to handle schemas used in Responses in components
if (schema.Reference != null)
{
case OpenApiRequestBody requestBody:
EnsureComponentsExist();
EnsureSchemasExist();
if (!Components.Schemas.ContainsKey(schema.Reference.Id))
EnsureResponsesExist();
EnsureRequestBodiesExist();
if (!Components.RequestBodies.ContainsKey(requestBody.Reference.Id))
{
Components.Schemas.Add(schema.Reference.Id, schema);
Components.RequestBodies.Add(requestBody.Reference.Id, requestBody);
}
}
base.Visit(schema);
}
break;

private void EnsureComponentsExist()
{
_target.Components ??= new();
}
case OpenApiExample example:
EnsureComponentsExist();
EnsureExamplesExist();
if (!Components.Examples.ContainsKey(example.Reference.Id))
{
Components.Examples.Add(example.Reference.Id, example);
}
break;

private void EnsureSchemasExist()
{
_target.Components.Schemas ??= new Dictionary<string, OpenApiSchema>();
}
case OpenApiHeader header:
EnsureComponentsExist();
EnsureHeadersExist();
if (!Components.Headers.ContainsKey(header.Reference.Id))
{
Components.Headers.Add(header.Reference.Id, header);
}
break;

private void EnsureParametersExist()
{
_target.Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
}
case OpenApiCallback callback:
EnsureComponentsExist();
EnsureCallbacksExist();
if (!Components.Callbacks.ContainsKey(callback.Reference.Id))
{
Components.Callbacks.Add(callback.Reference.Id, callback);
}
break;

private void EnsureResponsesExist()
{
_target.Components.Responses ??= new Dictionary<string, OpenApiResponse>();
}
case OpenApiLink link:
EnsureComponentsExist();
EnsureLinksExist();
if (!Components.Links.ContainsKey(link.Reference.Id))
{
Components.Links.Add(link.Reference.Id, link);
}
break;

private void EnsureRequestBodiesExist()
{
_target.Components.RequestBodies ??= new Dictionary<string, OpenApiRequestBody>();
}
case OpenApiSecurityScheme securityScheme:
EnsureComponentsExist();
EnsureSecuritySchemesExist();
if (!Components.SecuritySchemes.ContainsKey(securityScheme.Reference.Id))
{
Components.SecuritySchemes.Add(securityScheme.Reference.Id, securityScheme);
}
break;

private void EnsureExamplesExist()
{
_target.Components.Examples ??= new Dictionary<string, OpenApiExample>();
default:
break;
}

private void EnsureHeadersExist()
{
_target.Components.Headers ??= new Dictionary<string, OpenApiHeader>();
}
base.Visit(referenceable);
}

private void EnsureCallbacksExist()
private void AddSchemaToComponents(OpenApiSchema schema, string referenceId = null)
{
EnsureComponentsExist();
EnsureSchemasExist();
if (!Components.Schemas.ContainsKey(referenceId ?? schema.Reference.Id))
{
_target.Components.Callbacks ??= new Dictionary<string, OpenApiCallback>();
Components.Schemas.Add(referenceId ?? schema.Reference.Id, schema);
}
}

private void EnsureLinksExist()
/// <inheritdoc/>
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<string, OpenApiLink>();
AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id);
}

private void EnsureSecuritySchemesExist()
else if (schema.Reference != null)
{
_target.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
AddSchemaToComponents(schema);
}
base.Visit(schema);
}

private void EnsureComponentsExist()
{
_target.Components ??= new();
}

private void EnsureSchemasExist()
{
_target.Components.Schemas ??= new Dictionary<string, OpenApiSchema>();
}

private void EnsureParametersExist()
{
_target.Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
}

private void EnsureResponsesExist()
{
_target.Components.Responses ??= new Dictionary<string, OpenApiResponse>();
}

private void EnsureRequestBodiesExist()
{
_target.Components.RequestBodies ??= new Dictionary<string, OpenApiRequestBody>();
}

private void EnsureExamplesExist()
{
_target.Components.Examples ??= new Dictionary<string, OpenApiExample>();
}

private void EnsureHeadersExist()
{
_target.Components.Headers ??= new Dictionary<string, OpenApiHeader>();
}

private void EnsureCallbacksExist()
{
_target.Components.Callbacks ??= new Dictionary<string, OpenApiCallback>();
}

private void EnsureLinksExist()
{
_target.Components.Links ??= new Dictionary<string, OpenApiLink>();
}

private void EnsureSecuritySchemesExist()
{
_target.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,7 @@ namespace Microsoft.OpenApi.Models.References
public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema
{
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<Microsoft.OpenApi.Models.OpenApiSchema> AllOf { get; set; }
Expand Down

0 comments on commit 88daad5

Please sign in to comment.