Skip to content

Commit 83b5d87

Browse files
Small readers optimization
1 parent 578e587 commit 83b5d87

File tree

4 files changed

+198
-148
lines changed

4 files changed

+198
-148
lines changed
Lines changed: 6 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4-
using System;
54
using System.IO;
6-
using System.Linq;
7-
using Microsoft.OpenApi.Exceptions;
8-
using Microsoft.OpenApi.Extensions;
95
using Microsoft.OpenApi.Interfaces;
106
using Microsoft.OpenApi.Models;
117
using Microsoft.OpenApi.Readers.Interface;
12-
using Microsoft.OpenApi.Readers.Services;
13-
using Microsoft.OpenApi.Services;
14-
using SharpYaml;
15-
using SharpYaml.Serialization;
168

179
namespace Microsoft.OpenApi.Readers
1810
{
@@ -21,7 +13,7 @@ namespace Microsoft.OpenApi.Readers
2113
/// </summary>
2214
public class OpenApiStreamReader : IOpenApiReader<Stream, OpenApiDiagnostic>
2315
{
24-
private OpenApiReaderSettings _settings;
16+
private readonly OpenApiReaderSettings _settings;
2517

2618
/// <summary>
2719
/// Create stream reader with custom settings if desired.
@@ -30,8 +22,8 @@ public class OpenApiStreamReader : IOpenApiReader<Stream, OpenApiDiagnostic>
3022
public OpenApiStreamReader(OpenApiReaderSettings settings = null)
3123
{
3224
_settings = settings ?? new OpenApiReaderSettings();
33-
3425
}
26+
3527
/// <summary>
3628
/// Reads the stream input and parses it into an Open API document.
3729
/// </summary>
@@ -40,68 +32,10 @@ public OpenApiStreamReader(OpenApiReaderSettings settings = null)
4032
/// <returns>Instance of newly created OpenApiDocument</returns>
4133
public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
4234
{
43-
ParsingContext context;
44-
YamlDocument yamlDocument;
45-
diagnostic = new OpenApiDiagnostic();
46-
47-
// Parse the YAML/JSON
48-
try
49-
{
50-
yamlDocument = LoadYamlDocument(input);
51-
}
52-
catch (YamlException ex)
53-
{
54-
diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message));
55-
return new OpenApiDocument();
56-
}
57-
58-
context = new ParsingContext
59-
{
60-
ExtensionParsers = _settings.ExtensionParsers,
61-
BaseUrl = _settings.BaseUrl
62-
};
63-
64-
OpenApiDocument document = null;
65-
66-
try
67-
{
68-
// Parse the OpenAPI Document
69-
document = context.Parse(yamlDocument, diagnostic);
70-
71-
// Resolve References if requested
72-
switch (_settings.ReferenceResolution)
73-
{
74-
case ReferenceResolutionSetting.ResolveAllReferences:
75-
throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously);
76-
case ReferenceResolutionSetting.ResolveLocalReferences:
77-
var resolver = new OpenApiReferenceResolver(document);
78-
var walker = new OpenApiWalker(resolver);
79-
walker.Walk(document);
80-
foreach (var item in resolver.Errors)
81-
{
82-
diagnostic.Errors.Add(item);
83-
}
84-
break;
85-
case ReferenceResolutionSetting.DoNotResolveReferences:
86-
break;
87-
}
88-
}
89-
catch (OpenApiException ex)
90-
{
91-
diagnostic.Errors.Add(new OpenApiError(ex));
92-
}
93-
94-
// Validate the document
95-
if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
35+
using (var reader = new StreamReader(input))
9636
{
97-
var errors = document.Validate(_settings.RuleSet);
98-
foreach (var item in errors)
99-
{
100-
diagnostic.Errors.Add(item);
101-
}
37+
return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
10238
}
103-
104-
return document;
10539
}
10640

