Skip to content

Commit 3e1077a

Browse files
authored
Update Reference implementation to handle all tag, security scheme, and $ref-style pointers correctly. (#90)
* Update name from IExtension and IReference to IExtensible and IReferenceable * Update Reference implementation to correctly handle tag, security scheme, and other ref-style referenceable objects. * Add GetReferencedObject to all applicable deserializers * Move files for ReferenceService and remove duplicate implementation of LoadTag * Add OperationTests. This writes both Tag and SecurityScheme as references. * Always write tag as strings regardless of whether Pointer exists in the Operation. * Remove ReferenceService Base * Add Unit Test for full document reading including schema/tag/securityScheme. One test is not working properly since we can't do dictionary comparison with securityScheme being the key right now, so I'm using JsonConvert as workaround for the equality issue. * Minor cleanup for RootNode and ParsingContext
1 parent 8f6b612 commit 3e1077a

File tree

104 files changed

+3288
-1327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+3288
-1327
lines changed

src/Microsoft.OpenApi.Readers/Interface/IOpenApiReferenceService.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/Microsoft.OpenApi.Readers/Interface/OpenApiReferenceServiceBase.cs

Lines changed: 0 additions & 111 deletions
This file was deleted.

src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.OpenApi.xml</DocumentationFile>
1818
</PropertyGroup>
1919

20+
<ItemGroup>
21+
<Compile Remove="ReferenceServices\OpenApiReferenceServiceBase.cs" />
22+
</ItemGroup>
23+
2024
<ItemGroup>
2125
<PackageReference Include="SharpYaml" Version="1.6.1" />
2226
</ItemGroup>

src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55

66
using System.IO;
77
using System.Linq;
8+
using Microsoft.OpenApi.Models;
89
using Microsoft.OpenApi.Readers.Interface;
910
using Microsoft.OpenApi.Readers.ParseNodes;
10-
using SharpYaml;
11-
using SharpYaml.Serialization;
12-
using Microsoft.OpenApi.Models;
11+
using Microsoft.OpenApi.Readers.ReferenceServices;
1312
using Microsoft.OpenApi.Readers.V2;
1413
using Microsoft.OpenApi.Readers.V3;
14+
using SharpYaml;
15+
using SharpYaml.Serialization;
1516

1617
namespace Microsoft.OpenApi.Readers
1718
{
@@ -69,13 +70,13 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
6970
switch (inputVersion)
7071
{
7172
case "2.0":
72-
context.SetReferenceService(new OpenApiV2ReferenceService(rootNode));
73+
context.ReferenceService = new OpenApiV2ReferenceService(rootNode);
7374
return OpenApiV2Deserializer.LoadOpenApi(rootNode);
7475

7576
default:
76-
context.SetReferenceService(new OpenApiV3ReferenceService(rootNode));
77+
context.ReferenceService = new OpenApiV3ReferenceService(rootNode);
7778
return OpenApiV3Deserializer.LoadOpenApi(rootNode);
7879
}
7980
}
8081
}
81-
}
82+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4+
// ------------------------------------------------------------
5+
6+
using System;
7+
using SharpYaml.Serialization;
8+
9+
namespace Microsoft.OpenApi.Readers.ParseNodes
10+
{
11+
/// <summary>
12+
/// Extensions for JSON pointers.
13+
/// </summary>
14+
public static class JsonPointerExtensions
15+
{
16+
/// <summary>
17+
/// Finds the YAML node that corresponds to this JSON pointer based on the base YAML node.
18+
/// </summary>
19+
public static YamlNode Find(this JsonPointer currentpointer, YamlNode baseYamlNode)
20+
{
21+
if (currentpointer.Tokens.Length == 0)
22+
{
23+
return baseYamlNode;
24+
}
25+
26+
try
27+
{
28+
var pointer = baseYamlNode;
29+
foreach (var token in currentpointer.Tokens)
30+
{
31+
var sequence = pointer as YamlSequenceNode;
32+
33+
if (sequence != null)
34+
{
35+
pointer = sequence.Children[Convert.ToInt32(token)];
36+
}
37+
else
38+
{
39+
var map = pointer as YamlMappingNode;
40+
if (map != null)
41+
{
42+
if (!map.Children.TryGetValue(new YamlScalarNode(token), out pointer))
43+
{
44+
return null;
45+
}
46+
}
47+
}
48+
}
49+
50+
return pointer;
51+
}
52+
catch (Exception ex)
53+
{
54+
throw new ArgumentException("Failed to dereference pointer", ex);
55+
}
56+
}
57+
}
58+
}

src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
using System.Collections;
88
using System.Collections.Generic;
99
using System.Linq;
10-
using SharpYaml.Schemas;
11-
using SharpYaml.Serialization;
1210
using Microsoft.OpenApi.Any;
1311
using Microsoft.OpenApi.Exceptions;
1412
using Microsoft.OpenApi.Interfaces;
13+
using Microsoft.OpenApi.Models;
14+
using SharpYaml.Schemas;
15+
using SharpYaml.Serialization;
1516

