Skip to content

Commit 88daad5

Browse files
committed
fix: components schema copy
1 parent 66e4101 commit 88daad5

File tree

3 files changed

+163
-158
lines changed

3 files changed

+163
-158
lines changed

src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.Models.References
1414
/// </summary>
1515
public class OpenApiSchemaReference : OpenApiSchema
1616
{
17-
#nullable enable
17+
#nullable enable
1818
private OpenApiSchema? _target;
1919
private readonly OpenApiReference _reference;
2020
private string? _description;
@@ -69,8 +69,14 @@ public class OpenApiSchemaReference : OpenApiSchema
6969
private bool? _unevaluatedProperties;
7070
private IList<JsonNode>? _enum;
7171

72-
private OpenApiSchema? Target
73-
#nullable restore
72+
/// <summary>
73+
/// Gets the target schema.
74+
/// </summary>
75+
/// <remarks>
76+
/// If the reference is not resolved, this will return null.
77+
/// </remarks>
78+
public OpenApiSchema? Target
79+
#nullable restore
7480
{
7581
get
7682
{
@@ -190,7 +196,7 @@ public override string Description
190196
/// <inheritdoc/>
191197
public override bool? UniqueItems { get => _uniqueItems is not null ? _uniqueItems : Target?.UniqueItems; set => _uniqueItems = value; }
192198
/// <inheritdoc/>
193-
public override IDictionary<string, OpenApiSchema> Properties { get => _properties is not null ? _properties : Target?.Properties ; set => _properties = value; }
199+
public override IDictionary<string, OpenApiSchema> Properties { get => _properties is not null ? _properties : Target?.Properties; set => _properties = value; }
194200
/// <inheritdoc/>
195201
public override IDictionary<string, OpenApiSchema> PatternProperties { get => _patternProperties is not null ? _patternProperties : Target?.PatternProperties; set => _patternProperties = value; }
196202
/// <inheritdoc/>
@@ -257,7 +263,7 @@ public override void SerializeAsV3(IOpenApiWriter writer)
257263
_reference.SerializeAsV3(writer);
258264
return;
259265
}
260-
266+
261267
SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer));
262268
writer.GetSettings().LoopDetector.PopLoop<OpenApiSchema>();
263269
}

src/Microsoft.OpenApi/Services/CopyReferences.cs

Lines changed: 151 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -4,183 +4,181 @@
44
using System.Collections.Generic;
55
using Microsoft.OpenApi.Interfaces;
66
using Microsoft.OpenApi.Models;
7+
using Microsoft.OpenApi.Models.References;
78

