Skip to content

Commit 8c1493b

Browse files
committed
Merged latest changes from ref-overflow
2 parents 3d37908 + fb31544 commit 8c1493b

File tree

10 files changed

+212
-52
lines changed

10 files changed

+212
-52
lines changed

src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public enum ReferenceResolutionSetting
2626
/// <summary>
2727
/// Convert all references to references of valid domain objects.
2828
/// </summary>
29-
ResolveRemoteReferences
29+
ResolveAllReferences
3030
}
3131

3232
/// <summary>

src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
4747
// Resolve References if requested
4848
switch (_settings.ReferenceResolution)
4949
{
50-
case ReferenceResolutionSetting.ResolveRemoteReferences:
50+
case ReferenceResolutionSetting.ResolveAllReferences:
5151
throw new ArgumentException("Cannot resolve remote references using synchronous Read method, use ReadAsync instead");
5252
case ReferenceResolutionSetting.ResolveLocalReferences:
5353
ResolveReferences(document,false);
@@ -84,7 +84,7 @@ internal async Task<OpenApiDocument> ReadAsync(Stream input, OpenApiDiagnostic d
8484
// Resolve References if requested
8585
switch (_settings.ReferenceResolution)
8686
{
87-
case ReferenceResolutionSetting.ResolveRemoteReferences:
87+
case ReferenceResolutionSetting.ResolveAllReferences:
8888
// Resolve references in documents
8989
foreach (var item in workspace.Documents)
9090
{

src/Microsoft.OpenApi.Readers/ParsingContext.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ public void StartObject(string objectName)
160160
/// <summary>
161161
/// Maintain history of traversals to avoid stack overflows from cycles
162162
/// </summary>
163-
/// <param name="loopId">Any unique identifier for a stack</param>
164-
/// <param name="key">Identifier used to </param>
165-
/// <returns></returns>
163+
/// <param name="loopId">Any unique identifier for a stack.</param>
164+
/// <param name="key">Identifier used for current context.</param>
165+
/// <returns>If method returns false a loop was detected and the key is not added.</returns>
166166
public bool PushLoop(string loopId, string key)
167167
{
168168
Stack<string> stack;
@@ -185,7 +185,7 @@ public bool PushLoop(string loopId, string key)
185185
/// <summary>
186186
/// Reset loop tracking stack
187187
/// </summary>
188-
/// <param name="loopid"></param>
188+
/// <param name="loopid">Identifier of loop to clear</param>
189189
internal void ClearLoop(string loopid)
190190
{
191191
_loopStacks[loopid].Clear();
@@ -194,7 +194,7 @@ internal void ClearLoop(string loopid)
194194
/// <summary>
195195
/// Exit from the context in cycle detection
196196
/// </summary>
197-
/// <param name="loopid"></param>
197+
/// <param name="loopid">Identifier of loop</param>
198198
public void PopLoop(string loopid)
199199
{
200200
if (_loopStacks[loopid].Count > 0)

src/Microsoft.OpenApi.Readers/V3/OpenApiSchemaDeserializer.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ internal static partial class OpenApiV3Deserializer
234234
{s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, n.CreateAny())}
235235
};
236236

237-
private const string schemaLoopId = "schema";
238-
239237
public static OpenApiSchema LoadSchema(ParseNode node)
240238
{
241239
var mapNode = node.CheckMapNode(OpenApiConstants.Schema);

src/Microsoft.OpenApi/Models/OpenApiSchema.cs

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public class OpenApiSchema : IOpenApiSerializable, IOpenApiReferenceable, IOpenA
228228
/// <summary>
229229
/// Indicates object is a placeholder reference to an actual object and does not contain valid data.
230230
/// </summary>
231-
public bool UnresolvedReference { get; set; } = false;
231+
public bool UnresolvedReference { get; set; }
232232

233233
/// <summary>
234234
/// Reference object.
@@ -379,6 +379,32 @@ public void SerializeAsV3WithoutReference(IOpenApiWriter writer)
379379
/// Serialize <see cref="OpenApiSchema"/> to Open Api v2.0
380380
/// </summary>
381381
public void SerializeAsV2(IOpenApiWriter writer)
382+
{
383+
SerializeAsV2(writer: writer, parentRequiredProperties: new List<string>(), propertyName: null);
384+
}
385+
386+
/// <summary>
387+
/// Serialize to OpenAPI V2 document without using reference.
388+
/// </summary>
389+
public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
390+
{
391+
SerializeAsV2WithoutReference(
392+
writer: writer,
393+
parentRequiredProperties: new List<string>(),
394+
propertyName: null);
395+
}
396+
397+
/// <summary>
398+
/// Serialize <see cref="OpenApiSchema"/> to Open Api v2.0 and handles not marking the provided property
399+
/// as readonly if its included in the provided list of required properties of parent schema.
400+
/// </summary>
401+
/// <param name="writer">The open api writer.</param>
402+
/// <param name="parentRequiredProperties">The list of required properties in parent schema.</param>
403+
/// <param name="propertyName">The property name that will be serialized.</param>
404+
internal void SerializeAsV2(
405+
IOpenApiWriter writer,
406+
IList<string> parentRequiredProperties,
407+
string propertyName)
382408
{
383409
if (writer == null)
384410
{
@@ -391,16 +417,28 @@ public void SerializeAsV2(IOpenApiWriter writer)
391417
return;
392418
}
393419

394-
SerializeAsV2WithoutReference(writer);
420+
if (parentRequiredProperties == null)
421+
{
422+
parentRequiredProperties = new List<string>();
423+
}
424+
425+
SerializeAsV2WithoutReference(writer, parentRequiredProperties, propertyName);
395426
}
396427

397428
/// <summary>
398-
/// Serialize to OpenAPI V2 document without using reference.
429+
/// Serialize to OpenAPI V2 document without using reference and handles not marking the provided property
430+
/// as readonly if its included in the provided list of required properties of parent schema.
399431
/// </summary>
400-
public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
432+
/// <param name="writer">The open api writer.</param>
433+
/// <param name="parentRequiredProperties">The list of required properties in parent schema.</param>
434+
/// <param name="propertyName">The property name that will be serialized.</param>
435+
internal void SerializeAsV2WithoutReference(
436+
IOpenApiWriter writer,
437+
IList<string> parentRequiredProperties,
438+
string propertyName)
401439
{
402440
writer.WriteStartObject();
403-
WriteAsSchemaProperties(writer);
441+
WriteAsSchemaProperties(writer, parentRequiredProperties, propertyName);
404442
writer.WriteEndObject();
405443
}
406444

@@ -468,7 +506,10 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer)
468506
writer.WriteExtensions(Extensions);
469507
}
470508

471-
internal void WriteAsSchemaProperties(IOpenApiWriter writer)
509+
internal void WriteAsSchemaProperties(
510+
IOpenApiWriter writer,
511+
IList<string> parentRequiredProperties,
512+
string propertyName)
472513
{
473514
if (writer == null)
474515
{
@@ -542,7 +583,8 @@ internal void WriteAsSchemaProperties(IOpenApiWriter writer)
542583
writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, (w, s) => s.SerializeAsV2(w));
543584

544585
// properties
545-
writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, s) => s.SerializeAsV2(w));
586+
writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, key, s) =>
587+
s.SerializeAsV2(w, Required, key));
546588

547589
// additionalProperties
548590
writer.WriteOptionalObject(
@@ -554,7 +596,12 @@ internal void WriteAsSchemaProperties(IOpenApiWriter writer)
554596
writer.WriteProperty(OpenApiConstants.Discriminator, Discriminator?.PropertyName);
555597

556598
// readOnly
557-
writer.WriteProperty(OpenApiConstants.ReadOnly, ReadOnly, false);
599+
// In V2 schema if a property is part of required properties of parent schema,
600+
// it cannot be marked as readonly.
601+
if (!parentRequiredProperties.Contains(propertyName))
602+
{
603+
writer.WriteProperty(name: OpenApiConstants.ReadOnly, value: ReadOnly, defaultValue: false);
604+
}
558605

559606
// xml
560607
writer.WriteOptionalObject(OpenApiConstants.Xml, Xml, (w, s) => s.SerializeAsV2(w));

src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public virtual void Visit(IDictionary<string, OpenApiHeader> headers)
153153
}
154154

155155
/// <summary>
156-
/// Visits headers.
156+
/// Visits callbacks.
157157
/// </summary>
158158
public virtual void Visit(IDictionary<string, OpenApiCallback> callbacks)
159159
{

src/Microsoft.OpenApi/Services/OpenApiWalker.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ internal void Walk(OpenApiPaths paths)
210210
{
211211
foreach (var pathItem in paths)
212212
{
213-
Walk(pathItem.Key.Replace("/", "~1"), () => Walk(pathItem.Value));// JSON Pointer uses ~1 as an escape character for /
213+
Walk(pathItem.Key, () => Walk(pathItem.Value));// JSON Pointer uses ~1 as an escape character for /
214214
}
215215
}
216216
}
@@ -469,6 +469,7 @@ internal void Walk(OpenApiOperation operation)
469469
Walk(OpenApiConstants.RequestBody, () => Walk(operation.RequestBody));
470470
Walk(OpenApiConstants.Responses, () => Walk(operation.Responses));
471471
Walk(OpenApiConstants.Callbacks, () => Walk(operation.Callbacks));
472+
Walk(OpenApiConstants.Tags, () => Walk(operation.Tags));
472473

473474
Walk(operation as IOpenApiExtensible);
474475
}
@@ -588,7 +589,7 @@ internal void Walk(IDictionary<string, OpenApiHeader> headers)
588589
{
589590
foreach (var header in headers)
590591
{
591-
Walk(header.Key.Replace("/", "~1"), () => Walk(header.Value));
592+
Walk(header.Key, () => Walk(header.Value));
592593
}
593594
}
594595
}
@@ -608,7 +609,7 @@ internal void Walk(IDictionary<string, OpenApiCallback> callbacks)
608609
{
609610
foreach (var header in callbacks)
610611
{
611-
Walk(header.Key.Replace("/", "~1"), () => Walk(header.Value));
612+
Walk(header.Key, () => Walk(header.Value));
612613
}
613614
}
614615
}
@@ -628,7 +629,7 @@ internal void Walk(IDictionary<string, OpenApiMediaType> content)
628629
{
629630
foreach (var mediaType in content)
630631
{
631-
Walk(mediaType.Key.Replace("/", "~1"), () => Walk(mediaType.Value));
632+
Walk(mediaType.Key, () => Walk(mediaType.Value));
632633
}
633634
}
634635
}
@@ -988,7 +989,7 @@ internal void Walk(IOpenApiElement element)
988989
/// <param name="walk">An action that walks objects within the context.</param>
989990
private void Walk(string context, Action walk)
990991
{
991-
_visitor.Enter(context);
992+
_visitor.Enter(context.Replace("/", "~1"));
992993
walk();
993994
_visitor.Exit();
994995
}