1617
namespace Microsoft.OpenApi.Readers.ParseNodes
1718
{
@@ -28,7 +29,9 @@ public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, string yaml
2829
{
2930
}
3031

31-
public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlMappingNode node) : base(context, diagnostic)
32+
public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlMappingNode node) : base(
33+
context,
34+
diagnostic)
3235
{
3336
if (node == null)
3437
{
@@ -74,7 +77,10 @@ public override Dictionary<string, T> CreateMap<T>(Func<MapNode, T> map)
7477
return nodes.ToDictionary(k => k.key, v => v.value);
7578
}
7679

77-
public override Dictionary<string, T> CreateMapWithReference<T>(string refpointerbase, Func<MapNode, T> map)
80+
public override Dictionary<string, T> CreateMapWithReference<T>(
81+
ReferenceType referenceType,
82+
string refpointerbase,
83+
Func<MapNode, T> map)
7884
{
7985
var yamlMap = node;
8086
if (yamlMap == null)
@@ -86,32 +92,12 @@ public override Dictionary<string, T> CreateMapWithReference<T>(string refpointe
8692
n => new
8793
{
8894
key = n.Key.GetScalarValue(),
89-
value = GetReferencedObject<T>(refpointerbase + n.Key.GetScalarValue()) ??
95+
value = GetReferencedObject<T>(referenceType, refpointerbase + n.Key.GetScalarValue()) ??
9096
map(new MapNode(Context, Diagnostic, (YamlMappingNode)n.Value))
9197
});
9298
return nodes.ToDictionary(k => k.key, v => v.value);
9399
}
94100

95-
public T CreateOrReferenceDomainObject<T>(Func<T> factory) where T : IOpenApiReference
96-
{
97-
T domainObject;
98-
var refPointer = GetReferencePointer(); // What should the DOM of a reference look like?
99-
// Duplicated object - poor perf/more memory/unsynchronized changes
100-
// Intermediate object - require common base class/client code has to explicitly code for it.
101-
// Delegating object - lot of setup work/maintenance/ require full interfaces
102-
// **current favourite***Shared object - marker to indicate its a reference/serialization code must serialize as reference everywhere except components.
103-
if (refPointer != null)
104-
{
105-
domainObject = (T)Context.GetReferencedObject(Diagnostic, refPointer);
106-
}
107-
else
108-
{
109-
domainObject = factory();
110-
}
111-
112-
return domainObject;
113-
}
114-
115101
public override Dictionary<string, T> CreateSimpleMap<T>(Func<ValueNode, T> map)
116102
{
117103
var yamlMap = node;
@@ -145,9 +131,13 @@ public override string GetRaw()
145131
return x.Serialize(node);
146132
}
147133

148-
public T GetReferencedObject<T>(string refPointer) where T : IOpenApiReference
134+
public T GetReferencedObject<T>(ReferenceType referenceType, string referenceId)
135+
where T : IOpenApiReferenceable
149136
{
150-
return (T)Context.GetReferencedObject(Diagnostic, refPointer);
137+
return (T)Context.GetReferencedObject(
138+
Diagnostic,
139+
referenceType,
140+
referenceId);
151141
}
152142

153143
public string GetReferencePointer()

src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
using System;
77
using System.Collections.Generic;
88
using System.Text.RegularExpressions;
9-
using SharpYaml.Serialization;
109
using Microsoft.OpenApi.Any;
1110
using Microsoft.OpenApi.Exceptions;
1211
using Microsoft.OpenApi.Interfaces;
12+
using Microsoft.OpenApi.Models;
13+
using SharpYaml.Serialization;
1314

1415
namespace Microsoft.OpenApi.Readers.ParseNodes
1516
{
@@ -78,8 +79,11 @@ public virtual Dictionary<string, T> CreateMap<T>(Func<MapNode, T> map)
7879
throw new OpenApiException("Cannot create map");
7980
}
8081

81-
public virtual Dictionary<string, T> CreateMapWithReference<T>(string refpointer, Func<MapNode, T> map)
82-
where T : class, IOpenApiReference
82+
public virtual Dictionary<string, T> CreateMapWithReference<T>(
83+
ReferenceType referenceType,
84+
string refpointer,
85+
Func<MapNode, T> map)
86+
where T : class, IOpenApiReferenceable
8387
{
8488
throw new OpenApiException("Cannot create map from reference");
8589
}

src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
using System;
77
using System.Collections.Generic;
88
using System.Linq;
9-
using SharpYaml.Serialization;
109
using Microsoft.OpenApi.Any;
1110
using Microsoft.OpenApi.Exceptions;
11+
using SharpYaml.Serialization;
1212

1313
namespace Microsoft.OpenApi.Readers.ParseNodes
1414
{

0 commit comments

Comments
 (0)