diff --git a/.editorconfig b/.editorconfig
index 63068ab4..3bf927f9 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -218,6 +218,11 @@ dotnet_diagnostic.SA1633.severity = none
dotnet_diagnostic.SA1642.severity = suggestion
# CSharpGuidelines
+
+# Purpose: Argument for parameter calls nested method
+# Rationale: Modern debuggers allow stepping into nested calls, so no need to avoid them.
+dotnet_diagnostic.AV1580.severity = none
+
dotnet_diagnostic.AV1561.max_parameter_count = 5
# AV1008: Class should be non-static or its name should be suffixed with Extensions
dotnet_diagnostic.AV1008.severity = none
@@ -262,6 +267,16 @@ dotnet_diagnostic.AV2305.severity = none
# AV2407: Region should be removed
dotnet_diagnostic.AV2407.severity = none
+# Meziantou.Analyzer
+
+# Purpose: Use string.Equals instead of Equals operator
+# Rationale: Does not improve readability
+dotnet_diagnostic.MA0006.severity = none
+
+# Purpose: Regular expressions should not be vulnerable to Denial of Service attacks
+# Rationale: See https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0009.md
+dotnet_diagnostic.MA0009.severity = suggestion
+
# ReSharper/Rider
# Convert lambda expression to method group
resharper_convert_closure_to_method_group_highlighting=none
diff --git a/Build/_build.csproj b/Build/_build.csproj
index 3d7812d3..39c84fb5 100644
--- a/Build/_build.csproj
+++ b/Build/_build.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 00000000..6c747a1d
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,40 @@
+
+
+ 13.0
+ true
+
+
+
+ false
+ false
+ false
+
+
+ true
+ 9.0
+ All
+ true
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/FluentAssertions.Json.sln b/FluentAssertions.Json.sln
index 35f712b7..daaa4852 100644
--- a/FluentAssertions.Json.sln
+++ b/FluentAssertions.Json.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.2.32210.308
+# Visual Studio Version 18
+VisualStudioVersion = 18.0.11205.157 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E5A0B454-22D4-4694-99FF-D6A8B7DE7DA3}"
ProjectSection(SolutionItems) = preProject
diff --git a/Src/FluentAssertions.Json/Common/JTokenExtensions.cs b/Src/FluentAssertions.Json/Common/JTokenExtensions.cs
index 6dd845c5..7322bfce 100644
--- a/Src/FluentAssertions.Json/Common/JTokenExtensions.cs
+++ b/Src/FluentAssertions.Json/Common/JTokenExtensions.cs
@@ -3,91 +3,102 @@
using System.Linq;
using Newtonsoft.Json.Linq;
-namespace FluentAssertions.Json.Common
+namespace FluentAssertions.Json.Common;
+
+internal static class JTokenExtensions
{
- internal static class JTokenExtensions
- {
- private static readonly JTokenComparer Comparer = new();
+ private static readonly JTokenComparer Comparer = new();
- ///
- /// Recursively sorts the properties of JObject instances by name and
- /// the elements of JArray instances by their string representation,
- /// producing a normalized JToken for consistent comparison
- ///
- public static JToken Normalize(this JToken token)
+ ///
+ /// Recursively sorts the properties of JObject instances by name and
+ /// the elements of JArray instances by their string representation,
+ /// producing a normalized JToken for consistent comparison
+ ///
+ public static JToken Normalize(this JToken token)
+ {
+ return token switch
{
- return token switch
- {
- JObject obj => new JObject(obj.Properties().OrderBy(p => p.Name).Select(p => new JProperty(p.Name, Normalize(p.Value)))),
- JArray array => new JArray(array.Select(Normalize).OrderBy(x => x, Comparer)),
- _ => token
- };
- }
+ JObject obj => new JObject(obj.Properties().OrderBy(p => p.Name, StringComparer.Ordinal).Select(p => new JProperty(p.Name, Normalize(p.Value)))),
+ JArray array => new JArray(array.Select(Normalize).OrderBy(x => x, Comparer)),
+ _ => token
+ };
+ }
- private sealed class JTokenComparer : IComparer
+ private sealed class JTokenComparer : IComparer
+ {
+ public int Compare(JToken x, JToken y)
{
- public int Compare(JToken x, JToken y)
+ if (ReferenceEquals(x, y))
{
- if (ReferenceEquals(x, y))
- return 0;
-
- if (x is null)
- return -1;
-
- if (y is null)
- return 1;
-
- var typeComparison = x.Type.CompareTo(y.Type);
- if (typeComparison != 0)
- return typeComparison;
-
- return x switch
- {
- JArray a => Compare(a, (JArray)y),
- JObject o => Compare(o, (JObject)y),
- JProperty p => Compare(p, (JProperty)y),
- JValue v => Compare(v, (JValue)y),
- JConstructor c => Compare(c, (JConstructor)y),
- _ => string.Compare(x.ToString(), y.ToString(), StringComparison.Ordinal)
- };
+ return 0;
}
- private static int Compare(JValue x, JValue y) => Comparer