Skip to content

Commit 216d62b

Browse files
Simplify OpenApiDocumentReferencesAreValid
Remove reparsing of the document and just validate the in-memory `OpenApiDocument` instead.
1 parent a22ac92 commit 216d62b

File tree

1 file changed

+13
-62
lines changed

1 file changed

+13
-62
lines changed

src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Licensed under the MIT license.
33

44
using System;
5-
using System.Text.Json.Nodes;
6-
using Microsoft.OpenApi.Reader;
75

86
namespace Microsoft.OpenApi
97
{
@@ -39,101 +37,54 @@ public static class OpenApiDocumentRules
3937
{
4038
const string RuleName = nameof(OpenApiDocumentReferencesAreValid);
4139

42-
JsonNode document;
43-
44-
using (var textWriter = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture))
45-
{
46-
var writer = new OpenApiJsonWriter(textWriter);
47-
48-
item.SerializeAsV31(writer);
49-
50-
var json = textWriter.ToString();
51-
52-
document = JsonNode.Parse(json)!;
53-
}
54-
55-
var visitor = new OpenApiSchemaReferenceVisitor(RuleName, context, document);
40+
var visitor = new OpenApiSchemaReferenceVisitor(RuleName, context);
5641
var walker = new OpenApiWalker(visitor);
5742

5843
walker.Walk(item);
5944
});
6045

6146
private sealed class OpenApiSchemaReferenceVisitor(
6247
string ruleName,
63-
IValidationContext context,
64-
JsonNode document) : OpenApiVisitorBase
48+
IValidationContext context) : OpenApiVisitorBase
6549
{
6650
public override void Visit(IOpenApiReferenceHolder referenceHolder)
6751
{
68-
if (referenceHolder is OpenApiSchemaReference { Reference.IsLocal: true } reference)
52+
if (referenceHolder is OpenApiSchemaReference reference)
6953
{
7054
ValidateSchemaReference(reference);
7155
}
7256
}
7357

7458
public override void Visit(IOpenApiSchema schema)
7559
{
76-
if (schema is OpenApiSchemaReference { Reference.IsLocal: true } reference)
60+
if (schema is OpenApiSchemaReference reference)
7761
{
7862
ValidateSchemaReference(reference);
7963
}
8064
}
8165

8266
private void ValidateSchemaReference(OpenApiSchemaReference reference)
8367
{
84-
try
68+
if (!reference.Reference.IsLocal)
8569
{
86-
if (reference.RecursiveTarget is not null)
87-
{
88-
// The reference was followed to a valid schema somewhere in the document
89-
return;
90-
}
91-
}
92-
catch (InvalidOperationException ex)
93-
{
94-
context.Enter(GetSegment());
95-
context.CreateWarning(ruleName, ex.Message);
96-
context.Exit();
97-
9870
return;
9971
}
10072

101-
var id = reference.Reference.ReferenceV3;
102-
103-
if (id is { Length: > 0 } && !IsValidSchemaReference(id, document))
73+
try
10474
{
105-
var isValid = false;
106-
107-
// Sometimes ReferenceV3 is not a JSON valid JSON pointer, but the $ref
108-
// associated with it still points to a valid location in the document.
109-
// In these cases, we need to find it manually to verify that fact before
110-
// generating a warning that the schema reference is indeed invalid.
111-
// TODO Why is this, and can it be avoided?
112-
var parent = Find(PathString, document);
113-
114-
if (parent?["$ref"] is { } @ref &&
115-
@ref.GetValueKind() is System.Text.Json.JsonValueKind.String &&
116-
@ref.GetValue<string>() is { Length: > 0 } refId)
117-
{
118-
id = refId;
119-
isValid = IsValidSchemaReference(id, document);
120-
}
121-
122-
if (!isValid)
75+
if (reference.RecursiveTarget is null)
12376
{
77+
// The reference was not followed to a valid schema somewhere in the document
12478
context.Enter(GetSegment());
125-
context.CreateWarning(ruleName, string.Format(SRResource.Validation_SchemaReferenceDoesNotExist, id));
79+
context.CreateWarning(ruleName, string.Format(SRResource.Validation_SchemaReferenceDoesNotExist, reference.Reference.ReferenceV3));
12680
context.Exit();
12781
}
12882
}
129-
130-
static bool IsValidSchemaReference(string id, JsonNode baseNode)
131-
=> Find(id, baseNode) is not null;
132-
133-
static JsonNode? Find(string id, JsonNode baseNode)
83+
catch (InvalidOperationException ex)
13484
{
135-
var pointer = new JsonPointer(id.Replace("#/", "/"));
136-
return pointer.Find(baseNode);
85+
context.Enter(GetSegment());
86+
context.CreateWarning(ruleName, ex.Message);
87+
context.Exit();
13788
}
13889

13990
string GetSegment()

0 commit comments

Comments
 (0)