1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT license.
3
3
4
- using System ;
5
4
using System . IO ;
6
- using System . Net . Http ;
7
- using System . Security ;
8
5
using System . Text . Json . Nodes ;
6
+ using System . Text . Json ;
9
7
using System . Threading ;
10
8
using System . Threading . Tasks ;
11
9
using Microsoft . OpenApi . Interfaces ;
12
- using Microsoft . OpenApi . Models ;
13
10
using Microsoft . OpenApi . Reader ;
11
+ using SharpYaml . Serialization ;
12
+ using System . Linq ;
14
13
15
14
namespace Microsoft . OpenApi . Readers
16
15
{
@@ -19,156 +18,78 @@ namespace Microsoft.OpenApi.Readers
19
18
/// </summary>
20
19
public class OpenApiYamlReader : IOpenApiReader
21
20
{
22
- private static readonly HttpClient _httpClient = HttpClientFactory . GetHttpClient ( ) ;
23
-
24
21
/// <inheritdoc/>
25
- public OpenApiDocument Parse ( string input , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null )
22
+ public async Task < ReadResult > ReadAsync ( TextReader input ,
23
+ OpenApiReaderSettings settings = null ,
24
+ CancellationToken cancellationToken = default )
26
25
{
27
- using var reader = new StringReader ( input ) ;
28
- return Read ( reader , out diagnostic , settings ) ;
29
- }
26
+ JsonNode jsonNode ;
30
27
31
- /// <inheritdoc/>
32
- public OpenApiDocument Read ( string url , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null )
33
- {
34
- var stream = GetStream ( url ) . GetAwaiter ( ) . GetResult ( ) ;
35
- return Read ( stream , out diagnostic , settings ) ;
36
- }
28
+ // Parse the YAML text in the TextReader into a sequence of JsonNodes
29
+ try
30
+ {
31
+ jsonNode = LoadJsonNodesFromYamlDocument ( input ) ;
32
+ }
33
+ catch ( JsonException ex )
34
+ {
35
+ var diagnostic = new OpenApiDiagnostic ( ) ;
36
+ diagnostic . Errors . Add ( new ( $ "#line={ ex . LineNumber } ", ex . Message ) ) ;
37
+ return new ( )
38
+ {
39
+ OpenApiDocument = null ,
40
+ OpenApiDiagnostic = diagnostic
41
+ } ;
42
+ }
37
43
38
- /// <inheritdoc/>
39
- public OpenApiDocument Read ( Stream stream , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null )
40
- {
41
- return new OpenApiStreamReader ( settings ) . Read ( stream , out diagnostic ) ;
44
+ return await ReadAsync ( jsonNode , settings , cancellationToken ) ;
42
45
}
43
46
44
47
/// <inheritdoc/>
45
- public OpenApiDocument Read ( TextReader input , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null )
48
+ public T ReadFragment < T > ( TextReader input ,
49
+ OpenApiSpecVersion version ,
50
+ out OpenApiDiagnostic diagnostic ,
51
+ OpenApiReaderSettings settings = null ) where T : IOpenApiElement
46
52
{
47
- return new OpenApiTextReaderReader ( settings ) . Read ( input , out diagnostic ) ;
48
- }
53
+ JsonNode jsonNode ;
49
54
50
- /// <inheritdoc/>
51
- public async Task < ReadResult > ReadAsync ( string url , OpenApiReaderSettings settings = null , CancellationToken cancellationToken = default )
52
- {
53
- var stream = GetStream ( url ) . Result ;
54
- return await ReadAsync ( stream , settings , cancellationToken ) ;
55
- }
55
+ // Parse the YAML
56
+ try
57
+ {
58
+ jsonNode = LoadJsonNodesFromYamlDocument ( input ) ;
59
+ }
60
+ catch ( JsonException ex )
61
+ {
62
+ diagnostic = new ( ) ;
63
+ diagnostic . Errors . Add ( new ( $ "#line={ ex . LineNumber } ", ex . Message ) ) ;
64
+ return default ;
65
+ }
56
66
57
- /// <inheritdoc/>
58
- public async Task < ReadResult > ReadAsync ( Stream stream , OpenApiReaderSettings settings = null , CancellationToken cancellationToken = default )
59
- {
60
- return await new OpenApiStreamReader ( settings ) . ReadAsync ( stream , cancellationToken ) ;
67
+ return ReadFragment < T > ( jsonNode , version , out diagnostic ) ;
61
68
}
62
69
63
- /// <inheritdoc/>
64
- public async Task < ReadResult > ReadAsync ( TextReader input ,
65
- OpenApiReaderSettings settings = null ,
66
- CancellationToken cancellationToken = default )
67
- {
68
- return await new OpenApiTextReaderReader ( settings ) . ReadAsync ( input , cancellationToken ) ;
69
- }
70
-
71
-
72
70
/// <summary>
73
- /// Takes in an input URL and parses it into an Open API document
71
+ /// Helper method to turn streams into a sequence of JsonNodes
74
72
/// </summary>
75
- /// <param name="url">The path to the Open API file</param>
76
- /// <param name="version">The OpenAPI specification version.</param>
77
- /// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing.</param>
78
- /// <param name="settings">The Reader settings to be used during parsing.</param>
79
- /// <returns></returns>
80
- /// <exception cref="ArgumentException"></exception>
81
- public T Read < T > ( string url ,
82
- OpenApiSpecVersion version ,
83
- out OpenApiDiagnostic diagnostic ,
84
- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
85
- {
86
- settings ??= new OpenApiReaderSettings ( ) ;
87
- var stream = GetStream ( url ) . GetAwaiter ( ) . GetResult ( ) ;
88
- return Read < T > ( stream , version , out diagnostic , settings ) ;
89
- }
90
-
91
- /// <inheritdoc/>
92
- public T Read < T > ( Stream input ,
93
- OpenApiSpecVersion version ,
94
- out OpenApiDiagnostic diagnostic ,
95
- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
73
+ /// <param name="input">Stream containing YAML formatted text</param>
74
+ /// <returns>Instance of a YamlDocument</returns>
75
+ static JsonNode LoadJsonNodesFromYamlDocument ( TextReader input )
96
76
{
97
- return new OpenApiStreamReader ( settings ) . ReadFragment < T > ( input , version , out diagnostic ) ;
77
+ var yamlStream = new YamlStream ( ) ;
78
+ yamlStream . Load ( input ) ;
79
+ var yamlDocument = yamlStream . Documents . First ( ) ;
80
+ return yamlDocument . ToJsonNode ( ) ;
98
81
}
99
82
100
- /// <inheritdoc/>
101
- public T Read < T > ( TextReader input ,
102
- OpenApiSpecVersion version ,
103
- out OpenApiDiagnostic diagnostic ,
104
- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
83
+ /// <inheritdoc/>
84
+ public async Task < ReadResult > ReadAsync ( JsonNode jsonNode , OpenApiReaderSettings settings , CancellationToken cancellationToken = default )
105
85
{
106
- return new OpenApiTextReaderReader ( settings ) . ReadFragment < T > ( input , version , out diagnostic ) ;
86
+ return await OpenApiReaderRegistry . DefaultReader . ReadAsync ( jsonNode , settings , cancellationToken ) ;
107
87
}
108
88
109
89
/// <inheritdoc/>
110
- public T Read < T > ( JsonNode input ,
111
- OpenApiSpecVersion version ,
112
- out OpenApiDiagnostic diagnostic ,
113
- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
90
+ public T ReadFragment < T > ( JsonNode input , OpenApiSpecVersion version , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null ) where T : IOpenApiElement
114
91
{
115
- return new OpenApiYamlDocumentReader ( settings ) . ReadFragment < T > ( input , version , out diagnostic ) ;
92
+ return OpenApiReaderRegistry . DefaultReader . ReadFragment < T > ( input , version , out diagnostic ) ;
116
93
}
117
-
118
- /// <summary>
119
- /// Parses an input string into an Open API document.
120
- /// </summary>
121
- /// <param name="input"></param>
122
- /// <param name="version"></param>
123
- /// <param name="diagnostic"></param>
124
- /// <param name="settings"></param>
125
- /// <returns></returns>
126
- public T Parse < T > ( string input ,
127
- OpenApiSpecVersion version ,
128
- out OpenApiDiagnostic diagnostic ,
129
- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
130
- {
131
- settings ??= new OpenApiReaderSettings ( ) ;
132
- using var reader = new StringReader ( input ) ;
133
- return Read < T > ( reader , version , out diagnostic , settings ) ;
134
- }
135
-
136
- private async Task < Stream > GetStream ( string url )
137
- {
138
- Stream stream ;
139
- if ( url . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase ) || url . StartsWith ( "https" , StringComparison . OrdinalIgnoreCase ) )
140
- {
141
- try
142
- {
143
- stream = await _httpClient . GetStreamAsync ( new Uri ( url ) ) ;
144
- }
145
- catch ( HttpRequestException ex )
146
- {
147
- throw new InvalidOperationException ( $ "Could not download the file at { url } ", ex ) ;
148
- }
149
- }
150
- else
151
- {
152
- try
153
- {
154
- var fileInput = new FileInfo ( url ) ;
155
- stream = fileInput . OpenRead ( ) ;
156
- }
157
- catch ( Exception ex ) when (
158
- ex is
159
- FileNotFoundException or
160
- PathTooLongException or
161
- DirectoryNotFoundException or
162
- IOException or
163
- UnauthorizedAccessException or
164
- SecurityException or
165
- NotSupportedException )
166
- {
167
- throw new InvalidOperationException ( $ "Could not open the file at { url } ", ex ) ;
168
- }
169
- }
170
-
171
- return stream ;
172
- }
173
94
}
174
95
}
0 commit comments