diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..49de0d370
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,123 @@
+# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
+###############################
+# Core EditorConfig Options #
+###############################
+# All files
+[*]
+indent_style = space
+# Code files
+[*.{cs,csx,vb,vbx}]
+indent_size = 4
+insert_final_newline = true
+charset = utf-8-bom
+###############################
+# .NET Coding Conventions #
+###############################
+[*.{cs,vb}]
+# Organize usings
+dotnet_sort_system_directives_first = true
+# this. preferences
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_readonly_field = true:suggestion
+# Expression-level preferences
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+###############################
+# Naming Conventions #
+###############################
+# Style Definitions
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+# Use PascalCase for constant fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+###############################
+# C# Coding Conventions #
+###############################
+[*.cs]
+# var preferences
+csharp_style_var_for_built_in_types = true:silent
+csharp_style_var_when_type_is_apparent = true:silent
+csharp_style_var_elsewhere = true:silent
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+# Pattern matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+# Null-checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+# Modifier preferences
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+# Expression-level preferences
+csharp_prefer_braces = true:silent
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+###############################
+# C# Formatting Rules #
+###############################
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+# Indentation preferences
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+# Wrapping preferences
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
+###############################
+# VB Coding Conventions #
+###############################
+[*.vb]
+# Modifier preferences
+visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
diff --git a/Microsoft.OpenApi.sln b/Microsoft.OpenApi.sln
index d957905d4..e64ff3a24 100644
--- a/Microsoft.OpenApi.sln
+++ b/Microsoft.OpenApi.sln
@@ -1,12 +1,13 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2027
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi", "src\Microsoft.OpenApi\Microsoft.OpenApi.csproj", "{A8E50143-69B2-472A-9D45-3F9A05D13202}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4AEDAD90-F854-4940-BFEE-6374CC92CAB0}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
build.cmd = build.cmd
readme.md = readme.md
EndProjectSection
@@ -25,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6357D7FD-2
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.SmokeTests", "test\Microsoft.OpenApi.SmokeTests\Microsoft.OpenApi.SmokeTests.csproj", "{AD79B61D-88CF-497C-9ED5-41AE3867C5AC}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Tool", "src\Microsoft.OpenApi.Tool\Microsoft.OpenApi.Tool.csproj", "{254841B5-7DAC-4D1D-A9C5-44FE5CE467BE}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -55,6 +58,10 @@ Global
{AD79B61D-88CF-497C-9ED5-41AE3867C5AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD79B61D-88CF-497C-9ED5-41AE3867C5AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD79B61D-88CF-497C-9ED5-41AE3867C5AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {254841B5-7DAC-4D1D-A9C5-44FE5CE467BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {254841B5-7DAC-4D1D-A9C5-44FE5CE467BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {254841B5-7DAC-4D1D-A9C5-44FE5CE467BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {254841B5-7DAC-4D1D-A9C5-44FE5CE467BE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -66,6 +73,7 @@ Global
{AD83F991-DBF3-4251-8613-9CC54C826964} = {6357D7FD-2DE4-4900-ADB9-ABC37052040A}
{1ED3C2C1-E1E7-4925-B4E6-2D969C3F5237} = {6357D7FD-2DE4-4900-ADB9-ABC37052040A}
{AD79B61D-88CF-497C-9ED5-41AE3867C5AC} = {6357D7FD-2DE4-4900-ADB9-ABC37052040A}
+ {254841B5-7DAC-4D1D-A9C5-44FE5CE467BE} = {E546B92F-20A8-49C3-8323-4B25BB78F3E1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F171EFC-0DB5-4B10-ABFA-AF48D52CC565}
diff --git a/README.md b/README.md
index 36fd15dbc..bce79b6a3 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,11 @@ Project Objectives
- Provide OpenAPI description writers for both V2 and V3 specification formats.
- Enable developers to create Readers that translate different data formats into OpenAPI descriptions.
+# Installation
+
+- Install core Nuget package `Microsoft.OpenApi`
+- Install readers Nuget package `Microsoft.OpenApi.Readers`
+
# Processors
The OpenAPI.NET project holds the base object model for representing OpenAPI documents as .NET objects. Some developers have found the need to write processors that convert other data formats into this OpenAPI.NET object model. We'd like to curate that list of processors in this section of the readme.
diff --git a/build.cmd b/build.cmd
index cbae2cb0e..3c65e48bd 100644
--- a/build.cmd
+++ b/build.cmd
@@ -1,21 +1,17 @@
@echo off
-if "%~1"=="" goto :error
-
-SET VERSION=%~1
-
-Echo Building Microsoft.OpenApi
+Echo Building Microsoft.OpenApi
SET PROJ=%~dp0src\Microsoft.OpenApi\Microsoft.OpenApi.csproj
-dotnet build %PROJ% /t:restore /p:Configuration=Release
-dotnet build %PROJ% /t:build /p:Configuration=Release
-dotnet build %PROJ% /t:pack /p:Configuration=Release;PackageOutputPath=%~dp0artifacts;Version=%VERSION%
+dotnet msbuild %PROJ% /t:restore /p:Configuration=Release
+dotnet msbuild %PROJ% /t:build /p:Configuration=Release
+dotnet msbuild %PROJ% /t:pack /p:Configuration=Release;PackageOutputPath=%~dp0artifacts
Echo Building Microsoft.OpenApi.Readers
SET PROJ=%~dp0src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj
-dotnet build %PROJ% /t:restore /p:Configuration=Release
-dotnet build %PROJ% /t:build /p:Configuration=Release
-dotnet build %PROJ% /t:pack /p:Configuration=Release;PackageOutputPath=%~dp0artifacts;Version=%VERSION%
+dotnet msbuild %PROJ% /t:restore /p:Configuration=Release
+dotnet msbuild %PROJ% /t:build /p:Configuration=Release
+dotnet msbuild %PROJ% /t:pack /p:Configuration=Release;PackageOutputPath=%~dp0artifacts
goto :end
:error
diff --git a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs b/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs
index ee829d6b3..03f80c93e 100644
--- a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs
+++ b/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs
@@ -33,7 +33,7 @@ public OpenApiReaderException(string message, YamlNode node) : base(message)
{
// This only includes line because using a char range causes tests to break due to CR/LF & LF differences
// See https://tools.ietf.org/html/rfc5147 for syntax
- Pointer = $"#line={node.Start.Line}";
+ Pointer = $"#line={node.Start.Line}";
}
///
@@ -43,4 +43,4 @@ public OpenApiReaderException(string message, YamlNode node) : base(message)
/// Inner exception that caused this exception to be thrown.
public OpenApiReaderException(string message, Exception innerException) : base(message, innerException) { }
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs b/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs
index 199020784..705b212d0 100644
--- a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs
+++ b/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs
@@ -41,4 +41,4 @@ public OpenApiUnsupportedSpecVersionException(string specificationVersion, Excep
///
public string SpecificationVersion { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs b/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs
index 22d31e7a7..da3381f7e 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs
+++ b/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs
@@ -9,4 +9,4 @@ namespace Microsoft.OpenApi.Readers.Interface
public interface IDiagnostic
{
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs b/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs
index 170cde6fb..39724b3c6 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs
+++ b/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs
@@ -20,4 +20,4 @@ public interface IOpenApiReader where TDiagnostic : IDiagno
/// The Open API document.
OpenApiDocument Read(TInput input, out TDiagnostic diagnostic);
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs b/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs
index 32dd420f4..a7a98d781 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs
+++ b/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs
@@ -37,4 +37,4 @@ internal interface IOpenApiVersionService
/// Instance of OpenApiDocument populated with data from rootNode
OpenApiDocument LoadDocument(RootNode rootNode);
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
index f519fd340..931d296ac 100644
--- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
+++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
@@ -10,7 +10,7 @@
Microsoft
Microsoft.OpenApi.Readers
Microsoft.OpenApi.Readers
- 1.1.4
+ 1.2.0
OpenAPI.NET Readers for JSON and YAML documents
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
@@ -26,7 +26,7 @@
-
+
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiDiagnostic.cs b/src/Microsoft.OpenApi.Readers/OpenApiDiagnostic.cs
index cd3258eaa..ea11c7939 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiDiagnostic.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiDiagnostic.cs
@@ -22,4 +22,4 @@ public class OpenApiDiagnostic : IDiagnostic
///
public OpenApiSpecVersion SpecificationVersion { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs b/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
index 1b1c2f367..092699857 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
@@ -1,4 +1,7 @@
-using Microsoft.OpenApi.Any;
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Readers.ParseNodes;
using Microsoft.OpenApi.Validations;
@@ -42,7 +45,7 @@ public class OpenApiReaderSettings
///
/// Dictionary of parsers for converting extensions into strongly typed classes
///
- public Dictionary> ExtensionParsers { get; set; } = new Dictionary>();
+ public Dictionary> ExtensionParsers { get; set; } = new Dictionary>();
///
/// Rules to use for validating OpenAPI specification. If none are provided a default set of rules are applied.
@@ -52,6 +55,6 @@ public class OpenApiReaderSettings
///
/// URL where relative references should be resolved from if the description does not contain Server definitions
///
- public Uri BaseUrl { get; set; }
+ public Uri BaseUrl { get; set; }
}
}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs
index 1e0c08695..9dc14a7bd 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs
@@ -1,18 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-using System;
using System.IO;
-using System.Linq;
-using Microsoft.OpenApi.Exceptions;
-using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers.Interface;
-using Microsoft.OpenApi.Readers.Services;
-using Microsoft.OpenApi.Services;
-using SharpYaml;
-using SharpYaml.Serialization;
namespace Microsoft.OpenApi.Readers
{
@@ -21,7 +13,7 @@ namespace Microsoft.OpenApi.Readers
///
public class OpenApiStreamReader : IOpenApiReader
{
- private OpenApiReaderSettings _settings;
+ private readonly OpenApiReaderSettings _settings;
///
/// Create stream reader with custom settings if desired.
@@ -30,8 +22,8 @@ public class OpenApiStreamReader : IOpenApiReader
public OpenApiStreamReader(OpenApiReaderSettings settings = null)
{
_settings = settings ?? new OpenApiReaderSettings();
-
}
+
///
/// Reads the stream input and parses it into an Open API document.
///
@@ -40,68 +32,10 @@ public OpenApiStreamReader(OpenApiReaderSettings settings = null)
/// Instance of newly created OpenApiDocument
public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
{
- ParsingContext context;
- YamlDocument yamlDocument;
- diagnostic = new OpenApiDiagnostic();
-
- // Parse the YAML/JSON
- try
- {
- yamlDocument = LoadYamlDocument(input);
- }
- catch (YamlException ex)
- {
- diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message));
- return new OpenApiDocument();
- }
-
- context = new ParsingContext
- {
- ExtensionParsers = _settings.ExtensionParsers,
- BaseUrl = _settings.BaseUrl
- };
-
- OpenApiDocument document = null;
-
- try
- {
- // Parse the OpenAPI Document
- document = context.Parse(yamlDocument, diagnostic);
-
- // Resolve References if requested
- switch (_settings.ReferenceResolution)
- {
- case ReferenceResolutionSetting.ResolveAllReferences:
- throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously);
- case ReferenceResolutionSetting.ResolveLocalReferences:
- var resolver = new OpenApiReferenceResolver(document);
- var walker = new OpenApiWalker(resolver);
- walker.Walk(document);
- foreach (var item in resolver.Errors)
- {
- diagnostic.Errors.Add(item);
- }
- break;
- case ReferenceResolutionSetting.DoNotResolveReferences:
- break;
- }
- }
- catch (OpenApiException ex)
- {
- diagnostic.Errors.Add(new OpenApiError(ex));
- }
-
- // Validate the document
- if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
+ using (var reader = new StreamReader(input))
{
- var errors = document.Validate(_settings.RuleSet);
- foreach (var item in errors)
- {
- diagnostic.Errors.Add(item);
- }
+ return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
}
-
- return document;
}
///
@@ -113,66 +47,10 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
/// Instance of newly created OpenApiDocument
public T ReadFragment(Stream input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
{
- ParsingContext context;
- YamlDocument yamlDocument;
- diagnostic = new OpenApiDiagnostic();
-
- // Parse the YAML/JSON
- try
- {
- yamlDocument = LoadYamlDocument(input);
- }
- catch (YamlException ex)
- {
- diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message));
- return default(T);
- }
-
- context = new ParsingContext
- {
- ExtensionParsers = _settings.ExtensionParsers
- };
-
- IOpenApiElement element = null;
-
- try
- {
- // Parse the OpenAPI element
- element = context.ParseFragment(yamlDocument, version, diagnostic);
- }
- catch (OpenApiException ex)
- {
- diagnostic.Errors.Add(new OpenApiError(ex));
- }
-
- // Validate the element
- if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
- {
- var errors = element.Validate(_settings.RuleSet);
- foreach (var item in errors)
- {
- diagnostic.Errors.Add(item);
- }
- }
-
- return (T)element;
- }
-
- ///
- /// Helper method to turn streams into YamlDocument
- ///
- /// Stream containing YAML formatted text
- /// Instance of a YamlDocument
- internal static YamlDocument LoadYamlDocument(Stream input)
- {
- YamlDocument yamlDocument;
- using (var streamReader = new StreamReader(input))
+ using (var reader = new StreamReader(input))
{
- var yamlStream = new YamlStream();
- yamlStream.Load(streamReader);
- yamlDocument = yamlStream.Documents.First();
+ return new OpenApiTextReaderReader(_settings).ReadFragment(reader, version, out diagnostic);
}
- return yamlDocument;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs
index 82b3a3ce7..0cb9605dd 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs
@@ -29,14 +29,9 @@ public OpenApiStringReader(OpenApiReaderSettings settings = null)
///
public OpenApiDocument Read(string input, out OpenApiDiagnostic diagnostic)
{
- using (var memoryStream = new MemoryStream())
+ using (var reader = new StringReader(input))
{
- var writer = new StreamWriter(memoryStream);
- writer.Write(input);
- writer.Flush();
- memoryStream.Position = 0;
-
- return new OpenApiStreamReader(_settings).Read(memoryStream, out diagnostic);
+ return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
}
}
@@ -45,15 +40,10 @@ public OpenApiDocument Read(string input, out OpenApiDiagnostic diagnostic)
///
public T ReadFragment(string input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
{
- using (var memoryStream = new MemoryStream())
+ using (var reader = new StringReader(input))
{
- var writer = new StreamWriter(memoryStream);
- writer.Write(input);
- writer.Flush();
- memoryStream.Position = 0;
-
- return new OpenApiStreamReader(_settings).ReadFragment(memoryStream, version, out diagnostic);
+ return new OpenApiTextReaderReader(_settings).ReadFragment(reader, version, out diagnostic);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
new file mode 100644
index 000000000..107454796
--- /dev/null
+++ b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
@@ -0,0 +1,92 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.IO;
+using System.Linq;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Readers.Interface;
+using SharpYaml;
+using SharpYaml.Serialization;
+
+namespace Microsoft.OpenApi.Readers
+{
+ ///
+ /// Service class for converting contents of TextReader into OpenApiDocument instances
+ ///
+ public class OpenApiTextReaderReader : IOpenApiReader
+ {
+ private readonly OpenApiReaderSettings _settings;
+
+ ///
+ /// Create stream reader with custom settings if desired.
+ ///
+ ///
+ public OpenApiTextReaderReader(OpenApiReaderSettings settings = null)
+ {
+ _settings = settings ?? new OpenApiReaderSettings();
+ }
+
+ ///
+ /// Reads the stream input and parses it into an Open API document.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Returns diagnostic object containing errors detected during parsing
+ /// Instance of newly created OpenApiDocument
+ public OpenApiDocument Read(TextReader input, out OpenApiDiagnostic diagnostic)
+ {
+ YamlDocument yamlDocument;
+
+ // Parse the YAML/JSON text in the TextReader into the YamlDocument
+ try
+ {
+ yamlDocument = LoadYamlDocument(input);
+ }
+ catch (YamlException ex)
+ {
+ diagnostic = new OpenApiDiagnostic();
+ diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message));
+ return new OpenApiDocument();
+ }
+
+ return new OpenApiYamlDocumentReader(this._settings).Read(yamlDocument, out diagnostic);
+ }
+ ///
+ /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Version of the OpenAPI specification that the fragment conforms to.
+ /// Returns diagnostic object containing errors detected during parsing
+ /// Instance of newly created OpenApiDocument
+ public T ReadFragment(TextReader input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
+ {
+ YamlDocument yamlDocument;
+
+ // Parse the YAML/JSON
+ try
+ {
+ yamlDocument = LoadYamlDocument(input);
+ }
+ catch (YamlException ex)
+ {
+ diagnostic = new OpenApiDiagnostic();
+ diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message));
+ return default(T);
+ }
+
+ return new OpenApiYamlDocumentReader(this._settings).ReadFragment(yamlDocument, version, out diagnostic);
+ }
+
+ ///
+ /// Helper method to turn streams into YamlDocument
+ ///
+ /// Stream containing YAML formatted text
+ /// Instance of a YamlDocument
+ static YamlDocument LoadYamlDocument(TextReader input)
+ {
+ var yamlStream = new YamlStream();
+ yamlStream.Load(input);
+ return yamlStream.Documents.First();
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs
new file mode 100644
index 000000000..73a31eac3
--- /dev/null
+++ b/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs
@@ -0,0 +1,127 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using Microsoft.OpenApi.Exceptions;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Readers.Interface;
+using Microsoft.OpenApi.Readers.Services;
+using Microsoft.OpenApi.Services;
+using SharpYaml.Serialization;
+
+namespace Microsoft.OpenApi.Readers
+{
+ ///
+ /// Service class for converting contents of TextReader into OpenApiDocument instances
+ ///
+ internal class OpenApiYamlDocumentReader : IOpenApiReader
+ {
+ private readonly OpenApiReaderSettings _settings;
+
+ ///
+ /// Create stream reader with custom settings if desired.
+ ///
+ ///
+ public OpenApiYamlDocumentReader(OpenApiReaderSettings settings = null)
+ {
+ _settings = settings ?? new OpenApiReaderSettings();
+ }
+
+ ///
+ /// Reads the stream input and parses it into an Open API document.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Returns diagnostic object containing errors detected during parsing
+ /// Instance of newly created OpenApiDocument
+ public OpenApiDocument Read(YamlDocument input, out OpenApiDiagnostic diagnostic)
+ {
+ diagnostic = new OpenApiDiagnostic();
+ var context = new ParsingContext(diagnostic)
+ {
+ ExtensionParsers = _settings.ExtensionParsers,
+ BaseUrl = _settings.BaseUrl
+ };
+
+ OpenApiDocument document = null;
+ try
+ {
+ // Parse the OpenAPI Document
+ document = context.Parse(input);
+
+ // Resolve References if requested
+ switch (_settings.ReferenceResolution)
+ {
+ case ReferenceResolutionSetting.ResolveAllReferences:
+ throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously);
+ case ReferenceResolutionSetting.ResolveLocalReferences:
+ var resolver = new OpenApiReferenceResolver(document);
+ var walker = new OpenApiWalker(resolver);
+ walker.Walk(document);
+ foreach (var item in resolver.Errors)
+ {
+ diagnostic.Errors.Add(item);
+ }
+ break;
+ case ReferenceResolutionSetting.DoNotResolveReferences:
+ break;
+ }
+ }
+ catch (OpenApiException ex)
+ {
+ diagnostic.Errors.Add(new OpenApiError(ex));
+ }
+
+ // Validate the document
+ if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
+ {
+ var errors = document.Validate(_settings.RuleSet);
+ foreach (var item in errors)
+ {
+ diagnostic.Errors.Add(item);
+ }
+ }
+
+ return document;
+ }
+ ///
+ /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Version of the OpenAPI specification that the fragment conforms to.
+ /// Returns diagnostic object containing errors detected during parsing
+ /// Instance of newly created OpenApiDocument
+ public T ReadFragment(YamlDocument input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
+ {
+ diagnostic = new OpenApiDiagnostic();
+ var context = new ParsingContext(diagnostic)
+ {
+ ExtensionParsers = _settings.ExtensionParsers
+ };
+
+ IOpenApiElement element = null;
+ try
+ {
+ // Parse the OpenAPI element
+ element = context.ParseFragment(input, version);
+ }
+ catch (OpenApiException ex)
+ {
+ diagnostic.Errors.Add(new OpenApiError(ex));
+ }
+
+ // Validate the element
+ if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
+ {
+ var errors = element.Validate(_settings.RuleSet);
+ foreach (var item in errors)
+ {
+ diagnostic.Errors.Add(item);
+ }
+ }
+
+ return (T)element;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/AnyFieldMap.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/AnyFieldMap.cs
index ef11c448b..a135f7f02 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/AnyFieldMap.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/AnyFieldMap.cs
@@ -8,4 +8,4 @@ namespace Microsoft.OpenApi.Readers.ParseNodes
internal class AnyFieldMap : Dictionary>
{
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/AnyListFieldMap.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/AnyListFieldMap.cs
index acae8a976..dbc9eabeb 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/AnyListFieldMap.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/AnyListFieldMap.cs
@@ -9,4 +9,4 @@ internal class AnyListFieldMap : Dictionary : Dictionary : Dictionary>
{
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs
index de4d14aa3..d30863955 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs
@@ -53,4 +53,4 @@ public static YamlNode Find(this JsonPointer currentPointer, YamlNode baseYamlNo
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/ListNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/ListNode.cs
index ee3553ad4..e1149cc5a 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/ListNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/ListNode.cs
@@ -17,9 +17,8 @@ internal class ListNode : ParseNode, IEnumerable
{
private readonly YamlSequenceNode _nodeList;
- public ListNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlSequenceNode sequenceNode) : base(
- context,
- diagnostic)
+ public ListNode(ParsingContext context, YamlSequenceNode sequenceNode) : base(
+ context)
{
_nodeList = sequenceNode;
}
@@ -32,14 +31,14 @@ public override List CreateList(Func map)
$"Expected list at line {_nodeList.Start.Line} while parsing {typeof(T).Name}");
}
- return _nodeList.Select(n => map(new MapNode(Context, Diagnostic, n as YamlMappingNode)))
+ return _nodeList.Select(n => map(new MapNode(Context, n as YamlMappingNode)))
.Where(i => i != null)
.ToList();
}
public override List CreateListOfAny()
{
- return _nodeList.Select(n => ParseNode.Create(Context, Diagnostic,n).CreateAny())
+ return _nodeList.Select(n => ParseNode.Create(Context, n).CreateAny())
.Where(i => i != null)
.ToList();
}
@@ -52,12 +51,12 @@ public override List CreateSimpleList(Func map)
$"Expected list at line {_nodeList.Start.Line} while parsing {typeof(T).Name}");
}
- return _nodeList.Select(n => map(new ValueNode(Context, Diagnostic, n))).ToList();
+ return _nodeList.Select(n => map(new ValueNode(Context, n))).ToList();
}
public IEnumerator GetEnumerator()
{
- return _nodeList.Select(n => Create(Context, Diagnostic, n)).ToList().GetEnumerator();
+ return _nodeList.Select(n => Create(Context, n)).ToList().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
@@ -80,4 +79,4 @@ public override IOpenApiAny CreateAny()
return array;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs
index 95aa4ff62..26fc81076 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs
@@ -23,14 +23,13 @@ internal class MapNode : ParseNode, IEnumerable
private readonly YamlMappingNode _node;
private readonly List _nodes;
- public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, string yamlString) :
- this(context, diagnostic, (YamlMappingNode)YamlHelper.ParseYamlString(yamlString))
+ public MapNode(ParsingContext context, string yamlString) :
+ this(context, (YamlMappingNode)YamlHelper.ParseYamlString(yamlString))
{
}
- public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node) : base(
- context,
- diagnostic)
+ public MapNode(ParsingContext context, YamlNode node) : base(
+ context)
{
if (!(node is YamlMappingNode mapNode))
{
@@ -40,7 +39,7 @@ public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode no
this._node = mapNode;
_nodes = this._node.Children
- .Select(kvp => new PropertyNode(Context, Diagnostic, kvp.Key.GetScalarValue(), kvp.Value))
+ .Select(kvp => new PropertyNode(Context, kvp.Key.GetScalarValue(), kvp.Value))
.Cast()
.ToList();
}
@@ -52,7 +51,7 @@ public PropertyNode this[string key]
YamlNode node = null;
if (this._node.Children.TryGetValue(new YamlScalarNode(key), out node))
{
- return new PropertyNode(Context, Diagnostic, key, this._node.Children[new YamlScalarNode(key)]);
+ return new PropertyNode(Context, key, this._node.Children[new YamlScalarNode(key)]);
}
return null;
@@ -73,43 +72,48 @@ public override Dictionary CreateMap(Func map)
key = n.Key.GetScalarValue(),
value = n.Value as YamlMappingNode == null
? default(T)
- : map(new MapNode(Context, Diagnostic, n.Value as YamlMappingNode))
+ : map(new MapNode(Context, n.Value as YamlMappingNode))
});
return nodes.ToDictionary(k => k.key, v => v.value);
}
- public override Dictionary CreateMapWithReference(
- ReferenceType referenceType,
- Func map)
- {
- var yamlMap = _node;
- if (yamlMap == null)
- {
- throw new OpenApiException($"Expected map at line {yamlMap.Start.Line} while parsing {typeof(T).Name}");
- }
-
- var nodes = yamlMap.Select(
- n => {
- var entry = new
- {
- key = n.Key.GetScalarValue(),
- value = map(new MapNode(Context, Diagnostic, (YamlMappingNode)n.Value))
- };
- if (entry.value == null)
- {
- return null; // Body Parameters shouldn't be converted to Parameters
- }
- entry.value.Reference = new OpenApiReference()
- {
- Type = referenceType,
- Id = entry.key
- };
- return entry;
- }
- );
- return nodes.Where(n => n!= null).ToDictionary(k => k.key, v => v.value);
- }
+ public override Dictionary CreateMapWithReference(
+ ReferenceType referenceType,
+ Func map)
+ {
+ var yamlMap = _node;
+ if (yamlMap == null)
+ {
+ throw new OpenApiException($"Expected map at line {yamlMap.Start.Line} while parsing {typeof(T).Name}");
+ }
+
+ var nodes = yamlMap.Select(
+ n =>
+ {
+ var entry = new
+ {
+ key = n.Key.GetScalarValue(),
+ value = map(new MapNode(Context, (YamlMappingNode)n.Value))
+ };
+ if (entry.value == null)
+ {
+ return null; // Body Parameters shouldn't be converted to Parameters
+ }
+ // If the component isn't a reference to another component, then point it to itself.
+ if (entry.value.Reference == null)
+ {
+ entry.value.Reference = new OpenApiReference()
+ {
+ Type = referenceType,
+ Id = entry.key
+ };
+ }
+ return entry;
+ }
+ );
+ return nodes.Where(n => n != null).ToDictionary(k => k.key, v => v.value);
+ }
public override Dictionary CreateSimpleMap(Func map)
{
@@ -123,7 +127,7 @@ public override Dictionary CreateSimpleMap(Func map)
n => new
{
key = n.Key.GetScalarValue(),
- value = map(new ValueNode(Context, Diagnostic, (YamlScalarNode)n.Value))
+ value = map(new ValueNode(Context, (YamlScalarNode)n.Value))
});
return nodes.ToDictionary(k => k.key, v => v.value);
}
@@ -140,7 +144,7 @@ IEnumerator IEnumerable.GetEnumerator()
public override string GetRaw()
{
- var x = new Serializer(new SerializerSettings(new JsonSchema()) {EmitJsonComptible = true});
+ var x = new Serializer(new SerializerSettings(new JsonSchema()) { EmitJsonComptible = true });
return x.Serialize(_node);
}
@@ -148,10 +152,10 @@ public T GetReferencedObject(ReferenceType referenceType, string referenceId)
where T : IOpenApiReferenceable, new()
{
return new T()
- {
- UnresolvedReference = true,
- Reference = Context.VersionService.ConvertToOpenApiReference(referenceId,referenceType)
- };
+ {
+ UnresolvedReference = true,
+ Reference = Context.VersionService.ConvertToOpenApiReference(referenceId, referenceType)
+ };
}
public string GetReferencePointer()
@@ -192,4 +196,4 @@ public override IOpenApiAny CreateAny()
return apiObject;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs
index 50ec431cc..ae9254fe8 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs
@@ -6,7 +6,6 @@
using System.Linq;
using System.Text;
using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
namespace Microsoft.OpenApi.Readers.ParseNodes
@@ -15,16 +14,18 @@ internal static class OpenApiAnyConverter
{
///
/// Converts the s in the given
- /// into the most specific type based on the value.
+ /// into the appropriate type based on the given .
+ /// For those strings that the schema does not specify the type for, convert them into
+ /// the most specific type based on the value.
///
- public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny)
+ public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiSchema schema = null)
{
if (openApiAny is OpenApiArray openApiArray)
{
var newArray = new OpenApiArray();
foreach (var element in openApiArray)
{
- newArray.Add(GetSpecificOpenApiAny(element));
+ newArray.Add(GetSpecificOpenApiAny(element, schema?.Items));
}
return newArray;
@@ -36,223 +37,232 @@ public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny)
foreach (var key in openApiObject.Keys.ToList())
{
- newObject[key] = GetSpecificOpenApiAny(openApiObject[key]);
+ if (schema?.Properties != null && schema.Properties.TryGetValue(key, out var property))
+ {
+ newObject[key] = GetSpecificOpenApiAny(openApiObject[key], property);
+ }
+ else
+ {
+ newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema?.AdditionalProperties);
+ }
}
return newObject;
}
- if ( !(openApiAny is OpenApiString))
+ if (!(openApiAny is OpenApiString))
{
return openApiAny;
}
var value = ((OpenApiString)openApiAny).Value;
+ var type = schema?.Type;
+ var format = schema?.Format;
- if (value == null || value == "null")
- {
- return new OpenApiNull();
- }
-
- if (value == "true")
- {
- return new OpenApiBoolean(true);
- }
-
- if (value == "false")
- {
- return new OpenApiBoolean(false);
- }
-
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new OpenApiInteger(intValue);
- }
-
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
- {
- return new OpenApiLong(longValue);
- }
-
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new OpenApiDouble(doubleValue);
- }
-
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
+ if (((OpenApiString)openApiAny).IsExplicit())
{
- return new OpenApiDateTime(dateTimeValue);
- }
-
- // if we can't identify the type of value, return it as string.
- return new OpenApiString(value);
- }
-
- ///
- /// Converts the s in the given
- /// into the appropriate type based on the given .
- /// For those strings that the schema does not specify the type for, convert them into
- /// the most specific type based on the value.
- ///
- public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiSchema schema)
- {
- if (openApiAny is OpenApiArray openApiArray)
- {
- var newArray = new OpenApiArray();
- foreach (var element in openApiArray)
+ // More narrow type detection for explicit strings, only check types that are passed as strings
+ if (schema == null)
{
- newArray.Add(GetSpecificOpenApiAny(element, schema?.Items));
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
+ {
+ return new OpenApiDateTime(dateTimeValue);
+ }
}
+ else if (type == "string")
+ {
+ if (format == "byte")
+ {
+ try
+ {
+ return new OpenApiByte(Convert.FromBase64String(value));
+ }
+ catch (FormatException)
+ { }
+ }
- return newArray;
- }
+ if (format == "binary")
+ {
+ try
+ {
+ return new OpenApiBinary(Encoding.UTF8.GetBytes(value));
+ }
+ catch (EncoderFallbackException)
+ { }
+ }
- if (openApiAny is OpenApiObject openApiObject)
- {
- var newObject = new OpenApiObject();
+ if (format == "date")
+ {
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
+ {
+ return new OpenApiDate(dateValue.Date);
+ }
+ }
- foreach (var key in openApiObject.Keys.ToList())
- {
- if ( schema != null && schema.Properties != null && schema.Properties.ContainsKey(key) )
+ if (format == "date-time")
{
- newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema.Properties[key]);
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
+ {
+ return new OpenApiDateTime(dateTimeValue);
+ }
}
- else
+
+ if (format == "password")
{
- newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema?.AdditionalProperties);
+ return new OpenApiPassword(value);
}
}
- return newObject;
- }
-
- if (!(openApiAny is OpenApiString))
- {
return openApiAny;
}
- if (schema?.Type == null)
- {
- return GetSpecificOpenApiAny(openApiAny);
- }
-
- var type = schema.Type;
- var format = schema.Format;
-
- var value = ((OpenApiString)openApiAny).Value;
-
if (value == null || value == "null")
{
return new OpenApiNull();
}
- if (type == "integer" && format == "int32")
+ if (schema?.Type == null)
{
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+ if (value == "true")
{
- return new OpenApiInteger(intValue);
+ return new OpenApiBoolean(true);
}
- }
- if (type == "integer" && format == "int64")
- {
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
+ if (value == "false")
{
- return new OpenApiLong(longValue);
+ return new OpenApiBoolean(false);
}
- }
- if (type == "integer")
- {
if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
{
return new OpenApiInteger(intValue);
}
- }
- if (type == "number" && format == "float")
- {
- if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
+ if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
{
- return new OpenApiFloat(floatValue);
+ return new OpenApiLong(longValue);
}
- }
- if (type == "number" && format == "double" )
- {
if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
{
return new OpenApiDouble(doubleValue);
}
- }
- if (type == "number")
- {
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
{
- return new OpenApiDouble(doubleValue);
+ return new OpenApiDateTime(dateTimeValue);
}
}
-
- if (type == "string" && format == "byte")
+ else
{
- try
+ if (type == "integer" && format == "int32")
{
- return new OpenApiByte(Convert.FromBase64String(value));
+ if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+ {
+ return new OpenApiInteger(intValue);
+ }
}
- catch(FormatException)
- { }
- }
- // binary
- if (type == "string" && format == "binary")
- {
- try
+ if (type == "integer" && format == "int64")
{
- return new OpenApiBinary(Encoding.UTF8.GetBytes(value));
+ if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
+ {
+ return new OpenApiLong(longValue);
+ }
}
- catch(EncoderFallbackException)
- { }
- }
- if (type == "string" && format == "date")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
+ if (type == "integer")
{
- return new OpenApiDate(dateValue.Date);
+ if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+ {
+ return new OpenApiInteger(intValue);
+ }
}
- }
- if (type == "string" && format == "date-time")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
+ if (type == "number" && format == "float")
{
- return new OpenApiDateTime(dateTimeValue);
+ if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
+ {
+ return new OpenApiFloat(floatValue);
+ }
}
- }
- if (type == "string" && format == "password")
- {
- return new OpenApiPassword(value);
- }
+ if (type == "number" && format == "double")
+ {
+ if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
+ {
+ return new OpenApiDouble(doubleValue);
+ }
+ }
- if (type == "string")
- {
- return new OpenApiString(value);
- }
+ if (type == "number")
+ {
+ if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
+ {
+ return new OpenApiDouble(doubleValue);
+ }
+ }
- if (type == "boolean")
- {
- if (bool.TryParse(value, out var booleanValue))
+ if (type == "string" && format == "byte")
+ {
+ try
+ {
+ return new OpenApiByte(Convert.FromBase64String(value));
+ }
+ catch (FormatException)
+ { }
+ }
+
+ // binary
+ if (type == "string" && format == "binary")
{
- return new OpenApiBoolean(booleanValue);
+ try
+ {
+ return new OpenApiBinary(Encoding.UTF8.GetBytes(value));
+ }
+ catch (EncoderFallbackException)
+ { }
+ }
+
+ if (type == "string" && format == "date")
+ {
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
+ {
+ return new OpenApiDate(dateValue.Date);
+ }
+ }
+
+ if (type == "string" && format == "date-time")
+ {
+ if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
+ {
+ return new OpenApiDateTime(dateTimeValue);
+ }
+ }
+
+ if (type == "string" && format == "password")
+ {
+ return new OpenApiPassword(value);
+ }
+
+ if (type == "string")
+ {
+ return openApiAny;
+ }
+
+ if (type == "boolean")
+ {
+ if (bool.TryParse(value, out var booleanValue))
+ {
+ return new OpenApiBoolean(booleanValue);
+ }
}
}
// If data conflicts with the given type, return a string.
// This converter is used in the parser, so it does not perform any validations,
// but the validator can be used to validate whether the data and given type conflicts.
- return new OpenApiString(value);
+ return openApiAny;
}
}
}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs
index abeee3d26..25f0eabc1 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs
@@ -15,16 +15,13 @@ namespace Microsoft.OpenApi.Readers.ParseNodes
{
internal abstract class ParseNode
{
- protected ParseNode(ParsingContext parsingContext, OpenApiDiagnostic diagnostic)
+ protected ParseNode(ParsingContext parsingContext)
{
Context = parsingContext;
- Diagnostic = diagnostic;
}
public ParsingContext Context { get; }
- public OpenApiDiagnostic Diagnostic { get; }
-
public MapNode CheckMapNode(string nodeName)
{
if (!(this is MapNode mapNode))
@@ -35,20 +32,20 @@ public MapNode CheckMapNode(string nodeName)
return mapNode;
}
- public static ParseNode Create(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node)
+ public static ParseNode Create(ParsingContext context, YamlNode node)
{
if (node is YamlSequenceNode listNode)
{
- return new ListNode(context, diagnostic, listNode);
+ return new ListNode(context, listNode);
}
if (node is YamlMappingNode mapNode)
{
- return new MapNode(context, diagnostic, mapNode);
+ return new MapNode(context, mapNode);
}
- return new ValueNode(context, diagnostic, node as YamlScalarNode);
+ return new ValueNode(context, node as YamlScalarNode);
}
public virtual List CreateList(Func map)
@@ -100,4 +97,4 @@ public virtual List CreateListOfAny()
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/PatternFieldMap.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/PatternFieldMap.cs
index 8dadfcee2..bbd153688 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/PatternFieldMap.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/PatternFieldMap.cs
@@ -9,4 +9,4 @@ namespace Microsoft.OpenApi.Readers.ParseNodes
internal class PatternFieldMap : Dictionary, Action>
{
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs
index 39b9370f8..2dd2c7e8a 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs
@@ -14,12 +14,11 @@ namespace Microsoft.OpenApi.Readers.ParseNodes
{
internal class PropertyNode : ParseNode
{
- public PropertyNode(ParsingContext context, OpenApiDiagnostic diagnostic, string name, YamlNode node) : base(
- context,
- diagnostic)
+ public PropertyNode(ParsingContext context, string name, YamlNode node) : base(
+ context)
{
Name = name;
- Value = Create(context, diagnostic, node);
+ Value = Create(context, node);
}
public string Name { get; set; }
@@ -43,12 +42,12 @@ public void ParseField(
}
catch (OpenApiReaderException ex)
{
- Diagnostic.Errors.Add(new OpenApiError(ex));
+ Context.Diagnostic.Errors.Add(new OpenApiError(ex));
}
catch (OpenApiException ex)
{
ex.Pointer = Context.GetLocation();
- Diagnostic.Errors.Add(new OpenApiError(ex));
+ Context.Diagnostic.Errors.Add(new OpenApiError(ex));
}
finally
{
@@ -67,12 +66,12 @@ public void ParseField(
}
catch (OpenApiReaderException ex)
{
- Diagnostic.Errors.Add(new OpenApiError(ex));
+ Context.Diagnostic.Errors.Add(new OpenApiError(ex));
}
catch (OpenApiException ex)
{
ex.Pointer = Context.GetLocation();
- Diagnostic.Errors.Add(new OpenApiError(ex));
+ Context.Diagnostic.Errors.Add(new OpenApiError(ex));
}
finally
{
@@ -81,7 +80,7 @@ public void ParseField(
}
else
{
- Diagnostic.Errors.Add(
+ Context.Diagnostic.Errors.Add(
new OpenApiError("", $"{Name} is not a valid property at {Context.GetLocation()}"));
}
}
@@ -92,4 +91,4 @@ public override IOpenApiAny CreateAny()
throw new NotImplementedException();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs
index 014e2e71f..42909bee6 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs
@@ -14,8 +14,7 @@ internal class RootNode : ParseNode
public RootNode(
ParsingContext context,
- OpenApiDiagnostic diagnostic,
- YamlDocument yamlDocument) : base(context, diagnostic)
+ YamlDocument yamlDocument) : base(context)
{
_yamlDocument = yamlDocument;
}
@@ -28,12 +27,12 @@ public ParseNode Find(JsonPointer referencePointer)
return null;
}
- return Create(Context, Diagnostic, yamlNode);
+ return Create(Context, yamlNode);
}
public MapNode GetMap()
{
- return new MapNode(Context, Diagnostic, (YamlMappingNode)_yamlDocument.RootNode);
+ return new MapNode(Context, (YamlMappingNode)_yamlDocument.RootNode);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs
index b7669b538..68f4bd7ea 100644
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs
+++ b/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs
@@ -1,10 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-using System;
-using System.Globalization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Readers.Exceptions;
+using SharpYaml;
using SharpYaml.Serialization;
namespace Microsoft.OpenApi.Readers.ParseNodes
@@ -13,9 +12,8 @@ internal class ValueNode : ParseNode
{
private readonly YamlScalarNode _node;
- public ValueNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node) : base(
- context,
- diagnostic)
+ public ValueNode(ParsingContext context, YamlNode node) : base(
+ context)
{
if (!(node is YamlScalarNode scalarNode))
{
@@ -36,7 +34,7 @@ public override string GetScalarValue()
public override IOpenApiAny CreateAny()
{
var value = GetScalarValue();
- return new OpenApiString(value);
+ return new OpenApiString(value, this._node.Style == ScalarStyle.SingleQuoted || this._node.Style == ScalarStyle.DoubleQuoted || this._node.Style == ScalarStyle.Literal || this._node.Style == ScalarStyle.Folded);
}
}
}
diff --git a/src/Microsoft.OpenApi.Readers/ParsingContext.cs b/src/Microsoft.OpenApi.Readers/ParsingContext.cs
index e88e00423..9c7277136 100644
--- a/src/Microsoft.OpenApi.Readers/ParsingContext.cs
+++ b/src/Microsoft.OpenApi.Readers/ParsingContext.cs
@@ -24,22 +24,34 @@ public class ParsingContext
private readonly Stack _currentLocation = new Stack();
private readonly Dictionary _tempStorage = new Dictionary();
private readonly Dictionary