10741
/// <summary>
@@ -113,66 +47,10 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
11347
/// <returns>Instance of newly created OpenApiDocument</returns>
11448
public T ReadFragment<T>(Stream input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
11549
{
116-
ParsingContext context;
117-
YamlDocument yamlDocument;
118-
diagnostic = new OpenApiDiagnostic();
119-
120-
// Parse the YAML/JSON
121-
try
122-
{
123-
yamlDocument = LoadYamlDocument(input);
124-
}
125-
catch (YamlException ex)
126-
{
127-
diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message));
128-
return default(T);
129-
}
130-
131-
context = new ParsingContext
132-
{
133-
ExtensionParsers = _settings.ExtensionParsers
134-
};
135-
136-
IOpenApiElement element = null;
137-
138-
try
139-
{
140-
// Parse the OpenAPI element
141-
element = context.ParseFragment<T>(yamlDocument, version, diagnostic);
142-
}
143-
catch (OpenApiException ex)
144-
{
145-
diagnostic.Errors.Add(new OpenApiError(ex));
146-
}
147-
148-
// Validate the element
149-
if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
150-
{
151-
var errors = element.Validate(_settings.RuleSet);
152-
foreach (var item in errors)
153-
{
154-
diagnostic.Errors.Add(item);
155-
}
156-
}
157-
158-
return (T)element;
159-
}
160-
161-
/// <summary>
162-
/// Helper method to turn streams into YamlDocument
163-
/// </summary>
164-
/// <param name="input">Stream containing YAML formatted text</param>
165-
/// <returns>Instance of a YamlDocument</returns>
166-
internal static YamlDocument LoadYamlDocument(Stream input)
167-
{
168-
YamlDocument yamlDocument;
169-
using (var streamReader = new StreamReader(input))
50+
using (var reader = new StreamReader(input))
17051
{
171-
var yamlStream = new YamlStream();
172-
yamlStream.Load(streamReader);
173-
yamlDocument = yamlStream.Documents.First();
52+
return new OpenApiTextReaderReader(_settings).ReadFragment<T>(reader, version, out diagnostic);
17453
}
175-
return yamlDocument;
17654
}
17755
}
17856
}

src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,9 @@ public OpenApiStringReader(OpenApiReaderSettings settings = null)
2929
/// </summary>
3030
public OpenApiDocument Read(string input, out OpenApiDiagnostic diagnostic)
3131
{
32-
using (var memoryStream = new MemoryStream())
32+
using (var reader = new StringReader(input))
3333
{
34-
var writer = new StreamWriter(memoryStream);
35-
writer.Write(input);
36-
writer.Flush();
37-
memoryStream.Position = 0;
38-
39-
return new OpenApiStreamReader(_settings).Read(memoryStream, out diagnostic);
34+
return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
4035
}
4136
}
4237

