-
Notifications
You must be signed in to change notification settings - Fork 251
/
Copy pathOpenApiYamlReader.cs
135 lines (122 loc) · 4.98 KB
/
OpenApiYamlReader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System.IO;
using System.Text.Json.Nodes;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Reader;
using SharpYaml.Serialization;
using Microsoft.OpenApi.Models;
using System;
using System.Linq;
using System.Text;
namespace Microsoft.OpenApi.YamlReader
{
/// <summary>
/// Reader for parsing YAML files into an OpenAPI document.
/// </summary>
public class OpenApiYamlReader : IOpenApiReader
{
private const int copyBufferSize = 4096;
private static readonly OpenApiJsonReader _jsonReader = new();
/// <inheritdoc/>
public async Task<ReadResult> ReadAsync(Stream input,
OpenApiReaderSettings settings,
CancellationToken cancellationToken = default)
{
if (input is null) throw new ArgumentNullException(nameof(input));
if (input is MemoryStream memoryStream)
{
return Read(memoryStream, settings);
}
else
{
using var preparedStream = new MemoryStream();
await input.CopyToAsync(preparedStream, copyBufferSize, cancellationToken).ConfigureAwait(false);
preparedStream.Position = 0;
return Read(preparedStream, settings);
}
}
/// <inheritdoc/>
public ReadResult Read(MemoryStream input,
OpenApiReaderSettings settings)
{
if (input is null) throw new ArgumentNullException(nameof(input));
if (settings is null) throw new ArgumentNullException(nameof(settings));
JsonNode jsonNode;
// Parse the YAML text in the stream into a sequence of JsonNodes
try
{
#if NET
// this represents net core, net5 and up
using var stream = new StreamReader(input, default, true, -1, settings.LeaveStreamOpen);
#else
// the implementation differs and results in a null reference exception in NETFX
using var stream = new StreamReader(input, Encoding.UTF8, true, 4096, settings.LeaveStreamOpen);
#endif
jsonNode = LoadJsonNodesFromYamlDocument(stream);
}
catch (JsonException ex)
{
var diagnostic = new OpenApiDiagnostic();
diagnostic.Errors.Add(new($"#line={ex.LineNumber}", ex.Message));
return new()
{
Document = null,
Diagnostic = diagnostic
};
}
return Read(jsonNode, settings);
}
/// <inheritdoc/>
public static ReadResult Read(JsonNode jsonNode, OpenApiReaderSettings settings)
{
return _jsonReader.Read(jsonNode, settings);
}
/// <inheritdoc/>
public T? ReadFragment<T>(MemoryStream input,
OpenApiSpecVersion version,
OpenApiDocument openApiDocument,
out OpenApiDiagnostic diagnostic,
OpenApiReaderSettings? settings = null) where T : IOpenApiElement
{
if (input is null) throw new ArgumentNullException(nameof(input));
JsonNode jsonNode;
// Parse the YAML
try
{
using var stream = new StreamReader(input);
jsonNode = LoadJsonNodesFromYamlDocument(stream);
}
catch (JsonException ex)
{
diagnostic = new();
diagnostic.Errors.Add(new($"#line={ex.LineNumber}", ex.Message));
return default;
}
return ReadFragment<T>(jsonNode, version, openApiDocument, out diagnostic, settings);
}
/// <inheritdoc/>
public static T? ReadFragment<T>(JsonNode input, OpenApiSpecVersion version, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings? settings = null) where T : IOpenApiElement
{
return _jsonReader.ReadFragment<T>(input, version, openApiDocument, out diagnostic, settings);
}
/// <summary>
/// Helper method to turn streams into a sequence of JsonNodes
/// </summary>
/// <param name="input">Stream containing YAML formatted text</param>
/// <returns>Instance of a YamlDocument</returns>
static JsonNode LoadJsonNodesFromYamlDocument(TextReader input)
{
var yamlStream = new YamlStream();
yamlStream.Load(input);
if (yamlStream.Documents.Any())
{
return yamlStream.Documents[0].ToJsonNode();
}
throw new InvalidOperationException("No documents found in the YAML stream.");
}
}
}