8-
namespace Microsoft.OpenApi.Services
9+
namespace Microsoft.OpenApi.Services;
10+
internal class CopyReferences(OpenApiDocument target) : OpenApiVisitorBase
911
{
10-
internal class CopyReferences : OpenApiVisitorBase
12+
private readonly OpenApiDocument _target = target;
13+
public OpenApiComponents Components = new();
14+
15+
/// <summary>
16+
/// Visits IOpenApiReferenceable instances that are references and not in components.
17+
/// </summary>
18+
/// <param name="referenceable"> An IOpenApiReferenceable object.</param>
19+
public override void Visit(IOpenApiReferenceable referenceable)
1120
{
12-
private readonly OpenApiDocument _target;
13-
public OpenApiComponents Components = new();
14-
15-
public CopyReferences(OpenApiDocument target)
21+
switch (referenceable)
1622
{
17-
_target = target;
18-
}
23+
case OpenApiSchemaReference openApiSchemaReference:
24+
AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id);
25+
break;
26+
case OpenApiSchema schema:
27+
AddSchemaToComponents(schema);
28+
break;
29+
30+
case OpenApiParameter parameter:
31+
EnsureComponentsExist();
32+
EnsureParametersExist();
33+
if (!Components.Parameters.ContainsKey(parameter.Reference.Id))
34+
{
35+
Components.Parameters.Add(parameter.Reference.Id, parameter);
36+
}
37+
break;
1938

20-
/// <summary>
21-
/// Visits IOpenApiReferenceable instances that are references and not in components.
22-
/// </summary>
23-
/// <param name="referenceable"> An IOpenApiReferenceable object.</param>
24-
public override void Visit(IOpenApiReferenceable referenceable)
25-
{
26-
switch (referenceable)
27-
{
28-
case OpenApiSchema schema:
29-
EnsureComponentsExist();
30-
EnsureSchemasExist();
31-
if (!Components.Schemas.ContainsKey(schema.Reference.Id))
32-
{
33-
Components.Schemas.Add(schema.Reference.Id, schema);
34-
}
35-
break;
36-
37-
case OpenApiParameter parameter:
38-
EnsureComponentsExist();
39-
EnsureParametersExist();
40-
if (!Components.Parameters.ContainsKey(parameter.Reference.Id))
41-
{
42-
Components.Parameters.Add(parameter.Reference.Id, parameter);
43-
}
44-
break;
45-
46-
case OpenApiResponse response:
47-
EnsureComponentsExist();
48-
EnsureResponsesExist();
49-
if (!Components.Responses.ContainsKey(response.Reference.Id))
50-
{
51-
Components.Responses.Add(response.Reference.Id, response);
52-
}
53-
break;
54-
55-
case OpenApiRequestBody requestBody:
56-
EnsureComponentsExist();
57-
EnsureResponsesExist();
58-
EnsureRequestBodiesExist();
59-
if (!Components.RequestBodies.ContainsKey(requestBody.Reference.Id))
60-
{
61-
Components.RequestBodies.Add(requestBody.Reference.Id, requestBody);
62-
}
63-
break;
64-
65-
case OpenApiExample example:
66-
EnsureComponentsExist();
67-
EnsureExamplesExist();
68-
if (!Components.Examples.ContainsKey(example.Reference.Id))
69-
{
70-
Components.Examples.Add(example.Reference.Id, example);
71-
}
72-
break;
73-
74-
case OpenApiHeader header:
75-
EnsureComponentsExist();
76-
EnsureHeadersExist();
77-
if (!Components.Headers.ContainsKey(header.Reference.Id))
78-
{
79-
Components.Headers.Add(header.Reference.Id, header);
80-
}
81-
break;
82-
83-
case OpenApiCallback callback:
84-
EnsureComponentsExist();
85-
EnsureCallbacksExist();
86-
if (!Components.Callbacks.ContainsKey(callback.Reference.Id))
87-
{
88-
Components.Callbacks.Add(callback.Reference.Id, callback);
89-
}
90-
break;
91-
92-
case OpenApiLink link:
93-
EnsureComponentsExist();
94-
EnsureLinksExist();
95-
if (!Components.Links.ContainsKey(link.Reference.Id))
96-
{
97-
Components.Links.Add(link.Reference.Id, link);
98-
}
99-
break;
100-
101-
case OpenApiSecurityScheme securityScheme:
102-
EnsureComponentsExist();
103-
EnsureSecuritySchemesExist();
104-
if (!Components.SecuritySchemes.ContainsKey(securityScheme.Reference.Id))
105-
{
106-
Components.SecuritySchemes.Add(securityScheme.Reference.Id, securityScheme);
107-
}
108-
break;
109-
110-
default:
111-
break;
112-
}
113-
114-
base.Visit(referenceable);
115-
}
39+
case OpenApiResponse response:
40+
EnsureComponentsExist();
41+
EnsureResponsesExist();
42+
if (!Components.Responses.ContainsKey(response.Reference.Id))
43+
{
44+
Components.Responses.Add(response.Reference.Id, response);
45+
}
46+
break;
11647

117-
/// <summary>
118-
/// Visits <see cref="OpenApiSchema"/>
119-
/// </summary>
120-
/// <param name="schema">The OpenApiSchema to be visited.</param>
121-
public override void Visit(OpenApiSchema schema)
122-
{
123-
// This is needed to handle schemas used in Responses in components
124-
if (schema.Reference != null)
125-
{
48+
case OpenApiRequestBody requestBody:
12649
EnsureComponentsExist();
127-
EnsureSchemasExist();
128-
if (!Components.Schemas.ContainsKey(schema.Reference.Id))
50+
EnsureResponsesExist();
51+
EnsureRequestBodiesExist();
52+
if (!Components.RequestBodies.ContainsKey(requestBody.Reference.Id))
12953
{
130-
Components.Schemas.Add(schema.Reference.Id, schema);
54+
Components.RequestBodies.Add(requestBody.Reference.Id, requestBody);
13155
}
132-
}
133-
base.Visit(schema);
134-
}
56+
break;
13557

136-
private void EnsureComponentsExist()
137-
{
138-
_target.Components ??= new();
139-
}
58+
case OpenApiExample example:
59+
EnsureComponentsExist();
60+
EnsureExamplesExist();
61+
if (!Components.Examples.ContainsKey(example.Reference.Id))
62+
{
63+
Components.Examples.Add(example.Reference.Id, example);
64+
}
65+
break;
14066

141-
private void EnsureSchemasExist()
142-
{
143-
_target.Components.Schemas ??= new Dictionary<string, OpenApiSchema>();
144-
}
67+
case OpenApiHeader header:
68+
EnsureComponentsExist();
69+
EnsureHeadersExist();
70+
if (!Components.Headers.ContainsKey(header.Reference.Id))
71+
{
72+
Components.Headers.Add(header.Reference.Id, header);
73+
}
74+
break;
14575

146-
private void EnsureParametersExist()
147-
{
148-
_target.Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
149-
}
76+
case OpenApiCallback callback:
77+
EnsureComponentsExist();
78+
EnsureCallbacksExist();
79+
if (!Components.Callbacks.ContainsKey(callback.Reference.Id))
80+
{
81+
Components.Callbacks.Add(callback.Reference.Id, callback);
82+
}
83+
break;
15084

151-
private void EnsureResponsesExist()
152-
{
153-
_target.Components.Responses ??= new Dictionary<string, OpenApiResponse>();
154-
}
85+
case OpenApiLink link:
86+
EnsureComponentsExist();
87+
EnsureLinksExist();
88+
if (!Components.Links.ContainsKey(link.Reference.Id))
89+
{
90+
Components.Links.Add(link.Reference.Id, link);
91+
}
92+
break;
15593

156-
private void EnsureRequestBodiesExist()
157-
{
158-
_target.Components.RequestBodies ??= new Dictionary<string, OpenApiRequestBody>();
159-
}
94+
case OpenApiSecurityScheme securityScheme:
95+
EnsureComponentsExist();
96+
EnsureSecuritySchemesExist();
97+
if (!Components.SecuritySchemes.ContainsKey(securityScheme.Reference.Id))
98+
{
99+
Components.SecuritySchemes.Add(securityScheme.Reference.Id, securityScheme);
100+
}
101+
break;
160102

161-
private void EnsureExamplesExist()
162-
{
163-
_target.Components.Examples ??= new Dictionary<string, OpenApiExample>();
103+
default:
104+
break;
164105
}
165106

166-
private void EnsureHeadersExist()
167-
{
168-
_target.Components.Headers ??= new Dictionary<string, OpenApiHeader>();
169-
}
107+
base.Visit(referenceable);
108+
}
170109