test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -471,34 +471,34 @@ public void ParseSelfReferencingSchemaShouldNotStackOverflow()
471471
diagnostic.ShouldBeEquivalentTo(
472472
new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 });
473473

474-
//var schemaExtension = new OpenApiSchema()
475-
//{
476-
// AllOf = { new OpenApiSchema()
477-
// {
478-
// Title = "schemaExtension",
479-
// Type = "object",
480-
// Properties = {
481-
// ["description"] = new OpenApiSchema() { Type = "string", Nullable = true},
482-
// ["targetTypes"] = new OpenApiSchema() {
483-
// Type = "array",
484-
// Items = new OpenApiSchema() {
485-
// Type = "string"
486-
// }
487-
// },
488-
// ["status"] = new OpenApiSchema() { Type = "string"},
489-
// ["owner"] = new OpenApiSchema() { Type = "string"},
490-
// ["child"] = null
491-
// }
492-
// }
493-
// },
494-
// Reference = new OpenApiReference()
495-
// {
496-
// Type = ReferenceType.Schema,
497-
// Id = "microsoft.graph.schemaExtension"
498-
// }
499-
//};
500-
501-
//schemaExtension.AllOf[0].Properties["child"] = schemaExtension;
474+
var schemaExtension = new OpenApiSchema()
475+
{
476+
AllOf = { new OpenApiSchema()
477+
{
478+
Title = "schemaExtension",
479+
Type = "object",
480+
Properties = {
481+
["description"] = new OpenApiSchema() { Type = "string", Nullable = true},
482+
["targetTypes"] = new OpenApiSchema() {
483+
Type = "array",
484+
Items = new OpenApiSchema() {
485+
Type = "string"
486+
}
487+
},
488+
["status"] = new OpenApiSchema() { Type = "string"},
489+
["owner"] = new OpenApiSchema() { Type = "string"},
490+
["child"] = null
491+
}
492+
}
493+
},
494+
Reference = new OpenApiReference()
495+
{
496+
Type = ReferenceType.Schema,
497+
Id = "microsoft.graph.schemaExtension"
498+
}
499+
};
500+
501+
schemaExtension.AllOf[0].Properties["child"] = schemaExtension;
502502

503503
components.Schemas["microsoft.graph.schemaExtension"].ShouldBeEquivalentTo(components.Schemas["microsoft.graph.schemaExtension"].AllOf[0].Properties["child"]);
504504
}

0 commit comments

Comments
 (0)