diff --git a/Directory.Packages.props b/Directory.Packages.props
index 3f16082..d2f25c6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,11 +3,11 @@
true
-
-
+
+
-
-
+
+
diff --git a/src/Facility.Definition.Swagger/Facility.Definition.Swagger.csproj b/src/Facility.Definition.Swagger/Facility.Definition.Swagger.csproj
index e2d8e42..85d08dc 100644
--- a/src/Facility.Definition.Swagger/Facility.Definition.Swagger.csproj
+++ b/src/Facility.Definition.Swagger/Facility.Definition.Swagger.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ netstandard2.0;net6.0;net7.0;net8.0
Used to interpret Swagger (OpenAPI) 2.0 definitions.
Facility FSD Swagger OpenAPI Definition
true
diff --git a/src/Facility.Definition.Swagger/SwaggerConversion.cs b/src/Facility.Definition.Swagger/SwaggerConversion.cs
index 8b26199..acd662d 100644
--- a/src/Facility.Definition.Swagger/SwaggerConversion.cs
+++ b/src/Facility.Definition.Swagger/SwaggerConversion.cs
@@ -368,7 +368,9 @@ private KeyValuePair ResolveDefinition(SwaggerSchema swag
if (swaggerDefinition.Ref != null)
{
name = GetDefinitionNameFromRef(swaggerDefinition.Ref, position);
- if (!m_swaggerService.Definitions!.TryGetValue(name, out swaggerDefinition))
+ if (m_swaggerService.Definitions!.TryGetValue(name, out var resolvedDefinition))
+ swaggerDefinition = resolvedDefinition;
+ else
m_errors.Add(new ServiceDefinitionError($"Missing definition named '{name}'.", position));
}
@@ -383,8 +385,10 @@ private void ResolveOperations(ref SwaggerOperations swaggerOperations, ref Swag
if (!swaggerOperations.Ref.StartsWith(refPrefix, StringComparison.Ordinal))
m_errors.Add(new ServiceDefinitionError("Operations $ref must start with '#/paths/'.", context.CreatePosition()));
- string name = UnescapeRefPart(swaggerOperations.Ref.Substring(refPrefix.Length));
- if (!m_swaggerService.Paths!.TryGetValue(name, out swaggerOperations))
+ var name = UnescapeRefPart(swaggerOperations.Ref.Substring(refPrefix.Length));
+ if (m_swaggerService.Paths!.TryGetValue(name, out var resolvedOperations))
+ swaggerOperations = resolvedOperations;
+ else
m_errors.Add(new ServiceDefinitionError($"Missing path named '{name}'.", context.CreatePosition()));
context = context.Root.CreateContext("paths/" + name);
@@ -399,8 +403,10 @@ private SwaggerParameter ResolveParameter(SwaggerParameter swaggerParameter, Ser
if (!swaggerParameter.Ref.StartsWith(refPrefix, StringComparison.Ordinal))
m_errors.Add(new ServiceDefinitionError("Parameter $ref must start with '#/parameters/'.", position));
- string name = UnescapeRefPart(swaggerParameter.Ref.Substring(refPrefix.Length));
- if (!m_swaggerService.Parameters!.TryGetValue(name, out swaggerParameter))
+ var name = UnescapeRefPart(swaggerParameter.Ref.Substring(refPrefix.Length));
+ if (m_swaggerService.Parameters!.TryGetValue(name, out var resolvedParameter))
+ swaggerParameter = resolvedParameter;
+ else
m_errors.Add(new ServiceDefinitionError($"Missing parameter named '{name}'.", position));
}
@@ -415,8 +421,10 @@ private SwaggerResponse ResolveResponse(SwaggerResponse swaggerResponse, Service
if (!swaggerResponse.Ref.StartsWith(refPrefix, StringComparison.Ordinal))
m_errors.Add(new ServiceDefinitionError("Response $ref must start with '#/responses/'.", position));
- string name = UnescapeRefPart(swaggerResponse.Ref.Substring(refPrefix.Length));
- if (!m_swaggerService.Responses!.TryGetValue(name, out swaggerResponse))
+ var name = UnescapeRefPart(swaggerResponse.Ref.Substring(refPrefix.Length));
+ if (m_swaggerService.Responses!.TryGetValue(name, out var resolvedResponse))
+ swaggerResponse = resolvedResponse;
+ else
m_errors.Add(new ServiceDefinitionError($"Missing response named '{name}'.", position));
}
@@ -507,7 +515,7 @@ internal static bool IsFacilityError(KeyValuePair swagger
return TryGetFacilityTypeName(valueSchema, position);
}
- private static string UnescapeRefPart(string value) => value.Replace("~1", "/").Replace("~0", "~");
+ private static string UnescapeRefPart(string value) => value.ReplaceOrdinal("~1", "/").ReplaceOrdinal("~0", "~");
private static readonly Regex s_pathParameter = new Regex(@"\{[^}]+\}");
diff --git a/src/Facility.Definition.Swagger/SwaggerGenerator.cs b/src/Facility.Definition.Swagger/SwaggerGenerator.cs
index 6e4d136..4162bd1 100644
--- a/src/Facility.Definition.Swagger/SwaggerGenerator.cs
+++ b/src/Facility.Definition.Swagger/SwaggerGenerator.cs
@@ -540,7 +540,7 @@ public OurEventEmitter(IEventEmitter nextEmitter)
public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
{
// prefer the literal style for multi-line strings
- if (eventInfo.Source.Type == typeof(string) && eventInfo.Style == ScalarStyle.Any && ((string) eventInfo.Source.Value!).IndexOf('\n') != -1)
+ if (eventInfo.Source.Type == typeof(string) && eventInfo.Style == ScalarStyle.Any && ((string) eventInfo.Source.Value!).ContainsOrdinal("\n"))
eventInfo.Style = ScalarStyle.Literal;
// ensure strings that look like numbers remain strings
@@ -552,6 +552,7 @@ public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
}
private sealed class OurDictionary : IDictionary, IReadOnlyDictionary
+ where TKey : notnull
{
public OurDictionary()
{
@@ -608,7 +609,7 @@ public bool Remove(TKey key)
return true;
}
- public bool TryGetValue(TKey key, out TValue value) => m_dictionary.TryGetValue(key, out value);
+ public bool TryGetValue(TKey key, out TValue value) => m_dictionary.TryGetValue(key, out value!);
public TValue this[TKey key]
{
diff --git a/src/Facility.Definition.Swagger/SwaggerUtility.cs b/src/Facility.Definition.Swagger/SwaggerUtility.cs
index f40446c..978e7f1 100644
--- a/src/Facility.Definition.Swagger/SwaggerUtility.cs
+++ b/src/Facility.Definition.Swagger/SwaggerUtility.cs
@@ -29,9 +29,19 @@ public static class SwaggerUtility
internal static IList EmptyIfNull(this IList? list) => list ?? Array.Empty();
- internal static IReadOnlyDictionary EmptyIfNull(this IReadOnlyDictionary? list) => list ?? new Dictionary();
-
- internal static IDictionary EmptyIfNull(this IDictionary? list) => list ?? new Dictionary();
+ internal static IReadOnlyDictionary EmptyIfNull(this IReadOnlyDictionary? list)
+ where TKey : notnull => list ?? new Dictionary();
+
+ internal static IDictionary EmptyIfNull(this IDictionary? list)
+ where TKey : notnull => list ?? new Dictionary();
+
+#if NET6_0_OR_GREATER
+ internal static bool ContainsOrdinal(this string text, string value) => text.Contains(value, StringComparison.Ordinal);
+ internal static string ReplaceOrdinal(this string text, string oldValue, string newValue) => text.Replace(oldValue, newValue, StringComparison.Ordinal);
+#else
+ internal static bool ContainsOrdinal(this string text, string value) => text.Contains(value);
+ internal static string ReplaceOrdinal(this string text, string oldValue, string newValue) => text.Replace(oldValue, newValue);
+#endif
private sealed class CamelCaseExceptDictionaryKeysContractResolver : CamelCasePropertyNamesContractResolver
{