Skip to content

Commit 1394da7

Browse files
authored
Merge pull request #2031 from microsoft/fix/reference-proxy-single-copy
fix/reference proxy single copy
2 parents aa90edf + 45d49f1 commit 1394da7

File tree

8 files changed

+225
-93
lines changed

8 files changed

+225
-93
lines changed

src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license.
33

44
using Microsoft.OpenApi.Models;
5-
using Microsoft.OpenApi.Writers;
65

76
namespace Microsoft.OpenApi.Interfaces
87
{

src/Microsoft.OpenApi/Models/OpenApiComponents.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Linq;
76
using Microsoft.OpenApi.Interfaces;
87
using Microsoft.OpenApi.Models.References;
98
using Microsoft.OpenApi.Writers;

src/Microsoft.OpenApi/Models/OpenApiDocument.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,67 @@ public static ReadResult Parse(string input,
587587
{
588588
return OpenApiModelFactory.Parse(input, format, settings);
589589
}
590+
/// <summary>
591+
/// Adds a component to the components object of the current document and registers it to the underlying workspace.
592+
/// </summary>
593+
/// <param name="componentToRegister">The component to add</param>
594+
/// <param name="id">The id for the component</param>
595+
/// <typeparam name="T">The type of the component</typeparam>
596+
/// <returns>Whether the component was added to the components.</returns>
597+
/// <exception cref="ArgumentNullException">Thrown when the component is null.</exception>
598+
/// <exception cref="ArgumentException">Thrown when the id is null or empty.</exception>
599+
public bool AddComponent<T>(string id, T componentToRegister)
600+
{
601+
Utils.CheckArgumentNull(componentToRegister);
602+
Utils.CheckArgumentNullOrEmpty(id);
603+
Components ??= new();
604+
switch (componentToRegister)
605+
{
606+
case OpenApiSchema openApiSchema:
607+
Components.Schemas ??= new Dictionary<string, OpenApiSchema>();
608+
Components.Schemas.Add(id, openApiSchema);
609+
break;
610+
case OpenApiParameter openApiParameter:
611+
Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
612+
Components.Parameters.Add(id, openApiParameter);
613+
break;
614+
case OpenApiResponse openApiResponse:
615+
Components.Responses ??= new Dictionary<string, OpenApiResponse>();
616+
Components.Responses.Add(id, openApiResponse);
617+
break;
618+
case OpenApiRequestBody openApiRequestBody:
619+
Components.RequestBodies ??= new Dictionary<string, OpenApiRequestBody>();
620+
Components.RequestBodies.Add(id, openApiRequestBody);
621+
break;
622+
case OpenApiLink openApiLink:
623+
Components.Links ??= new Dictionary<string, OpenApiLink>();
624+
Components.Links.Add(id, openApiLink);
625+
break;
626+
case OpenApiCallback openApiCallback:
627+
Components.Callbacks ??= new Dictionary<string, OpenApiCallback>();
628+
Components.Callbacks.Add(id, openApiCallback);
629+
break;
630+
case OpenApiPathItem openApiPathItem:
631+
Components.PathItems ??= new Dictionary<string, OpenApiPathItem>();
632+
Components.PathItems.Add(id, openApiPathItem);
633+
break;
634+
case OpenApiExample openApiExample:
635+
Components.Examples ??= new Dictionary<string, OpenApiExample>();
636+
Components.Examples.Add(id, openApiExample);
637+
break;
638+
case OpenApiHeader openApiHeader:
639+
Components.Headers ??= new Dictionary<string, OpenApiHeader>();
640+
Components.Headers.Add(id, openApiHeader);
641+
break;
642+
case OpenApiSecurityScheme openApiSecurityScheme:
643+
Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
644+
Components.SecuritySchemes.Add(id, openApiSecurityScheme);
645+
break;
646+
default:
647+
throw new ArgumentException($"Component type {componentToRegister!.GetType().Name} is not supported.");
648+
}
649+
return Workspace?.RegisterComponentForDocument(this, componentToRegister, id) ?? false;
650+
}
590651
}
591652

592653
internal class FindSchemaReferences : OpenApiVisitorBase

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

Lines changed: 107 additions & 73 deletions
Large diffs are not rendered by default.

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public override void SerializeAsV3(IOpenApiWriter writer)
8080
if (!writer.GetSettings().ShouldInlineReference(_reference))
8181
{
8282
_reference.SerializeAsV3(writer);
83-
return;
8483
}
8584
else
8685
{
@@ -94,7 +93,6 @@ public override void SerializeAsV31(IOpenApiWriter writer)
9493
if (!writer.GetSettings().ShouldInlineReference(_reference))
9594
{
9695
_reference.SerializeAsV31(writer);
97-
return;
9896
}
9997
else
10098
{
@@ -108,7 +106,6 @@ public override void SerializeAsV2(IOpenApiWriter writer)
108106
if (!writer.GetSettings().ShouldInlineReference(_reference))
109107
{
110108
_reference.SerializeAsV2(writer);
111-
return;
112109
}
113110
else
114111
{
@@ -119,7 +116,7 @@ public override void SerializeAsV2(IOpenApiWriter writer)
119116
/// <inheritdoc/>
120117
private void SerializeInternal(IOpenApiWriter writer)
121118
{
122-
Utils.CheckArgumentNull(writer);;
119+
Utils.CheckArgumentNull(writer);
123120
writer.WriteValue(Name);
124121
}
125122
}

src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public int ComponentsCount()
5454
{
5555
return _IOpenApiReferenceableRegistry.Count + _artifactsRegistry.Count;
5656
}
57+
private const string ComponentSegmentSeparator = "/";
5758

5859
/// <summary>
5960
/// Registers a document's components into the workspace
@@ -63,89 +64,130 @@ public void RegisterComponents(OpenApiDocument document)
6364
{
6465
if (document?.Components == null) return;
6566

66-
string baseUri = document.BaseUri + OpenApiConstants.ComponentsSegment;
67+
string baseUri = getBaseUri(document);
6768
string location;
6869

6970
// Register Schema
7071
foreach (var item in document.Components.Schemas)
7172
{
72-
location = item.Value.Id ?? baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key;
73+
location = item.Value.Id ?? baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + item.Key;
7374

7475
RegisterComponent(location, item.Value);
7576
}
7677

7778
// Register Parameters
7879
foreach (var item in document.Components.Parameters)
7980
{
80-
location = baseUri + ReferenceType.Parameter.GetDisplayName() + "/" + item.Key;
81+
location = baseUri + ReferenceType.Parameter.GetDisplayName() + ComponentSegmentSeparator + item.Key;
8182
RegisterComponent(location, item.Value);
8283
}
8384

8485
// Register Responses
8586
foreach (var item in document.Components.Responses)
8687
{
87-
location = baseUri + ReferenceType.Response.GetDisplayName() + "/" + item.Key;
88+
location = baseUri + ReferenceType.Response.GetDisplayName() + ComponentSegmentSeparator + item.Key;
8889
RegisterComponent(location, item.Value);
8990
}
9091

9192
// Register RequestBodies
9293
foreach (var item in document.Components.RequestBodies)
9394
{
94-
location = baseUri + ReferenceType.RequestBody.GetDisplayName() + "/" + item.Key;
95+
location = baseUri + ReferenceType.RequestBody.GetDisplayName() + ComponentSegmentSeparator + item.Key;
9596
RegisterComponent(location, item.Value);
9697
}
9798

9899
// Register Links
99100
foreach (var item in document.Components.Links)
100101
{
101-
location = baseUri + ReferenceType.Link.GetDisplayName() + "/" + item.Key;
102+
location = baseUri + ReferenceType.Link.GetDisplayName() + ComponentSegmentSeparator + item.Key;
102103
RegisterComponent(location, item.Value);
103104
}
104105

105106
// Register Callbacks
106107
foreach (var item in document.Components.Callbacks)
107108
{
108-
location = baseUri + ReferenceType.Callback.GetDisplayName() + "/" + item.Key;
109+
location = baseUri + ReferenceType.Callback.GetDisplayName() + ComponentSegmentSeparator + item.Key;
109110
RegisterComponent(location, item.Value);
110111
}
111112

112113
// Register PathItems
113114
foreach (var item in document.Components.PathItems)
114115
{
115-
location = baseUri + ReferenceType.PathItem.GetDisplayName() + "/" + item.Key;
116+
location = baseUri + ReferenceType.PathItem.GetDisplayName() + ComponentSegmentSeparator + item.Key;
116117
RegisterComponent(location, item.Value);
117118
}
118119

119120
// Register Examples
120121
foreach (var item in document.Components.Examples)
121122
{
122-
location = baseUri + ReferenceType.Example.GetDisplayName() + "/" + item.Key;
123+
location = baseUri + ReferenceType.Example.GetDisplayName() + ComponentSegmentSeparator + item.Key;
123124
RegisterComponent(location, item.Value);
124125
}
125126

126127
// Register Headers
127128
foreach (var item in document.Components.Headers)
128129
{
129-
location = baseUri + ReferenceType.Header.GetDisplayName() + "/" + item.Key;
130+
location = baseUri + ReferenceType.Header.GetDisplayName() + ComponentSegmentSeparator + item.Key;
130131
RegisterComponent(location, item.Value);
131132
}
132133

133134
// Register SecuritySchemes
134135
foreach (var item in document.Components.SecuritySchemes)
135136
{
136-
location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key;
137+
location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + ComponentSegmentSeparator + item.Key;
137138
RegisterComponent(location, item.Value);
138139
}
139140
}
140141

142+
private string getBaseUri(OpenApiDocument openApiDocument)
143+
{
144+
return openApiDocument.BaseUri + OpenApiConstants.ComponentsSegment;
145+
}
146+
147+
/// <summary>
148+
/// Registers a component for a document in the workspace
149+
/// </summary>
150+
/// <param name="openApiDocument">The document to register the component for.</param>
151+
/// <param name="componentToRegister">The component to register.</param>
152+
/// <param name="id">The id of the component.</param>
153+
/// <typeparam name="T">The type of the component to register.</typeparam>
154+
/// <returns>true if the component is successfully registered; otherwise false.</returns>
155+
/// <exception cref="ArgumentNullException">openApiDocument is null</exception>
156+
/// <exception cref="ArgumentNullException">componentToRegister is null</exception>
157+
/// <exception cref="ArgumentNullException">id is null or empty</exception>
158+
public bool RegisterComponentForDocument<T>(OpenApiDocument openApiDocument, T componentToRegister, string id)
159+
{
160+
Utils.CheckArgumentNull(openApiDocument);
161+
Utils.CheckArgumentNull(componentToRegister);
162+
Utils.CheckArgumentNullOrEmpty(id);
163+
164+
var baseUri = getBaseUri(openApiDocument);
165+
166+
var location = componentToRegister switch
167+
{
168+
OpenApiSchema => baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + id,
169+
OpenApiParameter => baseUri + ReferenceType.Parameter.GetDisplayName() + ComponentSegmentSeparator + id,
170+
OpenApiResponse => baseUri + ReferenceType.Response.GetDisplayName() + ComponentSegmentSeparator + id,
171+
OpenApiRequestBody => baseUri + ReferenceType.RequestBody.GetDisplayName() + ComponentSegmentSeparator + id,
172+
OpenApiLink => baseUri + ReferenceType.Link.GetDisplayName() + ComponentSegmentSeparator + id,
173+
OpenApiCallback => baseUri + ReferenceType.Callback.GetDisplayName() + ComponentSegmentSeparator + id,
174+
OpenApiPathItem => baseUri + ReferenceType.PathItem.GetDisplayName() + ComponentSegmentSeparator + id,
175+
OpenApiExample => baseUri + ReferenceType.Example.GetDisplayName() + ComponentSegmentSeparator + id,
176+
OpenApiHeader => baseUri + ReferenceType.Header.GetDisplayName() + ComponentSegmentSeparator + id,
177+
OpenApiSecurityScheme => baseUri + ReferenceType.SecurityScheme.GetDisplayName() + ComponentSegmentSeparator + id,
178+
_ => throw new ArgumentException($"Invalid component type {componentToRegister.GetType().Name}"),
179+
};
180+
181+
return RegisterComponent(location, componentToRegister);
182+
}
141183

142184
/// <summary>
143185
/// Registers a component in the component registry.
144186
/// </summary>
145187
/// <param name="location"></param>
146188
/// <param name="component"></param>
147189
/// <returns>true if the component is successfully registered; otherwise false.</returns>
148-
public bool RegisterComponent<T>(string location, T component)
190+
internal bool RegisterComponent<T>(string location, T component)
149191
{
150192
var uri = ToLocationUrl(location);
151193
if (component is IOpenApiReferenceable referenceable)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ namespace Microsoft.OpenApi.Models
569569
public System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiTag>? Tags { get; set; }
570570
public System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.Models.OpenApiPathItem>? Webhooks { get; set; }
571571
public Microsoft.OpenApi.Services.OpenApiWorkspace? Workspace { get; set; }
572+
public bool AddComponent<T>(string id, T componentToRegister) { }
572573
public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
573574
public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
574575
public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
@@ -1528,7 +1529,7 @@ namespace Microsoft.OpenApi.Services
15281529
public int ComponentsCount() { }
15291530
public bool Contains(string location) { }
15301531
public System.Uri GetDocumentId(string key) { }
1531-
public bool RegisterComponent<T>(string location, T component) { }
1532+
public bool RegisterComponentForDocument<T>(Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, T componentToRegister, string id) { }
15321533
public void RegisterComponents(Microsoft.OpenApi.Models.OpenApiDocument document) { }
15331534
public T? ResolveReference<T>(string location) { }
15341535
}

test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public class OpenApiReferencableTests
4545
{ "link1", new OpenApiLink() }
4646
}
4747
};
48-
private static readonly OpenApiSchema _schemaFragment = new OpenApiSchema();
4948
private static readonly OpenApiSecurityScheme _securitySchemeFragment = new OpenApiSecurityScheme();
5049
private static readonly OpenApiTag _tagFragment = new OpenApiTag();
5150

0 commit comments

Comments
 (0)