|
2 | 2 | // Licensed under the MIT license.
|
3 | 3 |
|
4 | 4 | using System;
|
5 |
| -using System.Text.Json.Nodes; |
6 |
| -using Microsoft.OpenApi.Reader; |
7 | 5 |
|
8 | 6 | namespace Microsoft.OpenApi
|
9 | 7 | {
|
@@ -39,101 +37,54 @@ public static class OpenApiDocumentRules
|
39 | 37 | {
|
40 | 38 | const string RuleName = nameof(OpenApiDocumentReferencesAreValid);
|
41 | 39 |
|
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); |
56 | 41 | var walker = new OpenApiWalker(visitor);
|
57 | 42 |
|
58 | 43 | walker.Walk(item);
|
59 | 44 | });
|
60 | 45 |
|
61 | 46 | private sealed class OpenApiSchemaReferenceVisitor(
|
62 | 47 | string ruleName,
|
63 |
| - IValidationContext context, |
64 |
| - JsonNode document) : OpenApiVisitorBase |
| 48 | + IValidationContext context) : OpenApiVisitorBase |
65 | 49 | {
|
66 | 50 | public override void Visit(IOpenApiReferenceHolder referenceHolder)
|
67 | 51 | {
|
68 |
| - if (referenceHolder is OpenApiSchemaReference { Reference.IsLocal: true } reference) |
| 52 | + if (referenceHolder is OpenApiSchemaReference reference) |
69 | 53 | {
|
70 | 54 | ValidateSchemaReference(reference);
|
71 | 55 | }
|
72 | 56 | }
|
73 | 57 |
|
74 | 58 | public override void Visit(IOpenApiSchema schema)
|
75 | 59 | {
|
76 |
| - if (schema is OpenApiSchemaReference { Reference.IsLocal: true } reference) |
| 60 | + if (schema is OpenApiSchemaReference reference) |
77 | 61 | {
|
78 | 62 | ValidateSchemaReference(reference);
|
79 | 63 | }
|
80 | 64 | }
|
81 | 65 |
|
82 | 66 | private void ValidateSchemaReference(OpenApiSchemaReference reference)
|
83 | 67 | {
|
84 |
| - try |
| 68 | + if (!reference.Reference.IsLocal) |
85 | 69 | {
|
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 |
| - |
98 | 70 | return;
|
99 | 71 | }
|
100 | 72 |
|
101 |
| - var id = reference.Reference.ReferenceV3; |
102 |
| - |
103 |
| - if (id is { Length: > 0 } && !IsValidSchemaReference(id, document)) |
| 73 | + try |
104 | 74 | {
|
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) |
123 | 76 | {
|
| 77 | + // The reference was not followed to a valid schema somewhere in the document |
124 | 78 | 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)); |
126 | 80 | context.Exit();
|
127 | 81 | }
|
128 | 82 | }
|
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) |
134 | 84 | {
|
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(); |
137 | 88 | }
|
138 | 89 |
|
139 | 90 | string GetSegment()
|
|
0 commit comments