171-
private void EnsureCallbacksExist()
110+
private void AddSchemaToComponents(OpenApiSchema schema, string referenceId = null)
111+
{
112+
EnsureComponentsExist();
113+
EnsureSchemasExist();
114+
if (!Components.Schemas.ContainsKey(referenceId ?? schema.Reference.Id))
172115
{
173-
_target.Components.Callbacks ??= new Dictionary<string, OpenApiCallback>();
116+
Components.Schemas.Add(referenceId ?? schema.Reference.Id, schema);
174117
}
118+
}
175119

176-
private void EnsureLinksExist()
120+
/// <inheritdoc/>
121+
public override void Visit(OpenApiSchema schema)
122+
{
123+
// This is needed to handle schemas used in Responses in components
124+
if (schema is OpenApiSchemaReference openApiSchemaReference)
177125
{
178-
_target.Components.Links ??= new Dictionary<string, OpenApiLink>();
126+
AddSchemaToComponents(openApiSchemaReference.Target, openApiSchemaReference.Reference.Id);
179127
}
180-
181-
private void EnsureSecuritySchemesExist()
128+
else if (schema.Reference != null)
182129
{
183-
_target.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
130+
AddSchemaToComponents(schema);
184131
}
132+
base.Visit(schema);
133+
}
134+
135+
private void EnsureComponentsExist()
136+
{
137+
_target.Components ??= new();
138+
}
139+
140+
private void EnsureSchemasExist()
141+
{
142+
_target.Components.Schemas ??= new Dictionary<string, OpenApiSchema>();
143+
}
144+
145+
private void EnsureParametersExist()
146+
{
147+
_target.Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
148+
}
149+
150+
private void EnsureResponsesExist()
151+
{
152+
_target.Components.Responses ??= new Dictionary<string, OpenApiResponse>();
153+
}
154+
155+
private void EnsureRequestBodiesExist()
156+
{
157+
_target.Components.RequestBodies ??= new Dictionary<string, OpenApiRequestBody>();
158+
}
159+
160+
private void EnsureExamplesExist()
161+
{
162+
_target.Components.Examples ??= new Dictionary<string, OpenApiExample>();
163+
}
164+
165+
private void EnsureHeadersExist()
166+
{
167+
_target.Components.Headers ??= new Dictionary<string, OpenApiHeader>();
168+
}
169+
170+
private void EnsureCallbacksExist()
171+
{
172+
_target.Components.Callbacks ??= new Dictionary<string, OpenApiCallback>();
173+
}
174+
175+
private void EnsureLinksExist()
176+
{
177+
_target.Components.Links ??= new Dictionary<string, OpenApiLink>();
178+
}
179+
180+
private void EnsureSecuritySchemesExist()
181+
{
182+
_target.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
185183
}
186184
}

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,7 @@ namespace Microsoft.OpenApi.Models.References
12121212
public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema
12131213
{
12141214
public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { }
1215+
public Microsoft.OpenApi.Models.OpenApiSchema? Target { get; }
12151216
public override Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; }
12161217
public override bool AdditionalPropertiesAllowed { get; set; }
12171218
public override System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AllOf { get; set; }

0 commit comments

Comments
 (0)