diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index daf3c7fd..eb54de4c 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -4,10 +4,17 @@
true
+
+
+
+
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj
index 0e9565bf..0f0b6f40 100644
--- a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj
+++ b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj
@@ -21,12 +21,15 @@
-
-
+
+
+
+
+
+
-
diff --git a/src/PAModel/packages.lock.json b/src/PAModel/packages.lock.json
index 7b4250db..09f295cd 100644
--- a/src/PAModel/packages.lock.json
+++ b/src/PAModel/packages.lock.json
@@ -16,82 +16,93 @@
},
"System.Text.Encodings.Web": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "WUH+viO8VDG8NpFKvOBwpeyKUiPOMz3kQpA6AKCD4b2NG1pBhyC4AwTb357iZmTxZDnkM4IsFnvzN8W8OKmsHg==",
"dependencies": {
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "F8Pu2QLUMeniVbtiyk7n7LCfFYxlcJ8ASaSwglJyq6dxa34iCQrikQszsgJClIJWuSWjcyhKkV7daAzYJqeVwA==",
"dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0",
- "System.Text.Encodings.Web": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4",
- "System.ValueTuple": "4.5.0"
+ "Microsoft.Bcl.AsyncInterfaces": "10.0.7",
+ "System.Buffers": "4.6.1",
+ "System.IO.Pipelines": "10.0.7",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2",
+ "System.Text.Encodings.Web": "10.0.7",
+ "System.Threading.Tasks.Extensions": "4.6.3",
+ "System.ValueTuple": "4.6.2"
}
},
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
+ "resolved": "10.0.7",
+ "contentHash": "g0Xp9A+B8jCf5pNIIhFOQXPJkte3D87shfTLY+ylwfSh22U5oQH6tvvmcUuqJvt/wtwKk0WdNp2OGEczHJlJdg==",
"dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
+ "System.Threading.Tasks.Extensions": "4.6.3"
}
},
"System.Buffers": {
"type": "Transitive",
- "resolved": "4.5.1",
- "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ "resolved": "4.6.1",
+ "contentHash": "N8GXpmiLMtljq7gwvyS+1QvKT/W2J8sNAvx+HVg4NGmsG/H+2k/y9QI23auLJRterrzCiDH+IWAw4V/GPwsMlw=="
+ },
+ "System.IO.Pipelines": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "LTxXYYKmRhPKWveYmfzuRTUnzsfY7CN+WOq6aTRgYE9vJ8BUvIWPCaSx4HxqBwXViTPSjR9cHDOVuVPuZGRR/Q==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
},
"System.Numerics.Vectors": {
"type": "Transitive",
- "resolved": "4.5.0",
- "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
+ "resolved": "4.6.1",
+ "contentHash": "sQxefTnhagrhoq2ReR0D/6K0zJcr9Hrd6kikeXsA1I8kOCboTavcUC4r7TSfpKFeE163uMuxZcyfO1mGO3EN8Q=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ "resolved": "6.1.2",
+ "contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
},
"System.ValueTuple": {
"type": "Transitive",
- "resolved": "4.5.0",
- "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
+ "resolved": "4.6.2",
+ "contentHash": "yQgmjfFximrNm9LIV3mL6T5MzjeC+epeE5rl4hXxAlYmxby7RM1dPSkIKXk9HNkl6G54h2JHOmLD46+Pey+IRg=="
},
"System.Memory": {
"type": "CentralTransitive",
- "requested": "[4.5.5, )",
- "resolved": "4.5.5",
- "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
+ "requested": "[4.6.3, )",
+ "resolved": "4.6.3",
+ "contentHash": "qdcDOgnFZY40+Q9876JUHnlHu7bosOHX8XISRoH94fwk6hgaeQGSgfZd8srWRZNt5bV9ZW2TljcegDNxsf+96A==",
"dependencies": {
- "System.Buffers": "4.5.1",
- "System.Numerics.Vectors": "4.5.0",
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ "System.Buffers": "4.6.1",
+ "System.Numerics.Vectors": "4.6.1",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"System.Threading.Tasks.Extensions": {
"type": "CentralTransitive",
- "requested": "[4.5.4, )",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
+ "requested": "[4.6.3, )",
+ "resolved": "4.6.3",
+ "contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
"dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
}
},
@@ -102,23 +113,11 @@
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
- "System.Text.Encodings.Web": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
- },
- "System.Text.Json": {
- "type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
- },
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
}
},
"net8.0": {
@@ -128,23 +127,11 @@
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
- "System.Text.Encodings.Web": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
- },
- "System.Text.Json": {
- "type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
- },
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
}
}
}
diff --git a/src/PAModelTests/PAModelTests.csproj b/src/PAModelTests/PAModelTests.csproj
index 4f7c2ed1..840c197f 100644
--- a/src/PAModelTests/PAModelTests.csproj
+++ b/src/PAModelTests/PAModelTests.csproj
@@ -9,8 +9,6 @@
-
-
diff --git a/src/Persistence.Tests/PaYaml/Serialization/PaYamlSerializerTests.cs b/src/Persistence.Tests/PaYaml/Serialization/PaYamlSerializerTests.cs
index b64ec39e..d99c5449 100644
--- a/src/Persistence.Tests/PaYaml/Serialization/PaYamlSerializerTests.cs
+++ b/src/Persistence.Tests/PaYaml/Serialization/PaYamlSerializerTests.cs
@@ -304,4 +304,47 @@ public void SerializeComponentCustomPropertyUnionPropertyOrder()
Default: =true
""".Replace("\r\n", "\n"));
}
+
+ [TestMethod]
+ public void DeserializeRespectsConfiguredMaximumRecursion()
+ {
+ // Arrange: build a deeply-nested mapping that exceeds the configured recursion limit.
+ var options = new PaYamlSerializerOptions { MaximumRecursion = 5 };
+ var yaml = BuildNestedMappingYaml(depth: 20);
+
+ // Act
+ Action act = () => PaYamlSerializer.Deserialize>(yaml, options);
+
+ // Assert: the exception is wrapped as PersistenceLibraryException with the
+ // YamlDotNet MaximumRecursionLevelReachedException as the inner exception.
+ act.Should().Throw()
+ .WithErrorCode(PersistenceErrorCode.MaximumRecursionLevelReached)
+ .WithInnerException();
+ }
+
+ [TestMethod]
+ [DataRow(null)]
+ [DataRow(55)]
+ public void DeserializeSucceedsWhenMaximumRecursionRaisedOrNull(int? maxRecursion)
+ {
+ // Arrange: same depth-20 input that fails with default recursion, raised limit.
+ var options = new PaYamlSerializerOptions { MaximumRecursion = maxRecursion };
+ var yaml = BuildNestedMappingYaml(depth: 20);
+
+ // Act
+ FluentActions.Invoking(() => PaYamlSerializer.Deserialize>(yaml, options))
+ .Should().NotThrow()
+ .Which.Should().NotBeNull();
+ }
+
+ private static string BuildNestedMappingYaml(int depth)
+ {
+ var sb = new System.Text.StringBuilder();
+ for (var i = 0; i < depth; i++)
+ {
+ sb.Append(new string(' ', i * 2)).Append("k:").AppendLine();
+ }
+ sb.Append(new string(' ', depth * 2)).Append("k: leaf").AppendLine();
+ return sb.ToString();
+ }
}
diff --git a/src/Persistence/PaYaml/Serialization/PaYamlSerializationContext.cs b/src/Persistence/PaYaml/Serialization/PaYamlSerializationContext.cs
index e1d0ac6b..4a3773c4 100644
--- a/src/Persistence/PaYaml/Serialization/PaYamlSerializationContext.cs
+++ b/src/Persistence/PaYaml/Serialization/PaYamlSerializationContext.cs
@@ -13,6 +13,10 @@ public class PaYamlSerializationContext : IDisposable
public PaYamlSerializationContext(PaYamlSerializerOptions options)
{
Options = options ?? throw new ArgumentNullException(nameof(options));
+ if (Options.MaximumRecursion.HasValue && Options.MaximumRecursion.Value <= 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(options), "MaximumRecursion must be an integer greater than 0 or null.");
+ }
}
///
@@ -27,6 +31,11 @@ internal void ApplyToDeserializerBuilder(DeserializerBuilder builder)
.IgnoreFields()
;
+ if (Options.MaximumRecursion.HasValue)
+ {
+ builder.WithMaximumRecursion(Options.MaximumRecursion.Value);
+ }
+
AddTypeConverters(builder);
Options.AdditionalDeserializerConfiguration?.Invoke(builder);
}
diff --git a/src/Persistence/PaYaml/Serialization/PaYamlSerializer.cs b/src/Persistence/PaYaml/Serialization/PaYamlSerializer.cs
index c02873c8..fc64811f 100644
--- a/src/Persistence/PaYaml/Serialization/PaYamlSerializer.cs
+++ b/src/Persistence/PaYaml/Serialization/PaYamlSerializer.cs
@@ -114,7 +114,9 @@ private static void WriteTextWriter(TextWriter writer, in TValue? value,
catch (YamlException ex)
{
var errorCode = PersistenceErrorCode.YamlInvalidSyntax;
- if (ex.InnerException is ArgumentException && ex.InnerException.Message.Contains("An item with the same key has already been added"))
+ if (ex is MaximumRecursionLevelReachedException)
+ errorCode = PersistenceErrorCode.MaximumRecursionLevelReached;
+ else if (ex.InnerException is ArgumentException && ex.InnerException.Message.Contains("An item with the same key has already been added"))
errorCode = PersistenceErrorCode.DuplicateNameInSequence;
throw PersistenceLibraryException.FromYamlException(ex, errorCode);
diff --git a/src/Persistence/PaYaml/Serialization/PaYamlSerializerOptions.cs b/src/Persistence/PaYaml/Serialization/PaYamlSerializerOptions.cs
index f5e3d4f1..d0ee5e89 100644
--- a/src/Persistence/PaYaml/Serialization/PaYamlSerializerOptions.cs
+++ b/src/Persistence/PaYaml/Serialization/PaYamlSerializerOptions.cs
@@ -11,6 +11,12 @@ public record PaYamlSerializerOptions
public string NewLine { get; init; } = "\n";
+ ///
+ /// Maximum recursion depth allowed during deserialization.
+ /// Bounds pathological/untrusted YAML input.
+ ///
+ public int? MaximumRecursion { get; init; }
+
public PFxExpressionYamlFormattingOptions PFxExpressionYamlFormatting { get; init; } = new();
public Action? AdditionalDeserializerConfiguration { get; init; }
diff --git a/src/Persistence/PersistenceErrorCode.cs b/src/Persistence/PersistenceErrorCode.cs
index 61220186..795929fc 100644
--- a/src/Persistence/PersistenceErrorCode.cs
+++ b/src/Persistence/PersistenceErrorCode.cs
@@ -22,6 +22,12 @@ public enum PersistenceErrorCode
// 3xxx - Deserialization errors
DeserializationError = 3000,
YamlInvalidSyntax = 3001,
+ ///
+ /// Indicates that the deserializer exceeded the maximum recursion depth when processing the YAML document.
+ /// This can be caused by excessively deep or circular references in the object graph represented by the YAML.
+ /// The default maximum recursion depth can be configured through .
+ ///
+ MaximumRecursionLevelReached = 3002,
YamlInvalidSchema = 3101,
EditorStateJsonEmptyOrNull = 3102,
InvalidEditorStateJson = 3300,
diff --git a/src/Persistence/packages.lock.json b/src/Persistence/packages.lock.json
index 1b6927cf..afe64179 100644
--- a/src/Persistence/packages.lock.json
+++ b/src/Persistence/packages.lock.json
@@ -4,39 +4,40 @@
".NETFramework,Version=v4.8": {
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Direct",
- "requested": "[8.0.2, )",
- "resolved": "8.0.2",
- "contentHash": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw==",
"dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
+ "Microsoft.Bcl.AsyncInterfaces": "10.0.7",
+ "System.Threading.Tasks.Extensions": "4.6.3"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
- "requested": "[8.0.3, )",
- "resolved": "8.0.3",
- "contentHash": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "tIEcQ2gvERrH2KiCjdsVcHGhXt9lIsuDStfOIeZWr7/fP8IXhGiYfx0/80PNI7WPO2IYuFtlZLSlnTS8+/Mchw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "System.Buffers": "4.6.1",
+ "System.Diagnostics.DiagnosticSource": "10.0.7",
+ "System.Memory": "4.6.3"
}
},
"PolySharp": {
"type": "Direct",
- "requested": "[1.14.1, )",
- "resolved": "1.14.1",
- "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
+ "requested": "[1.15.0, )",
+ "resolved": "1.15.0",
+ "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g=="
},
"System.Collections.Immutable": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "0Ti4Jv1ga3eurH5HaCVsPybcBl+08YfzM9smqAJzHvqV494xK+0pSbytGrMTWhph+zsyKIaoGNiR5u3by5bj+A==",
"dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"System.IO.Compression": {
@@ -47,129 +48,155 @@
},
"System.Memory": {
"type": "Direct",
- "requested": "[4.5.5, )",
- "resolved": "4.5.5",
- "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
+ "requested": "[4.6.3, )",
+ "resolved": "4.6.3",
+ "contentHash": "qdcDOgnFZY40+Q9876JUHnlHu7bosOHX8XISRoH94fwk6hgaeQGSgfZd8srWRZNt5bV9ZW2TljcegDNxsf+96A==",
"dependencies": {
- "System.Buffers": "4.5.1",
- "System.Numerics.Vectors": "4.5.0",
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ "System.Buffers": "4.6.1",
+ "System.Numerics.Vectors": "4.6.1",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "F8Pu2QLUMeniVbtiyk7n7LCfFYxlcJ8ASaSwglJyq6dxa34iCQrikQszsgJClIJWuSWjcyhKkV7daAzYJqeVwA==",
"dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0",
- "System.Text.Encodings.Web": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4",
- "System.ValueTuple": "4.5.0"
+ "Microsoft.Bcl.AsyncInterfaces": "10.0.7",
+ "System.Buffers": "4.6.1",
+ "System.IO.Pipelines": "10.0.7",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2",
+ "System.Text.Encodings.Web": "10.0.7",
+ "System.Threading.Tasks.Extensions": "4.6.3",
+ "System.ValueTuple": "4.6.2"
}
},
"System.Threading.Tasks.Extensions": {
"type": "Direct",
- "requested": "[4.5.4, )",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
+ "requested": "[4.6.3, )",
+ "resolved": "4.6.3",
+ "contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
"dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
+ "resolved": "10.0.7",
+ "contentHash": "g0Xp9A+B8jCf5pNIIhFOQXPJkte3D87shfTLY+ylwfSh22U5oQH6tvvmcUuqJvt/wtwKk0WdNp2OGEczHJlJdg==",
"dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
+ "System.Threading.Tasks.Extensions": "4.6.3"
}
},
"System.Buffers": {
"type": "Transitive",
- "resolved": "4.5.1",
- "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ "resolved": "4.6.1",
+ "contentHash": "N8GXpmiLMtljq7gwvyS+1QvKT/W2J8sNAvx+HVg4NGmsG/H+2k/y9QI23auLJRterrzCiDH+IWAw4V/GPwsMlw=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Fu6AxFf9bHz/Q7DQmxKC0o+UgFes8bs2Xh+PH/x31yExRAOASTwlzjZsISTtqVU5gQshKHLZopxEBTaIyfv0wg==",
+ "dependencies": {
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "System.IO.Pipelines": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "LTxXYYKmRhPKWveYmfzuRTUnzsfY7CN+WOq6aTRgYE9vJ8BUvIWPCaSx4HxqBwXViTPSjR9cHDOVuVPuZGRR/Q==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
},
"System.Numerics.Vectors": {
"type": "Transitive",
- "resolved": "4.5.0",
- "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
+ "resolved": "4.6.1",
+ "contentHash": "sQxefTnhagrhoq2ReR0D/6K0zJcr9Hrd6kikeXsA1I8kOCboTavcUC4r7TSfpKFeE163uMuxZcyfO1mGO3EN8Q=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ "resolved": "6.1.2",
+ "contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
},
"System.ValueTuple": {
"type": "Transitive",
- "resolved": "4.5.0",
- "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
+ "resolved": "4.6.2",
+ "contentHash": "yQgmjfFximrNm9LIV3mL6T5MzjeC+epeE5rl4hXxAlYmxby7RM1dPSkIKXk9HNkl6G54h2JHOmLD46+Pey+IRg=="
},
"System.Text.Encodings.Web": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "WUH+viO8VDG8NpFKvOBwpeyKUiPOMz3kQpA6AKCD4b2NG1pBhyC4AwTb357iZmTxZDnkM4IsFnvzN8W8OKmsHg==",
"dependencies": {
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
}
},
"net10.0": {
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Direct",
- "requested": "[8.0.2, )",
- "resolved": "8.0.2",
- "contentHash": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg=="
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
- "requested": "[8.0.3, )",
- "resolved": "8.0.3",
- "contentHash": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "tIEcQ2gvERrH2KiCjdsVcHGhXt9lIsuDStfOIeZWr7/fP8IXhGiYfx0/80PNI7WPO2IYuFtlZLSlnTS8+/Mchw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
}
},
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
}
},
"net8.0": {
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Direct",
- "requested": "[8.0.2, )",
- "resolved": "8.0.2",
- "contentHash": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg=="
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
- "requested": "[8.0.3, )",
- "resolved": "8.0.3",
- "contentHash": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "tIEcQ2gvERrH2KiCjdsVcHGhXt9lIsuDStfOIeZWr7/fP8IXhGiYfx0/80PNI7WPO2IYuFtlZLSlnTS8+/Mchw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "System.Diagnostics.DiagnosticSource": "10.0.7"
}
},
"YamlDotNet": {
"type": "Direct",
- "requested": "[16.1.3, )",
- "resolved": "16.1.3",
- "contentHash": "gtHGiDvU9VTtWte8f0thIM38cL1oowOjStKpeAEKKfA+Rc4AvekJzqFDZiiPcc4kw00ZiwR4OTJS56L16q98DQ=="
+ "requested": "[17.1.0, )",
+ "resolved": "17.1.0",
+ "contentHash": "AhsNXgeAs3Ugt653t8LC44xXDuldFfwBpWbWX9pN3e4Yg8U5Bk8jLn8eXtGv5HV2V2nHu7F46fqsPC+tpcTGAA=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Fu6AxFf9bHz/Q7DQmxKC0o+UgFes8bs2Xh+PH/x31yExRAOASTwlzjZsISTtqVU5gQshKHLZopxEBTaIyfv0wg=="
}
}
}
diff --git a/src/YamlValidator/Microsoft.PowerPlatform.PowerApps.YamlValidator.csproj b/src/YamlValidator/Microsoft.PowerPlatform.PowerApps.YamlValidator.csproj
index 17a85fcf..e47c681c 100644
--- a/src/YamlValidator/Microsoft.PowerPlatform.PowerApps.YamlValidator.csproj
+++ b/src/YamlValidator/Microsoft.PowerPlatform.PowerApps.YamlValidator.csproj
@@ -1,7 +1,7 @@
- netstandard2.0;net8.0
+ net48;net8.0
Latest
enable
enable
@@ -19,7 +19,6 @@
-
diff --git a/src/YamlValidator/SchemaLoader.cs b/src/YamlValidator/SchemaLoader.cs
index 85e3e4fc..e67cce36 100644
--- a/src/YamlValidator/SchemaLoader.cs
+++ b/src/YamlValidator/SchemaLoader.cs
@@ -14,18 +14,12 @@ internal class SchemaLoader
public JsonSchema Load()
{
var assembly = typeof(SchemaLoader).Assembly;
+ var assemblyName = assembly.GetName().Name;
JsonSchema? node = null;
foreach (var file in assembly.GetManifestResourceNames())
{
- var fileStream = assembly.GetManifestResourceStream(file);
- var assemblyName = assembly.GetName().Name;
- if (fileStream == null)
- {
- throw new YamlValidatorLibraryException($"The schema could not be loaded from assembly.");
- }
- using var streamReader = new StreamReader(fileStream);
- var jsonSchemaString = streamReader.ReadToEnd();
+ string jsonSchemaString = ReadSchemaFromManifestFile(assembly, file);
var schema = JsonSchema.FromText(jsonSchemaString);
// assembly name is Microsoft.PowerPlatform.PowerApps.Persistence
@@ -48,6 +42,14 @@ public JsonSchema Load()
throw new YamlValidatorLibraryException("The schema could not be serialized from the assembly.");
}
return node;
+
+ static string ReadSchemaFromManifestFile(System.Reflection.Assembly assembly, string file)
+ {
+ var fileStream = assembly.GetManifestResourceStream(file)
+ ?? throw new YamlValidatorLibraryException($"The schema could not be loaded from assembly.");
+ using var streamReader = new StreamReader(fileStream);
+ return streamReader.ReadToEnd();
+ }
}
}
diff --git a/src/YamlValidator/Validator.cs b/src/YamlValidator/Validator.cs
index e3154d2e..7042dd13 100644
--- a/src/YamlValidator/Validator.cs
+++ b/src/YamlValidator/Validator.cs
@@ -12,12 +12,14 @@ internal class Validator : IValidator
{
private readonly EvaluationOptions _verbosityOptions;
private readonly JsonSchema _schema;
+
public Validator(EvaluationOptions options, JsonSchema schema)
{
// to do: add verbosity flag and allow users to choose verbosity of evaluation
_verbosityOptions = options;
_schema = schema;
}
+
public ValidatorResults Validate(string yamlFileData)
{
YamlStream yamlStream;
@@ -27,36 +29,30 @@ public ValidatorResults Validate(string yamlFileData)
}
catch (YamlException)
{
- return new ValidatorResults(false, new List { new(Constants.notYamlError) });
+ return new ValidatorResults(false, [new(Constants.notYamlError)]);
}
- var jsonData = yamlStream.Documents.Count > 0 ? yamlStream.Documents[0].ToJsonNode() : null;
-
// here we say that empty yaml is serialized as null json
- if (jsonData == null)
+ if (yamlStream.Documents.Count <= 0)
{
- return new ValidatorResults(false, new List { new(Constants.emptyYamlError) });
+ return new(false, [new(Constants.emptyYamlError)]);
}
+
+ var jsonData = yamlStream.Documents[0].ToJsonNode();
var results = _schema.Evaluate(jsonData, _verbosityOptions);
- var schemaValidity = results.IsValid;
var yamlValidatorErrors = new List();
- if (!schemaValidity)
+ if (!results.IsValid && results.Details is not null)
{
- IReadOnlyList traceList = results.Details.Where(
- node => !node.IsValid &&
- node.HasErrors).ToList();
+ var traceList = results.Details.Where(node => !node.IsValid);
foreach (var trace in traceList)
{
var instanceLocation = trace.InstanceLocation.ToString();
var schemaPath = trace.EvaluationPath.ToString();
- var errors = trace.Errors;
- yamlValidatorErrors.Add(new ValidatorError(instanceLocation, schemaPath, errors));
+ yamlValidatorErrors.Add(new(instanceLocation, schemaPath, trace.Errors));
}
}
- IReadOnlyList fileErrors = yamlValidatorErrors;
- var finalResults = new ValidatorResults(results.IsValid, fileErrors);
- return finalResults;
+ return new(results.IsValid, yamlValidatorErrors);
}
}