@@ -45,14 +40,9 @@ public OpenApiDocument Read(string input, out OpenApiDiagnostic diagnostic)
4540
/// </summary>
4641
public T ReadFragment<T>(string input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
4742
{
48-
using (var memoryStream = new MemoryStream())
43+
using (var reader = new StringReader(input))
4944
{
50-
var writer = new StreamWriter(memoryStream);
51-
writer.Write(input);
52-
writer.Flush();
53-
memoryStream.Position = 0;
54-
55-
return new OpenApiStreamReader(_settings).ReadFragment<T>(memoryStream, version, out diagnostic);
45+
return new OpenApiTextReaderReader(_settings).ReadFragment<T>(reader, version, out diagnostic);
5646
}
5747
}
5848
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using System.Linq;
7+
using Microsoft.OpenApi.Exceptions;
8+
using Microsoft.OpenApi.Extensions;
9+
using Microsoft.OpenApi.Interfaces;
10+
using Microsoft.OpenApi.Models;
11+
using Microsoft.OpenApi.Readers.Interface;
12+
using Microsoft.OpenApi.Readers.Services;
13+
using Microsoft.OpenApi.Services;
14+
using SharpYaml;
15+
using SharpYaml.Serialization;
16+
17+
namespace Microsoft.OpenApi.Readers
18+
{
19+
/// <summary>
20+
/// Service class for converting contents of TextReader into OpenApiDocument instances
21+
/// </summary>
22+
public class OpenApiTextReaderReader : IOpenApiReader<TextReader, OpenApiDiagnostic>
23+
{
24+
private readonly OpenApiReaderSettings _settings;
25+
26+
/// <summary>
27+
/// Create stream reader with custom settings if desired.
28+
/// </summary>
29+
/// <param name="settings"></param>
30+
public OpenApiTextReaderReader(OpenApiReaderSettings settings = null)
31+
{
32+
_settings = settings ?? new OpenApiReaderSettings();
33+
}
34+
35+
/// <summary>
36+
/// Reads the stream input and parses it into an Open API document.
37+
/// </summary>
38+
/// <param name="input">TextReader containing OpenAPI description to parse.</param>
39+
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
40+
/// <returns>Instance of newly created OpenApiDocument</returns>
41+
public OpenApiDocument Read(TextReader input, out OpenApiDiagnostic diagnostic)
42+
{
43+
ParsingContext context;
44+
YamlDocument yamlDocument;
45+
diagnostic = new OpenApiDiagnostic();
46+
47+
// Parse the YAML/JSON
48+
try
49+
{
50+
yamlDocument = LoadYamlDocument(input);
51+
}
52+
catch (YamlException ex)
53+
{
54+
diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message));
55+
return new OpenApiDocument();
56+
}
57+
58+
context = new ParsingContext
59+
{
60+
ExtensionParsers = _settings.ExtensionParsers,
61+
BaseUrl = _settings.BaseUrl
62+
};
63+
64+
OpenApiDocument document = null;
65+
66+
try
67+
{
68+
// Parse the OpenAPI Document
69+
document = context.Parse(yamlDocument, diagnostic);
70+
71+
// Resolve References if requested
72+
switch (_settings.ReferenceResolution)
73+
{
74+
case ReferenceResolutionSetting.ResolveAllReferences:
75+
throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously);
76+
case ReferenceResolutionSetting.ResolveLocalReferences:
77+
var resolver = new OpenApiReferenceResolver(document);
78+
var walker = new OpenApiWalker(resolver);
79+
walker.Walk(document);
80+
foreach (var item in resolver.Errors)
81+
{
82+
diagnostic.Errors.Add(item);
83+
}
84+
break;
85+
case ReferenceResolutionSetting.DoNotResolveReferences:
86+
break;
87+
}
88+
}
89+
catch (OpenApiException ex)
90+
{
91+
diagnostic.Errors.Add(new OpenApiError(ex));
92+
}
93+
94+
// Validate the document
95+
if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
96+
{
97+
var errors = document.Validate(_settings.RuleSet);
98+
foreach (var item in errors)
99+
{
100+
diagnostic.Errors.Add(item);
101+
}
102+
}
103+
104+
return document;
105+
}
106+
/// <summary>
107+
/// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
108+
/// </summary>
109+
/// <param name="input">TextReader containing OpenAPI description to parse.</param>
110+
/// <param name="version">Version of the OpenAPI specification that the fragment conforms to.</param>
111+
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
112+
/// <returns>Instance of newly created OpenApiDocument</returns>
113+
public T ReadFragment<T>(TextReader input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
114+
{
115+
ParsingContext context;
116+
YamlDocument yamlDocument;
117+
diagnostic = new OpenApiDiagnostic();
118+
119+
// Parse the YAML/JSON
120+
try
121+
{
122+
yamlDocument = LoadYamlDocument(input);
123+
}
124+
catch (YamlException ex)
125+
{
126+
diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message));
127+
return default(T);
128+
}
129+
130+
context = new ParsingContext
131+
{
132+
ExtensionParsers = _settings.ExtensionParsers
133+
};
134+
135+
IOpenApiElement element = null;
136+
137+
try
138+
{
139+
// Parse the OpenAPI element
140+
element = context.ParseFragment<T>(yamlDocument, version, diagnostic);
141+
}
142+
catch (OpenApiException ex)
143+
{
144+
diagnostic.Errors.Add(new OpenApiError(ex));
145+
}
146+
147+
// Validate the element
148+
if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
149+
{
150+
var errors = element.Validate(_settings.RuleSet);
151+
foreach (var item in errors)
152+
{
153+
diagnostic.Errors.Add(item);
154+
}
155+
}
156+
157+
return (T)element;
158+
}
159+
160+
/// <summary>
161+
/// Helper method to turn streams into YamlDocument
162+
/// </summary>
163+
/// <param name="input">Stream containing YAML formatted text</param>
164+
/// <returns>Instance of a YamlDocument</returns>
165+
static YamlDocument LoadYamlDocument(TextReader input)
166+
{
167+
var yamlStream = new YamlStream();
168+
yamlStream.Load(input);
169+
return yamlStream.Documents.First();
170+
}
171+
}
172+
}

0 commit comments

Comments
 (0)